[PATCH] Improve geometric types

Started by Emre Hasegeliover 8 years ago125 messages
#1Emre Hasegeli
emre@hasegeli.com
4 attachment(s)

This is my next attempt to bring more sanity to the geometric types.
After the previous one [1]/messages/by-id/CAE2gYzwwxPWbzxY3mtN4WL7W0DCkWo8gnB2ThUHU2XQ9XwgHMg@mail.gmail.com went nowhere, I extracted the parts I can
fix without touching the EPSILON. I still hope to improve the
problems around EPSILON after this. I organised the changes as 4
patches for ease of review:

== geo-funcs-v1 ==

Refactor geometric functions and operators code

The geometric types were not using each other's functions. I believe
the reason behind this is simpler types line point and line being
developed after more complicated ones. This patch reduces duplicate
code and makes functions of different datatypes more compatible. We can
do much better than that, but it would require touching many more lines.
The changes can be summarised as:

* Re-use more functions to implement others
* Unify *_construct functions to obtain pre-allocated memory
* Unify *_interpt_internal functions to obtain pre-allocated memory
* Remove private functions from geo_decls.h
* Switch using C11 hypot() as the comment suggested

src/backend/utils/adt/geo_ops.c | 810 +++++++++++++-------------------
src/include/utils/geo_decls.h | 12 +-
src/test/regress/regress.c | 11 +-
3 files changed, 345 insertions(+), 488 deletions(-)

== float-header-v04 ==

Provide header file for built-in float datatypes

Even though, some datatypes under adt/ have separate header files,
most of the simple ones do not. Their public functions were on
the builtins.h. We would need to make more functions of floats public
to let the geometric types built on top of them. This is a good
opportunity to make a separate header file for floats.

1acf7572554515b99ef6e783750aaea8777524ec made _cmp functions public
to solve NaN problem locally for GiST indexes. This patch reworks it
in favour of a more extensive API. Kevin Grittner suggested to design
the API using inline functions. They are easier to use compared
to macros, and avoid double-evaluation hazards.

contrib/btree_gin/btree_gin.c | 3 +-
contrib/btree_gist/btree_ts.c | 2 +-
contrib/cube/cube.c | 2 +-
contrib/postgres_fdw/postgres_fdw.c | 2 +-
src/backend/access/gist/gistget.c | 2 +-
src/backend/access/gist/gistproc.c | 55 +-
src/backend/access/gist/gistutil.c | 2 +-
src/backend/utils/adt/float.c | 593 ++++--------------
src/backend/utils/adt/formatting.c | 8 +-
src/backend/utils/adt/geo_ops.c | 6 +-
src/backend/utils/adt/geo_spgist.c | 2 +-
src/backend/utils/adt/numeric.c | 1 +
src/backend/utils/adt/rangetypes_gist.c | 3 +-
src/backend/utils/adt/rangetypes_selfuncs.c | 3 +-
src/backend/utils/adt/rangetypes_typanalyze.c | 3 +-
src/backend/utils/adt/timestamp.c | 1 +
src/backend/utils/misc/guc.c | 1 +
src/include/utils/builtins.h | 14 -
src/include/utils/float.h | 383 +++++++++++
src/include/utils/geo_decls.h | 1 +
20 files changed, 561 insertions(+), 526 deletions(-)

== geo-float-v1 ==

Use the built-in float datatype to implement geometric types

This will provide:

* Check for underflow and overflow
* Check for division by zero
* Handle NaNs consistently

The patch also replaces all occurrences of "double" as "float8". They
are the same, but were randomly spread around on the same file.

src/backend/access/gist/gistproc.c | 156 +++++----
src/backend/utils/adt/geo_ops.c | 546 +++++++++++++++--------------
src/backend/utils/adt/geo_spgist.c | 36 +-
src/include/utils/float.h | 13 +
src/include/utils/geo_decls.h | 40 +--
5 files changed, 412 insertions(+), 379 deletions(-)

== line-fixes-v1 ==

Fix obvious problems around the line datatype

I have noticed some line operators retuning wrong results, and Tom Lane
spotted similar problems on more places. Source history reveals that
during 1990s, the internal format of the line datatype is changed, but
most functions haven't got the hint. The fixes are:

* Make operators more symmetric
* Reject invalid specification A=B=0 on receive
* Avoid division by zero on perpendicular operator
* Fix intersection and distance operators when neither A nor B is 1
* Avoid point distance operator crashing on float precision loss
* Fix line segment distance by getting the minimum as the comment suggested

Previous discussion:
/messages/by-id/CAE2gYzw_-z=V2kh8QqFjenu=8MJXzOP44wRW=AzzeamrmTT1=Q@mail.gmail.com

src/backend/utils/adt/geo_ops.c | 115 +++++++++++++++++++++-----------
1 file changed, 77 insertions(+), 38 deletions(-)

[1]: /messages/by-id/CAE2gYzwwxPWbzxY3mtN4WL7W0DCkWo8gnB2ThUHU2XQ9XwgHMg@mail.gmail.com

Attachments:

0003-geo-float-v1.patchapplication/octet-stream; name=0003-geo-float-v1.patchDownload
From a7739d406a9ba47ef6927c3490897a22b96d7861 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 27 May 2017 16:17:42 -0400
Subject: [PATCH 3/4] geo-float-v1

Use the built-in float datatype to implement geometric types

This will provide:

* Check for underflow and overflow
* Check for division by zero
* Handle NaNs consistently

The patch also replaces all occurrences of "double" as "float8".  They
are the same, but were randomly spread around on the same file.
---
 src/backend/access/gist/gistproc.c | 156 +++++------
 src/backend/utils/adt/geo_ops.c    | 546 +++++++++++++++++++------------------
 src/backend/utils/adt/geo_spgist.c |  36 +--
 src/include/utils/float.h          |  13 +
 src/include/utils/geo_decls.h      |  40 ++-
 5 files changed, 412 insertions(+), 379 deletions(-)

diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index 818f5e3263..8a7a9a9faf 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -16,20 +16,21 @@
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/geo_decls.h"
 
 
 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
 						 StrategyNumber strategy);
 static bool rtree_internal_consistent(BOX *key, BOX *query,
 						  StrategyNumber strategy);
 
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
@@ -48,55 +49,56 @@ rt_box_union(BOX *n, const BOX *a, const BOX *b)
 	n->high.x = float8_max(a->high.x, b->high.x);
 	n->high.y = float8_max(a->high.y, b->high.y);
 	n->low.x = float8_min(a->low.x, b->low.x);
 	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
 	if (float8_le(box->high.x, box->low.x) ||
 		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
-	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
+	return float8_mul(float8_mi(box->high.x, box->low.x),
+					  float8_mi(box->high.y, box->low.y));
 }
 
 /*
  * Return amount by which the union of the two boxes is larger than
  * the original BOX's area.  The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 box_penalty(const BOX *original, const BOX *new)
 {
 	BOX			unionbox;
 
 	rt_box_union(&unionbox, original, new);
-	return size_box(&unionbox) - size_box(original);
+	return float8_mi(size_box(&unionbox), size_box(original));
 }
 
 /*
  * The GiST Consistent method for boxes
  *
  * Should return false if for all data items x below entry,
  * the predicate x op query must be FALSE, where op is the oper
  * corresponding to strategy in the pg_amop table.
  */
 Datum
@@ -284,74 +286,74 @@ fallbackSplit(GistEntryVector *entryvec, GIST_SPLITVEC *v)
 
 /*
  * Represents information about an entry that can be placed to either group
  * without affecting overlap over selected axis ("common entry").
  */
 typedef struct
 {
 	/* Index of entry in the initial array */
 	int			index;
 	/* Delta between penalties of entry insertion into different groups */
-	double		delta;
+	float8		delta;
 } CommonEntry;
 
 /*
  * Context for g_box_consider_split. Contains information about currently
  * selected split and some general information.
  */
 typedef struct
 {
 	int			entriesCount;	/* total number of entries being split */
 	BOX			boundingBox;	/* minimum bounding box across all entries */
 
 	/* Information about currently selected split follows */
 
 	bool		first;			/* true if no split was selected yet */
 
-	double		leftUpper;		/* upper bound of left interval */
-	double		rightLower;		/* lower bound of right interval */
+	float8		leftUpper;		/* upper bound of left interval */
+	float8		rightLower;		/* lower bound of right interval */
 
 	float4		ratio;
 	float4		overlap;
 	int			dim;			/* axis of this split */
-	double		range;			/* width of general MBR projection to the
+	float8		range;			/* width of general MBR projection to the
 								 * selected axis */
 } ConsiderSplitContext;
 
 /*
  * Interval represents projection of box to axis.
  */
 typedef struct
 {
-	double		lower,
+	float8		lower,
 				upper;
 } SplitInterval;
 
 /*
  * Interval comparison function by lower bound of the interval;
  */
 static int
 interval_cmp_lower(const void *i1, const void *i2)
 {
-	double		lower1 = ((const SplitInterval *) i1)->lower,
+	float8		lower1 = ((const SplitInterval *) i1)->lower,
 				lower2 = ((const SplitInterval *) i2)->lower;
 
 	return float8_cmp_internal(lower1, lower2);
 }
 
 /*
  * Interval comparison function by upper bound of the interval;
  */
 static int
 interval_cmp_upper(const void *i1, const void *i2)
 {
-	double		upper1 = ((const SplitInterval *) i1)->upper,
+	float8		upper1 = ((const SplitInterval *) i1)->upper,
 				upper2 = ((const SplitInterval *) i2)->upper;
 
 	return float8_cmp_internal(upper1, upper2);
 }
 
 /*
  * Replace negative (or NaN) value with zero.
  */
 static inline float
 non_negative(float val)
@@ -360,28 +362,28 @@ non_negative(float val)
 		return val;
 	else
 		return 0.0f;
 }
 
 /*
  * Consider replacement of currently selected split with the better one.
  */
 static inline void
 g_box_consider_split(ConsiderSplitContext *context, int dimNum,
-					 double rightLower, int minLeftCount,
-					 double leftUpper, int maxLeftCount)
+					 float8 rightLower, int minLeftCount,
+					 float8 leftUpper, int maxLeftCount)
 {
 	int			leftCount,
 				rightCount;
 	float4		ratio,
 				overlap;
-	double		range;
+	float8		range;
 
 	/*
 	 * Calculate entries distribution ratio assuming most uniform distribution
 	 * of common entries.
 	 */
 	if (minLeftCount >= (context->entriesCount + 1) / 2)
 	{
 		leftCount = minLeftCount;
 	}
 	else
@@ -390,52 +392,54 @@ g_box_consider_split(ConsiderSplitContext *context, int dimNum,
 			leftCount = maxLeftCount;
 		else
 			leftCount = context->entriesCount / 2;
 	}
 	rightCount = context->entriesCount - leftCount;
 
 	/*
 	 * Ratio of split - quotient between size of lesser group and total
 	 * entries count.
 	 */
-	ratio = ((float4) Min(leftCount, rightCount)) /
-		((float4) context->entriesCount);
+	ratio = float4_div(Min(leftCount, rightCount), context->entriesCount);
 
-	if (ratio > LIMIT_RATIO)
+	if (float4_gt(ratio, LIMIT_RATIO))
 	{
 		bool		selectthis = false;
 
 		/*
 		 * The ratio is acceptable, so compare current split with previously
 		 * selected one. Between splits of one dimension we search for minimal
 		 * overlap (allowing negative values) and minimal ration (between same
 		 * overlaps. We switch dimension if find less overlap (non-negative)
 		 * or less range with same overlap.
 		 */
 		if (dimNum == 0)
-			range = context->boundingBox.high.x - context->boundingBox.low.x;
+			range = float8_mi(context->boundingBox.high.x,
+							  context->boundingBox.low.x);
 		else
-			range = context->boundingBox.high.y - context->boundingBox.low.y;
+			range = float8_mi(context->boundingBox.high.y,
+							  context->boundingBox.low.y);
 
-		overlap = (leftUpper - rightLower) / range;
+		overlap = float8_div(float8_mi(leftUpper, rightLower), range);
 
 		/* If there is no previous selection, select this */
 		if (context->first)
 			selectthis = true;
 		else if (context->dim == dimNum)
 		{
 			/*
 			 * Within the same dimension, choose the new split if it has a
 			 * smaller overlap, or same overlap but better ratio.
 			 */
-			if (overlap < context->overlap ||
-				(overlap == context->overlap && ratio > context->ratio))
+			if (float4_lt(overlap, context->overlap) ||
+				(float4_eq(overlap, context->overlap) &&
+				 float4_gt(ratio, context->ratio)))
 				selectthis = true;
 		}
 		else
 		{
 			/*
 			 * Across dimensions, choose the new split if it has a smaller
 			 * *non-negative* overlap, or same *non-negative* overlap but
 			 * bigger range. This condition differs from the one described in
 			 * the article. On the datasets where leaf MBRs don't overlap
 			 * themselves, non-overlapping splits (i.e. splits which have zero
@@ -444,55 +448,49 @@ g_box_consider_split(ConsiderSplitContext *context, int dimNum,
 			 * non-overlapping splits (i.e. having lowest negative overlap)
 			 * appears to be in the same dimension as in the previous split.
 			 * Therefore MBRs appear to be very prolonged along another
 			 * dimension, which leads to bad search performance. Using range
 			 * as the second split criteria makes MBRs more quadratic. Using
 			 * *non-negative* overlap instead of overlap as the first split
 			 * criteria gives to range criteria a chance to matter, because
 			 * non-overlapping splits are equivalent in this criteria.
 			 */
 			if (non_negative(overlap) < non_negative(context->overlap) ||
-				(range > context->range &&
+				(float4_gt(range, context->range) &&
 				 non_negative(overlap) <= non_negative(context->overlap)))
 				selectthis = true;
 		}
 
 		if (selectthis)
 		{
 			/* save information about selected split */
 			context->first = false;
 			context->ratio = ratio;
 			context->range = range;
 			context->overlap = overlap;
 			context->rightLower = rightLower;
 			context->leftUpper = leftUpper;
 			context->dim = dimNum;
 		}
 	}
 }
 
 /*
  * Compare common entries by their deltas.
- * (We assume the deltas can't be NaN.)
  */
 static int
 common_entry_cmp(const void *i1, const void *i2)
 {
-	double		delta1 = ((const CommonEntry *) i1)->delta,
+	float8		delta1 = ((const CommonEntry *) i1)->delta,
 				delta2 = ((const CommonEntry *) i2)->delta;
 
-	if (delta1 < delta2)
-		return -1;
-	else if (delta1 > delta2)
-		return 1;
-	else
-		return 0;
+	return float8_cmp_internal(delta1, delta2);
 }
 
 /*
  * --------------------------------------------------------------------------
  * Double sorting split algorithm. This is used for both boxes and points.
  *
  * The algorithm finds split of boxes by considering splits along each axis.
  * Each entry is first projected as an interval on the X-axis, and different
  * ways to split the intervals into two groups are considered, trying to
  * minimize the overlap of the groups. Then the same is repeated for the
@@ -552,21 +550,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		else
 			adjustBox(&context.boundingBox, box);
 	}
 
 	/*
 	 * Iterate over axes for optimal split searching.
 	 */
 	context.first = true;		/* nothing selected yet */
 	for (dim = 0; dim < 2; dim++)
 	{
-		double		leftUpper,
+		float8		leftUpper,
 					rightLower;
 		int			i1,
 					i2;
 
 		/* Project each entry as an interval on the selected axis. */
 		for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 		{
 			box = DatumGetBoxP(entryvec->vector[i].key);
 			if (dim == 0)
 			{
@@ -749,21 +747,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 			*rightBox = *(box);					\
 		v->spl_right[v->spl_nright++] = off;	\
 	} while(0)
 
 	/*
 	 * Distribute entries which can be distributed unambiguously, and collect
 	 * common entries.
 	 */
 	for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 	{
-		double		lower,
+		float8		lower,
 					upper;
 
 		/*
 		 * Get upper and lower bounds along selected axis.
 		 */
 		box = DatumGetBoxP(entryvec->vector[i].key);
 		if (context.dim == 0)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
@@ -804,31 +802,31 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
 	{
 		/*
 		 * Calculate minimum number of entries that must be placed in both
 		 * groups, to reach LIMIT_RATIO.
 		 */
-		int			m = ceil(LIMIT_RATIO * (double) nentries);
+		int			m = ceil(LIMIT_RATIO * (float8) nentries);
 
 		/*
 		 * Calculate delta between penalties of join "common entries" to
 		 * different groups.
 		 */
 		for (i = 0; i < commonEntriesCount; i++)
 		{
 			box = DatumGetBoxP(entryvec->vector[commonEntries[i].index].key);
-			commonEntries[i].delta = Abs(box_penalty(leftBox, box) -
-										 box_penalty(rightBox, box));
+			commonEntries[i].delta = Abs(float8_mi(box_penalty(leftBox, box),
+												   box_penalty(rightBox, box)));
 		}
 
 		/*
 		 * Sort "common entries" by calculated deltas in order to distribute
 		 * the most ambiguous entries first.
 		 */
 		qsort(commonEntries, commonEntriesCount, sizeof(CommonEntry), common_entry_cmp);
 
 		/*
 		 * Distribute "common entries" between groups.
@@ -1128,24 +1126,24 @@ gist_circle_compress(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	GISTENTRY  *retval;
 
 	if (entry->leafkey)
 	{
 		CIRCLE	   *in = DatumGetCircleP(entry->key);
 		BOX		   *r;
 
 		r = (BOX *) palloc(sizeof(BOX));
-		r->high.x = in->center.x + in->radius;
-		r->low.x = in->center.x - in->radius;
-		r->high.y = in->center.y + in->radius;
-		r->low.y = in->center.y - in->radius;
+		r->high.x = float8_pl(in->center.x, in->radius);
+		r->low.x = float8_mi(in->center.x, in->radius);
+		r->high.y = float8_pl(in->center.y, in->radius);
+		r->low.y = float8_mi(in->center.y, in->radius);
 
 		retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
 		gistentryinit(*retval, PointerGetDatum(r),
 					  entry->rel, entry->page,
 					  entry->offset, FALSE);
 	}
 	else
 		retval = entry;
 	PG_RETURN_POINTER(retval);
 }
@@ -1169,24 +1167,24 @@ gist_circle_consistent(PG_FUNCTION_ARGS)
 	*recheck = true;
 
 	if (DatumGetBoxP(entry->key) == NULL || query == NULL)
 		PG_RETURN_BOOL(FALSE);
 
 	/*
 	 * Since the operators require recheck anyway, we can just use
 	 * rtree_internal_consistent even at leaf nodes.  (This works in part
 	 * because the index entries are bounding boxes not circles.)
 	 */
-	bbox.high.x = query->center.x + query->radius;
-	bbox.low.x = query->center.x - query->radius;
-	bbox.high.y = query->center.y + query->radius;
-	bbox.low.y = query->center.y - query->radius;
+	bbox.high.x = float8_pl(query->center.x, query->radius);
+	bbox.low.x = float8_mi(query->center.x, query->radius);
+	bbox.high.y = float8_pl(query->center.y, query->radius);
+	bbox.low.y = float8_mi(query->center.y, query->radius);
 
 	result = rtree_internal_consistent(DatumGetBoxP(entry->key),
 									   &bbox, strategy);
 
 	PG_RETURN_BOOL(result);
 }
 
 /**************************************************
  * Point ops
  **************************************************/
@@ -1237,80 +1235,84 @@ gist_point_fetch(PG_FUNCTION_ARGS)
 				  entry->offset, FALSE);
 
 	PG_RETURN_POINTER(retval);
 }
 
 
 #define point_point_distance(p1,p2) \
 	DatumGetFloat8(DirectFunctionCall2(point_distance, \
 									   PointPGetDatum(p1), PointPGetDatum(p2)))
 
-static double
+static float8
 computeDistance(bool isLeaf, BOX *box, Point *point)
 {
-	double		result = 0.0;
+	float8		result = 0.0;
 
 	if (isLeaf)
 	{
 		/* simple point to point distance */
 		result = point_point_distance(point, &box->low);
 	}
-	else if (point->x <= box->high.x && point->x >= box->low.x &&
-			 point->y <= box->high.y && point->y >= box->low.y)
+	else if (float8_le(point->x, box->high.x) &&
+			 float8_ge(point->x, box->low.x) &&
+			 float8_le(point->y, box->high.y) &&
+			 float8_ge(point->y, box->low.y))
 	{
 		/* point inside the box */
 		result = 0.0;
 	}
-	else if (point->x <= box->high.x && point->x >= box->low.x)
+	else if (float8_le(point->x, box->high.x) &&
+			 float8_ge(point->x, box->low.x))
 	{
 		/* point is over or below box */
-		Assert(box->low.y <= box->high.y);
-		if (point->y > box->high.y)
-			result = point->y - box->high.y;
-		else if (point->y < box->low.y)
-			result = box->low.y - point->y;
+		Assert(float8_le(box->low.y, box->high.y));
+		if (float8_gt(point->y, box->high.y))
+			result = float8_mi(point->y, box->high.y);
+		else if (float8_lt(point->y, box->low.y))
+			result = float8_mi(box->low.y, point->y);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
-	else if (point->y <= box->high.y && point->y >= box->low.y)
+	else if (float8_le(point->y, box->high.y) &&
+			 float8_ge(point->y, box->low.y))
 	{
 		/* point is to left or right of box */
-		Assert(box->low.x <= box->high.x);
-		if (point->x > box->high.x)
-			result = point->x - box->high.x;
-		else if (point->x < box->low.x)
-			result = box->low.x - point->x;
+		Assert(float8_lt(box->low.x, box->high.x));
+		if (float8_gt(point->x, box->high.x))
+			result = float8_mi(point->x, box->high.x);
+		else if (float8_lt(point->x, box->low.x))
+			result = float8_mi(box->low.x, point->x);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
 	else
 	{
 		/* closest point will be a vertex */
 		Point		p;
-		double		subresult;
+		float8		subresult;
 
 		result = point_point_distance(point, &box->low);
 
 		subresult = point_point_distance(point, &box->high);
-		if (result > subresult)
+		if (float8_gt(result, subresult))
 			result = subresult;
 
 		p.x = box->low.x;
 		p.y = box->high.y;
 		subresult = point_point_distance(point, &p);
-		if (result > subresult)
+		if (float8_gt(result, subresult))
 			result = subresult;
 
 		p.x = box->high.x;
 		p.y = box->low.y;
 		subresult = point_point_distance(point, &p);
-		if (result > subresult)
+		if (float8_gt(result, subresult))
 			result = subresult;
 	}
 
 	return result;
 }
 
 static bool
 gist_point_consistent_internal(StrategyNumber strategy,
 							   bool isLeaf, BOX *key, Point *query)
 {
@@ -1391,24 +1393,24 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 				 * Instead we write a non-fuzzy overlap test.  The same code
 				 * will also serve for leaf-page tests, since leaf keys have
 				 * high == low.
 				 */
 				BOX		   *query,
 						   *key;
 
 				query = PG_GETARG_BOX_P(1);
 				key = DatumGetBoxP(entry->key);
 
-				result = (key->high.x >= query->low.x &&
-						  key->low.x <= query->high.x &&
-						  key->high.y >= query->low.y &&
-						  key->low.y <= query->high.y);
+				result = (float8_ge(key->high.x, query->low.x) &&
+						  float8_le(key->low.x, query->high.x) &&
+						  float8_ge(key->high.y, query->low.y) &&
+						  float8_le(key->low.y, query->high.y));
 				*recheck = false;
 			}
 			break;
 		case PolygonStrategyNumberGroup:
 			{
 				POLYGON    *query = PG_GETARG_POLYGON_P(1);
 
 				result = DatumGetBool(DirectFunctionCall5(
 														gist_poly_consistent,
 													  PointerGetDatum(entry),
@@ -1417,22 +1419,22 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 											   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);
+					Assert(float8_eq(box->high.x, box->low.x) &&
+						   float8_eq(box->high.y, box->low.y));
 					result = DatumGetBool(DirectFunctionCall2(
 															  poly_contain_pt,
 													 PolygonPGetDatum(query),
 												PointPGetDatum(&box->high)));
 					*recheck = false;
 				}
 			}
 			break;
 		case CircleStrategyNumberGroup:
 			{
@@ -1446,22 +1448,22 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 											   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);
+					Assert(float8_eq(box->high.x, box->low.x) &&
+						   float8_eq(box->high.y, box->low.y));
 					result = DatumGetBool(DirectFunctionCall2(
 														   circle_contain_pt,
 													  CirclePGetDatum(query),
 												PointPGetDatum(&box->high)));
 					*recheck = false;
 				}
 			}
 			break;
 		default:
 			elog(ERROR, "unrecognized strategy number: %d", strategy);
@@ -1470,21 +1472,21 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 	}
 
 	PG_RETURN_BOOL(result);
 }
 
 Datum
 gist_point_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(GIST_LEAF(entry),
 									   DatumGetBoxP(entry->key),
 									   PG_GETARG_POINT_P(1));
 			break;
 		default:
@@ -1499,25 +1501,25 @@ gist_point_distance(PG_FUNCTION_ARGS)
 /*
  * The inexact GiST distance method for geometric types that store bounding
  * boxes.
  *
  * Compute lossy distance from point to index entries.  The result is inexact
  * because index entries are bounding boxes, not the exact shapes of the
  * indexed geometric types.  We use distance from point to MBR of index entry.
  * This is a lower bound estimate of distance from point to indexed geometric
  * type.
  */
-static double
+static float8
 gist_bbox_distance(GISTENTRY *entry, Datum query,
 				   StrategyNumber strategy, bool *recheck)
 {
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	/* Bounding box distance is always inexact. */
 	*recheck = true;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(false,
 									   DatumGetBoxP(entry->key),
@@ -1533,32 +1535,32 @@ gist_bbox_distance(GISTENTRY *entry, Datum query,
 
 Datum
 gist_circle_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
 
 Datum
 gist_poly_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 0936a57778..b1a6d55f8d 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -41,55 +41,55 @@ static void point_sub_internal(Point *result, Point *pt1, Point *pt2);
 static void point_mul_internal(Point *result, Point *pt1, Point *pt2);
 static void point_div_internal(Point *result, Point *pt1, Point *pt2);
 static bool point_eq_internal(Point *pt1, Point *pt2);
 static float8 point_dt(Point *pt1, Point *pt2);
 static float8 point_sl(Point *pt1, Point *pt2);
 static int	point_inside(Point *p, int npts, Point *plist);
 /* Methods on box */
 static void box_construct(BOX *result, float8 x1, float8 x2, float8 y1, float8 y2);
 static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
-static double box_ar(BOX *box);
-static double box_ht(BOX *box);
-static double box_wd(BOX *box);
+static float8 box_ar(BOX *box);
+static float8 box_ht(BOX *box);
+static float8 box_wd(BOX *box);
 /* Methods on circle */
-static double circle_ar(CIRCLE *circle);
+static float8 circle_ar(CIRCLE *circle);
 /* Methods on line */
 static void line_construct_pm(LINE *result, Point *pt, float8 m);
 static void line_construct_pts(LINE *line, Point *pt1, Point *pt2);
 static bool line_interpt_internal(Point *result, LINE *l1, LINE *l2);
 static float8 line_calculate_point(LINE *line, Point *pt);
 /* Methods on line segment */
 static bool lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line);
 static bool lseg_interpt_internal(Point *result, LSEG *l1, LSEG *l2);
 static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
 static float8 lseg_dt(LSEG *l1, LSEG *l2);
-static int	lseg_crossing(double x, double y, double px, double py);
+static int	lseg_crossing(float8 x, float8 y, float8 px, float8 py);
 /* Others */
 static bool on_ps_internal(Point *pt, LSEG *lseg);
 static void make_bound_box(POLYGON *poly);
 static bool plist_same(int npts, Point *p1, Point *p2);
-static double single_decode(char *num, char **endptr_p,
+static float8 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
-static void pair_decode(char *str, double *x, double *y, char **endptr_p,
+static void pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
 static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
 static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
-static double dist_pl_internal(Point *pt, LINE *line);
-static double dist_ps_internal(Point *pt, LSEG *lseg);
-static double dist_ppoly_internal(Point *pt, POLYGON *poly);
+static float8 dist_pl_internal(Point *pt, LINE *line);
+static float8 dist_ps_internal(Point *pt, LSEG *lseg);
+static float8 dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 
 /*
  * Delimiters for input and output strings.
  * LDELIM, RDELIM, and DELIM are left, right, and separator delimiters, respectively.
  * LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints.
  */
 
 #define LDELIM			'('
 #define RDELIM			')'
@@ -118,38 +118,38 @@ static double dist_ppoly_internal(Point *pt, POLYGON *poly);
  *
  * For boxes, the points are opposite corners with the first point at the top right.
  * For closed paths and polygons, the points should be reordered to allow
  *	fast and correct equality comparisons.
  *
  * XXX perhaps points in complex shapes should be reordered internally
  *	to allow faster internal operations, but should keep track of input order
  *	and restore that order for text output - tgl 97/01/16
  */
 
-static double
+static float8
 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string)
 {
 	return float8in_internal(num, endptr_p, type_name, orig_string);
 }	/* single_decode() */
 
 static void
 single_encode(float8 x, StringInfo str)
 {
 	char	   *xstr = float8out_internal(x);
 
 	appendStringInfoString(str, xstr);
 	pfree(xstr);
 }	/* single_encode() */
 
 static void
-pair_decode(char *str, double *x, double *y, char **endptr_p,
+pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string)
 {
 	bool		has_delim;
 
 	while (isspace((unsigned char) *str))
 		str++;
 	if ((has_delim = (*str == LDELIM)))
 		str++;
 
 	*x = float8in_internal(str, &str, type_name, orig_string);
@@ -351,33 +351,33 @@ pair_count(char *s, char delim)
  *		External format: (two corners of box)
  *				"(f8, f8), (f8, f8)"
  *				also supports the older style "(f8, f8, f8, f8)"
  */
 Datum
 box_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	BOX		   *box = (BOX *) palloc(sizeof(BOX));
 	bool		isopen;
-	double		x,
+	float8		x,
 				y;
 
 	path_decode(str, false, 2, &(box->high), &isopen, NULL, "box", str);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*		box_out -		convert a box to external form.
@@ -391,38 +391,38 @@ box_out(PG_FUNCTION_ARGS)
 }
 
 /*
  *		box_recv			- converts external binary format to box
  */
 Datum
 box_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	BOX		   *box;
-	double		x,
+	float8		x,
 				y;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
 	box->high.x = pq_getmsgfloat8(buf);
 	box->high.y = pq_getmsgfloat8(buf);
 	box->low.x = pq_getmsgfloat8(buf);
 	box->low.y = pq_getmsgfloat8(buf);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*
@@ -441,31 +441,31 @@ box_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, box->low.y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*		box_construct	-		fill in a new box.
  */
 static void
 box_construct(BOX *result, float8 x1, float8 x2, float8 y1, float8 y2)
 {
-	if (x1 > x2)
+	if (float8_gt(x1, x2))
 	{
 		result->high.x = x1;
 		result->low.x = x2;
 	}
 	else
 	{
 		result->high.x = x2;
 		result->low.x = x1;
 	}
-	if (y1 > y2)
+	if (float8_gt(y1, y2))
 	{
 		result->high.y = y1;
 		result->low.y = y2;
 	}
 	else
 	{
 		result->high.y = y2;
 		result->low.y = y1;
 	}
 }
@@ -777,54 +777,54 @@ box_center(PG_FUNCTION_ARGS)
 	Point	   *result = (Point *) palloc(sizeof(Point));
 
 	box_cn(result, box);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		box_ar	-		returns the area of the box.
  */
-static double
+static float8
 box_ar(BOX *box)
 {
-	return box_wd(box) * box_ht(box);
+	return float8_mul(box_wd(box), box_ht(box));
 }
 
 
 /*		box_cn	-		stores the centerpoint of the box into *center.
  */
 static void
 box_cn(Point *center, BOX *box)
 {
-	center->x = (box->high.x + box->low.x) / 2.0;
-	center->y = (box->high.y + box->low.y) / 2.0;
+	center->x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	center->y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 }
 
 
 /*		box_wd	-		returns the width (length) of the box
  *								  (horizontal magnitude).
  */
-static double
+static float8
 box_wd(BOX *box)
 {
-	return box->high.x - box->low.x;
+	return float8_mi(box->high.x, box->low.x);
 }
 
 
 /*		box_ht	-		returns the height of the box
  *								  (vertical magnitude).
  */
-static double
+static float8
 box_ht(BOX *box)
 {
-	return box->high.y - box->low.y;
+	return float8_mi(box->high.y, box->low.y);
 }
 
 
 /*----------------------------------------------------------
  *	Funky operations.
  *---------------------------------------------------------*/
 
 /*		box_intersect	-
  *				returns the overlapping portion of two boxes,
  *				  or NULL if they do not intersect.
@@ -834,24 +834,24 @@ box_intersect(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 	BOX		   *result;
 
 	if (!box_ov(box1, box2))
 		PG_RETURN_NULL();
 
 	result = (BOX *) palloc(sizeof(BOX));
 
-	result->high.x = Min(box1->high.x, box2->high.x);
-	result->low.x = Max(box1->low.x, box2->low.x);
-	result->high.y = Min(box1->high.y, box2->high.y);
-	result->low.y = Max(box1->low.y, box2->low.y);
+	result->high.x = float8_min(box1->high.x, box2->high.x);
+	result->low.x = float8_max(box1->low.x, box2->low.x);
+	result->high.y = float8_min(box1->high.y, box2->high.y);
+	result->low.y = float8_max(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(result);
 }
 
 
 /*		box_diagonal	-
  *				returns a line segment which happens to be the
  *				  positive-slope diagonal of "box".
  */
 Datum
@@ -982,65 +982,65 @@ line_send(PG_FUNCTION_ARGS)
 
 /* line_construct_pm()
  * point-slope
  */
 static void
 line_construct_pm(LINE *result, Point *pt, float8 m)
 {
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
-		result->A = -1;
-		result->B = 0;
+		result->A = -1.0;
+		result->B = 0.0;
 		result->C = pt->x;
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
-		result->C = pt->y - m * pt->x;
+		result->C = float8_mi(pt->y, float8_mul(m, pt->x));
 	}
 }
 
 /*
  * Fill already-allocated LINE struct from two points on the line
  */
 static void
 line_construct_pts(LINE *line, Point *pt1, Point *pt2)
 {
 	if (FPeq(pt1->x, pt2->x))
 	{							/* vertical */
 		/* use "x = C" */
-		line->A = -1;
-		line->B = 0;
+		line->A = -1.0;
+		line->B = 0.0;
 		line->C = pt1->x;
 #ifdef GEODEBUG
 		printf("line_construct_pts- line is vertical\n");
 #endif
 	}
 	else if (FPeq(pt1->y, pt2->y))
 	{							/* horizontal */
 		/* use "y = C" */
-		line->A = 0;
-		line->B = -1;
+		line->A = 0.0;
+		line->B = -1.0;
 		line->C = pt1->y;
 #ifdef GEODEBUG
 		printf("line_construct_pts- line is horizontal\n");
 #endif
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		line->A = point_sl(pt2, pt1);
 		line->B = -1.0;
-		line->C = pt1->y - line->A * pt1->x;
+		line->C = float8_mi(pt1->y, float8_mul(line->A, pt1->x));
 		/* on some platforms, the preceding expression tends to produce -0 */
 		if (line->C == 0.0)
 			line->C = 0.0;
 #ifdef GEODEBUG
 		printf("line_construct_pts- line is neither vertical nor horizontal (diffs x=%.*g, y=%.*g\n",
 			   DBL_DIG, (pt2->x - pt1->x), DBL_DIG, (pt2->y - pt1->y));
 #endif
 	}
 }
 
@@ -1060,21 +1060,22 @@ line_construct_pp(PG_FUNCTION_ARGS)
 
 /*
  * Calculate the line equation for a point
  *
  * This returns the result of the line equation Ax + By + C.  The result
  * needs to be 0 for the point to be on the line.
  */
 static float8
 line_calculate_point(LINE *line, Point *pt)
 {
-	return line->A * pt->x + line->B * pt->y + line->C;
+	return float8_pl(float8_pl(float8_mul(line->A, pt->x),
+							   float8_mul(line->B, pt->y)), line->C);
 }
 
 
 /*----------------------------------------------------------
  *	Relative position routines.
  *---------------------------------------------------------*/
 
 Datum
 line_intersect(PG_FUNCTION_ARGS)
 {
@@ -1097,21 +1098,22 @@ Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
 	else if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
 
-	PG_RETURN_BOOL(FPeq(((l1->A * l2->B) / (l1->B * l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
+								   float8_mul(l1->B, l2->A)), -1.0));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
@@ -1121,34 +1123,34 @@ line_horizontal(PG_FUNCTION_ARGS)
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->A));
 }
 
 Datum
 line_eq(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	double		k;
+	float8		ratio;
 
 	if (!FPzero(l2->A))
-		k = l1->A / l2->A;
+		ratio = float8_div(l1->A, l2->A);
 	else if (!FPzero(l2->B))
-		k = l1->B / l2->B;
+		ratio = float8_div(l1->B, l2->B);
 	else if (!FPzero(l2->C))
-		k = l1->C / l2->C;
+		ratio = float8_div(l1->C, l2->C);
 	else
-		k = 1.0;
+		ratio = 1.0;
 
-	PG_RETURN_BOOL(FPeq(l1->A, k * l2->A) &&
-				   FPeq(l1->B, k * l2->B) &&
-				   FPeq(l1->C, k * l2->C));
+	PG_RETURN_BOOL(FPeq(l1->A, float8_mul(ratio, l2->A)) &&
+				   FPeq(l1->B, float8_mul(ratio, l2->B)) &&
+				   FPeq(l1->C, float8_mul(ratio, l2->C)));
 }
 
 
 /*----------------------------------------------------------
  *	Line arithmetic routines.
  *---------------------------------------------------------*/
 
 /* line_distance()
  * Distance between two lines.
  */
@@ -1156,21 +1158,21 @@ Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
 	Point		tmp;
 
 	if (line_interpt_internal(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
+		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
 	point_construct(&tmp, 0.0, l1->C);
 	result = dist_pl_internal(&tmp, l2);
 	PG_RETURN_FLOAT8(result);
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
@@ -1193,41 +1195,41 @@ line_interpt(PG_FUNCTION_ARGS)
  * parallel), false if they do not.  This also sets the intersection point
  * to *result, if it is not NULL.
  *
  * NOTE: If the lines are identical then we will find they are parallel
  * and report "no intersection".  This is a little weird, but since
  * there's no *unique* intersection, maybe it's appropriate behavior.
  */
 static bool
 line_interpt_internal(Point *result, LINE *l1, LINE *l2)
 {
-	double		x,
+	float8		x,
 				y;
 
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
 		if (FPzero(l2->B))		/* l2 vertical? */
 			return false;
 
 		x = l1->C;
-		y = (l2->A * x + l2->C);
+		y = float8_pl(float8_mul(l2->A, x), l2->C);
 	}
 	else
 	{
-		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
 			return false;
 
 		if (FPzero(l2->B))
 			x = l2->C;
 		else
-			x = (l1->C - l2->C) / (l2->A - l1->A);
-		y = (l1->A * x + l1->C);
+			x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
+		y = float8_pl(float8_mul(l1->A, x), l1->C);
 	}
 	if (result != NULL)
 		point_construct(result, x, y);
 
 #ifdef GEODEBUG
 	printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
 		   DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
 	printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
 #endif
 
@@ -1254,36 +1256,35 @@ line_interpt_internal(Point *result, LINE *l1, LINE *l2)
  *				"(xcoord, ycoord),... "
  *				"[xcoord, ycoord,... ]"
  *		Also support older format:
  *				"(closed, npts, xcoord, ycoord,... )"
  *---------------------------------------------------------*/
 
 Datum
 path_area(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P(0);
-	double		area = 0.0;
+	float8		area = 0.0;
 	int			i,
 				j;
 
 	if (!path->closed)
 		PG_RETURN_NULL();
 
 	for (i = 0; i < path->npts; i++)
 	{
 		j = (i + 1) % path->npts;
-		area += path->p[i].x * path->p[j].y;
-		area -= path->p[i].y * path->p[j].x;
+		area = float8_pl(area, float8_mul(path->p[i].x, path->p[j].y));
+		area = float8_mi(area, float8_mul(path->p[i].y, path->p[j].x));
 	}
 
-	area *= 0.5;
-	PG_RETURN_FLOAT8(area < 0.0 ? -area : area);
+	PG_RETURN_FLOAT8(float8_div(fabs(area), 2.0));
 }
 
 
 Datum
 path_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	PATH	   *path;
 	bool		isopen;
 	char	   *s;
@@ -1500,31 +1501,31 @@ path_npoints(PG_FUNCTION_ARGS)
 
 	PG_RETURN_INT32(path->npts);
 }
 
 
 Datum
 path_close(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 
-	path->closed = TRUE;
+	path->closed = true;
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_open(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 
-	path->closed = FALSE;
+	path->closed = false;
 
 	PG_RETURN_PATH_P(path);
 }
 
 
 /* path_inter -
  *		Does p1 intersect p2 at any point?
  *		Use bounding boxes for a quick (O(n)) check, then do a
  *		O(n^2) iterative edge check.
  */
@@ -1540,33 +1541,33 @@ path_inter(PG_FUNCTION_ARGS)
 	LSEG		seg1,
 				seg2;
 
 	if (p1->npts <= 0 || p2->npts <= 0)
 		PG_RETURN_BOOL(false);
 
 	b1.high.x = b1.low.x = p1->p[0].x;
 	b1.high.y = b1.low.y = p1->p[0].y;
 	for (i = 1; i < p1->npts; i++)
 	{
-		b1.high.x = Max(p1->p[i].x, b1.high.x);
-		b1.high.y = Max(p1->p[i].y, b1.high.y);
-		b1.low.x = Min(p1->p[i].x, b1.low.x);
-		b1.low.y = Min(p1->p[i].y, b1.low.y);
+		b1.high.x = float8_max(p1->p[i].x, b1.high.x);
+		b1.high.y = float8_max(p1->p[i].y, b1.high.y);
+		b1.low.x = float8_min(p1->p[i].x, b1.low.x);
+		b1.low.y = float8_min(p1->p[i].y, b1.low.y);
 	}
 	b2.high.x = b2.low.x = p2->p[0].x;
 	b2.high.y = b2.low.y = p2->p[0].y;
 	for (i = 1; i < p2->npts; i++)
 	{
-		b2.high.x = Max(p2->p[i].x, b2.high.x);
-		b2.high.y = Max(p2->p[i].y, b2.high.y);
-		b2.low.x = Min(p2->p[i].x, b2.low.x);
-		b2.low.y = Min(p2->p[i].y, b2.low.y);
+		b2.high.x = float8_max(p2->p[i].x, b2.high.x);
+		b2.high.y = float8_max(p2->p[i].y, b2.high.y);
+		b2.low.x = float8_min(p2->p[i].x, b2.low.x);
+		b2.low.y = float8_min(p2->p[i].y, b2.low.y);
 	}
 	if (!box_ov(&b1, &b2))
 		PG_RETURN_BOOL(false);
 
 	/* pairwise check lseg intersections */
 	for (i = 0; i < p1->npts; i++)
 	{
 		int			iprev;
 
 		if (i > 0)
@@ -1642,21 +1643,21 @@ path_distance(PG_FUNCTION_ARGS)
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
 			tmp = lseg_dt(&seg1, &seg2);
-			if (!have_min || tmp < min)
+			if (!have_min || float8_lt(tmp, min))
 			{
 				min = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	if (!have_min)
 		PG_RETURN_NULL();
 
@@ -1681,21 +1682,21 @@ path_length(PG_FUNCTION_ARGS)
 
 		if (i > 0)
 			iprev = i - 1;
 		else
 		{
 			if (!path->closed)
 				continue;
 			iprev = path->npts - 1;		/* include the closure segment */
 		}
 
-		result += point_dt(&path->p[iprev], &path->p[i]);
+		result = float8_pl(result, point_dt(&path->p[iprev], &path->p[i]));
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /***********************************************************************
  **
  **		Routines for 2D points.
  **
  ***********************************************************************/
@@ -1867,43 +1868,48 @@ point_distance(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
 static float8
 point_dt(Point *pt1, Point *pt2)
 {
+	float8		result;
+
+	result = float8_hypot(float8_mi(pt1->x, pt2->x), float8_mi(pt1->y, pt2->y));
+
 #ifdef GEODEBUG
 	printf("point_dt- segment (%f,%f),(%f,%f) length is %f\n",
-	pt1->x, pt1->y, pt2->x, pt2->y, HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
+		   pt1->x, pt1->y, pt2->x, pt2->y, result);
 #endif
-	return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
+
+	return result;
 }
 
 Datum
 point_slope(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_sl(pt1, pt2));
 }
 
 
 static float8
 point_sl(Point *pt1, Point *pt2)
 {
-	return (FPeq(pt1->x, pt2->x)
-			? (double) DBL_MAX
-			: (pt1->y - pt2->y) / (pt1->x - pt2->x));
+	if (FPeq(pt1->x, pt2->x))
+		return DBL_MAX;
+	return float8_div(float8_mi(pt1->y, pt2->y), float8_mi(pt1->x, pt2->x));
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D line segments.
  **
  ***********************************************************************/
 
 /*----------------------------------------------------------
@@ -2043,35 +2049,35 @@ lseg_parallel(PG_FUNCTION_ARGS)
  *	'((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg
  * So, modified it to check explicitly for slope of vertical line
  *	returned by point_sl() and the results seem better.
  * - thomas 1998-01-31
  */
 Datum
 lseg_perp(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	double		m1,
+	float8		m1,
 				m2;
 
 	m1 = point_sl(&l1->p[0], &l1->p[1]);
 	m2 = point_sl(&l2->p[0], &l2->p[1]);
 
 #ifdef GEODEBUG
 	printf("lseg_perp- slopes are %g and %g\n", m1, m2);
 #endif
 	if (FPzero(m1))
 		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
 	else if (FPzero(m2))
 		PG_RETURN_BOOL(FPeq(m1, DBL_MAX));
 
-	PG_RETURN_BOOL(FPeq(m1 / m2, -1.0));
+	PG_RETURN_BOOL(FPeq(float8_div(m1, m2), -1.0));
 }
 
 Datum
 lseg_vertical(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 
 	PG_RETURN_BOOL(FPeq(lseg->p[0].x, lseg->p[1].x));
 }
 
@@ -2161,52 +2167,47 @@ lseg_distance(PG_FUNCTION_ARGS)
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_FLOAT8(lseg_dt(l1, l2));
 }
 
 /* lseg_dt()
  * Distance between two line segments.
  * Must check both sets of endpoints to ensure minimum distance is found.
  * - thomas 1998-02-01
  */
-static double
+static float8
 lseg_dt(LSEG *l1, LSEG *l2)
 {
-	double		result,
-				d;
+	float8		result;
 
 	if (lseg_interpt_internal(NULL, l1, l2))
 		return 0.0;
 
-	d = dist_ps_internal(&l1->p[0], l2);
-	result = d;
-	d = dist_ps_internal(&l1->p[1], l2);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[0], l1);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[1], l1);
-	result = Min(result, d);
+	result = dist_ps_internal(&l1->p[0], l2);
+	result = float8_min(result, dist_ps_internal(&l1->p[1], l2));
+	result = float8_min(result, dist_ps_internal(&l2->p[0], l1));
+	result = float8_min(result, dist_ps_internal(&l2->p[1], l1));
 
 	return result;
 }
 
 
 Datum
 lseg_center(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
-	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
+	result->x = float8_div(float8_pl(lseg->p[0].x, lseg->p[1].x), 2.0);
+	result->y = float8_div(float8_pl(lseg->p[0].y, lseg->p[1].y), 2.0);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static bool
 lseg_interpt_internal(Point *result, LSEG *l1, LSEG *l2)
 {
 	Point		interpt;
 	LINE		tmp1,
 				tmp2;
@@ -2290,58 +2291,58 @@ lseg_interpt(PG_FUNCTION_ARGS)
  */
 Datum
 dist_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
 	PG_RETURN_FLOAT8(dist_pl_internal(pt, line));
 }
 
-static double
+static float8
 dist_pl_internal(Point *pt, LINE *line)
 {
-	return fabs(line_calculate_point(line, pt) /
-				HYPOT(line->A, line->B));
+	return float8_div(fabs(line_calculate_point(line, pt)),
+					  float8_hypot(line->A, line->B));
 }
 
 /*
  * Distance from a point to a lseg
  */
 Datum
 dist_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_FLOAT8(dist_ps_internal(pt, lseg));
 }
 
-static double
+static float8
 dist_ps_internal(Point *pt, LSEG *lseg)
 {
-	double		m;				/* slope of perp. */
-	double		result,
+	float8		m;				/* slope of perp. */
+	float8		result,
 				tmpdist;
 	Point		interpt;
 	LINE		ln;
 
 	/*
 	 * Construct a line perpendicular to the input segment and through the
 	 * input point
 	 */
-	if (lseg->p[1].x == lseg->p[0].x)
-		m = 0;
-	else if (lseg->p[1].y == lseg->p[0].y)
-		m = (double) DBL_MAX;	/* slope is infinite */
+	if (float8_eq(lseg->p[0].x, lseg->p[1].x))
+		m = 0.0;
+	else if (float8_eq(lseg->p[0].y, lseg->p[1].y))
+		m = DBL_MAX;	/* slope is infinite */
 	else
-		m = -1.0 / point_sl(&lseg->p[0], &lseg->p[1]);
+		m = float8_div(-1.0, point_sl(&lseg->p[0], &lseg->p[1]));
 	line_construct_pm(&ln, pt, m);
 
 #ifdef GEODEBUG
 	printf("dist_ps- line is A=%g B=%g C=%g from (point) slope (%f,%f) %g\n",
 		   ln->A, ln->B, ln->C, pt->x, pt->y, m);
 #endif
 
 	/*
 	 * Calculate distance to the line segment or to the nearest endpoint of
 	 * the segment.
@@ -2353,24 +2354,22 @@ dist_ps_internal(Point *pt, LSEG *lseg)
 		/* yes, so use distance to the intersection point */
 		result = point_dt(pt, &interpt);
 #ifdef GEODEBUG
 		printf("dist_ps- distance is %f to intersection point is (%f,%f)\n",
 			   result, tmp.x, tmp.y);
 #endif
 	}
 	else
 	{
 		/* no, so use distance to the nearer endpoint */
-		result = point_dt(pt, &lseg->p[0]);
-		tmpdist = point_dt(pt, &lseg->p[1]);
-		if (tmpdist < result)
-			result = tmpdist;
+		result = float8_min(point_dt(pt, &lseg->p[0]),
+							point_dt(pt, &lseg->p[1]));
 	}
 
 	return result;
 }
 
 /*
  * Distance from a point to a path
  */
 Datum
 dist_ppath(PG_FUNCTION_ARGS)
@@ -2408,21 +2407,21 @@ dist_ppath(PG_FUNCTION_ARGS)
 					iprev = i - 1;
 				else
 				{
 					if (!path->closed)
 						continue;
 					iprev = path->npts - 1;		/* include the closure segment */
 				}
 
 				statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
 				tmp = dist_ps_internal(pt, &lseg);
-				if (!have_min || tmp < result)
+				if (!have_min || float8_lt(tmp, result))
 				{
 					result = tmp;
 					have_min = true;
 				}
 			}
 			break;
 	}
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -2446,33 +2445,28 @@ dist_pb(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
-	float8		result,
-				d2;
+	float8		result;
 
 	if (lseg_interpt_line_internal(NULL, lseg, line))
 		result = 0.0;
 	else
-	{
-		result = dist_pl_internal(&lseg->p[0], line);
-		d2 = dist_pl_internal(&lseg->p[1], line);
 		/* XXX shouldn't we take the min not max? */
-		if (d2 > result)
-			result = d2;
-	}
+		result = float8_max(dist_pl_internal(&lseg->p[0], line),
+							dist_pl_internal(&lseg->p[1], line));
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
@@ -2514,25 +2508,22 @@ dist_lb(PG_FUNCTION_ARGS)
  * Distance from a circle to a polygon
  */
 Datum
 dist_cpoly(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	POLYGON    *poly = PG_GETARG_POLYGON_P(1);
 	float8		result;
 
 	/* calculate distance to center, and subtract radius */
-	result = dist_ppoly_internal(&circle->center, poly);
-
-	result -= circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_min(float8_mi(dist_ppoly_internal(&circle->center, poly),
+								  circle->radius), 0.0);
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a point to a polygon
  */
 Datum
 dist_ppoly(PG_FUNCTION_ARGS)
 {
@@ -2550,21 +2541,21 @@ dist_polyp(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	float8		result;
 
 	result = dist_ppoly_internal(point, poly);
 
 	PG_RETURN_FLOAT8(result);
 }
 
-static double
+static float8
 dist_ppoly_internal(Point *pt, POLYGON *poly)
 {
 	float8		result;
 	float8		d;
 	int			i;
 	LSEG		seg;
 
 	if (point_inside(pt, poly->npts, poly->p) != 0)
 	{
 #ifdef GEODEBUG
@@ -2587,21 +2578,21 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
 	for (i = 0; (i < poly->npts - 1); i++)
 	{
 		seg.p[0].x = poly->p[i].x;
 		seg.p[0].y = poly->p[i].y;
 		seg.p[1].x = poly->p[i + 1].x;
 		seg.p[1].y = poly->p[i + 1].y;
 		d = dist_ps_internal(pt, &seg);
 #ifdef GEODEBUG
 		printf("dist_ppoly_internal- segment %d distance is %f\n", (i + 1), d);
 #endif
-		if (d < result)
+		if (float8_lt(d, result))
 			result = d;
 	}
 
 	return result;
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
  *				Intersection point of objects.
@@ -2655,41 +2646,41 @@ lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line)
 /* close_pl -
  *		The intersection point of a perpendicular of the line
  *		through the point.
  */
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
-	double		invm;
+	float8		invm;
 	LINE		tmp;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (FPzero(line->B))		/* vertical? */
 	{
 		result->x = line->C;
 		result->y = pt->y;
 		PG_RETURN_POINT_P(result);
 	}
 	if (FPzero(line->A))		/* horizontal? */
 	{
 		result->x = pt->x;
 		result->y = line->C;
 		PG_RETURN_POINT_P(result);
 	}
 	/* drop a perpendicular and find the intersection point */
 
 	/* invert and flip the sign on the slope to get a perpendicular */
-	invm = line->B / line->A;
+	invm = float8_div(line->B, line->A);
 	line_construct_pm(&tmp, pt, invm);
 	line_interpt_internal(result, &tmp, line);
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_ps()
  * Closest point on line segment to specified point.
  * Take the closest endpoint if the point is left, right,
  *	above, or below the segment, otherwise find the intersection
@@ -2698,21 +2689,21 @@ close_pl(PG_FUNCTION_ARGS)
  * Some tricky code here, relying on boolean expressions
  *	evaluating to only zero or one to use as an array index.
  *		bug fixes by gthaker@atl.lmco.com; May 1, 1998
  */
 Datum
 close_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
-	double		invm;
+	float8		invm;
 	int			xh,
 				yh;
 	LINE		tmp;
 
 	result = (Point *) palloc(sizeof(Point));
 
 #ifdef GEODEBUG
 	printf("close_sp:pt->x %f pt->y %f\nlseg(0).x %f lseg(0).y %f  lseg(1).x %f lseg(1).y %f\n",
 		   pt->x, pt->y, lseg->p[0].x, lseg->p[0].y,
 		   lseg->p[1].x, lseg->p[1].y);
@@ -2754,35 +2745,35 @@ close_ps(PG_FUNCTION_ARGS)
 			point_construct(result, pt->x, lseg->p[0].y);
 
 		PG_RETURN_POINT_P(result);
 	}
 
 	/*
 	 * vert. and horiz. cases are down, now check if the closest point is one
 	 * of the end points or someplace on the lseg.
 	 */
 
-	invm = -1.0 / point_sl(&(lseg->p[0]), &(lseg->p[1]));
+	invm = float8_div(-1.0, point_sl(&lseg->p[0], &lseg->p[1]));
 	line_construct_pm(&tmp, &lseg->p[!yh], invm);		/* lower edge of the
 														 * "band" */
-	if (pt->y < (tmp.A * pt->x + tmp.C))
+	if (pt->y < float8_pl(float8_mul(tmp.A, pt->x), tmp.C))
 	{							/* we are below the lower edge */
 		*result = lseg->p[!yh];		/* below the lseg, take lower end pt */
 #ifdef GEODEBUG
 		printf("close_ps below: tmp A %f  B %f   C %f\n",
 			   tmp->A, tmp->B, tmp->C);
 #endif
 		PG_RETURN_POINT_P(result);
 	}
 	line_construct_pm(&tmp, &lseg->p[yh], invm);		/* upper edge of the
 														 * "band" */
-	if (pt->y > (tmp.A * pt->x + tmp.C))
+	if (pt->y > float8_pl(float8_mul(tmp.A, pt->x), tmp.C))
 	{							/* we are below the lower edge */
 		*result = lseg->p[yh];		/* above the lseg, take higher end pt */
 #ifdef GEODEBUG
 		printf("close_ps above: tmp A %f  B %f   C %f\n",
 			   tmp->A, tmp->B, tmp->C);
 #endif
 		PG_RETURN_POINT_P(result);
 	}
 
 	/*
@@ -2818,32 +2809,32 @@ close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 	double		dist,
 				dist0,
 				dist1;
 
 	dist0 = dist_ps_internal(&l1->p[0], l2);
 	dist1 = dist_ps_internal(&l1->p[1], l2);
-	dist = Min(dist0, dist1);
+	dist = float8_min(dist0, dist1);
 
-	if (dist_ps_internal(&l2->p[0], l1) < dist)
+	if (float8_lt(dist_ps_internal(&l2->p[0], l1), dist))
 	{
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(&l2->p[0]),
 													LsegPGetDatum(l1)));
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(result),
 													LsegPGetDatum(l2)));
 	}
-	else if (dist_ps_internal(&l2->p[1], l1) < dist)
+	else if (float8_lt(dist_ps_internal(&l2->p[1], l1), dist))
 	{
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(&l2->p[1]),
 													LsegPGetDatum(l1)));
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(result),
 													LsegPGetDatum(l2)));
 	}
 	else
 	{
@@ -2858,52 +2849,55 @@ close_lseg(PG_FUNCTION_ARGS)
  * Closest point on or in box to specified point.
  */
 Datum
 close_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	LSEG		lseg,
 				seg;
 	Point		point;
-	double		dist,
+	float8		dist,
 				d;
 
 	if (DatumGetBool(DirectFunctionCall2(on_pb,
 										 PointPGetDatum(pt),
 										 BoxPGetDatum(box))))
 		PG_RETURN_POINT_P(pt);
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&lseg, &box->low, &point);
 	dist = dist_ps_internal(pt, &lseg);
 
 	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	d = dist_ps_internal(pt, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&lseg, &seg, sizeof(lseg));
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&seg, &box->low, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	d = dist_ps_internal(pt, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&lseg, &seg, sizeof(lseg));
 	}
 
 	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	d = dist_ps_internal(pt, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&lseg, &seg, sizeof(lseg));
 	}
 
 	PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
 										PointPGetDatum(pt),
 										LsegPGetDatum(&lseg)));
 }
 
@@ -2926,21 +2920,21 @@ close_sl(PG_FUNCTION_ARGS)
 	float8		d1,
 				d2;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (lseg_interpt_line_internal(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = dist_pl_internal(&lseg->p[0], line);
 	d2 = dist_pl_internal(&lseg->p[1], line);
-	if (d1 < d2)
+	if (float8_lt(d1, d2))
 		*result = lseg->p[0];
 	else
 		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
 
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_sl\" not implemented")));
@@ -2960,77 +2954,80 @@ close_ls(PG_FUNCTION_ARGS)
 	float8		d1,
 				d2;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (lseg_interpt_line_internal(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = dist_pl_internal(&lseg->p[0], line);
 	d2 = dist_pl_internal(&lseg->p[1], line);
-	if (d1 < d2)
+	if (float8_lt(d1, d2))
 		*result = lseg->p[0];
 	else
 		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 }
 
 /* close_sb()
  * Closest point on or in box to line segment.
  */
 Datum
 close_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	Point		point;
 	LSEG		bseg,
 				seg;
-	double		dist,
+	float8		dist,
 				d;
 
 	/* segment intersects box? then just return closest point to center */
 	if (DatumGetBool(DirectFunctionCall2(inter_sb,
 										 LsegPGetDatum(lseg),
 										 BoxPGetDatum(box))))
 	{
 		box_cn(&point, box);
 		PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
 											PointPGetDatum(&point),
 											LsegPGetDatum(lseg)));
 	}
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
 	dist = lseg_dt(lseg, &bseg);
 
 	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	d = lseg_dt(lseg, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&bseg, &seg, sizeof(bseg));
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&seg, &box->low, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	d = lseg_dt(lseg, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&bseg, &seg, sizeof(bseg));
 	}
 
 	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	d = lseg_dt(lseg, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&bseg, &seg, sizeof(bseg));
 	}
 
 	/* OK, we now have the closest line segment on the box boundary */
 	PG_RETURN_DATUM(DirectFunctionCall2(close_lseg,
 										LsegPGetDatum(lseg),
 										LsegPGetDatum(&bseg)));
 }
@@ -3078,75 +3075,80 @@ on_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_BOOL(on_ps_internal(pt, lseg));
 }
 
 static bool
 on_ps_internal(Point *pt, LSEG *lseg)
 {
-	return FPeq(point_dt(pt, &lseg->p[0]) + point_dt(pt, &lseg->p[1]),
+	return FPeq(float8_pl(point_dt(pt, &lseg->p[0]),
+						  point_dt(pt, &lseg->p[1])),
 				point_dt(&lseg->p[0], &lseg->p[1]));
 }
 
+
 Datum
 on_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_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);
+	PG_RETURN_BOOL(float8_le(pt->x, box->high.x) &&
+				   float8_ge(pt->x, box->low.x) &&
+				   float8_le(pt->y, box->high.y) &&
+				   float8_ge(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);
+	PG_RETURN_BOOL(float8_le(pt->x, box->high.x) &&
+				   float8_ge(pt->x, box->low.x) &&
+				   float8_le(pt->y, box->high.y) &&
+				   float8_ge(pt->y, box->low.y));
 }
 
 /* on_ppath -
  *		Whether a point lies within (on) a polyline.
  *		If open, we have to (groan) check each segment.
  * (uses same algorithm as for point intersecting segment - tgl 1997-07-09)
  *		If closed, we use the old O(n) ray method for point-in-polygon.
  *				The ray is horizontal, from pt out to the right.
  *				Each segment that crosses the ray counts as an
  *				intersection; note that an endpoint or edge may touch
  *				but not cross.
  *				(we can do p-in-p in lg(n), but it takes preprocessing)
  */
 Datum
 on_ppath(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	PATH	   *path = PG_GETARG_PATH_P(1);
 	int			i,
 				n;
-	double		a,
+	float8		a,
 				b;
 
 	/*-- OPEN --*/
 	if (!path->closed)
 	{
 		n = path->npts - 1;
 		a = point_dt(pt, &path->p[0]);
 		for (i = 0; i < n; i++)
 		{
 			b = point_dt(pt, &path->p[i + 1]);
-			if (FPeq(a + b,
-					 point_dt(&path->p[i], &path->p[i + 1])))
+			if (FPeq(float8_pl(a, b), point_dt(&path->p[i], &path->p[i + 1])))
 				PG_RETURN_BOOL(true);
 			a = b;
 		}
 		PG_RETURN_BOOL(false);
 	}
 
 	/*-- CLOSED --*/
 	PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
 }
 
@@ -3204,24 +3206,24 @@ inter_sl(PG_FUNCTION_ARGS)
  */
 Datum
 inter_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	BOX			lbox;
 	LSEG		bseg;
 	Point		point;
 
-	lbox.low.x = Min(lseg->p[0].x, lseg->p[1].x);
-	lbox.low.y = Min(lseg->p[0].y, lseg->p[1].y);
-	lbox.high.x = Max(lseg->p[0].x, lseg->p[1].x);
-	lbox.high.y = Max(lseg->p[0].y, lseg->p[1].y);
+	lbox.low.x = float8_min(lseg->p[0].x, lseg->p[1].x);
+	lbox.low.y = float8_min(lseg->p[0].y, lseg->p[1].y);
+	lbox.high.x = float8_max(lseg->p[0].x, lseg->p[1].x);
+	lbox.high.y = float8_max(lseg->p[0].y, lseg->p[1].y);
 
 	/* nothing close to overlap? then not going to intersect */
 	if (!box_ov(&lbox, box))
 		PG_RETURN_BOOL(false);
 
 	/* an endpoint of segment is inside box? then clearly intersects */
 	if (DatumGetBool(DirectFunctionCall2(on_pb,
 										 PointPGetDatum(&lseg->p[0]),
 										 BoxPGetDatum(box))) ||
 		DatumGetBool(DirectFunctionCall2(on_pb,
@@ -3302,38 +3304,38 @@ inter_lb(PG_FUNCTION_ARGS)
  * make_bound_box - create the bounding box for the input polygon
  *------------------------------------------------------------------*/
 
 /*---------------------------------------------------------------------
  * Make the smallest bounding box for the given polygon.
  *---------------------------------------------------------------------*/
 static void
 make_bound_box(POLYGON *poly)
 {
 	int			i;
-	double		x1,
+	float8		x1,
 				y1,
 				x2,
 				y2;
 
 	if (poly->npts > 0)
 	{
 		x2 = x1 = poly->p[0].x;
 		y2 = y1 = poly->p[0].y;
 		for (i = 1; i < poly->npts; i++)
 		{
-			if (poly->p[i].x < x1)
+			if (float8_lt(poly->p[i].x, x1))
 				x1 = poly->p[i].x;
-			if (poly->p[i].x > x2)
+			if (float8_gt(poly->p[i].x, x2))
 				x2 = poly->p[i].x;
-			if (poly->p[i].y < y1)
+			if (float8_lt(poly->p[i].y, y1))
 				y1 = poly->p[i].y;
-			if (poly->p[i].y > y2)
+			if (float8_gt(poly->p[i].y, y2))
 				y2 = poly->p[i].y;
 		}
 
 		box_construct(&poly->boundbox, x1, x2, y1, y2);
 	}
 	else
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("cannot create bounding box for empty polygon")));
 }
@@ -3461,21 +3463,21 @@ poly_send(PG_FUNCTION_ARGS)
  * the right most point of A left of the left most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_left(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.high.x < polyb->boundbox.low.x;
+	result = float8_lt(polya->boundbox.high.x, polyb->boundbox.low.x);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3484,21 +3486,21 @@ poly_left(PG_FUNCTION_ARGS)
  * the right most point of A at or left of the right most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_overleft(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.high.x <= polyb->boundbox.high.x;
+	result = float8_le(polya->boundbox.high.x, polyb->boundbox.high.x);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3507,21 +3509,21 @@ poly_overleft(PG_FUNCTION_ARGS)
  * the left most point of A right of the right most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_right(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.low.x > polyb->boundbox.high.x;
+	result = float8_gt(polya->boundbox.low.x, polyb->boundbox.high.x);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3530,21 +3532,21 @@ poly_right(PG_FUNCTION_ARGS)
  * the left most point of A at or right of the left most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_overright(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.low.x >= polyb->boundbox.low.x;
+	result = float8_ge(polya->boundbox.low.x, polyb->boundbox.low.x);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3553,21 +3555,21 @@ poly_overright(PG_FUNCTION_ARGS)
  * the upper most point of A below the lower most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_below(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.high.y < polyb->boundbox.low.y;
+	result = float8_lt(polya->boundbox.high.y, polyb->boundbox.low.y);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3576,21 +3578,21 @@ poly_below(PG_FUNCTION_ARGS)
  * the upper most point of A at or below the upper most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_overbelow(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.high.y <= polyb->boundbox.high.y;
+	result = float8_le(polya->boundbox.high.y, polyb->boundbox.high.y);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3599,21 +3601,21 @@ poly_overbelow(PG_FUNCTION_ARGS)
  * the lower most point of A above the upper most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_above(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.low.y > polyb->boundbox.high.y;
+	result = float8_gt(polya->boundbox.low.y, polyb->boundbox.high.y);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3622,21 +3624,21 @@ poly_above(PG_FUNCTION_ARGS)
  * the lower most point of A at or above the lower most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_overabove(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.low.y >= polyb->boundbox.low.y;
+	result = float8_ge(polya->boundbox.low.y, polyb->boundbox.low.y);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3833,22 +3835,22 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 	}
 
 	if (res && !intersection)
 	{
 		Point		p;
 
 		/*
 		 * if X-intersection wasn't found  then check central point of tested
 		 * segment. In opposite case we already check all subsegments
 		 */
-		p.x = (t.p[0].x + t.p[1].x) / 2.0;
-		p.y = (t.p[0].y + t.p[1].y) / 2.0;
+		p.x = float8_div(float8_pl(t.p[0].x, t.p[1].x), 2.0);
+		p.y = float8_div(float8_pl(t.p[0].y, t.p[1].y), 2.0);
 
 		res = point_inside(&p, poly->npts, poly->p);
 	}
 
 	return res;
 }
 
 /*-----------------------------------------------------------------
  * Determine if polygon A contains polygon B.
  *-----------------------------------------------------------------*/
@@ -3975,66 +3977,68 @@ point_add(PG_FUNCTION_ARGS)
 
 	point_add_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static void
 point_add_internal(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x + pt2->x,
-					pt1->y + pt2->y);
+					float8_pl(pt1->x, pt2->x),
+					float8_pl(pt1->y, pt2->y));
 }
 
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	point_sub_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static void
 point_sub_internal(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x - pt2->x,
-					pt1->y - pt2->y);
+					float8_mi(pt1->x, pt2->x),
+					float8_mi(pt1->y, pt2->y));
 }
 
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	point_mul_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static void
 point_mul_internal(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					(pt1->x * pt2->x) - (pt1->y * pt2->y),
-					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+					float8_mi(float8_mul(pt1->x, pt2->x),
+							  float8_mul(pt1->y, pt2->y)),
+					float8_pl(float8_mul(pt1->x, pt2->y),
+							  float8_mul(pt1->y, pt2->x)));
 }
 
 Datum
 point_div(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -4042,24 +4046,26 @@ point_div(PG_FUNCTION_ARGS)
 	point_div_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static void
 point_div_internal(Point *result, Point *pt1, Point *pt2)
 {
 	float8		div;
 
-	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
+	div = float8_pl(float8_mul(pt2->x, pt2->x), float8_mul(pt2->y, pt2->y));
 	point_construct(result,
-					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
-					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+					float8_div(float8_pl(float8_mul(pt1->x, pt2->x),
+										 float8_mul(pt1->y, pt2->y)), div),
+					float8_div(float8_mi(float8_mul(pt1->y, pt2->x),
+										 float8_mul(pt1->x, pt2->y)), div));
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D boxes.
  **
  ***********************************************************************/
 
 Datum
@@ -4168,24 +4174,24 @@ point_box(PG_FUNCTION_ARGS)
  */
 Datum
 boxes_bound_box(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0),
 			   *box2 = PG_GETARG_BOX_P(1),
 			   *container;
 
 	container = (BOX *) palloc(sizeof(BOX));
 
-	container->high.x = Max(box1->high.x, box2->high.x);
-	container->low.x = Min(box1->low.x, box2->low.x);
-	container->high.y = Max(box1->high.y, box2->high.y);
-	container->low.y = Min(box1->low.y, box2->low.y);
+	container->high.x = float8_max(box1->high.x, box2->high.x);
+	container->low.x = float8_min(box1->low.x, box2->low.x);
+	container->high.y = float8_max(box1->high.y, box2->high.y);
+	container->low.y = float8_min(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(container);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D paths.
  **
  ***********************************************************************/
@@ -4495,21 +4501,21 @@ circle_in(PG_FUNCTION_ARGS)
 		if (*cp == LDELIM)
 			s = cp;
 	}
 
 	pair_decode(s, &circle->center.x, &circle->center.y, &s, "circle", str);
 
 	if (*s == DELIM)
 		s++;
 
 	circle->radius = single_decode(s, &s, "circle", str);
-	if (circle->radius < 0)
+	if (float8_lt(circle->radius, 0.0))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
 
 	while (depth > 0)
 	{
 		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
@@ -4562,21 +4568,21 @@ circle_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	circle->center.x = pq_getmsgfloat8(buf);
 	circle->center.y = pq_getmsgfloat8(buf);
 	circle->radius = pq_getmsgfloat8(buf);
 
-	if (circle->radius < 0)
+	if (float8_lt(circle->radius, 0.0))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
 				 errmsg("invalid radius in external \"circle\" value")));
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 /*
  *		circle_send			- converts circle to binary format
  */
@@ -4613,144 +4619,146 @@ circle_same(PG_FUNCTION_ARGS)
 
 /*		circle_overlap	-		does circle1 overlap circle2?
  */
 Datum
 circle_overlap(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle1->radius + circle2->radius));
+						float8_pl(circle1->radius, circle2->radius)));
 }
 
 /*		circle_overleft -		is the right edge of circle1 at or left of
  *								the right edge of circle2?
  */
 Datum
 circle_overleft(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.x + circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_left		-		is circle1 strictly left of circle2?
  */
 Datum
 circle_left(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.x + circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_right	-		is circle1 strictly right of circle2?
  */
 Datum
 circle_right(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.x - circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_overright	-	is the left edge of circle1 at or right of
  *								the left edge of circle2?
  */
 Datum
 circle_overright(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.x - circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_contained		-		is circle1 contained by circle2?
  */
 Datum
 circle_contained(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle1->radius), circle2->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						float8_mi(circle2->radius, circle1->radius)));
 }
 
 /*		circle_contain	-		does circle1 contain circle2?
  */
 Datum
 circle_contain(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle2->radius), circle1->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						float8_mi(circle1->radius, circle2->radius)));
 }
 
 
 /*		circle_below		-		is circle1 strictly below circle2?
  */
 Datum
 circle_below(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.y + circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_above	-		is circle1 strictly above circle2?
  */
 Datum
 circle_above(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.y - circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overbelow -		is the upper edge of circle1 at or below
  *								the upper edge of circle2?
  */
 Datum
 circle_overbelow(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.y + circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overabove	-	is the lower edge of circle1 at or above
  *								the lower edge of circle2?
  */
 Datum
 circle_overabove(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.y - circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 
 /*		circle_relop	-		is area(circle1) relop area(circle2), within
  *								our accuracy constraint?
  */
 Datum
 circle_eq(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
@@ -4849,36 +4857,38 @@ circle_sub_pt(PG_FUNCTION_ARGS)
 Datum
 circle_mul_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_mul_internal(&result->center, &circle->center, point);
-	result->radius *= HYPOT(point->x, point->y);
+	result->radius = float8_mul(circle->radius,
+								float8_hypot(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_div_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_div_internal(&result->center, &circle->center, point);
-	result->radius /= HYPOT(point->x, point->y);
+	result->radius = float8_div(circle->radius,
+								float8_hypot(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /*		circle_area		-		returns the area of the circle.
  */
 Datum
 circle_area(PG_FUNCTION_ARGS)
 {
@@ -4888,21 +4898,21 @@ circle_area(PG_FUNCTION_ARGS)
 }
 
 
 /*		circle_diameter -		returns the diameter of the circle.
  */
 Datum
 circle_diameter(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
-	PG_RETURN_FLOAT8(2 * circle->radius);
+	PG_RETURN_FLOAT8(float8_mul(circle->radius, 2.0));
 }
 
 
 /*		circle_radius	-		returns the radius of the circle.
  */
 Datum
 circle_radius(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
@@ -4913,81 +4923,84 @@ circle_radius(PG_FUNCTION_ARGS)
 /*		circle_distance -		returns the distance between
  *								  two circles.
  */
 Datum
 circle_distance(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(&circle1->center, &circle2->center)
-		- (circle1->radius + circle2->radius);
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(&circle1->center, &circle2->center),
+					   float8_pl(circle1->radius, circle2->radius));
+	if (float8_lt(result, 0.0))
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 
 Datum
 circle_contain_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
-	PG_RETURN_BOOL(d <= circle->radius);
+	PG_RETURN_BOOL(float8_le(d, circle->radius));
 }
 
 
 Datum
 pt_contained_circle(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
-	PG_RETURN_BOOL(d <= circle->radius);
+	PG_RETURN_BOOL(float8_le(d, circle->radius));
 }
 
 
 /*		dist_pc -		returns the distance between
  *						  a point and a circle.
  */
 Datum
 dist_pc(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center), circle->radius);
+	if (float8_lt(result, 0.0))
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a circle to a point
  */
 Datum
 dist_cpoint(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center), circle->radius);
+	if (float8_lt(result, 0.0))
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*		circle_center	-		returns the center point of the circle.
  */
 Datum
 circle_center(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *result;
@@ -4995,24 +5008,24 @@ circle_center(PG_FUNCTION_ARGS)
 	result = (Point *) palloc(sizeof(Point));
 	result->x = circle->center.x;
 	result->y = circle->center.y;
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		circle_ar		-		returns the area of the circle.
  */
-static double
+static float8
 circle_ar(CIRCLE *circle)
 {
-	return M_PI * (circle->radius * circle->radius);
+	return float8_mul(float8_mul(circle->radius, circle->radius), M_PI);
 }
 
 
 /*----------------------------------------------------------
  *	Conversion operators.
  *---------------------------------------------------------*/
 
 Datum
 cr_circle(PG_FUNCTION_ARGS)
 {
@@ -5027,65 +5040,65 @@ cr_circle(PG_FUNCTION_ARGS)
 	result->radius = radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_box(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	BOX		   *box;
-	double		delta;
+	float8		delta;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
-	delta = circle->radius / sqrt(2.0);
+	delta = float8_div(circle->radius, sqrt(2.0));
 
-	box->high.x = circle->center.x + delta;
-	box->low.x = circle->center.x - delta;
-	box->high.y = circle->center.y + delta;
-	box->low.y = circle->center.y - delta;
+	box->high.x = float8_pl(circle->center.x, delta);
+	box->low.x = float8_mi(circle->center.x, delta);
+	box->high.y = float8_pl(circle->center.y, delta);
+	box->low.y = float8_mi(circle->center.y, delta);
 
 	PG_RETURN_BOX_P(box);
 }
 
 /* box_circle()
  * Convert a box to a circle.
  */
 Datum
 box_circle(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	circle->center.x = (box->high.x + box->low.x) / 2;
-	circle->center.y = (box->high.y + box->low.y) / 2;
+	circle->center.x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	circle->center.y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 
 	circle->radius = point_dt(&circle->center, &box->high);
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 
 Datum
 circle_poly(PG_FUNCTION_ARGS)
 {
 	int32		npts = PG_GETARG_INT32(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	POLYGON    *poly;
 	int			base_size,
 				size;
 	int			i;
-	double		angle;
-	double		anglestep;
+	float8		angle;
+	float8		anglestep;
 
 	if (FPzero(circle->radius))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			   errmsg("cannot convert circle with radius zero to polygon")));
 
 	if (npts < 2)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("must request at least 2 points")));
@@ -5096,27 +5109,30 @@ circle_poly(PG_FUNCTION_ARGS)
 	/* Check for integer overflow */
 	if (base_size / npts != sizeof(poly->p[0]) || size <= base_size)
 		ereport(ERROR,
 				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 				 errmsg("too many points requested")));
 
 	poly = (POLYGON *) palloc0(size);	/* zero any holes */
 	SET_VARSIZE(poly, size);
 	poly->npts = npts;
 
-	anglestep = (2.0 * M_PI) / npts;
+	anglestep = float8_div(2.0 * M_PI, npts);
 
 	for (i = 0; i < npts; i++)
 	{
-		angle = i * anglestep;
-		poly->p[i].x = circle->center.x - (circle->radius * cos(angle));
-		poly->p[i].y = circle->center.y + (circle->radius * sin(angle));
+		angle = float8_mul(anglestep, i);
+
+		poly->p[i].x = float8_mi(circle->center.x,
+								 float8_mul(circle->radius, cos(angle)));
+		poly->p[i].y = float8_pl(circle->center.y,
+								 float8_mul(circle->radius, sin(angle)));
 	}
 
 	make_bound_box(poly);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
 /*		poly_circle		- convert polygon to circle
  *
  * XXX This algorithm should use weighted means of line segments
@@ -5135,29 +5151,30 @@ poly_circle(PG_FUNCTION_ARGS)
 				 errmsg("cannot convert empty polygon to circle")));
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	circle->center.x = 0;
 	circle->center.y = 0;
 	circle->radius = 0;
 
 	for (i = 0; i < poly->npts; i++)
 	{
-		circle->center.x += poly->p[i].x;
-		circle->center.y += poly->p[i].y;
+		circle->center.x = float8_pl(circle->center.x, poly->p[i].x);
+		circle->center.y = float8_pl(circle->center.y, poly->p[i].y);
 	}
-	circle->center.x /= poly->npts;
-	circle->center.y /= poly->npts;
+	circle->center.x = float8_div(circle->center.x, poly->npts);
+	circle->center.y = float8_div(circle->center.y, poly->npts);
 
 	for (i = 0; i < poly->npts; i++)
-		circle->radius += point_dt(&poly->p[i], &circle->center);
-	circle->radius /= poly->npts;
+		circle->radius = float8_pl(circle->radius, point_dt(&poly->p[i],
+															&circle->center));
+	circle->radius = float8_div(circle->radius, poly->npts);
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 
 /***********************************************************************
  **
  **		Private routines for multiple types.
  **
  ***********************************************************************/
@@ -5171,45 +5188,45 @@ poly_circle(PG_FUNCTION_ARGS)
  *	http://hopf.math.northwestern.edu/index.html
  *	Description of algorithm:  http://www.linuxjournal.com/article/2197
  *							   http://www.linuxjournal.com/article/2029
  */
 
 #define POINT_ON_POLYGON INT_MAX
 
 static int
 point_inside(Point *p, int npts, Point *plist)
 {
-	double		x0,
+	float8		x0,
 				y0;
-	double		prev_x,
+	float8		prev_x,
 				prev_y;
 	int			i = 0;
-	double		x,
+	float8		x,
 				y;
 	int			cross,
 				total_cross = 0;
 
 	if (npts <= 0)
 		return 0;
 
 	/* compute first polygon point relative to single point */
-	x0 = plist[0].x - p->x;
-	y0 = plist[0].y - p->y;
+	x0 = float8_mi(plist[0].x, p->x);
+	y0 = float8_mi(plist[0].y, p->y);
 
 	prev_x = x0;
 	prev_y = y0;
 	/* loop over polygon points and aggregate total_cross */
 	for (i = 1; i < npts; i++)
 	{
 		/* compute next polygon point relative to single point */
-		x = plist[i].x - p->x;
-		y = plist[i].y - p->y;
+		x = float8_mi(plist[i].x, p->x);
+		y = float8_mi(plist[i].y, p->y);
 
 		/* compute previous to current point crossing */
 		if ((cross = lseg_crossing(x, y, prev_x, prev_y)) == POINT_ON_POLYGON)
 			return 2;
 		total_cross += cross;
 
 		prev_x = x;
 		prev_y = y;
 	}
 
@@ -5227,69 +5244,74 @@ point_inside(Point *p, int npts, Point *plist)
 /* lseg_crossing()
  * Returns +/-2 if line segment crosses the positive X-axis in a +/- direction.
  * Returns +/-1 if one point is on the positive X-axis.
  * Returns 0 if both points are on the positive X-axis, or there is no crossing.
  * Returns POINT_ON_POLYGON if the segment contains (0,0).
  * Wow, that is one confusing API, but it is used above, and when summed,
  * can tell is if a point is in a polygon.
  */
 
 static int
-lseg_crossing(double x, double y, double prev_x, double prev_y)
+lseg_crossing(float8 x, float8 y, float8 prev_x, float8 prev_y)
 {
-	double		z;
+	float8		z;
 	int			y_sign;
 
 	if (FPzero(y))
 	{							/* y == 0, on X axis */
 		if (FPzero(x))			/* (x,y) is (0,0)? */
 			return POINT_ON_POLYGON;
 		else if (FPgt(x, 0))
 		{						/* x > 0 */
 			if (FPzero(prev_y)) /* y and prev_y are zero */
 				/* prev_x > 0? */
-				return FPgt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
-			return FPlt(prev_y, 0) ? 1 : -1;
+				return FPgt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
+			return FPlt(prev_y, 0.0) ? 1 : -1;
 		}
 		else
 		{						/* x < 0, x not on positive X axis */
 			if (FPzero(prev_y))
 				/* prev_x < 0? */
-				return FPlt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
+				return FPlt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
 			return 0;
 		}
 	}
 	else
 	{							/* y != 0 */
 		/* compute y crossing direction from previous point */
-		y_sign = FPgt(y, 0) ? 1 : -1;
+		y_sign = FPgt(y, 0.0) ? 1 : -1;
 
 		if (FPzero(prev_y))
 			/* previous point was on X axis, so new point is either off or on */
-			return FPlt(prev_x, 0) ? 0 : y_sign;
-		else if (FPgt(y_sign * prev_y, 0))
+			return FPlt(prev_x, 0.0) ? 0 : y_sign;
+		else if ((y_sign < 0 && FPlt(prev_y, 0.0)) ||
+			(y_sign > 0 && FPgt(prev_y, 0.0)))
 			/* both above or below X axis */
 			return 0;			/* same sign */
 		else
 		{						/* y and prev_y cross X-axis */
-			if (FPge(x, 0) && FPgt(prev_x, 0))
+			if (FPge(x, 0.0) && FPgt(prev_x, 0.0))
 				/* both non-negative so cross positive X-axis */
 				return 2 * y_sign;
-			if (FPlt(x, 0) && FPle(prev_x, 0))
+			if (FPlt(x, 0.0) && FPle(prev_x, 0.0))
 				/* both non-positive so do not cross positive X-axis */
 				return 0;
 
 			/* x and y cross axises, see URL above point_inside() */
-			z = (x - prev_x) * y - (y - prev_y) * x;
+			z = float8_mi(float8_mul(float8_mi(x, prev_x), y),
+						  float8_mul(float8_mi(y, prev_y), x));
 			if (FPzero(z))
 				return POINT_ON_POLYGON;
-			return FPgt((y_sign * z), 0) ? 0 : 2 * y_sign;
+			if ((y_sign < 0 && FPlt(z, 0.0)) ||
+				(y_sign > 0 && FPgt(z, 0.0)))
+				return 0;
+			return 2 * y_sign;
 		}
 	}
 }
 
 
 static bool
 plist_same(int npts, Point *p1, Point *p2)
 {
 	int			i,
 				ii,
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index c800bb1338..f62be1061e 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -76,38 +76,38 @@
 #include "access/spgist.h"
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
 #include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
- * is going only going to be used in a place to effect the performance
+ * is only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
 compareDoubles(const void *a, const void *b)
 {
-	double		x = *(double *) a;
-	double		y = *(double *) b;
+	float8		x = *(float8 *) a;
+	float8		y = *(float8 *) b;
 
 	if (x == y)
 		return 0;
 	return (x > y) ? 1 : -1;
 }
 
 typedef struct
 {
-	double		low;
-	double		high;
+	float8		low;
+	float8		high;
 } Range;
 
 typedef struct
 {
 	Range		left;
 	Range		right;
 } RangeBox;
 
 typedef struct
 {
@@ -121,30 +121,30 @@ typedef struct
  * The quadrant is 8 bit unsigned integer with 4 least bits in use.
  * This function accepts BOXes as input.  They are not casted to
  * RangeBoxes, yet.  All 4 bits are set by comparing a corner of the box.
  * This makes 16 quadrants in total.
  */
 static uint8
 getQuadrant(BOX *centroid, BOX *inBox)
 {
 	uint8		quadrant = 0;
 
-	if (inBox->low.x > centroid->low.x)
+	if (float8_gt(inBox->low.x, centroid->low.x))
 		quadrant |= 0x8;
 
-	if (inBox->high.x > centroid->high.x)
+	if (float8_gt(inBox->high.x, centroid->high.x))
 		quadrant |= 0x4;
 
-	if (inBox->low.y > centroid->low.y)
+	if (float8_gt(inBox->low.y, centroid->low.y))
 		quadrant |= 0x2;
 
-	if (inBox->high.y > centroid->high.y)
+	if (float8_gt(inBox->high.y, centroid->high.y))
 		quadrant |= 0x1;
 
 	return quadrant;
 }
 
 /*
  * Get RangeBox using BOX
  *
  * We are turning the BOX to our structures to emphasize their function
  * of representing points in 4D space.  It also is more convenient to
@@ -167,21 +167,21 @@ getRangeBox(BOX *box)
 /*
  * Initialize the traversal value
  *
  * In the beginning, we don't have any restrictions.  We have to
  * initialize the struct to cover the whole 4D space.
  */
 static RectBox *
 initRectBox(void)
 {
 	RectBox    *rect_box = (RectBox *) palloc(sizeof(RectBox));
-	double		infinity = get_float8_infinity();
+	float8		infinity = get_float8_infinity();
 
 	rect_box->range_box_x.left.low = -infinity;
 	rect_box->range_box_x.left.high = infinity;
 
 	rect_box->range_box_x.right.low = -infinity;
 	rect_box->range_box_x.right.high = infinity;
 
 	rect_box->range_box_y.left.low = -infinity;
 	rect_box->range_box_y.left.high = infinity;
 
@@ -410,40 +410,40 @@ spg_box_quad_choose(PG_FUNCTION_ARGS)
  * point as the median of the coordinates of the boxes.
  */
 Datum
 spg_box_quad_picksplit(PG_FUNCTION_ARGS)
 {
 	spgPickSplitIn *in = (spgPickSplitIn *) PG_GETARG_POINTER(0);
 	spgPickSplitOut *out = (spgPickSplitOut *) PG_GETARG_POINTER(1);
 	BOX		   *centroid;
 	int			median,
 				i;
-	double	   *lowXs = palloc(sizeof(double) * in->nTuples);
-	double	   *highXs = palloc(sizeof(double) * in->nTuples);
-	double	   *lowYs = palloc(sizeof(double) * in->nTuples);
-	double	   *highYs = palloc(sizeof(double) * in->nTuples);
+	float8	   *lowXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *lowYs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highYs = palloc(sizeof(float8) * in->nTuples);
 
 	/* Calculate median of all 4D coordinates */
 	for (i = 0; i < in->nTuples; i++)
 	{
 		BOX		   *box = DatumGetBoxP(in->datums[i]);
 
 		lowXs[i] = box->low.x;
 		highXs[i] = box->high.x;
 		lowYs[i] = box->low.y;
 		highYs[i] = box->high.y;
 	}
 
-	qsort(lowXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(lowYs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highYs, in->nTuples, sizeof(double), compareDoubles);
+	qsort(lowXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(lowYs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highYs, in->nTuples, sizeof(float8), compareDoubles);
 
 	median = in->nTuples / 2;
 
 	centroid = palloc(sizeof(BOX));
 
 	centroid->low.x = lowXs[median];
 	centroid->high.x = highXs[median];
 	centroid->low.y = lowYs[median];
 	centroid->high.y = highYs[median];
 
diff --git a/src/include/utils/float.h b/src/include/utils/float.h
index c26de1cca4..c893f79a4d 100644
--- a/src/include/utils/float.h
+++ b/src/include/utils/float.h
@@ -269,20 +269,33 @@ float8_div(float8 val1, float8 val2)
 		ereport(ERROR,
 				(errcode(ERRCODE_DIVISION_BY_ZERO),
 				 errmsg("division by zero")));
 
 	result = val1 / val2;
 	check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
 
 	return result;
 }
 
+static inline float8
+float8_hypot(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = hypot(val1, val2);
+	check_float8_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0 && val2 == 0.0);
+	Assert(isinf(result) || result >= 0.0);
+
+	return result;
+}
+
 /*
  * Routines for NaN-aware comparisons
  *
  * We consider all NANs to be equal and larger than any non-NAN. This is
  * somewhat arbitrary; the important thing is to have a consistent sort
  * order.
  */
 
 static inline bool
 float4_eq(float4 val1, float4 val2)
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index f845dffcb7..527036f1fc 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -1,23 +1,20 @@
 /*-------------------------------------------------------------------------
  *
  * geo_decls.h - Declarations for various 2D constructs.
  *
  *
  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * src/include/utils/geo_decls.h
  *
- * NOTE
- *	  These routines do *not* use the float types from adt/.
- *
  *	  XXX These routines were not written by a numerical analyst.
  *
  *	  XXX I have made some attempt to flesh out the operators
  *		and data types. There are still some more to do. - tgl 97/04/19
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEO_DECLS_H
 #define GEO_DECLS_H
 
@@ -28,44 +25,43 @@
 
 /*--------------------------------------------------------------------
  * Useful floating point utilities and constants.
  *-------------------------------------------------------------------*/
 
 
 #define EPSILON					1.0E-06
 
 #ifdef EPSILON
 #define FPzero(A)				(fabs(A) <= EPSILON)
-#define FPeq(A,B)				(fabs((A) - (B)) <= EPSILON)
-#define FPne(A,B)				(fabs((A) - (B)) > EPSILON)
-#define FPlt(A,B)				((B) - (A) > EPSILON)
-#define FPle(A,B)				((A) - (B) <= EPSILON)
-#define FPgt(A,B)				((A) - (B) > EPSILON)
-#define FPge(A,B)				((B) - (A) <= EPSILON)
+#define FPeq(A, B)				(float8_le(fabs(float8_mi(A, B)), EPSILON))
+#define FPne(A, B)				(float8_gt(fabs(float8_mi(A, B)), EPSILON))
+#define FPlt(A, B)				(float8_gt(float8_mi(B, A), EPSILON))
+#define FPle(A, B)				(float8_le(float8_mi(A, B), EPSILON))
+#define FPgt(A, B)				(float8_gt(float8_mi(A, B), EPSILON))
+#define FPge(A, B)				(float8_le(float8_mi(B, A), EPSILON))
 #else
-#define FPzero(A)				((A) == 0)
-#define FPeq(A,B)				((A) == (B))
-#define FPne(A,B)				((A) != (B))
-#define FPlt(A,B)				((A) < (B))
-#define FPle(A,B)				((A) <= (B))
-#define FPgt(A,B)				((A) > (B))
-#define FPge(A,B)				((A) >= (B))
+#define FPzero(A)				((A) == 0.0)
+#define FPeq(A, B)				(float8_eq(A, B))
+#define FPne(A, B)				(float8_ne(A, B))
+#define FPlt(A, B)				(float8_lt(A, B))
+#define FPle(A, B)				(float8_le(A, B))
+#define FPgt(A, B)				(float8_gt(A, B))
+#define FPge(A, B)				(float8_ge(A, B))
 #endif
 
-#define HYPOT(A, B)				hypot(A, B)
 
 /*---------------------------------------------------------------------
  * Point - (x,y)
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		x,
+	float8		x,
 				y;
 } Point;
 
 
 /*---------------------------------------------------------------------
  * LSEG - A straight line, specified by endpoints.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		p[2];
@@ -73,66 +69,66 @@ typedef struct
 
 
 /*---------------------------------------------------------------------
  * PATH - Specified by vertex points.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	int32		vl_len_;		/* varlena header (do not touch directly!) */
 	int32		npts;
 	int32		closed;			/* is this a closed polygon? */
-	int32		dummy;			/* padding to make it double align */
+	int32		dummy;			/* padding to make it float8 align */
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } PATH;
 
 
 /*---------------------------------------------------------------------
  * LINE - Specified by its general equation (Ax+By+C=0).
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		A,
+	float8		A,
 				B,
 				C;
 } LINE;
 
 
 /*---------------------------------------------------------------------
  * BOX	- Specified by two corner points, which are
  *		 sorted to save calculation time later.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		high,
 				low;			/* corner POINTs */
 } BOX;
 
 /*---------------------------------------------------------------------
- * POLYGON - Specified by an array of doubles defining the points,
+ * POLYGON - Specified by an array of float8s defining the points,
  *		keeping the number of points and the bounding box for
  *		speed purposes.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	int32		vl_len_;		/* varlena header (do not touch directly!) */
 	int32		npts;
 	BOX			boundbox;
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } POLYGON;
 
 /*---------------------------------------------------------------------
  * CIRCLE - Specified by a center point and radius.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		center;
-	double		radius;
+	float8		radius;
 } CIRCLE;
 
 /*
  * fmgr interface macros
  *
  * Path and Polygon are toastable varlena types, the others are just
  * fixed-size pass-by-reference types.
  */
 
 #define DatumGetPointP(X)	 ((Point *) DatumGetPointer(X))
-- 
2.11.0 (Apple Git-81)

0004-line-fixes-v1.patchapplication/octet-stream; name=0004-line-fixes-v1.patchDownload
From 79e38d38451e9b6c48183145d2396830e6442fda Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sun, 28 May 2017 11:35:17 +0200
Subject: [PATCH 4/4] line-fixes-v1

Fix obvious problems around the line datatype

I have noticed some line operators retuning wrong results, and Tom Lane
spotted similar problems on more places.  Source history reveals that
during 1990s, the internal format of the line datatype is changed, but
most functions haven't got the hint.  The fixes are:

* Make operators more symmetric
* Reject invalid specification A=B=0 on receive
* Avoid division by zero on perpendicular operator
* Fix intersection and distance operators when neither A nor B are 1
* Avoid point distance operator crashing on float precision loss
* Fix line segment distance by getting the minimum as the comment suggested

Previous discussion:
https://www.postgresql.org/message-id/flat/CAE2gYzw_-z%3DV2kh8QqFjenu%3D8MJXzOP44wRW%3DAzzeamrmTT1%3DQ%40mail.gmail.com
---
 src/backend/utils/adt/geo_ops.c | 115 +++++++++++++++++++++++++++-------------
 1 file changed, 77 insertions(+), 38 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index b1a6d55f8d..681970b0a1 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -948,20 +948,25 @@ line_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LINE	   *line;
 
 	line = (LINE *) palloc(sizeof(LINE));
 
 	line->A = pq_getmsgfloat8(buf);
 	line->B = pq_getmsgfloat8(buf);
 	line->C = pq_getmsgfloat8(buf);
 
+	if (line->A == 0.0 && line->B == 0.0)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+		 errmsg("invalid line specification: A and B cannot both be zero")));
+
 	PG_RETURN_LINE_P(line);
 }
 
 /*
  *		line_send			- converts line to binary format
  */
 Datum
 line_send(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -1095,25 +1100,28 @@ line_parallel(PG_FUNCTION_ARGS)
 }
 
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
-	else if (FPzero(l1->B))
+	if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
+	if (FPzero(l2->A))
+		PG_RETURN_BOOL(FPzero(l1->B));
+	if (FPzero(l2->B))
+		PG_RETURN_BOOL(FPzero(l1->A));
 
-	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
-								   float8_mul(l1->B, l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(float8_mul(l1->A, l2->B), -float8_mul(l1->B, l2->A)));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
@@ -1125,20 +1133,21 @@ line_horizontal(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(FPzero(line->A));
 }
 
 Datum
 line_eq(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		ratio;
 
+	/* A and B cannot be both 0, but we never really know with the EPSILON. */
 	if (!FPzero(l2->A))
 		ratio = float8_div(l1->A, l2->A);
 	else if (!FPzero(l2->B))
 		ratio = float8_div(l1->B, l2->B);
 	else if (!FPzero(l2->C))
 		ratio = float8_div(l1->C, l2->C);
 	else
 		ratio = 1.0;
 
 	PG_RETURN_BOOL(FPeq(l1->A, float8_mul(ratio, l2->A)) &&
@@ -1152,30 +1161,36 @@ line_eq(PG_FUNCTION_ARGS)
  *---------------------------------------------------------*/
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	float8		result;
-	Point		tmp;
+	float8		ratio;
 
 	if (line_interpt_internal(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
-	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
-	point_construct(&tmp, 0.0, l1->C);
-	result = dist_pl_internal(&tmp, l2);
-	PG_RETURN_FLOAT8(result);
+
+	/* A and B cannot be both 0, but we never really know with the EPSILON. */
+	if (!FPzero(l2->A))
+		ratio = float8_div(l1->A, l2->A);
+	else if (!FPzero(l2->B))
+		ratio = float8_div(l1->B, l2->B);
+	else
+		ratio = 1.0;
+
+	PG_RETURN_FLOAT8(float8_div(fabs(float8_mi(l1->C,
+											   float8_mul(ratio, l2->C))),
+								float8_hypot(l1->A, l1->B)));
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
@@ -1198,38 +1213,62 @@ line_interpt(PG_FUNCTION_ARGS)
  * NOTE: If the lines are identical then we will find they are parallel
  * and report "no intersection".  This is a little weird, but since
  * there's no *unique* intersection, maybe it's appropriate behavior.
  */
 static bool
 line_interpt_internal(Point *result, LINE *l1, LINE *l2)
 {
 	float8		x,
 				y;
 
-	if (FPzero(l1->B))			/* l1 vertical? */
+	if (FPzero(l1->A))			/* l1 horizontal? */
+	{
+		if (FPzero(l2->A))		/* l2 horizontal? */
+			return false;
+
+		y = float8_div(-l1->C, l1->B);
+		x = float8_div(-float8_pl(float8_mul(l2->B, y), l2->C), l2->A);
+	}
+	else if (FPzero(l1->B))		/* l1 vertical? */
 	{
 		if (FPzero(l2->B))		/* l2 vertical? */
 			return false;
 
-		x = l1->C;
-		y = float8_pl(float8_mul(l2->A, x), l2->C);
+		x = float8_div(-l1->C, l1->A);
+		y = float8_div(-float8_pl(float8_mul(l2->A, x), l2->C), l2->B);
+	}
+	else if (FPzero(l2->A))		/* l2 horizontal? */
+	{
+		if (FPzero(l1->A))		/* l1 horizontal? */
+			return false;
+
+		y = float8_div(-l2->C, l2->B);
+		x = float8_div(-float8_pl(float8_mul(l1->B, y), l1->C), l1->A);
+	}
+	else if (FPzero(l2->B))		/* l2 vertical? */
+	{
+		if (FPzero(l1->B))		/* l1 vertical? */
+			return false;
+
+		x = float8_div(-l2->C, l2->A);
+		y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
 	}
 	else
 	{
-		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
+		if (FPeq(float8_mul(l1->A, l2->B), float8_mul(l2->A, l1->B)))
 			return false;
 
-		if (FPzero(l2->B))
-			x = l2->C;
-		else
-			x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
-		y = float8_pl(float8_mul(l1->A, x), l1->C);
+		x = float8_div(float8_mi(float8_mul(l1->B, l2->C),
+								 float8_mul(l2->B, l1->C)),
+					   float8_mi(float8_mul(l1->A, l2->B),
+								 float8_mul(l2->A, l1->B)));
+		y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
 	}
 	if (result != NULL)
 		point_construct(result, x, y);
 
 #ifdef GEODEBUG
 	printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
 		   DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
 	printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
 #endif
 
@@ -2450,22 +2489,21 @@ dist_pb(PG_FUNCTION_ARGS)
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	float8		result;
 
 	if (lseg_interpt_line_internal(NULL, lseg, line))
 		result = 0.0;
 	else
-		/* XXX shouldn't we take the min not max? */
-		result = float8_max(dist_pl_internal(&lseg->p[0], line),
+		result = float8_min(dist_pl_internal(&lseg->p[0], line),
 							dist_pl_internal(&lseg->p[1], line));
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
@@ -2646,43 +2684,44 @@ lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line)
 /* close_pl -
  *		The intersection point of a perpendicular of the line
  *		through the point.
  */
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
-	float8		invm;
-	LINE		tmp;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (FPzero(line->B))		/* vertical? */
+		point_construct(result, float8_div(-line->C, line->A), pt->y);
+	else if (FPzero(line->A))	/* horizontal? */
+		point_construct(result, pt->x, float8_div(-line->C, line->B));
+	else
 	{
-		result->x = line->C;
-		result->y = pt->y;
-		PG_RETURN_POINT_P(result);
-	}
-	if (FPzero(line->A))		/* horizontal? */
-	{
-		result->x = pt->x;
-		result->y = line->C;
-		PG_RETURN_POINT_P(result);
-	}
-	/* drop a perpendicular and find the intersection point */
+		LINE		perp;
+
+		/*
+		 * Drop a perpendicular and find the intersection point
+		 *
+		 * We need to invert and flip the sign on the slope to get the
+		 * perpendicular.  We might lose some precision on the division.
+		 * It shouldn't be as much to turn the line.  If it happens anyway,
+		 * we will assume the point it on the line.
+		 */
+		line_construct_pm(&perp, pt, float8_div(line->B, line->A));
+		if (!line_interpt_internal(result, &perp, line))
+			*result = *pt;
+	}
 
-	/* invert and flip the sign on the slope to get a perpendicular */
-	invm = float8_div(line->B, line->A);
-	line_construct_pm(&tmp, pt, invm);
-	line_interpt_internal(result, &tmp, line);
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_ps()
  * Closest point on line segment to specified point.
  * Take the closest endpoint if the point is left, right,
  *	above, or below the segment, otherwise find the intersection
  *	point of the segment and its perpendicular through the point.
  *
-- 
2.11.0 (Apple Git-81)

0001-geo-funcs-v1.patchapplication/octet-stream; name=0001-geo-funcs-v1.patchDownload
From 7b2d0ba74c09b402f198b712b23132b53b9e1685 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 27 May 2017 11:27:18 -0400
Subject: [PATCH 1/4] geo-funcs-v1

Refactor geometric functions and operators code

The geometric types were not using each other's functions.  I believe
the reason behind this is simpler types line point and line being
developed after more complicated ones.  This patch reduces duplicate
code and makes functions of different datatypes more compatible.  We can
do much better than that, but it would require touching many more lines.
The changes can be summarised as:

* Re-use more functions to implement others
* Unify *_construct functions to obtain pre-allocated memory
* Unify *_interpt_internal functions to obtain pre-allocated memory
* Remove private functions from geo_decls.h
* Switch using C11 hypot() as the comment suggested
---
 src/backend/utils/adt/geo_ops.c | 810 +++++++++++++++++-----------------------
 src/include/utils/geo_decls.h   |  12 +-
 src/test/regress/regress.c      |  11 +-
 3 files changed, 345 insertions(+), 488 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 655b81cc46..1f1f32a78d 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -31,60 +31,68 @@
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
+/* Methods on point */
+static void point_construct(Point *result, float8 x, float8 y);
+static void point_add_internal(Point *result, Point *pt1, Point *pt2);
+static void point_sub_internal(Point *result, Point *pt1, Point *pt2);
+static void point_mul_internal(Point *result, Point *pt1, Point *pt2);
+static void point_div_internal(Point *result, Point *pt1, Point *pt2);
+static bool point_eq_internal(Point *pt1, Point *pt2);
+static float8 point_dt(Point *pt1, Point *pt2);
+static float8 point_sl(Point *pt1, Point *pt2);
 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);
+/* Methods on box */
+static void box_construct(BOX *result, float8 x1, float8 x2, float8 y1, float8 y2);
+static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
+static double box_ar(BOX *box);
 static double box_ht(BOX *box);
 static double box_wd(BOX *box);
+/* Methods on circle */
 static double circle_ar(CIRCLE *circle);
-static CIRCLE *circle_copy(CIRCLE *circle);
-static LINE *line_construct_pm(Point *pt, double m);
+/* Methods on line */
+static void line_construct_pm(LINE *result, Point *pt, float8 m);
 static void line_construct_pts(LINE *line, Point *pt1, Point *pt2);
-static bool lseg_intersect_internal(LSEG *l1, LSEG *l2);
-static double lseg_dt(LSEG *l1, LSEG *l2);
+static bool line_interpt_internal(Point *result, LINE *l1, LINE *l2);
+static float8 line_calculate_point(LINE *line, Point *pt);
+/* Methods on line segment */
+static bool lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line);
+static bool lseg_interpt_internal(Point *result, LSEG *l1, LSEG *l2);
+static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
+static float8 lseg_dt(LSEG *l1, LSEG *l2);
+static int	lseg_crossing(double x, double y, double px, double py);
+/* Others */
 static bool on_ps_internal(Point *pt, LSEG *lseg);
 static void make_bound_box(POLYGON *poly);
 static bool plist_same(int npts, Point *p1, Point *p2);
-static Point *point_construct(double x, double y);
-static Point *point_copy(Point *pt);
 static double single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
 static void pair_decode(char *str, double *x, double *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
 static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
 static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
-static double box_ar(BOX *box);
-static void box_cn(Point *center, BOX *box);
-static Point *interpt_sl(LSEG *lseg, LINE *line);
-static bool has_interpt_sl(LSEG *lseg, LINE *line);
 static double dist_pl_internal(Point *pt, LINE *line);
 static double dist_ps_internal(Point *pt, LSEG *lseg);
-static Point *line_interpt_internal(LINE *l1, LINE *l2);
-static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
-static Point *lseg_interpt_internal(LSEG *l1, LSEG *l2);
 static double dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 
 /*
  * Delimiters for input and output strings.
  * LDELIM, RDELIM, and DELIM are left, right, and separator delimiters, respectively.
  * LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints.
  */
 
 #define LDELIM			'('
@@ -434,33 +442,22 @@ box_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, box->high.x);
 	pq_sendfloat8(&buf, box->high.y);
 	pq_sendfloat8(&buf, box->low.x);
 	pq_sendfloat8(&buf, box->low.y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*		box_construct	-		fill in a new box.
  */
-static BOX *
-box_construct(double x1, double x2, double y1, double y2)
-{
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	return box_fill(result, x1, x2, y1, y2);
-}
-
-
-/*		box_fill		-		fill in a given box struct
- */
-static BOX *
-box_fill(BOX *result, double x1, double x2, double y1, double y2)
+static void
+box_construct(BOX *result, float8 x1, float8 x2, float8 y1, float8 y2)
 {
 	if (x1 > x2)
 	{
 		result->high.x = x1;
 		result->low.x = x2;
 	}
 	else
 	{
 		result->high.x = x2;
 		result->low.x = x1;
@@ -468,55 +465,38 @@ box_fill(BOX *result, double x1, double x2, double y1, double y2)
 	if (y1 > y2)
 	{
 		result->high.y = y1;
 		result->low.y = y2;
 	}
 	else
 	{
 		result->high.y = y2;
 		result->low.y = y1;
 	}
-
-	return result;
-}
-
-
-/*		box_copy		-		copy a box
- */
-static BOX *
-box_copy(BOX *box)
-{
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	memcpy((char *) result, (char *) box, sizeof(BOX));
-
-	return result;
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for BOXes.
  *		<, >, <=, >=, and == are based on box area.
  *---------------------------------------------------------*/
 
 /*		box_same		-		are two boxes identical?
  */
 Datum
 box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPeq(box1->high.x, box2->high.x) &&
-				   FPeq(box1->low.x, box2->low.x) &&
-				   FPeq(box1->high.y, box2->high.y) &&
-				   FPeq(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(point_eq_internal(&box1->high, &box2->high) &&
+				   point_eq_internal(&box1->low, &box2->low));
 }
 
 /*		box_overlap		-		does box1 overlap box2?
  */
 Datum
 box_overlap(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
@@ -751,51 +731,51 @@ box_area(PG_FUNCTION_ARGS)
 
 
 /*		box_width		-		returns the width of the box
  *								  (horizontal magnitude).
  */
 Datum
 box_width(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.x - box->low.x);
+	PG_RETURN_FLOAT8(box_wd(box));
 }
 
 
 /*		box_height		-		returns the height of the box
  *								  (vertical magnitude).
  */
 Datum
 box_height(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.y - box->low.y);
+	PG_RETURN_FLOAT8(box_ht(box));
 }
 
 
 /*		box_distance	-		returns the distance between the
  *								  center points of two boxes.
  */
 Datum
 box_distance(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 	Point		a,
 				b;
 
 	box_cn(&a, box1);
 	box_cn(&b, box2);
 
-	PG_RETURN_FLOAT8(HYPOT(a.x - b.x, a.y - b.y));
+	PG_RETURN_FLOAT8(point_dt(&a, &b));
 }
 
 
 /*		box_center		-		returns the center point of the box.
  */
 Datum
 box_center(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *result = (Point *) palloc(sizeof(Point));
@@ -934,22 +914,22 @@ line_in(PG_FUNCTION_ARGS)
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
 							"line", str)));
 		if (FPzero(line->A) && FPzero(line->B))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: A and B cannot both be zero")));
 	}
 	else
 	{
-		path_decode(s, true, 2, &(lseg.p[0]), &isopen, NULL, "line", str);
-		if (FPeq(lseg.p[0].x, lseg.p[1].x) && FPeq(lseg.p[0].y, lseg.p[1].y))
+		path_decode(s, true, 2, &lseg.p[0], &isopen, NULL, "line", str);
+		if (point_eq_internal(&lseg.p[0], &lseg.p[1]))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: must be two distinct points")));
 		line_construct_pts(line, &lseg.p[0], &lseg.p[1]);
 	}
 
 	PG_RETURN_LINE_P(line);
 }
 
 
@@ -1000,41 +980,37 @@ line_send(PG_FUNCTION_ARGS)
 
 
 /*----------------------------------------------------------
  *	Conversion routines from one line formula to internal.
  *		Internal form:	Ax+By+C=0
  *---------------------------------------------------------*/
 
 /* line_construct_pm()
  * point-slope
  */
-static LINE *
-line_construct_pm(Point *pt, double m)
+static void
+line_construct_pm(LINE *result, Point *pt, float8 m)
 {
-	LINE	   *result = (LINE *) palloc(sizeof(LINE));
-
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
 		result->A = -1;
 		result->B = 0;
 		result->C = pt->x;
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
 		result->C = pt->y - m * pt->x;
 	}
-
-	return result;
 }
 
 /*
  * Fill already-allocated LINE struct from two points on the line
  */
 static void
 line_construct_pts(LINE *line, Point *pt1, Point *pt2)
 {
 	if (FPeq(pt1->x, pt2->x))
 	{							/* vertical */
@@ -1052,21 +1028,21 @@ line_construct_pts(LINE *line, Point *pt1, Point *pt2)
 		line->A = 0;
 		line->B = -1;
 		line->C = pt1->y;
 #ifdef GEODEBUG
 		printf("line_construct_pts- line is horizontal\n");
 #endif
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
-		line->A = (pt2->y - pt1->y) / (pt2->x - pt1->x);
+		line->A = point_sl(pt2, pt1);
 		line->B = -1.0;
 		line->C = pt1->y - line->A * pt1->x;
 		/* on some platforms, the preceding expression tends to produce -0 */
 		if (line->C == 0.0)
 			line->C = 0.0;
 #ifdef GEODEBUG
 		printf("line_construct_pts- line is neither vertical nor horizontal (diffs x=%.*g, y=%.*g\n",
 			   DBL_DIG, (pt2->x - pt1->x), DBL_DIG, (pt2->y - pt1->y));
 #endif
 	}
@@ -1079,46 +1055,53 @@ Datum
 line_construct_pp(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 	LINE	   *result = (LINE *) palloc(sizeof(LINE));
 
 	line_construct_pts(result, pt1, pt2);
 	PG_RETURN_LINE_P(result);
 }
 
+/*
+ * Calculate the line equation for a point
+ *
+ * This returns the result of the line equation Ax + By + C.  The result
+ * needs to be 0 for the point to be on the line.
+ */
+static float8
+line_calculate_point(LINE *line, Point *pt)
+{
+	return line->A * pt->x + line->B * pt->y + line->C;
+}
+
 
 /*----------------------------------------------------------
  *	Relative position routines.
  *---------------------------------------------------------*/
 
 Datum
 line_intersect(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(!DatumGetBool(DirectFunctionCall2(line_parallel,
-													 LinePGetDatum(l1),
-													 LinePGetDatum(l2))));
+	PG_RETURN_BOOL(line_interpt_internal(NULL, l1, l2));
 }
 
 Datum
 line_parallel(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
-	if (FPzero(l1->B))
-		PG_RETURN_BOOL(FPzero(l2->B));
-
-	PG_RETURN_BOOL(FPeq(l2->A, l1->A * (l2->B / l1->B)));
+	PG_RETURN_BOOL(!line_interpt_internal(NULL, l1, l2));
 }
 
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
@@ -1172,96 +1155,94 @@ line_eq(PG_FUNCTION_ARGS)
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
-	Point	   *tmp;
+	Point		tmp;
 
-	if (!DatumGetBool(DirectFunctionCall2(line_parallel,
-										  LinePGetDatum(l1),
-										  LinePGetDatum(l2))))
+	if (line_interpt_internal(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
 		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
-	tmp = point_construct(0.0, l1->C);
-	result = dist_pl_internal(tmp, l2);
+	point_construct(&tmp, 0.0, l1->C);
+	result = dist_pl_internal(&tmp, l2);
 	PG_RETURN_FLOAT8(result);
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
-	result = line_interpt_internal(l1, l2);
+	result = (Point *) palloc(sizeof(Point));
 
-	if (result == NULL)
+	if (!line_interpt_internal(result, l1, l2))
 		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
 
 /*
  * Internal version of line_interpt
  *
- * returns a NULL pointer if no intersection point
+ * This returns true if two lines intersect (they do, if they are not
+ * parallel), false if they do not.  This also sets the intersection point
+ * to *result, if it is not NULL.
+ *
+ * NOTE: If the lines are identical then we will find they are parallel
+ * and report "no intersection".  This is a little weird, but since
+ * there's no *unique* intersection, maybe it's appropriate behavior.
  */
-static Point *
-line_interpt_internal(LINE *l1, LINE *l2)
+static bool
+line_interpt_internal(Point *result, LINE *l1, LINE *l2)
 {
-	Point	   *result;
 	double		x,
 				y;
 
-	/*
-	 * NOTE: if the lines are identical then we will find they are parallel
-	 * and report "no intersection".  This is a little weird, but since
-	 * there's no *unique* intersection, maybe it's appropriate behavior.
-	 */
-	if (DatumGetBool(DirectFunctionCall2(line_parallel,
-										 LinePGetDatum(l1),
-										 LinePGetDatum(l2))))
-		return NULL;
-
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
+		if (FPzero(l2->B))		/* l2 vertical? */
+			return false;
+
 		x = l1->C;
 		y = (l2->A * x + l2->C);
 	}
-	else if (FPzero(l2->B))		/* l2 vertical? */
-	{
-		x = l2->C;
-		y = (l1->A * x + l1->C);
-	}
 	else
 	{
-		x = (l1->C - l2->C) / (l2->A - l1->A);
+		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+			return false;
+
+		if (FPzero(l2->B))
+			x = l2->C;
+		else
+			x = (l1->C - l2->C) / (l2->A - l1->A);
 		y = (l1->A * x + l1->C);
 	}
-	result = point_construct(x, y);
+	if (result != NULL)
+		point_construct(result, x, y);
 
 #ifdef GEODEBUG
 	printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
 		   DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
 	printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
 #endif
 
-	return result;
+	return true;
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D paths (sequences of line segments, also
  **				called `polylines').
  **
  **				This is not a general package for geometric paths,
  **				which of course include polygons; the emphasis here
@@ -1609,21 +1590,21 @@ path_inter(PG_FUNCTION_ARGS)
 				jprev = j - 1;
 			else
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
-			if (lseg_intersect_internal(&seg1, &seg2))
+			if (lseg_interpt_internal(NULL, &seg1, &seg2))
 				PG_RETURN_BOOL(true);
 		}
 	}
 
 	/* if we dropped through, no two segs intersected */
 	PG_RETURN_BOOL(false);
 }
 
 /* path_distance()
  * This essentially does a cartesian product of the lsegs in the
@@ -1664,23 +1645,21 @@ path_distance(PG_FUNCTION_ARGS)
 			else
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
-			tmp = DatumGetFloat8(DirectFunctionCall2(lseg_distance,
-													 LsegPGetDatum(&seg1),
-													 LsegPGetDatum(&seg2)));
+			tmp = lseg_dt(&seg1, &seg2);
 			if (!have_min || tmp < min)
 			{
 				min = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	if (!have_min)
 		PG_RETURN_NULL();
@@ -1773,45 +1752,31 @@ point_send(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	StringInfoData buf;
 
 	pq_begintypsend(&buf);
 	pq_sendfloat8(&buf, pt->x);
 	pq_sendfloat8(&buf, pt->y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
-
-static Point *
-point_construct(double x, double y)
+/*
+ * Initialize a point
+ *
+ * This function is over-simple, but it is, at least, useful when the new
+ * point is calculated using the existing one.
+ */
+static void
+point_construct(Point *result, float8 x, float8 y)
 {
-	Point	   *result = (Point *) palloc(sizeof(Point));
-
 	result->x = x;
 	result->y = y;
-	return result;
-}
-
-
-static Point *
-point_copy(Point *pt)
-{
-	Point	   *result;
-
-	if (!PointerIsValid(pt))
-		return NULL;
-
-	result = (Point *) palloc(sizeof(Point));
-
-	result->x = pt->x;
-	result->y = pt->y;
-	return result;
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for Points.
  *		Since we do have a sense of coordinates being
  *		"equal" to a given accuracy (point_vert, point_horiz),
  *		the other ops must preserve that sense.  This means
  *		that results may, strictly speaking, be a lie (unless
  *		EPSILON = 0.0).
@@ -1870,66 +1835,74 @@ point_horiz(PG_FUNCTION_ARGS)
 
 	PG_RETURN_BOOL(FPeq(pt1->y, pt2->y));
 }
 
 Datum
 point_eq(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y));
+	PG_RETURN_BOOL(point_eq_internal(pt1, pt2));
 }
 
 Datum
 point_ne(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPne(pt1->x, pt2->x) || FPne(pt1->y, pt2->y));
+	PG_RETURN_BOOL(!point_eq_internal(pt1, pt2));
 }
 
+
+static bool
+point_eq_internal(Point *pt1, Point *pt2)
+{
+	return FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y);
+}
+
+
 /*----------------------------------------------------------
  *	"Arithmetic" operators on points.
  *---------------------------------------------------------*/
 
 Datum
 point_distance(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_FLOAT8(HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
+	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
-double
+static float8
 point_dt(Point *pt1, Point *pt2)
 {
 #ifdef GEODEBUG
 	printf("point_dt- segment (%f,%f),(%f,%f) length is %f\n",
 	pt1->x, pt1->y, pt2->x, pt2->y, HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
 #endif
 	return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
 }
 
 Datum
 point_slope(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_sl(pt1, pt2));
 }
 
 
-double
+static float8
 point_sl(Point *pt1, Point *pt2)
 {
 	return (FPeq(pt1->x, pt2->x)
 			? (double) DBL_MAX
 			: (pt1->y - pt2->y) / (pt1->x - pt2->x));
 }
 
 
 /***********************************************************************
  **
@@ -1946,31 +1919,31 @@ point_sl(Point *pt1, Point *pt2)
  *		(old form)		"(x1, y1, x2, y2)"
  *---------------------------------------------------------*/
 
 Datum
 lseg_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	LSEG	   *lseg = (LSEG *) palloc(sizeof(LSEG));
 	bool		isopen;
 
-	path_decode(str, true, 2, &(lseg->p[0]), &isopen, NULL, "lseg", str);
+	path_decode(str, true, 2, &lseg->p[0], &isopen, NULL, "lseg", str);
 	PG_RETURN_LSEG_P(lseg);
 }
 
 
 Datum
 lseg_out(PG_FUNCTION_ARGS)
 {
 	LSEG	   *ls = PG_GETARG_LSEG_P(0);
 
-	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, (Point *) &(ls->p[0])));
+	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, &ls->p[0]));
 }
 
 /*
  *		lseg_recv			- converts external binary format to lseg
  */
 Datum
 lseg_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LSEG	   *lseg;
@@ -2046,39 +2019,23 @@ lseg_length(PG_FUNCTION_ARGS)
 /*
  **  find intersection of the two lines, and see if it falls on
  **  both segments.
  */
 Datum
 lseg_intersect(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(lseg_intersect_internal(l1, l2));
+	PG_RETURN_BOOL(lseg_interpt_internal(NULL, l1, l2));
 }
 
-static bool
-lseg_intersect_internal(LSEG *l1, LSEG *l2)
-{
-	LINE		ln;
-	Point	   *interpt;
-	bool		retval;
-
-	line_construct_pts(&ln, &l2->p[0], &l2->p[1]);
-	interpt = interpt_sl(l1, &ln);
-
-	if (interpt != NULL && on_ps_internal(interpt, l2))
-		retval = true;			/* interpt on l1 and l2 */
-	else
-		retval = false;
-	return retval;
-}
 
 Datum
 lseg_parallel(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_BOOL(FPeq(point_sl(&l1->p[0], &l1->p[1]),
 						point_sl(&l2->p[0], &l2->p[1])));
 }
@@ -2093,22 +2050,22 @@ lseg_parallel(PG_FUNCTION_ARGS)
  * - thomas 1998-01-31
  */
 Datum
 lseg_perp(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	double		m1,
 				m2;
 
-	m1 = point_sl(&(l1->p[0]), &(l1->p[1]));
-	m2 = point_sl(&(l2->p[0]), &(l2->p[1]));
+	m1 = point_sl(&l1->p[0], &l1->p[1]);
+	m2 = point_sl(&l2->p[0], &l2->p[1]);
 
 #ifdef GEODEBUG
 	printf("lseg_perp- slopes are %g and %g\n", m1, m2);
 #endif
 	if (FPzero(m1))
 		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
 	else if (FPzero(m2))
 		PG_RETURN_BOOL(FPeq(m1, DBL_MAX));
 
 	PG_RETURN_BOOL(FPeq(m1 / m2, -1.0));
@@ -2130,36 +2087,32 @@ lseg_horizontal(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(FPeq(lseg->p[0].y, lseg->p[1].y));
 }
 
 
 Datum
 lseg_eq(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPeq(l1->p[0].x, l2->p[0].x) &&
-				   FPeq(l1->p[0].y, l2->p[0].y) &&
-				   FPeq(l1->p[1].x, l2->p[1].x) &&
-				   FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(point_eq_internal(&l1->p[0], &l2->p[0]) &&
+				   point_eq_internal(&l1->p[1], &l2->p[1]));
 }
 
 Datum
 lseg_ne(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(!FPeq(l1->p[0].x, l2->p[0].x) ||
-				   !FPeq(l1->p[0].y, l2->p[0].y) ||
-				   !FPeq(l1->p[1].x, l2->p[1].x) ||
-				   !FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(!point_eq_internal(&l1->p[0], &l2->p[0]) ||
+				   !point_eq_internal(&l1->p[1], &l2->p[1]));
 }
 
 Datum
 lseg_lt(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_BOOL(FPlt(point_dt(&l1->p[0], &l1->p[1]),
 						point_dt(&l2->p[0], &l2->p[1])));
@@ -2218,21 +2171,21 @@ lseg_distance(PG_FUNCTION_ARGS)
  * Distance between two line segments.
  * Must check both sets of endpoints to ensure minimum distance is found.
  * - thomas 1998-02-01
  */
 static double
 lseg_dt(LSEG *l1, LSEG *l2)
 {
 	double		result,
 				d;
 
-	if (lseg_intersect_internal(l1, l2))
+	if (lseg_interpt_internal(NULL, l1, l2))
 		return 0.0;
 
 	d = dist_ps_internal(&l1->p[0], l2);
 	result = d;
 	d = dist_ps_internal(&l1->p[1], l2);
 	result = Min(result, d);
 	d = dist_ps_internal(&l2->p[0], l1);
 	result = Min(result, d);
 	d = dist_ps_internal(&l2->p[1], l1);
 	result = Min(result, d);
@@ -2248,82 +2201,86 @@ lseg_center(PG_FUNCTION_ARGS)
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
 	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
 
 	PG_RETURN_POINT_P(result);
 }
 
-static Point *
-lseg_interpt_internal(LSEG *l1, LSEG *l2)
+static bool
+lseg_interpt_internal(Point *result, LSEG *l1, LSEG *l2)
 {
-	Point	   *result;
+	Point		interpt;
 	LINE		tmp1,
 				tmp2;
 
 	/*
 	 * Find the intersection of the appropriate lines, if any.
 	 */
 	line_construct_pts(&tmp1, &l1->p[0], &l1->p[1]);
 	line_construct_pts(&tmp2, &l2->p[0], &l2->p[1]);
-	result = line_interpt_internal(&tmp1, &tmp2);
-	if (!PointerIsValid(result))
-		return NULL;
+	if (!line_interpt_internal(&interpt, &tmp1, &tmp2))
+		return false;
 
 	/*
 	 * If the line intersection point isn't within l1 (or equivalently l2),
 	 * there is no valid segment intersection point at all.
 	 */
-	if (!on_ps_internal(result, l1) ||
-		!on_ps_internal(result, l2))
-	{
-		pfree(result);
-		return NULL;
-	}
+	if (!on_ps_internal(&interpt, l1) ||
+		!on_ps_internal(&interpt, l2))
+		return false;
+
+	if (result == NULL)
+		return true;
 
 	/*
 	 * If there is an intersection, then check explicitly for matching
 	 * endpoints since there may be rounding effects with annoying lsb
 	 * residue. - tgl 1997-07-09
 	 */
 	if ((FPeq(l1->p[0].x, l2->p[0].x) && FPeq(l1->p[0].y, l2->p[0].y)) ||
 		(FPeq(l1->p[0].x, l2->p[1].x) && FPeq(l1->p[0].y, l2->p[1].y)))
 	{
 		result->x = l1->p[0].x;
 		result->y = l1->p[0].y;
 	}
 	else if ((FPeq(l1->p[1].x, l2->p[0].x) && FPeq(l1->p[1].y, l2->p[0].y)) ||
 			 (FPeq(l1->p[1].x, l2->p[1].x) && FPeq(l1->p[1].y, l2->p[1].y)))
 	{
 		result->x = l1->p[1].x;
 		result->y = l1->p[1].y;
 	}
+	else
+	{
+		result->x = interpt.x;
+		result->y = interpt.y;
+	}
 
-	return result;
+	return true;
 }
 
 /* lseg_interpt -
  *		Find the intersection point of two segments (if any).
  */
 Datum
 lseg_interpt(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
-	result = lseg_interpt_internal(l1, l2);
-	if (!PointerIsValid(result))
-		PG_RETURN_NULL();
+	result = (Point *) palloc(sizeof(Point));
 
+	if (!lseg_interpt_internal(result, l1, l2))
+		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
 
 /***********************************************************************
  **
  **		Routines for position comparisons of differently-typed
  **				2D objects.
  **
  ***********************************************************************/
 
@@ -2340,75 +2297,75 @@ dist_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
 	PG_RETURN_FLOAT8(dist_pl_internal(pt, line));
 }
 
 static double
 dist_pl_internal(Point *pt, LINE *line)
 {
-	return fabs((line->A * pt->x + line->B * pt->y + line->C) /
+	return fabs(line_calculate_point(line, pt) /
 				HYPOT(line->A, line->B));
 }
 
 /*
  * Distance from a point to a lseg
  */
 Datum
 dist_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_FLOAT8(dist_ps_internal(pt, lseg));
 }
 
 static double
 dist_ps_internal(Point *pt, LSEG *lseg)
 {
 	double		m;				/* slope of perp. */
-	LINE	   *ln;
 	double		result,
 				tmpdist;
-	Point	   *ip;
+	Point		interpt;
+	LINE		ln;
 
 	/*
 	 * Construct a line perpendicular to the input segment and through the
 	 * input point
 	 */
 	if (lseg->p[1].x == lseg->p[0].x)
 		m = 0;
 	else if (lseg->p[1].y == lseg->p[0].y)
 		m = (double) DBL_MAX;	/* slope is infinite */
 	else
-		m = (lseg->p[0].x - lseg->p[1].x) / (lseg->p[1].y - lseg->p[0].y);
-	ln = line_construct_pm(pt, m);
+		m = -1.0 / point_sl(&lseg->p[0], &lseg->p[1]);
+	line_construct_pm(&ln, pt, m);
 
 #ifdef GEODEBUG
 	printf("dist_ps- line is A=%g B=%g C=%g from (point) slope (%f,%f) %g\n",
 		   ln->A, ln->B, ln->C, pt->x, pt->y, m);
 #endif
 
 	/*
 	 * Calculate distance to the line segment or to the nearest endpoint of
 	 * the segment.
 	 */
 
 	/* intersection is on the line segment? */
-	if ((ip = interpt_sl(lseg, ln)) != NULL)
+	if (lseg_interpt_line_internal(&interpt, lseg, &ln))
 	{
 		/* yes, so use distance to the intersection point */
-		result = point_dt(pt, ip);
+		result = point_dt(pt, &interpt);
 #ifdef GEODEBUG
 		printf("dist_ps- distance is %f to intersection point is (%f,%f)\n",
-			   result, ip->x, ip->y);
+			   result, tmp.x, tmp.y);
 #endif
 	}
 	else
 	{
 		/* no, so use distance to the nearer endpoint */
 		result = point_dt(pt, &lseg->p[0]);
 		tmpdist = point_dt(pt, &lseg->p[1]);
 		if (tmpdist < result)
 			result = tmpdist;
 	}
@@ -2496,21 +2453,21 @@ dist_pb(PG_FUNCTION_ARGS)
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	float8		result,
 				d2;
 
-	if (has_interpt_sl(lseg, line))
+	if (lseg_interpt_line_internal(NULL, lseg, line))
 		result = 0.0;
 	else
 	{
 		result = dist_pl_internal(&lseg->p[0], line);
 		d2 = dist_pl_internal(&lseg->p[1], line);
 		/* XXX shouldn't we take the min not max? */
 		if (d2 > result)
 			result = d2;
 	}
 
@@ -2649,284 +2606,261 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
  *				Intersection point of objects.
  *				We choose to ignore the "point" of intersection between
  *				  lines and boxes, since there are typically two.
  *-------------------------------------------------------------------*/
 
-/* Get intersection point of lseg and line; returns NULL if no intersection */
-static Point *
-interpt_sl(LSEG *lseg, LINE *line)
+/*
+ * Check if the line segment intersects with the line
+ *
+ * It sets the intersection point to *result, if it is not NULL.
+ */
+static bool
+lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line)
 {
+	Point		interpt;
 	LINE		tmp;
-	Point	   *p;
 
 	line_construct_pts(&tmp, &lseg->p[0], &lseg->p[1]);
-	p = line_interpt_internal(&tmp, line);
 #ifdef GEODEBUG
-	printf("interpt_sl- segment is (%.*g %.*g) (%.*g %.*g)\n",
+	printf("lseg_interpt_line- segment is (%.*g %.*g) (%.*g %.*g)\n",
 		   DBL_DIG, lseg->p[0].x, DBL_DIG, lseg->p[0].y, DBL_DIG, lseg->p[1].x, DBL_DIG, lseg->p[1].y);
-	printf("interpt_sl- segment becomes line A=%.*g B=%.*g C=%.*g\n",
+	printf("lseg_interpt_line_- segment becomes line A=%.*g B=%.*g C=%.*g\n",
 		   DBL_DIG, tmp.A, DBL_DIG, tmp.B, DBL_DIG, tmp.C);
 #endif
-	if (PointerIsValid(p))
+	if (line_interpt_internal(&interpt, &tmp, line))
 	{
 #ifdef GEODEBUG
-		printf("interpt_sl- intersection point is (%.*g %.*g)\n", DBL_DIG, p->x, DBL_DIG, p->y);
+		printf("lseg_interpt_line- intersection point is (%.*g %.*g)\n", DBL_DIG, p->x, DBL_DIG, p->y);
 #endif
-		if (on_ps_internal(p, lseg))
+		if (on_ps_internal(&interpt, lseg))
 		{
 #ifdef GEODEBUG
-			printf("interpt_sl- intersection point is on segment\n");
+			printf("lseg_interpt_line- intersection point is on segment\n");
 #endif
+			if (result != NULL)
+				*result = interpt;
+			return true;
 		}
-		else
-			p = NULL;
 	}
 
-	return p;
-}
-
-/* variant: just indicate if intersection point exists */
-static bool
-has_interpt_sl(LSEG *lseg, LINE *line)
-{
-	Point	   *tmp;
-
-	tmp = interpt_sl(lseg, line);
-	if (tmp)
-		return true;
 	return false;
 }
 
+
 /*---------------------------------------------------------------------
  *		close_
  *				Point of closest proximity between objects.
  *-------------------------------------------------------------------*/
 
 /* close_pl -
  *		The intersection point of a perpendicular of the line
  *		through the point.
  */
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
-	LINE	   *tmp;
 	double		invm;
+	LINE		tmp;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (FPzero(line->B))		/* vertical? */
 	{
 		result->x = line->C;
 		result->y = pt->y;
 		PG_RETURN_POINT_P(result);
 	}
 	if (FPzero(line->A))		/* horizontal? */
 	{
 		result->x = pt->x;
 		result->y = line->C;
 		PG_RETURN_POINT_P(result);
 	}
 	/* drop a perpendicular and find the intersection point */
 
 	/* invert and flip the sign on the slope to get a perpendicular */
 	invm = line->B / line->A;
-	tmp = line_construct_pm(pt, invm);
-	result = line_interpt_internal(tmp, line);
-	Assert(result != NULL);
+	line_construct_pm(&tmp, pt, invm);
+	line_interpt_internal(result, &tmp, line);
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_ps()
  * Closest point on line segment to specified point.
  * Take the closest endpoint if the point is left, right,
  *	above, or below the segment, otherwise find the intersection
  *	point of the segment and its perpendicular through the point.
  *
  * Some tricky code here, relying on boolean expressions
  *	evaluating to only zero or one to use as an array index.
  *		bug fixes by gthaker@atl.lmco.com; May 1, 1998
  */
 Datum
 close_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
-	LINE	   *tmp;
+	Point	   *result;
 	double		invm;
 	int			xh,
 				yh;
+	LINE		tmp;
+
+	result = (Point *) palloc(sizeof(Point));
 
 #ifdef GEODEBUG
 	printf("close_sp:pt->x %f pt->y %f\nlseg(0).x %f lseg(0).y %f  lseg(1).x %f lseg(1).y %f\n",
 		   pt->x, pt->y, lseg->p[0].x, lseg->p[0].y,
 		   lseg->p[1].x, lseg->p[1].y);
 #endif
 
 	/* xh (or yh) is the index of upper x( or y) end point of lseg */
 	/* !xh (or !yh) is the index of lower x( or y) end point of lseg */
 	xh = lseg->p[0].x < lseg->p[1].x;
 	yh = lseg->p[0].y < lseg->p[1].y;
 
 	if (FPeq(lseg->p[0].x, lseg->p[1].x))		/* vertical? */
 	{
 #ifdef GEODEBUG
 		printf("close_ps- segment is vertical\n");
 #endif
 		/* first check if point is below or above the entire lseg. */
 		if (pt->y < lseg->p[!yh].y)
-			result = point_copy(&lseg->p[!yh]); /* below the lseg */
+			*result = lseg->p[!yh];		/* below the lseg */
 		else if (pt->y > lseg->p[yh].y)
-			result = point_copy(&lseg->p[yh]);	/* above the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
+			*result = lseg->p[yh];		/* above the lseg */
+		else
+			/* point lines along (to left or right) of the vertical lseg. */
+			point_construct(result, lseg->p[0].x, pt->y);
 
-		/* point lines along (to left or right) of the vertical lseg. */
-
-		result = (Point *) palloc(sizeof(Point));
-		result->x = lseg->p[0].x;
-		result->y = pt->y;
 		PG_RETURN_POINT_P(result);
 	}
 	else if (FPeq(lseg->p[0].y, lseg->p[1].y))	/* horizontal? */
 	{
 #ifdef GEODEBUG
 		printf("close_ps- segment is horizontal\n");
 #endif
 		/* first check if point is left or right of the entire lseg. */
 		if (pt->x < lseg->p[!xh].x)
-			result = point_copy(&lseg->p[!xh]); /* left of the lseg */
+			*result = lseg->p[!xh];		/* left of the lseg */
 		else if (pt->x > lseg->p[xh].x)
-			result = point_copy(&lseg->p[xh]);	/* right of the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
+			*result = lseg->p[xh];		/* right of the lseg */
+		else
+			/* point lines along (at top or below) the horiz. lseg. */
+			point_construct(result, pt->x, lseg->p[0].y);
 
-		/* point lines along (at top or below) the horiz. lseg. */
-		result = (Point *) palloc(sizeof(Point));
-		result->x = pt->x;
-		result->y = lseg->p[0].y;
 		PG_RETURN_POINT_P(result);
 	}
 
 	/*
 	 * vert. and horiz. cases are down, now check if the closest point is one
 	 * of the end points or someplace on the lseg.
 	 */
 
 	invm = -1.0 / point_sl(&(lseg->p[0]), &(lseg->p[1]));
-	tmp = line_construct_pm(&lseg->p[!yh], invm);		/* lower edge of the
+	line_construct_pm(&tmp, &lseg->p[!yh], invm);		/* lower edge of the
 														 * "band" */
-	if (pt->y < (tmp->A * pt->x + tmp->C))
+	if (pt->y < (tmp.A * pt->x + tmp.C))
 	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[!yh]);		/* below the lseg, take lower
-												 * end pt */
+		*result = lseg->p[!yh];		/* below the lseg, take lower end pt */
 #ifdef GEODEBUG
 		printf("close_ps below: tmp A %f  B %f   C %f\n",
 			   tmp->A, tmp->B, tmp->C);
 #endif
 		PG_RETURN_POINT_P(result);
 	}
-	tmp = line_construct_pm(&lseg->p[yh], invm);		/* upper edge of the
+	line_construct_pm(&tmp, &lseg->p[yh], invm);		/* upper edge of the
 														 * "band" */
-	if (pt->y > (tmp->A * pt->x + tmp->C))
+	if (pt->y > (tmp.A * pt->x + tmp.C))
 	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[yh]);		/* above the lseg, take higher
-												 * end pt */
+		*result = lseg->p[yh];		/* above the lseg, take higher end pt */
 #ifdef GEODEBUG
 		printf("close_ps above: tmp A %f  B %f   C %f\n",
 			   tmp->A, tmp->B, tmp->C);
 #endif
 		PG_RETURN_POINT_P(result);
 	}
 
 	/*
 	 * at this point the "normal" from point will hit lseg. The closest point
 	 * will be somewhere on the lseg
 	 */
-	tmp = line_construct_pm(pt, invm);
+	line_construct_pm(&tmp, pt, invm);
 #ifdef GEODEBUG
 	printf("close_ps- tmp A %f  B %f   C %f\n",
 		   tmp->A, tmp->B, tmp->C);
 #endif
-	result = interpt_sl(lseg, tmp);
 
 	/*
 	 * ordinarily we should always find an intersection point, but that could
 	 * fail in the presence of NaN coordinates, and perhaps even from simple
 	 * roundoff issues.  Return a SQL NULL if so.
 	 */
-	if (result == NULL)
+	if (!lseg_interpt_line_internal(result, lseg, &tmp))
 		PG_RETURN_NULL();
 
 #ifdef GEODEBUG
 	printf("close_ps- result.x %f  result.y %f\n", result->x, result->y);
 #endif
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_lseg()
  * Closest point to l1 on l2.
  */
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
-	Point		point;
-	double		dist;
-	double		d;
+	Point	   *result;
+	double		dist,
+				dist0,
+				dist1;
 
-	d = dist_ps_internal(&l1->p[0], l2);
-	dist = d;
-	memcpy(&point, &l1->p[0], sizeof(Point));
-
-	if ((d = dist_ps_internal(&l1->p[1], l2)) < dist)
-	{
-		dist = d;
-		memcpy(&point, &l1->p[1], sizeof(Point));
-	}
+	dist0 = dist_ps_internal(&l1->p[0], l2);
+	dist1 = dist_ps_internal(&l1->p[1], l2);
+	dist = Min(dist0, dist1);
 
 	if (dist_ps_internal(&l2->p[0], l1) < dist)
 	{
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(&l2->p[0]),
 													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
+													PointPGetDatum(result),
 													LsegPGetDatum(l2)));
 	}
-
-	if (dist_ps_internal(&l2->p[1], l1) < dist)
+	else if (dist_ps_internal(&l2->p[1], l1) < dist)
 	{
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(&l2->p[1]),
 													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
+													PointPGetDatum(result),
 													LsegPGetDatum(l2)));
 	}
-
-	if (result == NULL)
-		result = point_copy(&point);
+	else
+	{
+		result = (Point *) palloc(sizeof(Point));
+		*result = l1->p[dist == dist0 ? 0 : 1];
+	}
 
 	PG_RETURN_POINT_P(result);
 }
 
 /* close_pb()
  * Closest point on or in box to specified point.
  */
 Datum
 close_pb(PG_FUNCTION_ARGS)
 {
@@ -2989,30 +2923,31 @@ close_pb(PG_FUNCTION_ARGS)
 Datum
 close_sl(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 	float8		d1,
 				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
+	result = (Point *) palloc(sizeof(Point));
+
+	if (lseg_interpt_line_internal(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = dist_pl_internal(&lseg->p[0], line);
 	d2 = dist_pl_internal(&lseg->p[1], line);
 	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
+		*result = lseg->p[0];
 	else
-		result = point_copy(&lseg->p[1]);
+		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
 
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_sl\" not implemented")));
 
 	PG_RETURN_NULL();
 }
@@ -3022,30 +2957,31 @@ close_sl(PG_FUNCTION_ARGS)
  */
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 	float8		d1,
 				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
+	result = (Point *) palloc(sizeof(Point));
+
+	if (lseg_interpt_line_internal(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = dist_pl_internal(&lseg->p[0], line);
 	d2 = dist_pl_internal(&lseg->p[1], line);
 	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
+		*result = lseg->p[0];
 	else
-		result = point_copy(&lseg->p[1]);
+		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 }
 
 /* close_sb()
  * Closest point on or in box to line segment.
  */
 Datum
 close_sb(PG_FUNCTION_ARGS)
 {
@@ -3126,21 +3062,21 @@ close_lb(PG_FUNCTION_ARGS)
 
 /* on_pl -
  *		Does the point satisfy the equation?
  */
 Datum
 on_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(FPzero(line->A * pt->x + line->B * pt->y + line->C));
+	PG_RETURN_BOOL(FPzero(line_calculate_point(line, pt)));
 }
 
 
 /* on_ps -
  *		Determine colinearity by detecting a triangle inequality.
  * This algorithm seems to behave nicely even with lsb residues - tgl 1997-07-09
  */
 Datum
 on_ps(PG_FUNCTION_ARGS)
 {
@@ -3250,21 +3186,21 @@ on_sb(PG_FUNCTION_ARGS)
  *		inter_
  *				Whether one object intersects another.
  *-------------------------------------------------------------------*/
 
 Datum
 inter_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(has_interpt_sl(lseg, line));
+	PG_RETURN_BOOL(lseg_interpt_line_internal(NULL, lseg, line));
 }
 
 /* inter_sb()
  * Do line segment and box intersect?
  *
  * Segment completely inside box counts as intersection.
  * If you want only segments crossing box boundaries,
  *	try converting box to path first.
  *
  * Optimize for non-intersection by checking for box intersection first.
@@ -3294,35 +3230,35 @@ inter_sb(PG_FUNCTION_ARGS)
 										 BoxPGetDatum(box))) ||
 		DatumGetBool(DirectFunctionCall2(on_pb,
 										 PointPGetDatum(&lseg->p[1]),
 										 BoxPGetDatum(box))))
 		PG_RETURN_BOOL(true);
 
 	/* pairwise check lseg intersections */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
+	if (lseg_interpt_internal(NULL, &bseg, lseg))
 		PG_RETURN_BOOL(true);
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
+	if (lseg_interpt_internal(NULL, &bseg, lseg))
 		PG_RETURN_BOOL(true);
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
+	if (lseg_interpt_internal(NULL, &bseg, lseg))
 		PG_RETURN_BOOL(true);
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
+	if (lseg_interpt_internal(NULL, &bseg, lseg))
 		PG_RETURN_BOOL(true);
 
 	/* if we dropped through, no two segs intersected */
 	PG_RETURN_BOOL(false);
 }
 
 /* inter_lb()
  * Do line and box intersect?
  */
 Datum
@@ -3333,36 +3269,36 @@ inter_lb(PG_FUNCTION_ARGS)
 	LSEG		bseg;
 	Point		p1,
 				p2;
 
 	/* pairwise check lseg intersections */
 	p1.x = box->low.x;
 	p1.y = box->low.y;
 	p2.x = box->low.x;
 	p2.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line_internal(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->high.x;
 	p1.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line_internal(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p2.x = box->high.x;
 	p2.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line_internal(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->low.x;
 	p1.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line_internal(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 
 	/* if we dropped through, no intersection */
 	PG_RETURN_BOOL(false);
 }
 
 /*------------------------------------------------------------------
  * The following routines define a data type and operator class for
  * POLYGONS .... Part of which (the polygon's bounding box) is built on
  * top of the BOX data type.
@@ -3391,21 +3327,21 @@ make_bound_box(POLYGON *poly)
 			if (poly->p[i].x < x1)
 				x1 = poly->p[i].x;
 			if (poly->p[i].x > x2)
 				x2 = poly->p[i].x;
 			if (poly->p[i].y < y1)
 				y1 = poly->p[i].y;
 			if (poly->p[i].y > y2)
 				y2 = poly->p[i].y;
 		}
 
-		box_fill(&(poly->boundbox), x1, x2, y1, y2);
+		box_construct(&poly->boundbox, x1, x2, y1, y2);
 	}
 	else
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("cannot create bounding box for empty polygon")));
 }
 
 /*------------------------------------------------------------------
  * poly_in - read in the polygon from a string specification
  *
@@ -3742,21 +3678,21 @@ poly_same(PG_FUNCTION_ARGS)
  *-----------------------------------------------------------------*/
 Datum
 poly_overlap(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
 	/* Quick check by bounding box */
 	result = (polya->npts > 0 && polyb->npts > 0 &&
-			  box_ov(&polya->boundbox, &polyb->boundbox)) ? true : false;
+			  box_ov(&polya->boundbox, &polyb->boundbox));
 
 	/*
 	 * Brute-force algorithm - try to find intersected edges, if so then
 	 * polygons are overlapped else check is one polygon inside other or not
 	 * by testing single point of them.
 	 */
 	if (result)
 	{
 		int			ia,
 					ib;
@@ -3771,34 +3707,33 @@ poly_overlap(PG_FUNCTION_ARGS)
 		{
 			/* Second point of polya's edge is a current one */
 			sa.p[1] = polya->p[ia];
 
 			/* Init first of polyb's edge with last point */
 			sb.p[0] = polyb->p[polyb->npts - 1];
 
 			for (ib = 0; ib < polyb->npts && result == false; ib++)
 			{
 				sb.p[1] = polyb->p[ib];
-				result = lseg_intersect_internal(&sa, &sb);
+				result = lseg_interpt_internal(NULL, &sa, &sb);
 				sb.p[0] = sb.p[1];
 			}
 
 			/*
 			 * move current endpoint to the first point of next edge
 			 */
 			sa.p[0] = sa.p[1];
 		}
 
 		if (result == false)
 		{
-			result = (point_inside(polya->p, polyb->npts, polyb->p)
-					  ||
+			result = (point_inside(polya->p, polyb->npts, polyb->p) ||
 					  point_inside(polyb->p, polya->npts, polya->p));
 		}
 	}
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
@@ -3818,27 +3753,26 @@ poly_overlap(PG_FUNCTION_ARGS)
 
 static bool
 touched_lseg_inside_poly(Point *a, Point *b, LSEG *s, POLYGON *poly, int start)
 {
 	/* point a is on s, b is not */
 	LSEG		t;
 
 	t.p[0] = *a;
 	t.p[1] = *b;
 
-#define POINTEQ(pt1, pt2)	(FPeq((pt1)->x, (pt2)->x) && FPeq((pt1)->y, (pt2)->y))
-	if (POINTEQ(a, s->p))
+	if (point_eq_internal(a, s->p))
 	{
 		if (on_ps_internal(s->p + 1, &t))
 			return lseg_inside_poly(b, s->p + 1, poly, start);
 	}
-	else if (POINTEQ(a, s->p + 1))
+	else if (point_eq_internal(a, s->p + 1))
 	{
 		if (on_ps_internal(s->p, &t))
 			return lseg_inside_poly(b, s->p, poly, start);
 	}
 	else if (on_ps_internal(s->p, &t))
 	{
 		return lseg_inside_poly(b, s->p, poly, start);
 	}
 	else if (on_ps_internal(s->p + 1, &t))
 	{
@@ -3861,50 +3795,49 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 	int			i;
 	bool		res = true,
 				intersection = false;
 
 	t.p[0] = *a;
 	t.p[1] = *b;
 	s.p[0] = poly->p[(start == 0) ? (poly->npts - 1) : (start - 1)];
 
 	for (i = start; i < poly->npts && res; i++)
 	{
-		Point	   *interpt;
+		Point		interpt;
 
 		CHECK_FOR_INTERRUPTS();
 
 		s.p[1] = poly->p[i];
 
 		if (on_ps_internal(t.p, &s))
 		{
 			if (on_ps_internal(t.p + 1, &s))
 				return true;	/* t is contained by s */
 
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p, t.p + 1, &s, poly, i + 1);
 		}
 		else if (on_ps_internal(t.p + 1, &s))
 		{
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p + 1, t.p, &s, poly, i + 1);
 		}
-		else if ((interpt = lseg_interpt_internal(&t, &s)) != NULL)
+		else if (lseg_interpt_internal(&interpt, &t, &s))
 		{
 			/*
 			 * segments are X-crossing, go to check each subsegment
 			 */
 
 			intersection = true;
-			res = lseg_inside_poly(t.p, interpt, poly, i + 1);
+			res = lseg_inside_poly(t.p, &interpt, poly, i + 1);
 			if (res)
-				res = lseg_inside_poly(t.p + 1, interpt, poly, i + 1);
-			pfree(interpt);
+				res = lseg_inside_poly(t.p + 1, &interpt, poly, i + 1);
 		}
 
 		s.p[0] = s.p[1];
 	}
 
 	if (res && !intersection)
 	{
 		Point		p;
 
 		/*
@@ -4019,170 +3952,205 @@ poly_distance(PG_FUNCTION_ARGS)
  **
  **		Routines for 2D points.
  **
  ***********************************************************************/
 
 Datum
 construct_point(PG_FUNCTION_ARGS)
 {
 	float8		x = PG_GETARG_FLOAT8(0);
 	float8		y = PG_GETARG_FLOAT8(1);
+	Point	   *result;
 
-	PG_RETURN_POINT_P(point_construct(x, y));
+	result = (Point *) palloc(sizeof(Point));
+
+	point_construct(result, x, y);
+
+	PG_RETURN_POINT_P(result);
 }
 
 Datum
 point_add(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x + p2->x);
-	result->y = (p1->y + p2->y);
+	point_add_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+static void
+point_add_internal(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x + pt2->x,
+					pt1->y + pt2->y);
+}
+
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x - p2->x);
-	result->y = (p1->y - p2->y);
+	point_sub_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+static void
+point_sub_internal(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x - pt2->x,
+					pt1->y - pt2->y);
+}
+
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x * p2->x) - (p1->y * p2->y);
-	result->y = (p1->x * p2->y) + (p1->y * p2->x);
+	point_mul_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+static void
+point_mul_internal(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					(pt1->x * pt2->x) - (pt1->y * pt2->y),
+					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+}
+
 Datum
 point_div(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
-	double		div;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	div = (p2->x * p2->x) + (p2->y * p2->y);
-
-	if (div == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result->x = ((p1->x * p2->x) + (p1->y * p2->y)) / div;
-	result->y = ((p2->x * p1->y) - (p2->y * p1->x)) / div;
+	point_div_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+static void
+point_div_internal(Point *result, Point *pt1, Point *pt2)
+{
+	float8		div;
+
+	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
+	point_construct(result,
+					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
+					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+}
+
 
 /***********************************************************************
  **
  **		Routines for 2D boxes.
  **
  ***********************************************************************/
 
 Datum
 points_box(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct(p1->x, p2->x, p1->y, p2->y));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	box_construct(result, p1->x, p2->x, p1->y, p2->y);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_add(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct((box->high.x + p->x),
-								  (box->low.x + p->x),
-								  (box->high.y + p->y),
-								  (box->low.y + p->y)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_add_internal(&result->high, &box->high, p);
+	point_add_internal(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_sub(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct((box->high.x - p->x),
-								  (box->low.x - p->x),
-								  (box->high.y - p->y),
-								  (box->low.y - p->y)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_sub_internal(&result->high, &box->high, p);
+	point_sub_internal(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_mul(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
 
-	high = DatumGetPointP(DirectFunctionCall2(point_mul,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_mul,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	result = (BOX *) palloc(sizeof(BOX));
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	point_mul_internal(&high, &box->high, p);
+	point_mul_internal(&low, &box->low, p);
+
+	box_construct(result, high.x, low.x, high.y, low.y);
 
 	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_div(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
 
-	high = DatumGetPointP(DirectFunctionCall2(point_div,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_div,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	result = (BOX *) palloc(sizeof(BOX));
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	point_div_internal(&high, &box->high, p);
+	point_div_internal(&low, &box->low, p);
+
+	box_construct(result, high.x, low.x, high.y, low.y);
 
 	PG_RETURN_BOX_P(result);
 }
 
 /*
  * Convert point to empty box
  */
 Datum
 point_box(PG_FUNCTION_ARGS)
 {
@@ -4278,83 +4246,63 @@ path_add(PG_FUNCTION_ARGS)
  * Translation operators.
  */
 Datum
 path_add_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x += point->x;
-		path->p[i].y += point->y;
-	}
+		point_add_internal(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_sub_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x -= point->x;
-		path->p[i].y -= point->y;
-	}
+		point_sub_internal(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 /* path_mul_pt()
  * Rotation and scaling operators.
  */
 Datum
 path_mul_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_mul,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_mul_internal(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_div_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_div,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_div_internal(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 
 Datum
 path_center(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	PATH	   *path = PG_GETARG_PATH_P(0);
@@ -4436,21 +4384,22 @@ poly_center(PG_FUNCTION_ARGS)
 
 Datum
 poly_box(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	BOX		   *box;
 
 	if (poly->npts < 1)
 		PG_RETURN_NULL();
 
-	box = box_copy(&poly->boundbox);
+	box = (BOX *) palloc(sizeof(BOX));
+	*box = poly->boundbox;
 
 	PG_RETURN_BOX_P(box);
 }
 
 
 /* box_poly()
  * Convert a box to a polygon.
  */
 Datum
 box_poly(PG_FUNCTION_ARGS)
@@ -4468,22 +4417,22 @@ box_poly(PG_FUNCTION_ARGS)
 
 	poly->p[0].x = box->low.x;
 	poly->p[0].y = box->low.y;
 	poly->p[1].x = box->low.x;
 	poly->p[1].y = box->high.y;
 	poly->p[2].x = box->high.x;
 	poly->p[2].y = box->high.y;
 	poly->p[3].x = box->high.x;
 	poly->p[3].y = box->low.y;
 
-	box_fill(&poly->boundbox, box->high.x, box->low.x,
-			 box->high.y, box->low.y);
+	box_construct(&poly->boundbox, box->high.x, box->low.x,
+				  box->high.y, box->low.y);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
 
 Datum
 poly_path(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	PATH	   *path;
@@ -4492,21 +4441,21 @@ poly_path(PG_FUNCTION_ARGS)
 
 	/*
 	 * Never overflows: the old size fit in MaxAllocSize, and the new size is
 	 * smaller by a small constant.
 	 */
 	size = offsetof(PATH, p) +sizeof(path->p[0]) * poly->npts;
 	path = (PATH *) palloc(size);
 
 	SET_VARSIZE(path, size);
 	path->npts = poly->npts;
-	path->closed = TRUE;
+	path->closed = true;
 	/* prevent instability in unused pad bytes */
 	path->dummy = 0;
 
 	for (i = 0; i < poly->npts; i++)
 	{
 		path->p[i].x = poly->p[i].x;
 		path->p[i].y = poly->p[i].y;
 	}
 
 	PG_RETURN_PATH_P(path);
@@ -4558,22 +4507,21 @@ circle_in(PG_FUNCTION_ARGS)
 
 	circle->radius = single_decode(s, &s, "circle", str);
 	if (circle->radius < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
 
 	while (depth > 0)
 	{
-		if ((*s == RDELIM)
-			|| ((*s == RDELIM_C) && (depth == 1)))
+		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
 			s++;
 			while (isspace((unsigned char) *s))
 				s++;
 		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
@@ -4657,22 +4605,21 @@ circle_send(PG_FUNCTION_ARGS)
 
 /*		circles identical?
  */
 Datum
 circle_same(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPeq(circle1->radius, circle2->radius) &&
-				   FPeq(circle1->center.x, circle2->center.x) &&
-				   FPeq(circle1->center.y, circle2->center.y));
+				   point_eq_internal(&circle1->center, &circle2->center));
 }
 
 /*		circle_overlap	-		does circle1 overlap circle2?
  */
 Datum
 circle_overlap(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
@@ -4859,106 +4806,82 @@ circle_ge(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPge(circle_ar(circle1), circle_ar(circle2)));
 }
 
 
 /*----------------------------------------------------------
  *	"Arithmetic" operators on circles.
  *---------------------------------------------------------*/
 
-static CIRCLE *
-circle_copy(CIRCLE *circle)
-{
-	CIRCLE	   *result;
-
-	if (!PointerIsValid(circle))
-		return NULL;
-
-	result = (CIRCLE *) palloc(sizeof(CIRCLE));
-	memcpy((char *) result, (char *) circle, sizeof(CIRCLE));
-	return result;
-}
-
-
 /* circle_add_pt()
  * Translation operator.
  */
 Datum
 circle_add_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x += point->x;
-	result->center.y += point->y;
+	point_add_internal(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_sub_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x -= point->x;
-	result->center.y -= point->y;
+	point_sub_internal(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /* circle_mul_pt()
  * Rotation and scaling operators.
  */
 Datum
 circle_mul_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_mul,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
+	point_mul_internal(&result->center, &circle->center, point);
 	result->radius *= HYPOT(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_div_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_div,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
+	point_div_internal(&result->center, &circle->center, point);
 	result->radius /= HYPOT(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /*		circle_area		-		returns the area of the circle.
  */
 Datum
 circle_area(PG_FUNCTION_ARGS)
@@ -5372,118 +5295,55 @@ lseg_crossing(double x, double y, double prev_x, double prev_y)
 static bool
 plist_same(int npts, Point *p1, Point *p2)
 {
 	int			i,
 				ii,
 				j;
 
 	/* find match for first point */
 	for (i = 0; i < npts; i++)
 	{
-		if ((FPeq(p2[i].x, p1[0].x))
-			&& (FPeq(p2[i].y, p1[0].y)))
+		if (point_eq_internal(&p2[i], &p1[0]))
 		{
 
 			/* match found? then look forward through remaining points */
 			for (ii = 1, j = i + 1; ii < npts; ii++, j++)
 			{
 				if (j >= npts)
 					j = 0;
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_internal(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed forward match with %d\n", j, ii);
 #endif
 					break;
 				}
 			}
 #ifdef GEODEBUG
 			printf("plist_same- ii = %d/%d after forward match\n", ii, npts);
 #endif
 			if (ii == npts)
-				return TRUE;
+				return true;
 
 			/* match not found forwards? then look backwards */
 			for (ii = 1, j = i - 1; ii < npts; ii++, j--)
 			{
 				if (j < 0)
 					j = (npts - 1);
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_internal(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed reverse match with %d\n", j, ii);
 #endif
 					break;
 				}
 			}
 #ifdef GEODEBUG
 			printf("plist_same- ii = %d/%d after reverse match\n", ii, npts);
 #endif
 			if (ii == npts)
-				return TRUE;
+				return true;
 		}
 	}
 
-	return FALSE;
-}
-
-
-/*-------------------------------------------------------------------------
- * Determine the hypotenuse.
- *
- * If required, x and y are swapped to make x the larger number. The
- * traditional formula of x^2+y^2 is rearranged to factor x outside the
- * sqrt. This allows computation of the hypotenuse for significantly
- * larger values, and with a higher precision than when using the naive
- * formula.  In particular, this cannot overflow unless the final result
- * would be out-of-range.
- *
- * sqrt( x^2 + y^2 ) = sqrt( x^2( 1 + y^2/x^2) )
- *					 = x * sqrt( 1 + y^2/x^2 )
- *					 = x * sqrt( 1 + y/x * y/x )
- *
- * It is expected that this routine will eventually be replaced with the
- * C99 hypot() function.
- *
- * This implementation conforms to IEEE Std 1003.1 and GLIBC, in that the
- * case of hypot(inf,nan) results in INF, and not NAN.
- *-----------------------------------------------------------------------
- */
-double
-pg_hypot(double x, double y)
-{
-	double		yx;
-
-	/* Handle INF and NaN properly */
-	if (isinf(x) || isinf(y))
-		return get_float8_infinity();
-
-	if (isnan(x) || isnan(y))
-		return get_float8_nan();
-
-	/* Else, drop any minus signs */
-	x = fabs(x);
-	y = fabs(y);
-
-	/* Swap x and y if needed to make x the larger one */
-	if (x < y)
-	{
-		double		temp = x;
-
-		x = y;
-		y = temp;
-	}
-
-	/*
-	 * If y is zero, the hypotenuse is x.  This test saves a few cycles in
-	 * such cases, but more importantly it also protects against
-	 * divide-by-zero errors, since now x >= y.
-	 */
-	if (y == 0.0)
-		return x;
-
-	/* Determine the hypotenuse */
-	yx = y / x;
-	return x * sqrt(1.0 + (yx * yx));
+	return false;
 }
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 9b530dbe3d..90119a0158 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -43,21 +43,21 @@
 #else
 #define FPzero(A)				((A) == 0)
 #define FPeq(A,B)				((A) == (B))
 #define FPne(A,B)				((A) != (B))
 #define FPlt(A,B)				((A) < (B))
 #define FPle(A,B)				((A) <= (B))
 #define FPgt(A,B)				((A) > (B))
 #define FPge(A,B)				((A) >= (B))
 #endif
 
-#define HYPOT(A, B)				pg_hypot(A, B)
+#define HYPOT(A, B)				hypot(A, B)
 
 /*---------------------------------------------------------------------
  * Point - (x,y)
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	double		x,
 				y;
 } Point;
 
@@ -166,21 +166,11 @@ typedef struct
 #define PolygonPGetDatum(X)			PointerGetDatum(X)
 #define PG_GETARG_POLYGON_P(n)		DatumGetPolygonP(PG_GETARG_DATUM(n))
 #define PG_GETARG_POLYGON_P_COPY(n) DatumGetPolygonPCopy(PG_GETARG_DATUM(n))
 #define PG_RETURN_POLYGON_P(x)		return PolygonPGetDatum(x)
 
 #define DatumGetCircleP(X)	  ((CIRCLE *) DatumGetPointer(X))
 #define CirclePGetDatum(X)	  PointerGetDatum(X)
 #define PG_GETARG_CIRCLE_P(n) DatumGetCircleP(PG_GETARG_DATUM(n))
 #define PG_RETURN_CIRCLE_P(x) return CirclePGetDatum(x)
 
-
-/*
- * 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 */
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index 6b1310344b..e6debb1370 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -64,21 +64,23 @@ regress_dist_ptpath(PG_FUNCTION_ARGS)
 	float8		result = 0.0;	/* keep compiler quiet */
 	float8		tmp;
 	int			i;
 	LSEG		lseg;
 
 	switch (path->npts)
 	{
 		case 0:
 			PG_RETURN_NULL();
 		case 1:
-			result = point_dt(pt, &path->p[0]);
+			result = DatumGetFloat8(DirectFunctionCall2(point_distance,
+														PointPGetDatum(pt),
+												PointPGetDatum(&path->p[0])));
 			break;
 		default:
 
 			/*
 			 * the distance from a point to a path is the smallest distance
 			 * from the point to any of its constituent segments.
 			 */
 			Assert(path->npts > 1);
 			for (i = 0; i < path->npts - 1; ++i)
 			{
@@ -282,22 +284,27 @@ widget_out(PG_FUNCTION_ARGS)
 	PG_RETURN_CSTRING(str);
 }
 
 PG_FUNCTION_INFO_V1(pt_in_widget);
 
 Datum
 pt_in_widget(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	WIDGET	   *widget = (WIDGET *) PG_GETARG_POINTER(1);
+	float8		distance;
 
-	PG_RETURN_BOOL(point_dt(point, &widget->center) < widget->radius);
+	distance = DatumGetFloat8(DirectFunctionCall2(point_distance,
+												  PointPGetDatum(point),
+											PointPGetDatum(&widget->center)));
+
+	PG_RETURN_BOOL(distance < widget->radius);
 }
 
 PG_FUNCTION_INFO_V1(boxarea);
 
 Datum
 boxarea(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	double		width,
 				height;
-- 
2.11.0 (Apple Git-81)

0002-float-header-v04.patchapplication/octet-stream; name=0002-float-header-v04.patchDownload
From e7bfe1d27fe4a33de79cf24254bae4923a236a21 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 28 May 2016 18:16:05 +0200
Subject: [PATCH 2/4] float-header-v04

Provide header file for built-in float datatypes

Even though, some datatypes under adt/ have separate header files,
most of the simple ones do not.  Their public functions were on
the builtins.h.  We would need to make more functions of floats public
to let the geometric types built on top of them.  This is a good
opportunity to make a separate header file for floats.

1acf7572554515b99ef6e783750aaea8777524ec made _cmp functions public
to solve NaN problem locally for GiST indexes.  This patch reworks it
in favour of a more extensive API.  Kevin Grittner suggested to design
the API using inline functions.  They are easier to use compared
to macros, and avoid double-evaluation hazards.
---
 contrib/btree_gin/btree_gin.c                 |   3 +-
 contrib/btree_gist/btree_ts.c                 |   2 +-
 contrib/cube/cube.c                           |   2 +-
 contrib/postgres_fdw/postgres_fdw.c           |   2 +-
 src/backend/access/gist/gistget.c             |   2 +-
 src/backend/access/gist/gistproc.c            |  55 +--
 src/backend/access/gist/gistutil.c            |   2 +-
 src/backend/utils/adt/float.c                 | 593 ++++++--------------------
 src/backend/utils/adt/formatting.c            |   8 +-
 src/backend/utils/adt/geo_ops.c               |   6 +-
 src/backend/utils/adt/geo_spgist.c            |   2 +-
 src/backend/utils/adt/numeric.c               |   1 +
 src/backend/utils/adt/rangetypes_gist.c       |   3 +-
 src/backend/utils/adt/rangetypes_selfuncs.c   |   3 +-
 src/backend/utils/adt/rangetypes_typanalyze.c |   3 +-
 src/backend/utils/adt/timestamp.c             |   1 +
 src/backend/utils/misc/guc.c                  |   1 +
 src/include/utils/builtins.h                  |  14 -
 src/include/utils/float.h                     | 383 +++++++++++++++++
 src/include/utils/geo_decls.h                 |   1 +
 20 files changed, 561 insertions(+), 526 deletions(-)
 create mode 100644 src/include/utils/float.h

diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index 6f0c752b2e..86efe454b4 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -1,22 +1,23 @@
 /*
  * contrib/btree_gin/btree_gin.c
  */
 #include "postgres.h"
 
 #include <limits.h>
 
 #include "access/stratnum.h"
-#include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/cash.h"
 #include "utils/date.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/inet.h"
 #include "utils/numeric.h"
 #include "utils/timestamp.h"
 #include "utils/varbit.h"
 
 PG_MODULE_MAGIC;
 
 typedef struct QueryInfo
 {
 	StrategyNumber strategy;
diff --git a/contrib/btree_gist/btree_ts.c b/contrib/btree_gist/btree_ts.c
index 592466c948..16f5107c6c 100644
--- a/contrib/btree_gist/btree_ts.c
+++ b/contrib/btree_gist/btree_ts.c
@@ -1,21 +1,21 @@
 /*
  * contrib/btree_gist/btree_ts.c
  */
 #include "postgres.h"
 
 #include <limits.h>
 
 #include "btree_gist.h"
 #include "btree_utils_num.h"
-#include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 typedef struct
 {
 	Timestamp	lower;
 	Timestamp	upper;
 } tsKEY;
 
 /*
 ** timestamp ops
 */
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c
index 2bb2ed029d..431495c02e 100644
--- a/contrib/cube/cube.c
+++ b/contrib/cube/cube.c
@@ -7,21 +7,21 @@
 ******************************************************************************/
 
 #include "postgres.h"
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 
 #include "cubedata.h"
 
 PG_MODULE_MAGIC;
 
 /*
  * Taken from the intarray contrib header
  */
 #define ARRPTR(x)  ( (double *) ARR_DATA_PTR(x) )
 #define ARRNELEMS(x)  ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x))
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 080cb0a074..f1747ac84a 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -27,21 +27,21 @@
 #include "nodes/nodeFuncs.h"
 #include "optimizer/cost.h"
 #include "optimizer/clauses.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
 #include "optimizer/planmain.h"
 #include "optimizer/restrictinfo.h"
 #include "optimizer/var.h"
 #include "optimizer/tlist.h"
 #include "parser/parsetree.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 #include "utils/sampling.h"
 #include "utils/selfuncs.h"
 
 PG_MODULE_MAGIC;
 
 /* Default CPU cost to start up a foreign query. */
diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c
index 5a4dea89ac..f380802c76 100644
--- a/src/backend/access/gist/gistget.c
+++ b/src/backend/access/gist/gistget.c
@@ -13,21 +13,21 @@
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/gist_private.h"
 #include "access/relscan.h"
 #include "catalog/pg_type.h"
 #include "miscadmin.h"
 #include "pgstat.h"
 #include "lib/pairingheap.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 
 /*
  * gistkillitems() -- set LP_DEAD state for items an indexscan caller has
  * told us were killed.
  *
  * We re-read page here, so it's important to check page LSN. If the page
  * has been modified since the last read (as determined by LSN), we cannot
  * flag any entries because it is possible that the old entry was vacuumed
diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index 15b89fd8ad..818f5e3263 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -27,62 +27,53 @@
 
 
 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
 						 StrategyNumber strategy);
 static bool rtree_internal_consistent(BOX *key, BOX *query,
 						  StrategyNumber strategy);
 
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
 
-/* Convenience macros for NaN-aware comparisons */
-#define FLOAT8_EQ(a,b)	(float8_cmp_internal(a, b) == 0)
-#define FLOAT8_LT(a,b)	(float8_cmp_internal(a, b) < 0)
-#define FLOAT8_LE(a,b)	(float8_cmp_internal(a, b) <= 0)
-#define FLOAT8_GT(a,b)	(float8_cmp_internal(a, b) > 0)
-#define FLOAT8_GE(a,b)	(float8_cmp_internal(a, b) >= 0)
-#define FLOAT8_MAX(a,b)  (FLOAT8_GT(a, b) ? (a) : (b))
-#define FLOAT8_MIN(a,b)  (FLOAT8_LT(a, b) ? (a) : (b))
-
 
 /**************************************************
  * Box ops
  **************************************************/
 
 /*
  * Calculates union of two boxes, a and b. The result is stored in *n.
  */
 static void
 rt_box_union(BOX *n, const BOX *a, const BOX *b)
 {
-	n->high.x = FLOAT8_MAX(a->high.x, b->high.x);
-	n->high.y = FLOAT8_MAX(a->high.y, b->high.y);
-	n->low.x = FLOAT8_MIN(a->low.x, b->low.x);
-	n->low.y = FLOAT8_MIN(a->low.y, b->low.y);
+	n->high.x = float8_max(a->high.x, b->high.x);
+	n->high.y = float8_max(a->high.y, b->high.y);
+	n->low.x = float8_min(a->low.x, b->low.x);
+	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
 static double
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
-	if (FLOAT8_LE(box->high.x, box->low.x) ||
-		FLOAT8_LE(box->high.y, box->low.y))
+	if (float8_le(box->high.x, box->low.x) ||
+		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
 	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
@@ -137,27 +128,27 @@ gist_box_consistent(PG_FUNCTION_ARGS)
 												 query,
 												 strategy));
 }
 
 /*
  * Increase BOX b to include addon.
  */
 static void
 adjustBox(BOX *b, const BOX *addon)
 {
-	if (FLOAT8_LT(b->high.x, addon->high.x))
+	if (float8_lt(b->high.x, addon->high.x))
 		b->high.x = addon->high.x;
-	if (FLOAT8_GT(b->low.x, addon->low.x))
+	if (float8_gt(b->low.x, addon->low.x))
 		b->low.x = addon->low.x;
-	if (FLOAT8_LT(b->high.y, addon->high.y))
+	if (float8_lt(b->high.y, addon->high.y))
 		b->high.y = addon->high.y;
-	if (FLOAT8_GT(b->low.y, addon->low.y))
+	if (float8_gt(b->low.y, addon->low.y))
 		b->low.y = addon->low.y;
 }
 
 /*
  * The GiST Union method for boxes
  *
  * returns the minimal bounding box that encloses all the entries in entryvec
  */
 Datum
 gist_box_union(PG_FUNCTION_ARGS)
@@ -637,36 +628,36 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		i1 = 0;
 		i2 = 0;
 		rightLower = intervalsLower[i1].lower;
 		leftUpper = intervalsUpper[i2].lower;
 		while (true)
 		{
 			/*
 			 * Find next lower bound of right group.
 			 */
 			while (i1 < nentries &&
-				   FLOAT8_EQ(rightLower, intervalsLower[i1].lower))
+				   float8_eq(rightLower, intervalsLower[i1].lower))
 			{
-				if (FLOAT8_LT(leftUpper, intervalsLower[i1].upper))
+				if (float8_lt(leftUpper, intervalsLower[i1].upper))
 					leftUpper = intervalsLower[i1].upper;
 				i1++;
 			}
 			if (i1 >= nentries)
 				break;
 			rightLower = intervalsLower[i1].lower;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * left group.
 			 */
 			while (i2 < nentries &&
-				   FLOAT8_LE(intervalsUpper[i2].upper, leftUpper))
+				   float8_le(intervalsUpper[i2].upper, leftUpper))
 				i2++;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim, rightLower, i1, leftUpper, i2);
 		}
 
 		/*
 		 * Iterate over upper bound of left group finding greatest possible
@@ -674,35 +665,35 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		 */
 		i1 = nentries - 1;
 		i2 = nentries - 1;
 		rightLower = intervalsLower[i1].upper;
 		leftUpper = intervalsUpper[i2].upper;
 		while (true)
 		{
 			/*
 			 * Find next upper bound of left group.
 			 */
-			while (i2 >= 0 && FLOAT8_EQ(leftUpper, intervalsUpper[i2].upper))
+			while (i2 >= 0 && float8_eq(leftUpper, intervalsUpper[i2].upper))
 			{
-				if (FLOAT8_GT(rightLower, intervalsUpper[i2].lower))
+				if (float8_gt(rightLower, intervalsUpper[i2].lower))
 					rightLower = intervalsUpper[i2].lower;
 				i2--;
 			}
 			if (i2 < 0)
 				break;
 			leftUpper = intervalsUpper[i2].upper;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * right group.
 			 */
-			while (i1 >= 0 && FLOAT8_GE(intervalsLower[i1].lower, rightLower))
+			while (i1 >= 0 && float8_ge(intervalsLower[i1].lower, rightLower))
 				i1--;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim,
 								 rightLower, i1 + 1, leftUpper, i2 + 1);
 		}
 	}
 
@@ -776,42 +767,42 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
 		}
 		else
 		{
 			lower = box->low.y;
 			upper = box->high.y;
 		}
 
-		if (FLOAT8_LE(upper, context.leftUpper))
+		if (float8_le(upper, context.leftUpper))
 		{
 			/* Fits to the left group */
-			if (FLOAT8_GE(lower, context.rightLower))
+			if (float8_ge(lower, context.rightLower))
 			{
 				/* Fits also to the right group, so "common entry" */
 				commonEntries[commonEntriesCount++].index = i;
 			}
 			else
 			{
 				/* Doesn't fit to the right group, so join to the left group */
 				PLACE_LEFT(box, i);
 			}
 		}
 		else
 		{
 			/*
 			 * Each entry should fit on either left or right group. Since this
 			 * entry didn't fit on the left group, it better fit in the right
 			 * group.
 			 */
-			Assert(FLOAT8_GE(lower, context.rightLower));
+			Assert(float8_ge(lower, context.rightLower));
 
 			/* Doesn't fit to the left group, so join to the right group */
 			PLACE_RIGHT(box, i);
 		}
 	}
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
@@ -881,24 +872,24 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
  * equivalent to box_same().
  */
 Datum
 gist_box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *b1 = PG_GETARG_BOX_P(0);
 	BOX		   *b2 = PG_GETARG_BOX_P(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
 	if (b1 && b2)
-		*result = (FLOAT8_EQ(b1->low.x, b2->low.x) &&
-				   FLOAT8_EQ(b1->low.y, b2->low.y) &&
-				   FLOAT8_EQ(b1->high.x, b2->high.x) &&
-				   FLOAT8_EQ(b1->high.y, b2->high.y));
+		*result = (float8_eq(b1->low.x, b2->low.x) &&
+				   float8_eq(b1->low.y, b2->low.y) &&
+				   float8_eq(b1->high.x, b2->high.x) &&
+				   float8_eq(b1->high.y, b2->high.y));
 	else
 		*result = (b1 == NULL && b2 == NULL);
 	PG_RETURN_POINTER(result);
 }
 
 /*
  * Leaf-level consistency for boxes: just apply the query operator
  */
 static bool
 gist_box_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy)
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index cbdaec9d2b..ebe709086b 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -15,21 +15,21 @@
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist_private.h"
 #include "access/htup_details.h"
 #include "access/reloptions.h"
 #include "catalog/pg_opclass.h"
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/syscache.h"
 
 
 /*
  * Write itup vector to page, has no control of free space.
  */
 void
 gistfillbuffer(Page page, IndexTuple *itup, int len, OffsetNumber off)
 {
 	OffsetNumber l = InvalidOffsetNumber;
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index 894f026a41..d4697d036e 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -15,62 +15,25 @@
 #include "postgres.h"
 
 #include <ctype.h>
 #include <float.h>
 #include <math.h>
 #include <limits.h>
 
 #include "catalog/pg_type.h"
 #include "libpq/pqformat.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/sortsupport.h"
 
 
-#ifndef M_PI
-/* from my RH5.2 gcc math.h file - thomas 2000-04-03 */
-#define M_PI 3.14159265358979323846
-#endif
-
-/* Radians per degree, a.k.a. PI / 180 */
-#define RADIANS_PER_DEGREE 0.0174532925199432957692
-
-/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0.  NAN definition from
- * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfNotNumberNANItems.asp
- */
-#if defined(WIN32) && !defined(NAN)
-static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
-
-#define NAN (*(const double *) nan)
-#endif
-
-/* not sure what the following should be, but better to make it over-sufficient */
-#define MAXFLOATWIDTH	64
-#define MAXDOUBLEWIDTH	128
-
-/*
- * check to see if a float4/8 val has underflowed or overflowed
- */
-#define CHECKFLOATVAL(val, inf_is_valid, zero_is_valid)			\
-do {															\
-	if (isinf(val) && !(inf_is_valid))							\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		  errmsg("value out of range: overflow")));				\
-																\
-	if ((val) == 0.0 && !(zero_is_valid))						\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		 errmsg("value out of range: underflow")));				\
-} while(0)
-
-
 /* Configurable GUC parameter */
 int			extra_float_digits = 0;		/* Added to DBL_DIG or FLT_DIG */
 
 /* Cached constants for degree-based trig functions */
 static bool degree_consts_set = false;
 static float8 sin_30 = 0;
 static float8 one_minus_cos_60 = 0;
 static float8 asin_0_5 = 0;
 static float8 acos_0_5 = 0;
 static float8 atan_1_0 = 0;
@@ -102,100 +65,20 @@ static void init_degree_constants(void);
  * their compilers spit up at the mismatch between extern declaration
  * and static definition.  We work around that here by the expedient
  * of a #define to make the actual name of the static function different.
  */
 #define cbrt my_cbrt
 static double cbrt(double x);
 #endif   /* HAVE_CBRT */
 
 
 /*
- * Routines to provide reasonably platform-independent handling of
- * infinity and NaN.  We assume that isinf() and isnan() are available
- * and work per spec.  (On some platforms, we have to supply our own;
- * see src/port.)  However, generating an Infinity or NaN in the first
- * place is less well standardized; pre-C99 systems tend not to have C99's
- * INFINITY and NAN macros.  We centralize our workarounds for this here.
- */
-
-double
-get_float8_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (double) INFINITY;
-#else
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (double) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-/*
-* The funny placements of the two #pragmas is necessary because of a
-* long lived bug in the Microsoft compilers.
-* See http://support.microsoft.com/kb/120968/en-us for details
-*/
-#if (_MSC_VER >= 1800)
-#pragma warning(disable:4756)
-#endif
-float
-get_float4_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (float) INFINITY;
-#else
-#if (_MSC_VER >= 1800)
-#pragma warning(default:4756)
-#endif
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (float) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-double
-get_float8_nan(void)
-{
-	/* (double) NAN doesn't work on some NetBSD/MIPS releases */
-#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
-	/* C99 standard way */
-	return (double) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (double) (0.0 / 0.0);
-#endif
-}
-
-float
-get_float4_nan(void)
-{
-#ifdef NAN
-	/* C99 standard way */
-	return (float) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (float) (0.0 / 0.0);
-#endif
-}
-
-
-/*
  * Returns -1 if 'val' represents negative infinity, 1 if 'val'
  * represents (positive) infinity, and 0 otherwise. On some platforms,
  * this is equivalent to the isinf() macro, but not everywhere: C99
  * does not specify that isinf() needs to distinguish between positive
  * and negative infinity.
  */
 int
 is_infinite(double val)
 {
 	int			inf = isinf(val);
@@ -339,21 +222,21 @@ float4in(PG_FUNCTION_ARGS)
 	if (*endptr != '\0')
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"real", orig_num)));
 
 	/*
 	 * if we get here, we have a legal double, still need to check to see if
 	 * it's a legal float4
 	 */
-	CHECKFLOATVAL((float4) val, isinf(val), val == 0);
+	check_float4_val((float4) val, isinf(val), val == 0);
 
 	PG_RETURN_FLOAT4((float4) val);
 }
 
 /*
  *		float4out		- converts a float4 number to a string
  *						  using a standard output format
  */
 Datum
 float4out(PG_FUNCTION_ARGS)
@@ -689,35 +572,35 @@ float4up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT4(arg);
 }
 
 Datum
 float4larger(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) > 0)
+	if (float4_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 Datum
 float4smaller(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) < 0)
+	if (float4_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 /*
  *		======================
  *		FLOAT8 BASE OPERATIONS
  *		======================
@@ -756,35 +639,35 @@ float8up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT8(arg);
 }
 
 Datum
 float8larger(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) > 0)
+	if (float8_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 Datum
 float8smaller(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) < 0)
+	if (float8_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		====================
  *		ARITHMETIC OPERATORS
@@ -795,234 +678,165 @@ float8smaller(PG_FUNCTION_ARGS)
  *		float4pl		- returns arg1 + arg2
  *		float4mi		- returns arg1 - arg2
  *		float4mul		- returns arg1 * arg2
  *		float4div		- returns arg1 / arg2
  */
 Datum
 float4pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 + arg2;
-
-	/*
-	 * There isn't any way to check for underflow of addition/subtraction
-	 * because numbers near the underflow value have already been rounded to
-	 * the point where we can't detect that the two values were originally
-	 * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
-	 * 1.4013e-45.
-	 */
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_pl(arg1, arg2));
 }
 
 Datum
 float4mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mi(arg1, arg2));
 }
 
 Datum
 float4mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mul(arg1, arg2));
 }
 
 Datum
 float4div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_div(arg1, arg2));
 }
 
 /*
  *		float8pl		- returns arg1 + arg2
  *		float8mi		- returns arg1 - arg2
  *		float8mul		- returns arg1 * arg2
  *		float8div		- returns arg1 / arg2
  */
 Datum
 float8pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 + arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, arg2));
 }
 
 Datum
 float8mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 - arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, arg2));
 }
 
 Datum
 float8mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 * arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, arg2));
 }
 
 Datum
 float8div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, arg2));
 }
 
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float4{eq,ne,lt,le,gt,ge}		- float4/float4 comparison operations
  */
 int
 float4_cmp_internal(float4 a, float4 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float4_gt(a, b))
+		return 1;
+	if (float4_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
 float4eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float4_eq(arg1, arg2));
 }
 
 Datum
 float4ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float4_ne(arg1, arg2));
 }
 
 Datum
 float4lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float4_lt(arg1, arg2));
 }
 
 Datum
 float4le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float4_le(arg1, arg2));
 }
 
 Datum
 float4gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float4_gt(arg1, arg2));
 }
 
 Datum
 float4ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float4_ge(arg1, arg2));
 }
 
 Datum
 btfloat4cmp(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
 	PG_RETURN_INT32(float4_cmp_internal(arg1, arg2));
 }
@@ -1044,99 +858,79 @@ btfloat4sortsupport(PG_FUNCTION_ARGS)
 	ssup->comparator = btfloat4fastcmp;
 	PG_RETURN_VOID();
 }
 
 /*
  *		float8{eq,ne,lt,le,gt,ge}		- float8/float8 comparison operations
  */
 int
 float8_cmp_internal(float8 a, float8 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float8_gt(a, b))
+		return 1;
+	if (float8_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
 float8eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, arg2));
 }
 
 Datum
 float8ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, arg2));
 }
 
 Datum
 float8lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, arg2));
 }
 
 Datum
 float8le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, arg2));
 }
 
 Datum
 float8gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, arg2));
 }
 
 Datum
 float8ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, arg2));
 }
 
 Datum
 btfloat8cmp(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
 	PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
 }
@@ -1199,21 +993,21 @@ ftod(PG_FUNCTION_ARGS)
 
 
 /*
  *		dtof			- converts a float8 number to a float4 number
  */
 Datum
 dtof(PG_FUNCTION_ARGS)
 {
 	float8		num = PG_GETARG_FLOAT8(0);
 
-	CHECKFLOATVAL((float4) num, isinf(num), num == 0);
+	check_float4_val((float4) num, isinf(num), num == 0);
 
 	PG_RETURN_FLOAT4((float4) num);
 }
 
 
 /*
  *		dtoi4			- converts a float8 number to an int4 number
  */
 Datum
 dtoi4(PG_FUNCTION_ARGS)
@@ -1424,36 +1218,36 @@ dsqrt(PG_FUNCTION_ARGS)
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
 				 errmsg("cannot take square root of a negative number")));
 
 	result = sqrt(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcbrt			- returns cube root of arg1
  */
 Datum
 dcbrt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	result = cbrt(arg1);
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dpow			- returns pow(arg1,arg2)
  */
 Datum
 dpow(PG_FUNCTION_ARGS)
 {
@@ -1492,40 +1286,40 @@ dpow(PG_FUNCTION_ARGS)
 			/* The sign of Inf is not significant in this case. */
 			result = get_float8_infinity();
 		else if (fabs(arg1) != 1)
 			result = 0;
 		else
 			result = 1;
 	}
 	else if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
+	check_float8_val(result, isinf(arg1) || isinf(arg2), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dexp			- returns the exponential function of arg1
  */
 Datum
 dexp(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	errno = 0;
 	result = exp(arg1);
 	if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1), false);
+	check_float8_val(result, isinf(arg1), false);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dlog1			- returns the natural logarithm of arg1
  */
 Datum
 dlog1(PG_FUNCTION_ARGS)
 {
@@ -1540,21 +1334,21 @@ dlog1(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of zero")));
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of a negative number")));
 
 	result = log(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dlog10			- returns the base 10 logarithm of arg1
  */
 Datum
 dlog10(PG_FUNCTION_ARGS)
 {
@@ -1570,21 +1364,21 @@ dlog10(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of zero")));
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of a negative number")));
 
 	result = log10(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dacos			- returns the arccos of arg1 (radians)
  */
 Datum
 dacos(PG_FUNCTION_ARGS)
 {
@@ -1600,21 +1394,21 @@ dacos(PG_FUNCTION_ARGS)
 	 * range [-1, 1] to values in the range [0, Pi], so we should reject any
 	 * inputs outside that range and the result will always be finite.
 	 */
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = acos(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dasin			- returns the arcsin of arg1 (radians)
  */
 Datum
 dasin(PG_FUNCTION_ARGS)
 {
@@ -1630,21 +1424,21 @@ dasin(PG_FUNCTION_ARGS)
 	 * range [-1, 1] to values in the range [-Pi/2, Pi/2], so we should reject
 	 * any inputs outside that range and the result will always be finite.
 	 */
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = asin(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		datan			- returns the arctan of arg1 (radians)
  */
 Datum
 datan(PG_FUNCTION_ARGS)
 {
@@ -1655,21 +1449,21 @@ datan(PG_FUNCTION_ARGS)
 	if (isnan(arg1))
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/*
 	 * The principal branch of the inverse tangent function maps all inputs to
 	 * values in the range [-Pi/2, Pi/2], so the result should always be
 	 * finite, even if the input is infinite.
 	 */
 	result = atan(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		atan2			- returns the arctan of arg1/arg2 (radians)
  */
 Datum
 datan2(PG_FUNCTION_ARGS)
 {
@@ -1680,21 +1474,21 @@ datan2(PG_FUNCTION_ARGS)
 	/* Per the POSIX spec, return NaN if either input is NaN */
 	if (isnan(arg1) || isnan(arg2))
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/*
 	 * atan2 maps all inputs to values in the range [-Pi, Pi], so the result
 	 * should always be finite, even if the inputs are infinite.
 	 */
 	result = atan2(arg1, arg2);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcos			- returns the cosine of arg1 (radians)
  */
 Datum
 dcos(PG_FUNCTION_ARGS)
 {
@@ -1720,21 +1514,21 @@ dcos(PG_FUNCTION_ARGS)
 	 * platform reports via errno, so also explicitly test for infinite
 	 * inputs.
 	 */
 	errno = 0;
 	result = cos(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcot			- returns the cotangent of arg1 (radians)
  */
 Datum
 dcot(PG_FUNCTION_ARGS)
 {
@@ -1747,21 +1541,21 @@ dcot(PG_FUNCTION_ARGS)
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = tan(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = 1.0 / result;
-	CHECKFLOATVAL(result, true /* cot(0) == Inf */ , true);
+	check_float8_val(result, true /* cot(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dsin			- returns the sine of arg1 (radians)
  */
 Datum
 dsin(PG_FUNCTION_ARGS)
 {
@@ -1773,21 +1567,21 @@ dsin(PG_FUNCTION_ARGS)
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = sin(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dtan			- returns the tangent of arg1 (radians)
  */
 Datum
 dtan(PG_FUNCTION_ARGS)
 {
@@ -1799,21 +1593,21 @@ dtan(PG_FUNCTION_ARGS)
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = tan(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, true /* tan(pi/2) == Inf */ , true);
+	check_float8_val(result, true /* tan(pi/2) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /* ========== DEGREE-BASED TRIGONOMETRIC FUNCTIONS ========== */
 
 
 /*
  * Initialize the cached constants declared at the head of this file
  * (sin_30 etc).  The fact that we need those at all, let alone need this
@@ -1951,21 +1745,21 @@ dacosd(PG_FUNCTION_ARGS)
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	if (arg1 >= 0.0)
 		result = acosd_q1(arg1);
 	else
 		result = 90.0 + asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dasind			- returns the arcsin of arg1 (degrees)
  */
 Datum
 dasind(PG_FUNCTION_ARGS)
 {
@@ -1986,21 +1780,21 @@ dasind(PG_FUNCTION_ARGS)
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	if (arg1 >= 0.0)
 		result = asind_q1(arg1);
 	else
 		result = -asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		datand			- returns the arctan of arg1 (degrees)
  */
 Datum
 datand(PG_FUNCTION_ARGS)
 {
@@ -2016,21 +1810,21 @@ datand(PG_FUNCTION_ARGS)
 
 	/*
 	 * The principal branch of the inverse tangent function maps all inputs to
 	 * values in the range [-90, 90], so the result should always be finite,
 	 * even if the input is infinite.  Additionally, we take care to ensure
 	 * than when arg1 is 1, the result is exactly 45.
 	 */
 	atan_arg1 = atan(arg1);
 	result = (atan_arg1 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		atan2d			- returns the arctan of arg1/arg2 (degrees)
  */
 Datum
 datan2d(PG_FUNCTION_ARGS)
 {
@@ -2050,21 +1844,21 @@ datan2d(PG_FUNCTION_ARGS)
 	 * result should always be finite, even if the inputs are infinite.
 	 *
 	 * Note: this coding assumes that atan(1.0) is a suitable scaling constant
 	 * to get an exact result from atan2().  This might well fail on us at
 	 * some point, requiring us to decide exactly what inputs we think we're
 	 * going to guarantee an exact result for.
 	 */
 	atan2_arg1_arg2 = atan2(arg1, arg2);
 	result = (atan2_arg1_arg2 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		sind_0_to_30	- returns the sine of an angle that lies between 0 and
  *						  30 degrees.  This will return exactly 0 when x is 0,
  *						  and exactly 0.5 when x is 30 degrees.
  */
 static double
@@ -2171,21 +1965,21 @@ dcosd(PG_FUNCTION_ARGS)
 
 	if (arg1 > 90.0)
 	{
 		/* cosd(180-x) = -cosd(x) */
 		arg1 = 180.0 - arg1;
 		sign = -sign;
 	}
 
 	result = sign * cosd_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcotd			- returns the cotangent of arg1 (degrees)
  */
 Datum
 dcotd(PG_FUNCTION_ARGS)
 {
@@ -2236,21 +2030,21 @@ dcotd(PG_FUNCTION_ARGS)
 	result = sign * (cot_arg1 / cot_45);
 
 	/*
 	 * On some machines we get cotd(270) = minus zero, but this isn't always
 	 * true.  For portability, and because the user constituency for this
 	 * function probably doesn't want minus zero, force it to plain zero.
 	 */
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* cotd(0) == Inf */ , true);
+	check_float8_val(result, true /* cotd(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dsind			- returns the sine of arg1 (degrees)
  */
 Datum
 dsind(PG_FUNCTION_ARGS)
 {
@@ -2290,21 +2084,21 @@ dsind(PG_FUNCTION_ARGS)
 	}
 
 	if (arg1 > 90.0)
 	{
 		/* sind(180-x) = sind(x) */
 		arg1 = 180.0 - arg1;
 	}
 
 	result = sign * sind_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dtand			- returns the tangent of arg1 (degrees)
  */
 Datum
 dtand(PG_FUNCTION_ARGS)
 {
@@ -2355,64 +2149,56 @@ dtand(PG_FUNCTION_ARGS)
 	result = sign * (tan_arg1 / tan_45);
 
 	/*
 	 * On some machines we get tand(180) = minus zero, but this isn't always
 	 * true.  For portability, and because the user constituency for this
 	 * function probably doesn't want minus zero, force it to plain zero.
 	 */
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* tand(90) == Inf */ , true);
+	check_float8_val(result, true /* tand(90) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		degrees		- returns degrees converted from radians
  */
 Datum
 degrees(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
 
-	result = arg1 / RADIANS_PER_DEGREE;
-
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, RADIANS_PER_DEGREE));
 }
 
 
 /*
  *		dpi				- returns the constant PI
  */
 Datum
 dpi(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_FLOAT8(M_PI);
 }
 
 
 /*
  *		radians		- returns radians converted from degrees
  */
 Datum
 radians(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
 
-	result = arg1 * RADIANS_PER_DEGREE;
-
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, RADIANS_PER_DEGREE));
 }
 
 
 /*
  *		drandom		- returns a random number
  */
 Datum
 drandom(PG_FUNCTION_ARGS)
 {
 	float8		result;
@@ -2490,144 +2276,105 @@ check_float8_array(ArrayType *transarray, const char *caller, int n)
  * This function is used only in two stage aggregation and
  * shouldn't be called outside aggregate context.
  */
 Datum
 float8_combine(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_combine", 3);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-
 	transvalues2 = check_float8_array(transarray2, "float8_combine", 3);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
 
 Datum
 float8_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8		newval = PG_GETARG_FLOAT8(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float8_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
 	else
 	{
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
 								 sizeof(float8), FLOAT8PASSBYVAL, 'd');
 
 		PG_RETURN_ARRAYTYPE_P(result);
 	}
 }
 
 Datum
 float4_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 
 	/* do computations as float8 */
 	float8		newval = PG_GETARG_FLOAT4(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float4_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
 	else
 	{
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
 								 sizeof(float8), FLOAT8PASSBYVAL, 'd');
 
 		PG_RETURN_ARRAYTYPE_P(result);
 	}
 }
 
 Datum
@@ -2663,21 +2410,21 @@ float8_var_pop(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_var_pop", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Population variance is undefined when N is 0, so return NULL */
 	if (N == 0.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / (N * N));
 }
 
 Datum
 float8_var_samp(PG_FUNCTION_ARGS)
@@ -2692,21 +2439,21 @@ float8_var_samp(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_var_samp", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Sample variance is undefined when N is 0 or 1, so return NULL */
 	if (N <= 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
 }
 
 Datum
 float8_stddev_pop(PG_FUNCTION_ARGS)
@@ -2721,21 +2468,21 @@ float8_stddev_pop(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_stddev_pop", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Population stddev is undefined when N is 0, so return NULL */
 	if (N == 0.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(sqrt(numerator / (N * N)));
 }
 
 Datum
 float8_stddev_samp(PG_FUNCTION_ARGS)
@@ -2750,21 +2497,21 @@ float8_stddev_samp(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_stddev_samp", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Sample stddev is undefined when N is 0 or 1, so return NULL */
 	if (N <= 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(sqrt(numerator / (N * (N - 1.0))));
 }
 
 /*
  *		=========================
@@ -2799,30 +2546,30 @@ float8_regr_accum(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_accum", 6);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	N += 1.0;
 	sumX += newvalX;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
+	check_float8_val(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
 	sumX2 += newvalX * newvalX;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
+	check_float8_val(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
 	sumY += newvalY;
-	CHECKFLOATVAL(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
+	check_float8_val(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
 	sumY2 += newvalY * newvalY;
-	CHECKFLOATVAL(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
+	check_float8_val(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
 	sumXY += newvalX * newvalY;
-	CHECKFLOATVAL(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
-				  isinf(newvalY), true);
+	check_float8_val(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
+					 isinf(newvalY), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
 		transvalues[0] = N;
 		transvalues[1] = sumX;
@@ -2861,63 +2608,33 @@ float8_regr_accum(PG_FUNCTION_ARGS)
  * This function is used only in two stage aggregation and
  * shouldn't be called outside aggregate context.
  */
 Datum
 float8_regr_combine(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2,
-				sumY,
-				sumY2,
-				sumXY;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_regr_combine", 6);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-	sumY = transvalues1[3];
-	sumY2 = transvalues1[4];
-	sumXY = transvalues1[5];
-
 	transvalues2 = check_float8_array(transarray2, "float8_regr_combine", 6);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-	sumY += transvalues2[3];
-	CHECKFLOATVAL(sumY, isinf(transvalues1[3]) || isinf(transvalues2[3]),
-				  true);
-	sumY2 += transvalues2[4];
-	CHECKFLOATVAL(sumY2, isinf(transvalues1[4]) || isinf(transvalues2[4]),
-				  true);
-	sumXY += transvalues2[5];
-	CHECKFLOATVAL(sumXY, isinf(transvalues1[5]) || isinf(transvalues2[5]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
-	transvalues1[3] = sumY;
-	transvalues1[4] = sumY2;
-	transvalues1[5] = sumXY;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
+	transvalues1[3] = float8_pl(transvalues1[3], transvalues2[3]);
+	transvalues1[4] = float8_pl(transvalues1[4], transvalues2[4]);
+	transvalues1[5] = float8_pl(transvalues1[5], transvalues2[5]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
 
 
 Datum
 float8_regr_sxx(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
@@ -2929,21 +2646,21 @@ float8_regr_sxx(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_sxx", 6);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_syy(PG_FUNCTION_ARGS)
@@ -2958,21 +2675,21 @@ float8_regr_syy(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_syy", 6);
 	N = transvalues[0];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumY2) || isinf(sumY), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_sxy(PG_FUNCTION_ARGS)
@@ -2989,22 +2706,22 @@ float8_regr_sxy(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	/* A negative result is valid here */
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_avgx(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3057,22 +2774,22 @@ float8_covar_pop(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * N));
 }
 
 Datum
 float8_covar_samp(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
 	float8		N,
@@ -3085,22 +2802,22 @@ float8_covar_samp(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is <= 1 we should return NULL */
 	if (N < 2.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
 }
 
 Datum
 float8_corr(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
 	float8		N,
@@ -3119,26 +2836,26 @@ float8_corr(PG_FUNCTION_ARGS)
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0 || numeratorY <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXY / sqrt(numeratorX * numeratorY));
 }
 
 Datum
 float8_regr_r2(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3159,26 +2876,26 @@ float8_regr_r2(PG_FUNCTION_ARGS)
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 	/* per spec, horizontal line produces 1.0 */
 	if (numeratorY <= 0)
 		PG_RETURN_FLOAT8(1.0);
 
 	PG_RETURN_FLOAT8((numeratorXY * numeratorXY) /
 					 (numeratorX * numeratorY));
 }
 
@@ -3200,24 +2917,24 @@ float8_regr_slope(PG_FUNCTION_ARGS)
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXY / numeratorX);
 }
 
 Datum
 float8_regr_intercept(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3235,24 +2952,24 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXXY = sumY * sumX2 - sumX * sumXY;
-	CHECKFLOATVAL(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
-				  isinf(sumX) || isinf(sumXY), true);
+	check_float8_val(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
+					 isinf(sumX) || isinf(sumXY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXXY / numeratorX);
 }
 
 
 /*
  *		====================================
  *		MIXED-PRECISION ARITHMETIC OPERATORS
@@ -3263,251 +2980,211 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
  *		float48pl		- returns arg1 + arg2
  *		float48mi		- returns arg1 - arg2
  *		float48mul		- returns arg1 * arg2
  *		float48div		- returns arg1 / arg2
  */
 Datum
 float48pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 + arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl((float8) arg1, arg2));
 }
 
 Datum
 float48mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi((float8) arg1, arg2));
 }
 
 Datum
 float48mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul((float8) arg1, arg2));
 }
 
 Datum
 float48div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div((float8) arg1, arg2));
 }
 
 /*
  *		float84pl		- returns arg1 + arg2
  *		float84mi		- returns arg1 - arg2
  *		float84mul		- returns arg1 * arg2
  *		float84div		- returns arg1 / arg2
  */
 Datum
 float84pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 + arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, (float8) arg2));
 }
 
 Datum
 float84mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 - arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, (float8) arg2));
 }
 
 Datum
 float84mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 * arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, (float8) arg2));
 }
 
 Datum
 float84div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, (float8) arg2));
 }
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float48{eq,ne,lt,le,gt,ge}		- float4/float8 comparison operations
  */
 Datum
 float48eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq((float8) arg1, arg2));
 }
 
 Datum
 float48ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne((float8) arg1, arg2));
 }
 
 Datum
 float48lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt((float8) arg1, arg2));
 }
 
 Datum
 float48le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le((float8) arg1, arg2));
 }
 
 Datum
 float48gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt((float8) arg1, arg2));
 }
 
 Datum
 float48ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge((float8) arg1, arg2));
 }
 
 /*
  *		float84{eq,ne,lt,le,gt,ge}		- float8/float4 comparison operations
  */
 Datum
 float84eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, (float8) arg2));
 }
 
 Datum
 float84ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, (float8) arg2));
 }
 
 Datum
 float84lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, (float8) arg2));
 }
 
 Datum
 float84le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, (float8) arg2));
 }
 
 Datum
 float84gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, (float8) arg2));
 }
 
 Datum
 float84ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, (float8) arg2));
 }
 
 /*
  * Implements the float8 version of the width_bucket() function
  * defined by SQL2003. See also width_bucket_numeric().
  *
  * 'bound1' and 'bound2' are the lower and upper bounds of the
  * histogram's range, respectively. 'count' is the number of buckets
  * in the histogram. width_bucket() returns an integer indicating the
  * bucket number that 'operand' belongs to in an equiwidth histogram
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c
index 4127bece12..7a3bf97c70 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -84,20 +84,21 @@
 
 #ifdef USE_ICU
 #include <unicode/ustring.h>
 #endif
 
 #include "catalog/pg_collation.h"
 #include "mb/pg_wchar.h"
 #include "utils/builtins.h"
 #include "utils/date.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 #include "utils/formatting.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/pg_locale.h"
 
 /* ----------
  * Routines type
  * ----------
  */
 #define DCH_TYPE		1		/* DATE-TIME version	*/
@@ -110,27 +111,20 @@
 #define KeyWord_INDEX_SIZE		('~' - ' ')
 #define KeyWord_INDEX_FILTER(_c)	((_c) <= ' ' || (_c) >= '~' ? 0 : 1)
 
 /* ----------
  * Maximal length of one node
  * ----------
  */
 #define DCH_MAX_ITEM_SIZ	   12		/* max localized day name		*/
 #define NUM_MAX_ITEM_SIZ		8		/* roman number (RN has 15 chars)	*/
 
-/* ----------
- * More is in float.c
- * ----------
- */
-#define MAXFLOATWIDTH	60
-#define MAXDOUBLEWIDTH	500
-
 
 /* ----------
  * Format parser structs
  * ----------
  */
 typedef struct
 {
 	char	   *name;			/* suffix string		*/
 	int			len,			/* suffix length		*/
 				id,				/* used in node->suffix */
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 1f1f32a78d..0936a57778 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -14,27 +14,23 @@
  */
 #include "postgres.h"
 
 #include <math.h>
 #include <limits.h>
 #include <float.h>
 #include <ctype.h>
 
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
-#include "utils/builtins.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index f6334bae14..c800bb1338 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -69,21 +69,21 @@
  *			src/backend/utils/adt/geo_spgist.c
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
 
 #include "access/spgist.h"
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
  * is going only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 6cce0f292c..38b20092c0 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -28,20 +28,21 @@
 
 #include "access/hash.h"
 #include "catalog/pg_type.h"
 #include "funcapi.h"
 #include "lib/hyperloglog.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/sortsupport.h"
 
 /* ----------
  * Uncomment the following to enable compilation of dump_numeric()
  * and dump_var() and to get a dump of any result produced by make_result().
  * ----------
 #define NUMERIC_DEBUG
diff --git a/src/backend/utils/adt/rangetypes_gist.c b/src/backend/utils/adt/rangetypes_gist.c
index f81b16c236..e51567285f 100644
--- a/src/backend/utils/adt/rangetypes_gist.c
+++ b/src/backend/utils/adt/rangetypes_gist.c
@@ -9,21 +9,22 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_gist.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/gist.h"
 #include "access/stratnum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/datum.h"
 #include "utils/rangetypes.h"
 
 
 /*
  * Range class properties used to segregate different classes of ranges in
  * GiST.  Each unique combination of properties is a class.  CLS_EMPTY cannot
  * be combined with anything else.
  */
 #define CLS_NORMAL			0	/* Ordinary finite range (no bits set) */
diff --git a/src/backend/utils/adt/rangetypes_selfuncs.c b/src/backend/utils/adt/rangetypes_selfuncs.c
index c4c549658d..fd4ce8168a 100644
--- a/src/backend/utils/adt/rangetypes_selfuncs.c
+++ b/src/backend/utils/adt/rangetypes_selfuncs.c
@@ -14,21 +14,22 @@
  *	  src/backend/utils/adt/rangetypes_selfuncs.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/htup_details.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 #include "utils/selfuncs.h"
 #include "utils/typcache.h"
 
 static double calc_rangesel(TypeCacheEntry *typcache, VariableStatData *vardata,
 			  RangeType *constval, Oid operator);
 static double default_range_selectivity(Oid operator);
 static double calc_hist_selectivity(TypeCacheEntry *typcache,
 					  VariableStatData *vardata, RangeType *constval,
diff --git a/src/backend/utils/adt/rangetypes_typanalyze.c b/src/backend/utils/adt/rangetypes_typanalyze.c
index a8d585ce7a..7746b66396 100644
--- a/src/backend/utils/adt/rangetypes_typanalyze.c
+++ b/src/backend/utils/adt/rangetypes_typanalyze.c
@@ -19,21 +19,22 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_typanalyze.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "catalog/pg_operator.h"
 #include "commands/vacuum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 
 static int	float8_qsort_cmp(const void *a1, const void *a2);
 static int	range_bound_qsort_cmp(const void *a1, const void *a2, void *arg);
 static void compute_range_stats(VacAttrStats *stats,
 		   AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows);
 
 /*
  * range_typanalyze -- typanalyze function for range columns
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 3f6e0d4497..21021517a3 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -27,20 +27,21 @@
 #include "common/int128.h"
 #include "funcapi.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
 #include "parser/scansup.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 /*
  * gcc's -ffast-math switch breaks routines that expect exact results from
  * expressions like timeval / SECS_PER_HOUR, where timeval is double.
  */
 #ifdef __FAST_MATH__
 #error -ffast-math is known to break this code
 #endif
 
 #define SAMESIGN(a,b)	(((a) < 0) == ((b) < 0))
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 92e1d63b2f..58883d390c 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -72,20 +72,21 @@
 #include "storage/standby.h"
 #include "storage/fd.h"
 #include "storage/pg_shmem.h"
 #include "storage/proc.h"
 #include "storage/predicate.h"
 #include "tcop/tcopprot.h"
 #include "tsearch/ts_cache.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/guc_tables.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/pg_locale.h"
 #include "utils/plancache.h"
 #include "utils/portal.h"
 #include "utils/ps_status.h"
 #include "utils/rls.h"
 #include "utils/snapmgr.h"
 #include "utils/tzparser.h"
 #include "utils/varlena.h"
 #include "utils/xml.h"
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 1435a7b57a..8de7fdf2a5 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -43,34 +43,20 @@ extern int	namestrcmp(Name name, const char *str);
 
 /* numutils.c */
 extern int32 pg_atoi(const char *s, int size, int c);
 extern void pg_itoa(int16 i, char *a);
 extern void pg_ltoa(int32 l, char *a);
 extern void pg_lltoa(int64 ll, char *a);
 extern char *pg_ltostr_zeropad(char *str, int32 value, int32 minwidth);
 extern char *pg_ltostr(char *str, int32 value);
 extern uint64 pg_strtouint64(const char *str, char **endptr, int base);
 
-/* float.c */
-extern PGDLLIMPORT int extra_float_digits;
-
-extern double get_float8_infinity(void);
-extern float get_float4_infinity(void);
-extern double get_float8_nan(void);
-extern float get_float4_nan(void);
-extern int	is_infinite(double val);
-extern double float8in_internal(char *num, char **endptr_p,
-				  const char *type_name, const char *orig_string);
-extern char *float8out_internal(double num);
-extern int	float4_cmp_internal(float4 a, float4 b);
-extern int	float8_cmp_internal(float8 a, float8 b);
-
 /* oid.c */
 extern oidvector *buildoidvector(const Oid *oids, int n);
 extern Oid	oidparse(Node *node);
 extern int	oid_cmp(const void *p1, const void *p2);
 
 /* regexp.c */
 extern char *regexp_fixed_prefix(text *text_re, bool case_insensitive,
 					Oid collation, bool *exact);
 
 /* ruleutils.c */
diff --git a/src/include/utils/float.h b/src/include/utils/float.h
new file mode 100644
index 0000000000..c26de1cca4
--- /dev/null
+++ b/src/include/utils/float.h
@@ -0,0 +1,383 @@
+/*-------------------------------------------------------------------------
+ *
+ * float.h
+ *	  Definitions for the built-in floating-point types
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/include/utils/float.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef FLOAT_H
+#define FLOAT_H
+
+#include <math.h>
+
+#ifndef M_PI
+/* From my RH5.2 gcc math.h file - thomas 2000-04-03 */
+#define M_PI 3.14159265358979323846
+#endif
+
+/* Radians per degree, a.k.a. PI / 180 */
+#define RADIANS_PER_DEGREE 0.0174532925199432957692
+
+/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0.  NAN definition from
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfNotNumberNANItems.asp
+ */
+#if defined(WIN32) && !defined(NAN)
+static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
+
+#define NAN (*(const float8 *) nan)
+#endif
+
+/*
+ * We are not sure what the following should be, but better to make it
+ * over-sufficient.
+ */
+#define MAXFLOATWIDTH	64
+#define MAXDOUBLEWIDTH	128
+
+extern PGDLLIMPORT int extra_float_digits;
+
+/*
+ * Utility functions in float.c
+ */
+extern int	is_infinite(float8 val);
+extern float8 float8in_internal(char *num, char **endptr_p,
+				  const char *type_name, const char *orig_string);
+extern char *float8out_internal(float8 num);
+extern int	float4_cmp_internal(float4 a, float4 b);
+extern int	float8_cmp_internal(float8 a, float8 b);
+
+/*
+ * Routines to provide reasonably platform-independent handling of
+ * infinity and NaN
+ *
+ * We assume that isinf() and isnan() are available and work per spec.
+ * (On some platforms, we have to supply our own; see src/port.)  However,
+ * generating an Infinity or NaN in the first place is less well standardized;
+ * pre-C99 systems tend not to have C99's INFINITY and NAN macros.  We
+ * centralize our workarounds for this here.
+ */
+
+/*
+* The funny placements of the two #pragmas is necessary because of a
+* long lived bug in the Microsoft compilers.
+* See http://support.microsoft.com/kb/120968/en-us for details
+*/
+#if (_MSC_VER >= 1800)
+#pragma warning(disable:4756)
+#endif
+static inline float
+get_float4_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float) INFINITY;
+#else
+#if (_MSC_VER >= 1800)
+#pragma warning(default:4756)
+#endif
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float8
+get_float8_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float8) INFINITY;
+#else
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float8) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float4
+get_float4_nan(void)
+{
+#ifdef NAN
+	/* C99 standard way */
+	return (float) NAN;
+#else
+	/* Assume we can get a NAN via zero divide */
+	return (float) (0.0 / 0.0);
+#endif
+}
+
+static inline float8
+get_float8_nan(void)
+{
+	/* (float8) NAN doesn't work on some NetBSD/MIPS releases */
+#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
+	/* C99 standard way */
+	return (float8) NAN;
+#else
+	/* Assume we can get a NAN via zero divide */
+	return (float8) (0.0 / 0.0);
+#endif
+}
+
+/*
+ * Checks to see if a float4/8 val has underflowed or overflowed
+ */
+
+static inline void
+check_float4_val(float4 val, bool inf_is_valid, bool zero_is_valid)
+{
+	if (isinf(val) && !(inf_is_valid))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if ((val) == 0.0 && !(zero_is_valid))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+static inline void
+check_float8_val(float8 val, bool inf_is_valid, bool zero_is_valid)
+{
+	if (isinf(val) && !(inf_is_valid))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if ((val) == 0.0 && !(zero_is_valid))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+/*
+ * Routines for operations with the checks above
+ *
+ * There isn't any way to check for underflow of addition/subtraction
+ * because numbers near the underflow value have already been rounded to
+ * the point where we can't detect that the two values were originally
+ * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
+ * 1.4013e-45.
+ */
+
+static inline float4
+float4_pl(float4 val1, float4 val2)
+{
+	float4		result;
+
+	result = val1 + val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_pl(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = val1 + val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mi(float4 val1, float4 val2)
+{
+	float4		result;
+
+	result = val1 - val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_mi(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = val1 - val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mul(float4 val1, float4 val2)
+{
+	float4		result;
+
+	result = val1 * val2;
+	check_float4_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0f || val2 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_mul(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = val1 * val2;
+	check_float8_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0 || val2 == 0.0);
+
+	return result;
+}
+
+static inline float4
+float4_div(float4 val1, float4 val2)
+{
+	float4		result;
+
+	if (val2 == 0.0f)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), val1 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_div(float8 val1, float8 val2)
+{
+	float8		result;
+
+	if (val2 == 0.0)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
+
+	return result;
+}
+
+/*
+ * Routines for NaN-aware comparisons
+ *
+ * We consider all NANs to be equal and larger than any non-NAN. This is
+ * somewhat arbitrary; the important thing is to have a consistent sort
+ * order.
+ */
+
+static inline bool
+float4_eq(float4 val1, float4 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float8_eq(float8 val1, float8 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float4_ne(float4 val1, float4 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float8_ne(float8 val1, float8 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float4_lt(float4 val1, float4 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float8_lt(float8 val1, float8 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float4_le(float4 val1, float4 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float8_le(float8 val1, float8 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float4_gt(float4 val1, float4 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float8_gt(float8 val1, float8 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float4_ge(float4 val1, float4 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline bool
+float8_ge(float8 val1, float8 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline float4
+float4_min(float4 val1, float4 val2)
+{
+	return float4_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_min(float8 val1, float8 val2)
+{
+	return float8_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float4
+float4_max(float4 val1, float4 val2)
+{
+	return float4_gt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_max(float8 val1, float8 val2)
+{
+	return float8_gt(val1, val2) ? val1 : val2;
+}
+
+#endif   /* FLOAT_H */
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 90119a0158..f845dffcb7 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -17,20 +17,21 @@
  *		and data types. There are still some more to do. - tgl 97/04/19
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEO_DECLS_H
 #define GEO_DECLS_H
 
 #include <math.h>
 
 #include "fmgr.h"
+#include "utils/float.h"
 
 /*--------------------------------------------------------------------
  * Useful floating point utilities and constants.
  *-------------------------------------------------------------------*/
 
 
 #define EPSILON					1.0E-06
 
 #ifdef EPSILON
 #define FPzero(A)				(fabs(A) <= EPSILON)
-- 
2.11.0 (Apple Git-81)

#2Aleksander Alekseev
a.alekseev@postgrespro.ru
In reply to: Emre Hasegeli (#1)
Re: [PATCH] Improve geometric types

The following review has been posted through the commitfest application:
make installcheck-world: not tested
Implements feature: not tested
Spec compliant: not tested
Documentation: not tested

Hi Emre,

I'm afraid these patches conflict with current master branch.

The new status of this patch is: Waiting on Author

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

#3Emre Hasegeli
emre@hasegeli.com
In reply to: Aleksander Alekseev (#2)
4 attachment(s)
Re: [PATCH] Improve geometric types

I'm afraid these patches conflict with current master branch.

Rebased.

Attachments:

0001-geo-funcs-v2.patchapplication/octet-stream; name=0001-geo-funcs-v2.patchDownload
From a9a82d5e67f89d3466841ffc34719e0e1861050f Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 27 May 2017 11:27:18 -0400
Subject: [PATCH 1/4] geo-funcs-v2

Refactor geometric functions and operators code

Most of the geometric types were not using functions of each other's.
I believe the reason behind this is simpler types line point and line
being developed after more complicated ones.  This patch reduces duplicate
code and makes functions of different datatypes more compatible.  We can
do better than that, but it would require touching many more lines.
The changes can be summarised as:

* Re-use more functions to implement others
* Unify *_construct and *_interpt_internal functions to obtain
  pre-allocated memory
* Remove private functions from geo_decls.h
* Switch using C11 hypot() as the comment suggested
---
 src/backend/utils/adt/geo_ops.c | 810 +++++++++++++++++-----------------------
 src/include/utils/geo_decls.h   |  14 +-
 src/test/regress/regress.c      |  11 +-
 3 files changed, 346 insertions(+), 489 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 0348855b11..c43d02ac14 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -31,60 +31,68 @@
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
+/* Methods on point */
+static void point_construct(Point *result, float8 x, float8 y);
+static void point_add_internal(Point *result, Point *pt1, Point *pt2);
+static void point_sub_internal(Point *result, Point *pt1, Point *pt2);
+static void point_mul_internal(Point *result, Point *pt1, Point *pt2);
+static void point_div_internal(Point *result, Point *pt1, Point *pt2);
+static bool point_eq_internal(Point *pt1, Point *pt2);
+static float8 point_dt(Point *pt1, Point *pt2);
+static float8 point_sl(Point *pt1, Point *pt2);
 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);
+/* Methods on box */
+static void box_construct(BOX *result, float8 x1, float8 x2, float8 y1, float8 y2);
+static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
+static double box_ar(BOX *box);
 static double box_ht(BOX *box);
 static double box_wd(BOX *box);
+/* Methods on circle */
 static double circle_ar(CIRCLE *circle);
-static CIRCLE *circle_copy(CIRCLE *circle);
-static LINE *line_construct_pm(Point *pt, double m);
+/* Methods on line */
+static void line_construct_pm(LINE *result, Point *pt, float8 m);
 static void line_construct_pts(LINE *line, Point *pt1, Point *pt2);
-static bool lseg_intersect_internal(LSEG *l1, LSEG *l2);
-static double lseg_dt(LSEG *l1, LSEG *l2);
+static bool line_interpt_internal(Point *result, LINE *l1, LINE *l2);
+static float8 line_calculate_point(LINE *line, Point *pt);
+/* Methods on line segment */
+static bool lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line);
+static bool lseg_interpt_internal(Point *result, LSEG *l1, LSEG *l2);
+static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
+static float8 lseg_dt(LSEG *l1, LSEG *l2);
+static int	lseg_crossing(double x, double y, double px, double py);
+/* Others */
 static bool on_ps_internal(Point *pt, LSEG *lseg);
 static void make_bound_box(POLYGON *poly);
 static bool plist_same(int npts, Point *p1, Point *p2);
-static Point *point_construct(double x, double y);
-static Point *point_copy(Point *pt);
 static double single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
 static void pair_decode(char *str, double *x, double *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
 static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
 static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
-static double box_ar(BOX *box);
-static void box_cn(Point *center, BOX *box);
-static Point *interpt_sl(LSEG *lseg, LINE *line);
-static bool has_interpt_sl(LSEG *lseg, LINE *line);
 static double dist_pl_internal(Point *pt, LINE *line);
 static double dist_ps_internal(Point *pt, LSEG *lseg);
-static Point *line_interpt_internal(LINE *l1, LINE *l2);
-static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
-static Point *lseg_interpt_internal(LSEG *l1, LSEG *l2);
 static double dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 
 /*
  * Delimiters for input and output strings.
  * LDELIM, RDELIM, and DELIM are left, right, and separator delimiters, respectively.
  * LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints.
  */
 
 #define LDELIM			'('
@@ -434,33 +442,22 @@ box_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, box->high.x);
 	pq_sendfloat8(&buf, box->high.y);
 	pq_sendfloat8(&buf, box->low.x);
 	pq_sendfloat8(&buf, box->low.y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*		box_construct	-		fill in a new box.
  */
-static BOX *
-box_construct(double x1, double x2, double y1, double y2)
-{
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	return box_fill(result, x1, x2, y1, y2);
-}
-
-
-/*		box_fill		-		fill in a given box struct
- */
-static BOX *
-box_fill(BOX *result, double x1, double x2, double y1, double y2)
+static void
+box_construct(BOX *result, float8 x1, float8 x2, float8 y1, float8 y2)
 {
 	if (x1 > x2)
 	{
 		result->high.x = x1;
 		result->low.x = x2;
 	}
 	else
 	{
 		result->high.x = x2;
 		result->low.x = x1;
@@ -468,55 +465,38 @@ box_fill(BOX *result, double x1, double x2, double y1, double y2)
 	if (y1 > y2)
 	{
 		result->high.y = y1;
 		result->low.y = y2;
 	}
 	else
 	{
 		result->high.y = y2;
 		result->low.y = y1;
 	}
-
-	return result;
-}
-
-
-/*		box_copy		-		copy a box
- */
-static BOX *
-box_copy(BOX *box)
-{
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	memcpy((char *) result, (char *) box, sizeof(BOX));
-
-	return result;
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for BOXes.
  *		<, >, <=, >=, and == are based on box area.
  *---------------------------------------------------------*/
 
 /*		box_same		-		are two boxes identical?
  */
 Datum
 box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPeq(box1->high.x, box2->high.x) &&
-				   FPeq(box1->low.x, box2->low.x) &&
-				   FPeq(box1->high.y, box2->high.y) &&
-				   FPeq(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(point_eq_internal(&box1->high, &box2->high) &&
+				   point_eq_internal(&box1->low, &box2->low));
 }
 
 /*		box_overlap		-		does box1 overlap box2?
  */
 Datum
 box_overlap(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
@@ -751,51 +731,51 @@ box_area(PG_FUNCTION_ARGS)
 
 
 /*		box_width		-		returns the width of the box
  *								  (horizontal magnitude).
  */
 Datum
 box_width(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.x - box->low.x);
+	PG_RETURN_FLOAT8(box_wd(box));
 }
 
 
 /*		box_height		-		returns the height of the box
  *								  (vertical magnitude).
  */
 Datum
 box_height(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.y - box->low.y);
+	PG_RETURN_FLOAT8(box_ht(box));
 }
 
 
 /*		box_distance	-		returns the distance between the
  *								  center points of two boxes.
  */
 Datum
 box_distance(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 	Point		a,
 				b;
 
 	box_cn(&a, box1);
 	box_cn(&b, box2);
 
-	PG_RETURN_FLOAT8(HYPOT(a.x - b.x, a.y - b.y));
+	PG_RETURN_FLOAT8(point_dt(&a, &b));
 }
 
 
 /*		box_center		-		returns the center point of the box.
  */
 Datum
 box_center(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *result = (Point *) palloc(sizeof(Point));
@@ -934,22 +914,22 @@ line_in(PG_FUNCTION_ARGS)
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
 							"line", str)));
 		if (FPzero(line->A) && FPzero(line->B))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: A and B cannot both be zero")));
 	}
 	else
 	{
-		path_decode(s, true, 2, &(lseg.p[0]), &isopen, NULL, "line", str);
-		if (FPeq(lseg.p[0].x, lseg.p[1].x) && FPeq(lseg.p[0].y, lseg.p[1].y))
+		path_decode(s, true, 2, &lseg.p[0], &isopen, NULL, "line", str);
+		if (point_eq_internal(&lseg.p[0], &lseg.p[1]))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: must be two distinct points")));
 		line_construct_pts(line, &lseg.p[0], &lseg.p[1]);
 	}
 
 	PG_RETURN_LINE_P(line);
 }
 
 
@@ -1000,41 +980,37 @@ line_send(PG_FUNCTION_ARGS)
 
 
 /*----------------------------------------------------------
  *	Conversion routines from one line formula to internal.
  *		Internal form:	Ax+By+C=0
  *---------------------------------------------------------*/
 
 /* line_construct_pm()
  * point-slope
  */
-static LINE *
-line_construct_pm(Point *pt, double m)
+static void
+line_construct_pm(LINE *result, Point *pt, float8 m)
 {
-	LINE	   *result = (LINE *) palloc(sizeof(LINE));
-
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
 		result->A = -1;
 		result->B = 0;
 		result->C = pt->x;
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
 		result->C = pt->y - m * pt->x;
 	}
-
-	return result;
 }
 
 /*
  * Fill already-allocated LINE struct from two points on the line
  */
 static void
 line_construct_pts(LINE *line, Point *pt1, Point *pt2)
 {
 	if (FPeq(pt1->x, pt2->x))
 	{							/* vertical */
@@ -1052,21 +1028,21 @@ line_construct_pts(LINE *line, Point *pt1, Point *pt2)
 		line->A = 0;
 		line->B = -1;
 		line->C = pt1->y;
 #ifdef GEODEBUG
 		printf("line_construct_pts- line is horizontal\n");
 #endif
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
-		line->A = (pt2->y - pt1->y) / (pt2->x - pt1->x);
+		line->A = point_sl(pt2, pt1);
 		line->B = -1.0;
 		line->C = pt1->y - line->A * pt1->x;
 		/* on some platforms, the preceding expression tends to produce -0 */
 		if (line->C == 0.0)
 			line->C = 0.0;
 #ifdef GEODEBUG
 		printf("line_construct_pts- line is neither vertical nor horizontal (diffs x=%.*g, y=%.*g\n",
 			   DBL_DIG, (pt2->x - pt1->x), DBL_DIG, (pt2->y - pt1->y));
 #endif
 	}
@@ -1079,46 +1055,53 @@ Datum
 line_construct_pp(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 	LINE	   *result = (LINE *) palloc(sizeof(LINE));
 
 	line_construct_pts(result, pt1, pt2);
 	PG_RETURN_LINE_P(result);
 }
 
+/*
+ * Calculate the line equation for a point
+ *
+ * This returns the result of the line equation Ax + By + C.  The result
+ * needs to be 0 for the point to be on the line.
+ */
+static float8
+line_calculate_point(LINE *line, Point *pt)
+{
+	return line->A * pt->x + line->B * pt->y + line->C;
+}
+
 
 /*----------------------------------------------------------
  *	Relative position routines.
  *---------------------------------------------------------*/
 
 Datum
 line_intersect(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(!DatumGetBool(DirectFunctionCall2(line_parallel,
-													 LinePGetDatum(l1),
-													 LinePGetDatum(l2))));
+	PG_RETURN_BOOL(line_interpt_internal(NULL, l1, l2));
 }
 
 Datum
 line_parallel(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
-	if (FPzero(l1->B))
-		PG_RETURN_BOOL(FPzero(l2->B));
-
-	PG_RETURN_BOOL(FPeq(l2->A, l1->A * (l2->B / l1->B)));
+	PG_RETURN_BOOL(!line_interpt_internal(NULL, l1, l2));
 }
 
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
@@ -1172,96 +1155,94 @@ line_eq(PG_FUNCTION_ARGS)
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
-	Point	   *tmp;
+	Point		tmp;
 
-	if (!DatumGetBool(DirectFunctionCall2(line_parallel,
-										  LinePGetDatum(l1),
-										  LinePGetDatum(l2))))
+	if (line_interpt_internal(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
 		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
-	tmp = point_construct(0.0, l1->C);
-	result = dist_pl_internal(tmp, l2);
+	point_construct(&tmp, 0.0, l1->C);
+	result = dist_pl_internal(&tmp, l2);
 	PG_RETURN_FLOAT8(result);
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
-	result = line_interpt_internal(l1, l2);
+	result = (Point *) palloc(sizeof(Point));
 
-	if (result == NULL)
+	if (!line_interpt_internal(result, l1, l2))
 		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
 
 /*
  * Internal version of line_interpt
  *
- * returns a NULL pointer if no intersection point
+ * This returns true if two lines intersect (they do, if they are not
+ * parallel), false if they do not.  This also sets the intersection point
+ * to *result, if it is not NULL.
+ *
+ * NOTE: If the lines are identical then we will find they are parallel
+ * and report "no intersection".  This is a little weird, but since
+ * there's no *unique* intersection, maybe it's appropriate behavior.
  */
-static Point *
-line_interpt_internal(LINE *l1, LINE *l2)
+static bool
+line_interpt_internal(Point *result, LINE *l1, LINE *l2)
 {
-	Point	   *result;
 	double		x,
 				y;
 
-	/*
-	 * NOTE: if the lines are identical then we will find they are parallel
-	 * and report "no intersection".  This is a little weird, but since
-	 * there's no *unique* intersection, maybe it's appropriate behavior.
-	 */
-	if (DatumGetBool(DirectFunctionCall2(line_parallel,
-										 LinePGetDatum(l1),
-										 LinePGetDatum(l2))))
-		return NULL;
-
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
+		if (FPzero(l2->B))		/* l2 vertical? */
+			return false;
+
 		x = l1->C;
 		y = (l2->A * x + l2->C);
 	}
-	else if (FPzero(l2->B))		/* l2 vertical? */
-	{
-		x = l2->C;
-		y = (l1->A * x + l1->C);
-	}
 	else
 	{
-		x = (l1->C - l2->C) / (l2->A - l1->A);
+		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+			return false;
+
+		if (FPzero(l2->B))
+			x = l2->C;
+		else
+			x = (l1->C - l2->C) / (l2->A - l1->A);
 		y = (l1->A * x + l1->C);
 	}
-	result = point_construct(x, y);
+	if (result != NULL)
+		point_construct(result, x, y);
 
 #ifdef GEODEBUG
 	printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
 		   DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
 	printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
 #endif
 
-	return result;
+	return true;
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D paths (sequences of line segments, also
  **				called `polylines').
  **
  **				This is not a general package for geometric paths,
  **				which of course include polygons; the emphasis here
@@ -1609,21 +1590,21 @@ path_inter(PG_FUNCTION_ARGS)
 				jprev = j - 1;
 			else
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
-			if (lseg_intersect_internal(&seg1, &seg2))
+			if (lseg_interpt_internal(NULL, &seg1, &seg2))
 				PG_RETURN_BOOL(true);
 		}
 	}
 
 	/* if we dropped through, no two segs intersected */
 	PG_RETURN_BOOL(false);
 }
 
 /* path_distance()
  * This essentially does a cartesian product of the lsegs in the
@@ -1664,23 +1645,21 @@ path_distance(PG_FUNCTION_ARGS)
 			else
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
-			tmp = DatumGetFloat8(DirectFunctionCall2(lseg_distance,
-													 LsegPGetDatum(&seg1),
-													 LsegPGetDatum(&seg2)));
+			tmp = lseg_dt(&seg1, &seg2);
 			if (!have_min || tmp < min)
 			{
 				min = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	if (!have_min)
 		PG_RETURN_NULL();
@@ -1773,45 +1752,31 @@ point_send(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	StringInfoData buf;
 
 	pq_begintypsend(&buf);
 	pq_sendfloat8(&buf, pt->x);
 	pq_sendfloat8(&buf, pt->y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
-
-static Point *
-point_construct(double x, double y)
+/*
+ * Initialize a point
+ *
+ * This function is over-simple, but it is, at least, useful when the new
+ * point is calculated using the existing one.
+ */
+static void
+point_construct(Point *result, float8 x, float8 y)
 {
-	Point	   *result = (Point *) palloc(sizeof(Point));
-
 	result->x = x;
 	result->y = y;
-	return result;
-}
-
-
-static Point *
-point_copy(Point *pt)
-{
-	Point	   *result;
-
-	if (!PointerIsValid(pt))
-		return NULL;
-
-	result = (Point *) palloc(sizeof(Point));
-
-	result->x = pt->x;
-	result->y = pt->y;
-	return result;
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for Points.
  *		Since we do have a sense of coordinates being
  *		"equal" to a given accuracy (point_vert, point_horiz),
  *		the other ops must preserve that sense.  This means
  *		that results may, strictly speaking, be a lie (unless
  *		EPSILON = 0.0).
@@ -1870,66 +1835,74 @@ point_horiz(PG_FUNCTION_ARGS)
 
 	PG_RETURN_BOOL(FPeq(pt1->y, pt2->y));
 }
 
 Datum
 point_eq(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y));
+	PG_RETURN_BOOL(point_eq_internal(pt1, pt2));
 }
 
 Datum
 point_ne(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPne(pt1->x, pt2->x) || FPne(pt1->y, pt2->y));
+	PG_RETURN_BOOL(!point_eq_internal(pt1, pt2));
 }
 
+
+static bool
+point_eq_internal(Point *pt1, Point *pt2)
+{
+	return FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y);
+}
+
+
 /*----------------------------------------------------------
  *	"Arithmetic" operators on points.
  *---------------------------------------------------------*/
 
 Datum
 point_distance(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_FLOAT8(HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
+	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
-double
+static float8
 point_dt(Point *pt1, Point *pt2)
 {
 #ifdef GEODEBUG
 	printf("point_dt- segment (%f,%f),(%f,%f) length is %f\n",
 		   pt1->x, pt1->y, pt2->x, pt2->y, HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
 #endif
 	return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
 }
 
 Datum
 point_slope(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_sl(pt1, pt2));
 }
 
 
-double
+static float8
 point_sl(Point *pt1, Point *pt2)
 {
 	return (FPeq(pt1->x, pt2->x)
 			? (double) DBL_MAX
 			: (pt1->y - pt2->y) / (pt1->x - pt2->x));
 }
 
 
 /***********************************************************************
  **
@@ -1946,31 +1919,31 @@ point_sl(Point *pt1, Point *pt2)
  *		(old form)		"(x1, y1, x2, y2)"
  *---------------------------------------------------------*/
 
 Datum
 lseg_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	LSEG	   *lseg = (LSEG *) palloc(sizeof(LSEG));
 	bool		isopen;
 
-	path_decode(str, true, 2, &(lseg->p[0]), &isopen, NULL, "lseg", str);
+	path_decode(str, true, 2, &lseg->p[0], &isopen, NULL, "lseg", str);
 	PG_RETURN_LSEG_P(lseg);
 }
 
 
 Datum
 lseg_out(PG_FUNCTION_ARGS)
 {
 	LSEG	   *ls = PG_GETARG_LSEG_P(0);
 
-	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, (Point *) &(ls->p[0])));
+	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, &ls->p[0]));
 }
 
 /*
  *		lseg_recv			- converts external binary format to lseg
  */
 Datum
 lseg_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LSEG	   *lseg;
@@ -2046,39 +2019,23 @@ lseg_length(PG_FUNCTION_ARGS)
 /*
  **  find intersection of the two lines, and see if it falls on
  **  both segments.
  */
 Datum
 lseg_intersect(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(lseg_intersect_internal(l1, l2));
+	PG_RETURN_BOOL(lseg_interpt_internal(NULL, l1, l2));
 }
 
-static bool
-lseg_intersect_internal(LSEG *l1, LSEG *l2)
-{
-	LINE		ln;
-	Point	   *interpt;
-	bool		retval;
-
-	line_construct_pts(&ln, &l2->p[0], &l2->p[1]);
-	interpt = interpt_sl(l1, &ln);
-
-	if (interpt != NULL && on_ps_internal(interpt, l2))
-		retval = true;			/* interpt on l1 and l2 */
-	else
-		retval = false;
-	return retval;
-}
 
 Datum
 lseg_parallel(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_BOOL(FPeq(point_sl(&l1->p[0], &l1->p[1]),
 						point_sl(&l2->p[0], &l2->p[1])));
 }
@@ -2093,22 +2050,22 @@ lseg_parallel(PG_FUNCTION_ARGS)
  * - thomas 1998-01-31
  */
 Datum
 lseg_perp(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	double		m1,
 				m2;
 
-	m1 = point_sl(&(l1->p[0]), &(l1->p[1]));
-	m2 = point_sl(&(l2->p[0]), &(l2->p[1]));
+	m1 = point_sl(&l1->p[0], &l1->p[1]);
+	m2 = point_sl(&l2->p[0], &l2->p[1]);
 
 #ifdef GEODEBUG
 	printf("lseg_perp- slopes are %g and %g\n", m1, m2);
 #endif
 	if (FPzero(m1))
 		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
 	else if (FPzero(m2))
 		PG_RETURN_BOOL(FPeq(m1, DBL_MAX));
 
 	PG_RETURN_BOOL(FPeq(m1 / m2, -1.0));
@@ -2130,36 +2087,32 @@ lseg_horizontal(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(FPeq(lseg->p[0].y, lseg->p[1].y));
 }
 
 
 Datum
 lseg_eq(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPeq(l1->p[0].x, l2->p[0].x) &&
-				   FPeq(l1->p[0].y, l2->p[0].y) &&
-				   FPeq(l1->p[1].x, l2->p[1].x) &&
-				   FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(point_eq_internal(&l1->p[0], &l2->p[0]) &&
+				   point_eq_internal(&l1->p[1], &l2->p[1]));
 }
 
 Datum
 lseg_ne(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(!FPeq(l1->p[0].x, l2->p[0].x) ||
-				   !FPeq(l1->p[0].y, l2->p[0].y) ||
-				   !FPeq(l1->p[1].x, l2->p[1].x) ||
-				   !FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(!point_eq_internal(&l1->p[0], &l2->p[0]) ||
+				   !point_eq_internal(&l1->p[1], &l2->p[1]));
 }
 
 Datum
 lseg_lt(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_BOOL(FPlt(point_dt(&l1->p[0], &l1->p[1]),
 						point_dt(&l2->p[0], &l2->p[1])));
@@ -2218,21 +2171,21 @@ lseg_distance(PG_FUNCTION_ARGS)
  * Distance between two line segments.
  * Must check both sets of endpoints to ensure minimum distance is found.
  * - thomas 1998-02-01
  */
 static double
 lseg_dt(LSEG *l1, LSEG *l2)
 {
 	double		result,
 				d;
 
-	if (lseg_intersect_internal(l1, l2))
+	if (lseg_interpt_internal(NULL, l1, l2))
 		return 0.0;
 
 	d = dist_ps_internal(&l1->p[0], l2);
 	result = d;
 	d = dist_ps_internal(&l1->p[1], l2);
 	result = Min(result, d);
 	d = dist_ps_internal(&l2->p[0], l1);
 	result = Min(result, d);
 	d = dist_ps_internal(&l2->p[1], l1);
 	result = Min(result, d);
@@ -2248,82 +2201,86 @@ lseg_center(PG_FUNCTION_ARGS)
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
 	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
 
 	PG_RETURN_POINT_P(result);
 }
 
-static Point *
-lseg_interpt_internal(LSEG *l1, LSEG *l2)
+static bool
+lseg_interpt_internal(Point *result, LSEG *l1, LSEG *l2)
 {
-	Point	   *result;
+	Point		interpt;
 	LINE		tmp1,
 				tmp2;
 
 	/*
 	 * Find the intersection of the appropriate lines, if any.
 	 */
 	line_construct_pts(&tmp1, &l1->p[0], &l1->p[1]);
 	line_construct_pts(&tmp2, &l2->p[0], &l2->p[1]);
-	result = line_interpt_internal(&tmp1, &tmp2);
-	if (!PointerIsValid(result))
-		return NULL;
+	if (!line_interpt_internal(&interpt, &tmp1, &tmp2))
+		return false;
 
 	/*
 	 * If the line intersection point isn't within l1 (or equivalently l2),
 	 * there is no valid segment intersection point at all.
 	 */
-	if (!on_ps_internal(result, l1) ||
-		!on_ps_internal(result, l2))
-	{
-		pfree(result);
-		return NULL;
-	}
+	if (!on_ps_internal(&interpt, l1) ||
+		!on_ps_internal(&interpt, l2))
+		return false;
+
+	if (result == NULL)
+		return true;
 
 	/*
 	 * If there is an intersection, then check explicitly for matching
 	 * endpoints since there may be rounding effects with annoying lsb
 	 * residue. - tgl 1997-07-09
 	 */
 	if ((FPeq(l1->p[0].x, l2->p[0].x) && FPeq(l1->p[0].y, l2->p[0].y)) ||
 		(FPeq(l1->p[0].x, l2->p[1].x) && FPeq(l1->p[0].y, l2->p[1].y)))
 	{
 		result->x = l1->p[0].x;
 		result->y = l1->p[0].y;
 	}
 	else if ((FPeq(l1->p[1].x, l2->p[0].x) && FPeq(l1->p[1].y, l2->p[0].y)) ||
 			 (FPeq(l1->p[1].x, l2->p[1].x) && FPeq(l1->p[1].y, l2->p[1].y)))
 	{
 		result->x = l1->p[1].x;
 		result->y = l1->p[1].y;
 	}
+	else
+	{
+		result->x = interpt.x;
+		result->y = interpt.y;
+	}
 
-	return result;
+	return true;
 }
 
 /* lseg_interpt -
  *		Find the intersection point of two segments (if any).
  */
 Datum
 lseg_interpt(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
-	result = lseg_interpt_internal(l1, l2);
-	if (!PointerIsValid(result))
-		PG_RETURN_NULL();
+	result = (Point *) palloc(sizeof(Point));
 
+	if (!lseg_interpt_internal(result, l1, l2))
+		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
 
 /***********************************************************************
  **
  **		Routines for position comparisons of differently-typed
  **				2D objects.
  **
  ***********************************************************************/
 
@@ -2340,75 +2297,75 @@ dist_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
 	PG_RETURN_FLOAT8(dist_pl_internal(pt, line));
 }
 
 static double
 dist_pl_internal(Point *pt, LINE *line)
 {
-	return fabs((line->A * pt->x + line->B * pt->y + line->C) /
+	return fabs(line_calculate_point(line, pt) /
 				HYPOT(line->A, line->B));
 }
 
 /*
  * Distance from a point to a lseg
  */
 Datum
 dist_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_FLOAT8(dist_ps_internal(pt, lseg));
 }
 
 static double
 dist_ps_internal(Point *pt, LSEG *lseg)
 {
 	double		m;				/* slope of perp. */
-	LINE	   *ln;
 	double		result,
 				tmpdist;
-	Point	   *ip;
+	Point		interpt;
+	LINE		ln;
 
 	/*
 	 * Construct a line perpendicular to the input segment and through the
 	 * input point
 	 */
 	if (lseg->p[1].x == lseg->p[0].x)
 		m = 0;
 	else if (lseg->p[1].y == lseg->p[0].y)
 		m = (double) DBL_MAX;	/* slope is infinite */
 	else
-		m = (lseg->p[0].x - lseg->p[1].x) / (lseg->p[1].y - lseg->p[0].y);
-	ln = line_construct_pm(pt, m);
+		m = -1.0 / point_sl(&lseg->p[0], &lseg->p[1]);
+	line_construct_pm(&ln, pt, m);
 
 #ifdef GEODEBUG
 	printf("dist_ps- line is A=%g B=%g C=%g from (point) slope (%f,%f) %g\n",
 		   ln->A, ln->B, ln->C, pt->x, pt->y, m);
 #endif
 
 	/*
 	 * Calculate distance to the line segment or to the nearest endpoint of
 	 * the segment.
 	 */
 
 	/* intersection is on the line segment? */
-	if ((ip = interpt_sl(lseg, ln)) != NULL)
+	if (lseg_interpt_line_internal(&interpt, lseg, &ln))
 	{
 		/* yes, so use distance to the intersection point */
-		result = point_dt(pt, ip);
+		result = point_dt(pt, &interpt);
 #ifdef GEODEBUG
 		printf("dist_ps- distance is %f to intersection point is (%f,%f)\n",
-			   result, ip->x, ip->y);
+			   result, tmp.x, tmp.y);
 #endif
 	}
 	else
 	{
 		/* no, so use distance to the nearer endpoint */
 		result = point_dt(pt, &lseg->p[0]);
 		tmpdist = point_dt(pt, &lseg->p[1]);
 		if (tmpdist < result)
 			result = tmpdist;
 	}
@@ -2496,21 +2453,21 @@ dist_pb(PG_FUNCTION_ARGS)
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	float8		result,
 				d2;
 
-	if (has_interpt_sl(lseg, line))
+	if (lseg_interpt_line_internal(NULL, lseg, line))
 		result = 0.0;
 	else
 	{
 		result = dist_pl_internal(&lseg->p[0], line);
 		d2 = dist_pl_internal(&lseg->p[1], line);
 		/* XXX shouldn't we take the min not max? */
 		if (d2 > result)
 			result = d2;
 	}
 
@@ -2649,284 +2606,261 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
  *				Intersection point of objects.
  *				We choose to ignore the "point" of intersection between
  *				  lines and boxes, since there are typically two.
  *-------------------------------------------------------------------*/
 
-/* Get intersection point of lseg and line; returns NULL if no intersection */
-static Point *
-interpt_sl(LSEG *lseg, LINE *line)
+/*
+ * Check if the line segment intersects with the line
+ *
+ * It sets the intersection point to *result, if it is not NULL.
+ */
+static bool
+lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line)
 {
+	Point		interpt;
 	LINE		tmp;
-	Point	   *p;
 
 	line_construct_pts(&tmp, &lseg->p[0], &lseg->p[1]);
-	p = line_interpt_internal(&tmp, line);
 #ifdef GEODEBUG
-	printf("interpt_sl- segment is (%.*g %.*g) (%.*g %.*g)\n",
+	printf("lseg_interpt_line- segment is (%.*g %.*g) (%.*g %.*g)\n",
 		   DBL_DIG, lseg->p[0].x, DBL_DIG, lseg->p[0].y, DBL_DIG, lseg->p[1].x, DBL_DIG, lseg->p[1].y);
-	printf("interpt_sl- segment becomes line A=%.*g B=%.*g C=%.*g\n",
+	printf("lseg_interpt_line_- segment becomes line A=%.*g B=%.*g C=%.*g\n",
 		   DBL_DIG, tmp.A, DBL_DIG, tmp.B, DBL_DIG, tmp.C);
 #endif
-	if (PointerIsValid(p))
+	if (line_interpt_internal(&interpt, &tmp, line))
 	{
 #ifdef GEODEBUG
-		printf("interpt_sl- intersection point is (%.*g %.*g)\n", DBL_DIG, p->x, DBL_DIG, p->y);
+		printf("lseg_interpt_line- intersection point is (%.*g %.*g)\n", DBL_DIG, p->x, DBL_DIG, p->y);
 #endif
-		if (on_ps_internal(p, lseg))
+		if (on_ps_internal(&interpt, lseg))
 		{
 #ifdef GEODEBUG
-			printf("interpt_sl- intersection point is on segment\n");
+			printf("lseg_interpt_line- intersection point is on segment\n");
 #endif
+			if (result != NULL)
+				*result = interpt;
+			return true;
 		}
-		else
-			p = NULL;
 	}
 
-	return p;
-}
-
-/* variant: just indicate if intersection point exists */
-static bool
-has_interpt_sl(LSEG *lseg, LINE *line)
-{
-	Point	   *tmp;
-
-	tmp = interpt_sl(lseg, line);
-	if (tmp)
-		return true;
 	return false;
 }
 
+
 /*---------------------------------------------------------------------
  *		close_
  *				Point of closest proximity between objects.
  *-------------------------------------------------------------------*/
 
 /* close_pl -
  *		The intersection point of a perpendicular of the line
  *		through the point.
  */
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
-	LINE	   *tmp;
 	double		invm;
+	LINE		tmp;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (FPzero(line->B))		/* vertical? */
 	{
 		result->x = line->C;
 		result->y = pt->y;
 		PG_RETURN_POINT_P(result);
 	}
 	if (FPzero(line->A))		/* horizontal? */
 	{
 		result->x = pt->x;
 		result->y = line->C;
 		PG_RETURN_POINT_P(result);
 	}
 	/* drop a perpendicular and find the intersection point */
 
 	/* invert and flip the sign on the slope to get a perpendicular */
 	invm = line->B / line->A;
-	tmp = line_construct_pm(pt, invm);
-	result = line_interpt_internal(tmp, line);
-	Assert(result != NULL);
+	line_construct_pm(&tmp, pt, invm);
+	line_interpt_internal(result, &tmp, line);
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_ps()
  * Closest point on line segment to specified point.
  * Take the closest endpoint if the point is left, right,
  *	above, or below the segment, otherwise find the intersection
  *	point of the segment and its perpendicular through the point.
  *
  * Some tricky code here, relying on boolean expressions
  *	evaluating to only zero or one to use as an array index.
  *		bug fixes by gthaker@atl.lmco.com; May 1, 1998
  */
 Datum
 close_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
-	LINE	   *tmp;
+	Point	   *result;
 	double		invm;
 	int			xh,
 				yh;
+	LINE		tmp;
+
+	result = (Point *) palloc(sizeof(Point));
 
 #ifdef GEODEBUG
 	printf("close_sp:pt->x %f pt->y %f\nlseg(0).x %f lseg(0).y %f  lseg(1).x %f lseg(1).y %f\n",
 		   pt->x, pt->y, lseg->p[0].x, lseg->p[0].y,
 		   lseg->p[1].x, lseg->p[1].y);
 #endif
 
 	/* xh (or yh) is the index of upper x( or y) end point of lseg */
 	/* !xh (or !yh) is the index of lower x( or y) end point of lseg */
 	xh = lseg->p[0].x < lseg->p[1].x;
 	yh = lseg->p[0].y < lseg->p[1].y;
 
 	if (FPeq(lseg->p[0].x, lseg->p[1].x))	/* vertical? */
 	{
 #ifdef GEODEBUG
 		printf("close_ps- segment is vertical\n");
 #endif
 		/* first check if point is below or above the entire lseg. */
 		if (pt->y < lseg->p[!yh].y)
-			result = point_copy(&lseg->p[!yh]); /* below the lseg */
+			*result = lseg->p[!yh];		/* below the lseg */
 		else if (pt->y > lseg->p[yh].y)
-			result = point_copy(&lseg->p[yh]);	/* above the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
+			*result = lseg->p[yh];		/* above the lseg */
+		else
+			/* point lines along (to left or right) of the vertical lseg. */
+			point_construct(result, lseg->p[0].x, pt->y);
 
-		/* point lines along (to left or right) of the vertical lseg. */
-
-		result = (Point *) palloc(sizeof(Point));
-		result->x = lseg->p[0].x;
-		result->y = pt->y;
 		PG_RETURN_POINT_P(result);
 	}
 	else if (FPeq(lseg->p[0].y, lseg->p[1].y))	/* horizontal? */
 	{
 #ifdef GEODEBUG
 		printf("close_ps- segment is horizontal\n");
 #endif
 		/* first check if point is left or right of the entire lseg. */
 		if (pt->x < lseg->p[!xh].x)
-			result = point_copy(&lseg->p[!xh]); /* left of the lseg */
+			*result = lseg->p[!xh];		/* left of the lseg */
 		else if (pt->x > lseg->p[xh].x)
-			result = point_copy(&lseg->p[xh]);	/* right of the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
+			*result = lseg->p[xh];		/* right of the lseg */
+		else
+			/* point lines along (at top or below) the horiz. lseg. */
+			point_construct(result, pt->x, lseg->p[0].y);
 
-		/* point lines along (at top or below) the horiz. lseg. */
-		result = (Point *) palloc(sizeof(Point));
-		result->x = pt->x;
-		result->y = lseg->p[0].y;
 		PG_RETURN_POINT_P(result);
 	}
 
 	/*
 	 * vert. and horiz. cases are down, now check if the closest point is one
 	 * of the end points or someplace on the lseg.
 	 */
 
 	invm = -1.0 / point_sl(&(lseg->p[0]), &(lseg->p[1]));
-	tmp = line_construct_pm(&lseg->p[!yh], invm);	/* lower edge of the
+	line_construct_pm(&tmp, &lseg->p[!yh], invm);	/* lower edge of the
 													 * "band" */
-	if (pt->y < (tmp->A * pt->x + tmp->C))
+	if (pt->y < (tmp.A * pt->x + tmp.C))
 	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[!yh]); /* below the lseg, take lower end
-											 * pt */
+		*result = lseg->p[!yh];	/* below the lseg, take lower end pt */
 #ifdef GEODEBUG
 		printf("close_ps below: tmp A %f  B %f   C %f\n",
 			   tmp->A, tmp->B, tmp->C);
 #endif
 		PG_RETURN_POINT_P(result);
 	}
-	tmp = line_construct_pm(&lseg->p[yh], invm);	/* upper edge of the
+	line_construct_pm(&tmp, &lseg->p[yh], invm);	/* upper edge of the
 													 * "band" */
-	if (pt->y > (tmp->A * pt->x + tmp->C))
+	if (pt->y > (tmp.A * pt->x + tmp.C))
 	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[yh]);	/* above the lseg, take higher end
-											 * pt */
+		*result = lseg->p[yh];	/* above the lseg, take higher end pt */
 #ifdef GEODEBUG
 		printf("close_ps above: tmp A %f  B %f   C %f\n",
 			   tmp->A, tmp->B, tmp->C);
 #endif
 		PG_RETURN_POINT_P(result);
 	}
 
 	/*
 	 * at this point the "normal" from point will hit lseg. The closest point
 	 * will be somewhere on the lseg
 	 */
-	tmp = line_construct_pm(pt, invm);
+	line_construct_pm(&tmp, pt, invm);
 #ifdef GEODEBUG
 	printf("close_ps- tmp A %f  B %f   C %f\n",
 		   tmp->A, tmp->B, tmp->C);
 #endif
-	result = interpt_sl(lseg, tmp);
 
 	/*
 	 * ordinarily we should always find an intersection point, but that could
 	 * fail in the presence of NaN coordinates, and perhaps even from simple
 	 * roundoff issues.  Return a SQL NULL if so.
 	 */
-	if (result == NULL)
+	if (!lseg_interpt_line_internal(result, lseg, &tmp))
 		PG_RETURN_NULL();
 
 #ifdef GEODEBUG
 	printf("close_ps- result.x %f  result.y %f\n", result->x, result->y);
 #endif
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_lseg()
  * Closest point to l1 on l2.
  */
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
-	Point		point;
-	double		dist;
-	double		d;
+	Point	   *result;
+	double		dist,
+				dist0,
+				dist1;
 
-	d = dist_ps_internal(&l1->p[0], l2);
-	dist = d;
-	memcpy(&point, &l1->p[0], sizeof(Point));
-
-	if ((d = dist_ps_internal(&l1->p[1], l2)) < dist)
-	{
-		dist = d;
-		memcpy(&point, &l1->p[1], sizeof(Point));
-	}
+	dist0 = dist_ps_internal(&l1->p[0], l2);
+	dist1 = dist_ps_internal(&l1->p[1], l2);
+	dist = Min(dist0, dist1);
 
 	if (dist_ps_internal(&l2->p[0], l1) < dist)
 	{
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(&l2->p[0]),
 													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
+													PointPGetDatum(result),
 													LsegPGetDatum(l2)));
 	}
-
-	if (dist_ps_internal(&l2->p[1], l1) < dist)
+	else if (dist_ps_internal(&l2->p[1], l1) < dist)
 	{
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(&l2->p[1]),
 													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
+													PointPGetDatum(result),
 													LsegPGetDatum(l2)));
 	}
-
-	if (result == NULL)
-		result = point_copy(&point);
+	else
+	{
+		result = (Point *) palloc(sizeof(Point));
+		*result = l1->p[dist == dist0 ? 0 : 1];
+	}
 
 	PG_RETURN_POINT_P(result);
 }
 
 /* close_pb()
  * Closest point on or in box to specified point.
  */
 Datum
 close_pb(PG_FUNCTION_ARGS)
 {
@@ -2989,30 +2923,31 @@ close_pb(PG_FUNCTION_ARGS)
 Datum
 close_sl(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 	float8		d1,
 				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
+	result = (Point *) palloc(sizeof(Point));
+
+	if (lseg_interpt_line_internal(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = dist_pl_internal(&lseg->p[0], line);
 	d2 = dist_pl_internal(&lseg->p[1], line);
 	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
+		*result = lseg->p[0];
 	else
-		result = point_copy(&lseg->p[1]);
+		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
 
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_sl\" not implemented")));
 
 	PG_RETURN_NULL();
 }
@@ -3022,30 +2957,31 @@ close_sl(PG_FUNCTION_ARGS)
  */
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 	float8		d1,
 				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
+	result = (Point *) palloc(sizeof(Point));
+
+	if (lseg_interpt_line_internal(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = dist_pl_internal(&lseg->p[0], line);
 	d2 = dist_pl_internal(&lseg->p[1], line);
 	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
+		*result = lseg->p[0];
 	else
-		result = point_copy(&lseg->p[1]);
+		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 }
 
 /* close_sb()
  * Closest point on or in box to line segment.
  */
 Datum
 close_sb(PG_FUNCTION_ARGS)
 {
@@ -3126,21 +3062,21 @@ close_lb(PG_FUNCTION_ARGS)
 
 /* on_pl -
  *		Does the point satisfy the equation?
  */
 Datum
 on_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(FPzero(line->A * pt->x + line->B * pt->y + line->C));
+	PG_RETURN_BOOL(FPzero(line_calculate_point(line, pt)));
 }
 
 
 /* on_ps -
  *		Determine colinearity by detecting a triangle inequality.
  * This algorithm seems to behave nicely even with lsb residues - tgl 1997-07-09
  */
 Datum
 on_ps(PG_FUNCTION_ARGS)
 {
@@ -3250,21 +3186,21 @@ on_sb(PG_FUNCTION_ARGS)
  *		inter_
  *				Whether one object intersects another.
  *-------------------------------------------------------------------*/
 
 Datum
 inter_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(has_interpt_sl(lseg, line));
+	PG_RETURN_BOOL(lseg_interpt_line_internal(NULL, lseg, line));
 }
 
 /* inter_sb()
  * Do line segment and box intersect?
  *
  * Segment completely inside box counts as intersection.
  * If you want only segments crossing box boundaries,
  *	try converting box to path first.
  *
  * Optimize for non-intersection by checking for box intersection first.
@@ -3294,35 +3230,35 @@ inter_sb(PG_FUNCTION_ARGS)
 										 BoxPGetDatum(box))) ||
 		DatumGetBool(DirectFunctionCall2(on_pb,
 										 PointPGetDatum(&lseg->p[1]),
 										 BoxPGetDatum(box))))
 		PG_RETURN_BOOL(true);
 
 	/* pairwise check lseg intersections */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
+	if (lseg_interpt_internal(NULL, &bseg, lseg))
 		PG_RETURN_BOOL(true);
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
+	if (lseg_interpt_internal(NULL, &bseg, lseg))
 		PG_RETURN_BOOL(true);
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
+	if (lseg_interpt_internal(NULL, &bseg, lseg))
 		PG_RETURN_BOOL(true);
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
+	if (lseg_interpt_internal(NULL, &bseg, lseg))
 		PG_RETURN_BOOL(true);
 
 	/* if we dropped through, no two segs intersected */
 	PG_RETURN_BOOL(false);
 }
 
 /* inter_lb()
  * Do line and box intersect?
  */
 Datum
@@ -3333,36 +3269,36 @@ inter_lb(PG_FUNCTION_ARGS)
 	LSEG		bseg;
 	Point		p1,
 				p2;
 
 	/* pairwise check lseg intersections */
 	p1.x = box->low.x;
 	p1.y = box->low.y;
 	p2.x = box->low.x;
 	p2.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line_internal(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->high.x;
 	p1.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line_internal(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p2.x = box->high.x;
 	p2.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line_internal(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->low.x;
 	p1.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line_internal(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 
 	/* if we dropped through, no intersection */
 	PG_RETURN_BOOL(false);
 }
 
 /*------------------------------------------------------------------
  * The following routines define a data type and operator class for
  * POLYGONS .... Part of which (the polygon's bounding box) is built on
  * top of the BOX data type.
@@ -3391,21 +3327,21 @@ make_bound_box(POLYGON *poly)
 			if (poly->p[i].x < x1)
 				x1 = poly->p[i].x;
 			if (poly->p[i].x > x2)
 				x2 = poly->p[i].x;
 			if (poly->p[i].y < y1)
 				y1 = poly->p[i].y;
 			if (poly->p[i].y > y2)
 				y2 = poly->p[i].y;
 		}
 
-		box_fill(&(poly->boundbox), x1, x2, y1, y2);
+		box_construct(&poly->boundbox, x1, x2, y1, y2);
 	}
 	else
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("cannot create bounding box for empty polygon")));
 }
 
 /*------------------------------------------------------------------
  * poly_in - read in the polygon from a string specification
  *
@@ -3742,21 +3678,21 @@ poly_same(PG_FUNCTION_ARGS)
  *-----------------------------------------------------------------*/
 Datum
 poly_overlap(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
 	/* Quick check by bounding box */
 	result = (polya->npts > 0 && polyb->npts > 0 &&
-			  box_ov(&polya->boundbox, &polyb->boundbox)) ? true : false;
+			  box_ov(&polya->boundbox, &polyb->boundbox));
 
 	/*
 	 * Brute-force algorithm - try to find intersected edges, if so then
 	 * polygons are overlapped else check is one polygon inside other or not
 	 * by testing single point of them.
 	 */
 	if (result)
 	{
 		int			ia,
 					ib;
@@ -3771,34 +3707,33 @@ poly_overlap(PG_FUNCTION_ARGS)
 		{
 			/* Second point of polya's edge is a current one */
 			sa.p[1] = polya->p[ia];
 
 			/* Init first of polyb's edge with last point */
 			sb.p[0] = polyb->p[polyb->npts - 1];
 
 			for (ib = 0; ib < polyb->npts && result == false; ib++)
 			{
 				sb.p[1] = polyb->p[ib];
-				result = lseg_intersect_internal(&sa, &sb);
+				result = lseg_interpt_internal(NULL, &sa, &sb);
 				sb.p[0] = sb.p[1];
 			}
 
 			/*
 			 * move current endpoint to the first point of next edge
 			 */
 			sa.p[0] = sa.p[1];
 		}
 
 		if (result == false)
 		{
-			result = (point_inside(polya->p, polyb->npts, polyb->p)
-					  ||
+			result = (point_inside(polya->p, polyb->npts, polyb->p) ||
 					  point_inside(polyb->p, polya->npts, polya->p));
 		}
 	}
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
@@ -3818,27 +3753,26 @@ poly_overlap(PG_FUNCTION_ARGS)
 
 static bool
 touched_lseg_inside_poly(Point *a, Point *b, LSEG *s, POLYGON *poly, int start)
 {
 	/* point a is on s, b is not */
 	LSEG		t;
 
 	t.p[0] = *a;
 	t.p[1] = *b;
 
-#define POINTEQ(pt1, pt2)	(FPeq((pt1)->x, (pt2)->x) && FPeq((pt1)->y, (pt2)->y))
-	if (POINTEQ(a, s->p))
+	if (point_eq_internal(a, s->p))
 	{
 		if (on_ps_internal(s->p + 1, &t))
 			return lseg_inside_poly(b, s->p + 1, poly, start);
 	}
-	else if (POINTEQ(a, s->p + 1))
+	else if (point_eq_internal(a, s->p + 1))
 	{
 		if (on_ps_internal(s->p, &t))
 			return lseg_inside_poly(b, s->p, poly, start);
 	}
 	else if (on_ps_internal(s->p, &t))
 	{
 		return lseg_inside_poly(b, s->p, poly, start);
 	}
 	else if (on_ps_internal(s->p + 1, &t))
 	{
@@ -3861,50 +3795,49 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 	int			i;
 	bool		res = true,
 				intersection = false;
 
 	t.p[0] = *a;
 	t.p[1] = *b;
 	s.p[0] = poly->p[(start == 0) ? (poly->npts - 1) : (start - 1)];
 
 	for (i = start; i < poly->npts && res; i++)
 	{
-		Point	   *interpt;
+		Point		interpt;
 
 		CHECK_FOR_INTERRUPTS();
 
 		s.p[1] = poly->p[i];
 
 		if (on_ps_internal(t.p, &s))
 		{
 			if (on_ps_internal(t.p + 1, &s))
 				return true;	/* t is contained by s */
 
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p, t.p + 1, &s, poly, i + 1);
 		}
 		else if (on_ps_internal(t.p + 1, &s))
 		{
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p + 1, t.p, &s, poly, i + 1);
 		}
-		else if ((interpt = lseg_interpt_internal(&t, &s)) != NULL)
+		else if (lseg_interpt_internal(&interpt, &t, &s))
 		{
 			/*
 			 * segments are X-crossing, go to check each subsegment
 			 */
 
 			intersection = true;
-			res = lseg_inside_poly(t.p, interpt, poly, i + 1);
+			res = lseg_inside_poly(t.p, &interpt, poly, i + 1);
 			if (res)
-				res = lseg_inside_poly(t.p + 1, interpt, poly, i + 1);
-			pfree(interpt);
+				res = lseg_inside_poly(t.p + 1, &interpt, poly, i + 1);
 		}
 
 		s.p[0] = s.p[1];
 	}
 
 	if (res && !intersection)
 	{
 		Point		p;
 
 		/*
@@ -4019,170 +3952,205 @@ poly_distance(PG_FUNCTION_ARGS)
  **
  **		Routines for 2D points.
  **
  ***********************************************************************/
 
 Datum
 construct_point(PG_FUNCTION_ARGS)
 {
 	float8		x = PG_GETARG_FLOAT8(0);
 	float8		y = PG_GETARG_FLOAT8(1);
+	Point	   *result;
 
-	PG_RETURN_POINT_P(point_construct(x, y));
+	result = (Point *) palloc(sizeof(Point));
+
+	point_construct(result, x, y);
+
+	PG_RETURN_POINT_P(result);
 }
 
 Datum
 point_add(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x + p2->x);
-	result->y = (p1->y + p2->y);
+	point_add_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+static void
+point_add_internal(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x + pt2->x,
+					pt1->y + pt2->y);
+}
+
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x - p2->x);
-	result->y = (p1->y - p2->y);
+	point_sub_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+static void
+point_sub_internal(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x - pt2->x,
+					pt1->y - pt2->y);
+}
+
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x * p2->x) - (p1->y * p2->y);
-	result->y = (p1->x * p2->y) + (p1->y * p2->x);
+	point_mul_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+static void
+point_mul_internal(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					(pt1->x * pt2->x) - (pt1->y * pt2->y),
+					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+}
+
 Datum
 point_div(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
-	double		div;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	div = (p2->x * p2->x) + (p2->y * p2->y);
-
-	if (div == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result->x = ((p1->x * p2->x) + (p1->y * p2->y)) / div;
-	result->y = ((p2->x * p1->y) - (p2->y * p1->x)) / div;
+	point_div_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+static void
+point_div_internal(Point *result, Point *pt1, Point *pt2)
+{
+	float8		div;
+
+	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
+	point_construct(result,
+					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
+					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+}
+
 
 /***********************************************************************
  **
  **		Routines for 2D boxes.
  **
  ***********************************************************************/
 
 Datum
 points_box(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct(p1->x, p2->x, p1->y, p2->y));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	box_construct(result, p1->x, p2->x, p1->y, p2->y);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_add(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct((box->high.x + p->x),
-								  (box->low.x + p->x),
-								  (box->high.y + p->y),
-								  (box->low.y + p->y)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_add_internal(&result->high, &box->high, p);
+	point_add_internal(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_sub(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct((box->high.x - p->x),
-								  (box->low.x - p->x),
-								  (box->high.y - p->y),
-								  (box->low.y - p->y)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_sub_internal(&result->high, &box->high, p);
+	point_sub_internal(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_mul(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
 
-	high = DatumGetPointP(DirectFunctionCall2(point_mul,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_mul,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	result = (BOX *) palloc(sizeof(BOX));
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	point_mul_internal(&high, &box->high, p);
+	point_mul_internal(&low, &box->low, p);
+
+	box_construct(result, high.x, low.x, high.y, low.y);
 
 	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_div(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
 
-	high = DatumGetPointP(DirectFunctionCall2(point_div,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_div,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	result = (BOX *) palloc(sizeof(BOX));
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	point_div_internal(&high, &box->high, p);
+	point_div_internal(&low, &box->low, p);
+
+	box_construct(result, high.x, low.x, high.y, low.y);
 
 	PG_RETURN_BOX_P(result);
 }
 
 /*
  * Convert point to empty box
  */
 Datum
 point_box(PG_FUNCTION_ARGS)
 {
@@ -4278,83 +4246,63 @@ path_add(PG_FUNCTION_ARGS)
  * Translation operators.
  */
 Datum
 path_add_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x += point->x;
-		path->p[i].y += point->y;
-	}
+		point_add_internal(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_sub_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x -= point->x;
-		path->p[i].y -= point->y;
-	}
+		point_sub_internal(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 /* path_mul_pt()
  * Rotation and scaling operators.
  */
 Datum
 path_mul_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_mul,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_mul_internal(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_div_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_div,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_div_internal(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 
 Datum
 path_center(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	PATH	   *path = PG_GETARG_PATH_P(0);
@@ -4436,21 +4384,22 @@ poly_center(PG_FUNCTION_ARGS)
 
 Datum
 poly_box(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	BOX		   *box;
 
 	if (poly->npts < 1)
 		PG_RETURN_NULL();
 
-	box = box_copy(&poly->boundbox);
+	box = (BOX *) palloc(sizeof(BOX));
+	*box = poly->boundbox;
 
 	PG_RETURN_BOX_P(box);
 }
 
 
 /* box_poly()
  * Convert a box to a polygon.
  */
 Datum
 box_poly(PG_FUNCTION_ARGS)
@@ -4468,22 +4417,22 @@ box_poly(PG_FUNCTION_ARGS)
 
 	poly->p[0].x = box->low.x;
 	poly->p[0].y = box->low.y;
 	poly->p[1].x = box->low.x;
 	poly->p[1].y = box->high.y;
 	poly->p[2].x = box->high.x;
 	poly->p[2].y = box->high.y;
 	poly->p[3].x = box->high.x;
 	poly->p[3].y = box->low.y;
 
-	box_fill(&poly->boundbox, box->high.x, box->low.x,
-			 box->high.y, box->low.y);
+	box_construct(&poly->boundbox, box->high.x, box->low.x,
+				  box->high.y, box->low.y);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
 
 Datum
 poly_path(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	PATH	   *path;
@@ -4492,21 +4441,21 @@ poly_path(PG_FUNCTION_ARGS)
 
 	/*
 	 * Never overflows: the old size fit in MaxAllocSize, and the new size is
 	 * smaller by a small constant.
 	 */
 	size = offsetof(PATH, p) + sizeof(path->p[0]) * poly->npts;
 	path = (PATH *) palloc(size);
 
 	SET_VARSIZE(path, size);
 	path->npts = poly->npts;
-	path->closed = TRUE;
+	path->closed = true;
 	/* prevent instability in unused pad bytes */
 	path->dummy = 0;
 
 	for (i = 0; i < poly->npts; i++)
 	{
 		path->p[i].x = poly->p[i].x;
 		path->p[i].y = poly->p[i].y;
 	}
 
 	PG_RETURN_PATH_P(path);
@@ -4558,22 +4507,21 @@ circle_in(PG_FUNCTION_ARGS)
 
 	circle->radius = single_decode(s, &s, "circle", str);
 	if (circle->radius < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
 
 	while (depth > 0)
 	{
-		if ((*s == RDELIM)
-			|| ((*s == RDELIM_C) && (depth == 1)))
+		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
 			s++;
 			while (isspace((unsigned char) *s))
 				s++;
 		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
@@ -4657,22 +4605,21 @@ circle_send(PG_FUNCTION_ARGS)
 
 /*		circles identical?
  */
 Datum
 circle_same(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPeq(circle1->radius, circle2->radius) &&
-				   FPeq(circle1->center.x, circle2->center.x) &&
-				   FPeq(circle1->center.y, circle2->center.y));
+				   point_eq_internal(&circle1->center, &circle2->center));
 }
 
 /*		circle_overlap	-		does circle1 overlap circle2?
  */
 Datum
 circle_overlap(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
@@ -4859,106 +4806,82 @@ circle_ge(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPge(circle_ar(circle1), circle_ar(circle2)));
 }
 
 
 /*----------------------------------------------------------
  *	"Arithmetic" operators on circles.
  *---------------------------------------------------------*/
 
-static CIRCLE *
-circle_copy(CIRCLE *circle)
-{
-	CIRCLE	   *result;
-
-	if (!PointerIsValid(circle))
-		return NULL;
-
-	result = (CIRCLE *) palloc(sizeof(CIRCLE));
-	memcpy((char *) result, (char *) circle, sizeof(CIRCLE));
-	return result;
-}
-
-
 /* circle_add_pt()
  * Translation operator.
  */
 Datum
 circle_add_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x += point->x;
-	result->center.y += point->y;
+	point_add_internal(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_sub_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x -= point->x;
-	result->center.y -= point->y;
+	point_sub_internal(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /* circle_mul_pt()
  * Rotation and scaling operators.
  */
 Datum
 circle_mul_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_mul,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
+	point_mul_internal(&result->center, &circle->center, point);
 	result->radius *= HYPOT(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_div_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_div,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
+	point_div_internal(&result->center, &circle->center, point);
 	result->radius /= HYPOT(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /*		circle_area		-		returns the area of the circle.
  */
 Datum
 circle_area(PG_FUNCTION_ARGS)
@@ -5372,118 +5295,55 @@ lseg_crossing(double x, double y, double prev_x, double prev_y)
 static bool
 plist_same(int npts, Point *p1, Point *p2)
 {
 	int			i,
 				ii,
 				j;
 
 	/* find match for first point */
 	for (i = 0; i < npts; i++)
 	{
-		if ((FPeq(p2[i].x, p1[0].x))
-			&& (FPeq(p2[i].y, p1[0].y)))
+		if (point_eq_internal(&p2[i], &p1[0]))
 		{
 
 			/* match found? then look forward through remaining points */
 			for (ii = 1, j = i + 1; ii < npts; ii++, j++)
 			{
 				if (j >= npts)
 					j = 0;
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_internal(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed forward match with %d\n", j, ii);
 #endif
 					break;
 				}
 			}
 #ifdef GEODEBUG
 			printf("plist_same- ii = %d/%d after forward match\n", ii, npts);
 #endif
 			if (ii == npts)
-				return TRUE;
+				return true;
 
 			/* match not found forwards? then look backwards */
 			for (ii = 1, j = i - 1; ii < npts; ii++, j--)
 			{
 				if (j < 0)
 					j = (npts - 1);
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_internal(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed reverse match with %d\n", j, ii);
 #endif
 					break;
 				}
 			}
 #ifdef GEODEBUG
 			printf("plist_same- ii = %d/%d after reverse match\n", ii, npts);
 #endif
 			if (ii == npts)
-				return TRUE;
+				return true;
 		}
 	}
 
-	return FALSE;
-}
-
-
-/*-------------------------------------------------------------------------
- * Determine the hypotenuse.
- *
- * If required, x and y are swapped to make x the larger number. The
- * traditional formula of x^2+y^2 is rearranged to factor x outside the
- * sqrt. This allows computation of the hypotenuse for significantly
- * larger values, and with a higher precision than when using the naive
- * formula.  In particular, this cannot overflow unless the final result
- * would be out-of-range.
- *
- * sqrt( x^2 + y^2 ) = sqrt( x^2( 1 + y^2/x^2) )
- *					 = x * sqrt( 1 + y^2/x^2 )
- *					 = x * sqrt( 1 + y/x * y/x )
- *
- * It is expected that this routine will eventually be replaced with the
- * C99 hypot() function.
- *
- * This implementation conforms to IEEE Std 1003.1 and GLIBC, in that the
- * case of hypot(inf,nan) results in INF, and not NAN.
- *-----------------------------------------------------------------------
- */
-double
-pg_hypot(double x, double y)
-{
-	double		yx;
-
-	/* Handle INF and NaN properly */
-	if (isinf(x) || isinf(y))
-		return get_float8_infinity();
-
-	if (isnan(x) || isnan(y))
-		return get_float8_nan();
-
-	/* Else, drop any minus signs */
-	x = fabs(x);
-	y = fabs(y);
-
-	/* Swap x and y if needed to make x the larger one */
-	if (x < y)
-	{
-		double		temp = x;
-
-		x = y;
-		y = temp;
-	}
-
-	/*
-	 * If y is zero, the hypotenuse is x.  This test saves a few cycles in
-	 * such cases, but more importantly it also protects against
-	 * divide-by-zero errors, since now x >= y.
-	 */
-	if (y == 0.0)
-		return x;
-
-	/* Determine the hypotenuse */
-	yx = y / x;
-	return x * sqrt(1.0 + (yx * yx));
+	return false;
 }
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 44c6381b85..90119a0158 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -43,21 +43,21 @@
 #else
 #define FPzero(A)				((A) == 0)
 #define FPeq(A,B)				((A) == (B))
 #define FPne(A,B)				((A) != (B))
 #define FPlt(A,B)				((A) < (B))
 #define FPle(A,B)				((A) <= (B))
 #define FPgt(A,B)				((A) > (B))
 #define FPge(A,B)				((A) >= (B))
 #endif
 
-#define HYPOT(A, B)				pg_hypot(A, B)
+#define HYPOT(A, B)				hypot(A, B)
 
 /*---------------------------------------------------------------------
  * Point - (x,y)
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	double		x,
 				y;
 } Point;
 
@@ -166,21 +166,11 @@ typedef struct
 #define PolygonPGetDatum(X)			PointerGetDatum(X)
 #define PG_GETARG_POLYGON_P(n)		DatumGetPolygonP(PG_GETARG_DATUM(n))
 #define PG_GETARG_POLYGON_P_COPY(n) DatumGetPolygonPCopy(PG_GETARG_DATUM(n))
 #define PG_RETURN_POLYGON_P(x)		return PolygonPGetDatum(x)
 
 #define DatumGetCircleP(X)	  ((CIRCLE *) DatumGetPointer(X))
 #define CirclePGetDatum(X)	  PointerGetDatum(X)
 #define PG_GETARG_CIRCLE_P(n) DatumGetCircleP(PG_GETARG_DATUM(n))
 #define PG_RETURN_CIRCLE_P(x) return CirclePGetDatum(x)
 
-
-/*
- * 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 */
+#endif   /* GEO_DECLS_H */
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index 734947cc98..6988500067 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -62,21 +62,23 @@ regress_dist_ptpath(PG_FUNCTION_ARGS)
 	float8		result = 0.0;	/* keep compiler quiet */
 	float8		tmp;
 	int			i;
 	LSEG		lseg;
 
 	switch (path->npts)
 	{
 		case 0:
 			PG_RETURN_NULL();
 		case 1:
-			result = point_dt(pt, &path->p[0]);
+			result = DatumGetFloat8(DirectFunctionCall2(point_distance,
+														PointPGetDatum(pt),
+												PointPGetDatum(&path->p[0])));
 			break;
 		default:
 
 			/*
 			 * the distance from a point to a path is the smallest distance
 			 * from the point to any of its constituent segments.
 			 */
 			Assert(path->npts > 1);
 			for (i = 0; i < path->npts - 1; ++i)
 			{
@@ -280,22 +282,27 @@ widget_out(PG_FUNCTION_ARGS)
 	PG_RETURN_CSTRING(str);
 }
 
 PG_FUNCTION_INFO_V1(pt_in_widget);
 
 Datum
 pt_in_widget(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	WIDGET	   *widget = (WIDGET *) PG_GETARG_POINTER(1);
+	float8		distance;
 
-	PG_RETURN_BOOL(point_dt(point, &widget->center) < widget->radius);
+	distance = DatumGetFloat8(DirectFunctionCall2(point_distance,
+												  PointPGetDatum(point),
+											PointPGetDatum(&widget->center)));
+
+	PG_RETURN_BOOL(distance < widget->radius);
 }
 
 PG_FUNCTION_INFO_V1(boxarea);
 
 Datum
 boxarea(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	double		width,
 				height;
-- 
2.11.0 (Apple Git-81)

0002-float-header-v05.patchapplication/octet-stream; name=0002-float-header-v05.patchDownload
From 23ee80ed7ffe812e0b979126e2b64c7cf8519c43 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 28 May 2016 18:16:05 +0200
Subject: [PATCH 2/4] float-header-v05

Provide header file for built-in float datatypes

Even though, some datatypes under adt/ have separate header files,
most of the simple ones do not.  Their public functions were on
the builtins.h.  We would need to make more functions of floats public
to let the geometric types built on top of them.  This is a good
opportunity to make a separate header file for floats.

1acf7572554515b99ef6e783750aaea8777524ec made _cmp functions public
to solve NaN problem locally for GiST indexes.  This patch reworks it
in favour of a more extensive API.  Kevin Grittner suggested to design
the API using inline functions.  They are easier to use compared
to macros, and avoid double-evaluation hazards.
---
 contrib/btree_gin/btree_gin.c                 |   3 +-
 contrib/btree_gist/btree_ts.c                 |   2 +-
 contrib/cube/cube.c                           |   2 +-
 contrib/postgres_fdw/postgres_fdw.c           |   2 +-
 src/backend/access/gist/gistget.c             |   2 +-
 src/backend/access/gist/gistproc.c            |  55 +--
 src/backend/access/gist/gistutil.c            |   2 +-
 src/backend/utils/adt/float.c                 | 593 ++++++--------------------
 src/backend/utils/adt/formatting.c            |   8 +-
 src/backend/utils/adt/geo_ops.c               |   6 +-
 src/backend/utils/adt/geo_spgist.c            |   2 +-
 src/backend/utils/adt/numeric.c               |   1 +
 src/backend/utils/adt/rangetypes_gist.c       |   3 +-
 src/backend/utils/adt/rangetypes_selfuncs.c   |   3 +-
 src/backend/utils/adt/rangetypes_typanalyze.c |   3 +-
 src/backend/utils/adt/timestamp.c             |   1 +
 src/backend/utils/misc/guc.c                  |   1 +
 src/include/utils/builtins.h                  |  14 -
 src/include/utils/float.h                     | 383 +++++++++++++++++
 src/include/utils/geo_decls.h                 |   1 +
 20 files changed, 561 insertions(+), 526 deletions(-)
 create mode 100644 src/include/utils/float.h

diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index 2473f79ca1..8d9d906c3e 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -1,22 +1,23 @@
 /*
  * contrib/btree_gin/btree_gin.c
  */
 #include "postgres.h"
 
 #include <limits.h>
 
 #include "access/stratnum.h"
-#include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/cash.h"
 #include "utils/date.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/inet.h"
 #include "utils/numeric.h"
 #include "utils/timestamp.h"
 #include "utils/varbit.h"
 
 PG_MODULE_MAGIC;
 
 typedef struct QueryInfo
 {
 	StrategyNumber strategy;
diff --git a/contrib/btree_gist/btree_ts.c b/contrib/btree_gist/btree_ts.c
index 1582cff102..cffbbd5c69 100644
--- a/contrib/btree_gist/btree_ts.c
+++ b/contrib/btree_gist/btree_ts.c
@@ -1,21 +1,21 @@
 /*
  * contrib/btree_gist/btree_ts.c
  */
 #include "postgres.h"
 
 #include <limits.h>
 
 #include "btree_gist.h"
 #include "btree_utils_num.h"
-#include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 typedef struct
 {
 	Timestamp	lower;
 	Timestamp	upper;
 } tsKEY;
 
 /*
 ** timestamp ops
 */
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c
index 149558c763..c94fc93ffd 100644
--- a/contrib/cube/cube.c
+++ b/contrib/cube/cube.c
@@ -7,21 +7,21 @@
 ******************************************************************************/
 
 #include "postgres.h"
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 
 #include "cubedata.h"
 
 PG_MODULE_MAGIC;
 
 /*
  * Taken from the intarray contrib header
  */
 #define ARRPTR(x)  ( (double *) ARR_DATA_PTR(x) )
 #define ARRNELEMS(x)  ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x))
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 32dc4e6301..b768a0dc10 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -27,21 +27,21 @@
 #include "nodes/nodeFuncs.h"
 #include "optimizer/cost.h"
 #include "optimizer/clauses.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
 #include "optimizer/planmain.h"
 #include "optimizer/restrictinfo.h"
 #include "optimizer/var.h"
 #include "optimizer/tlist.h"
 #include "parser/parsetree.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 #include "utils/sampling.h"
 #include "utils/selfuncs.h"
 
 PG_MODULE_MAGIC;
 
 /* Default CPU cost to start up a foreign query. */
diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c
index 760ea0c997..9828587add 100644
--- a/src/backend/access/gist/gistget.c
+++ b/src/backend/access/gist/gistget.c
@@ -13,21 +13,21 @@
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/gist_private.h"
 #include "access/relscan.h"
 #include "catalog/pg_type.h"
 #include "miscadmin.h"
 #include "pgstat.h"
 #include "lib/pairingheap.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 
 /*
  * gistkillitems() -- set LP_DEAD state for items an indexscan caller has
  * told us were killed.
  *
  * We re-read page here, so it's important to check page LSN. If the page
  * has been modified since the last read (as determined by LSN), we cannot
  * flag any entries because it is possible that the old entry was vacuumed
diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index 08990f5a1b..c1ea88f90d 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -27,62 +27,53 @@
 
 
 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
 						 StrategyNumber strategy);
 static bool rtree_internal_consistent(BOX *key, BOX *query,
 						  StrategyNumber strategy);
 
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
 
-/* Convenience macros for NaN-aware comparisons */
-#define FLOAT8_EQ(a,b)	(float8_cmp_internal(a, b) == 0)
-#define FLOAT8_LT(a,b)	(float8_cmp_internal(a, b) < 0)
-#define FLOAT8_LE(a,b)	(float8_cmp_internal(a, b) <= 0)
-#define FLOAT8_GT(a,b)	(float8_cmp_internal(a, b) > 0)
-#define FLOAT8_GE(a,b)	(float8_cmp_internal(a, b) >= 0)
-#define FLOAT8_MAX(a,b)  (FLOAT8_GT(a, b) ? (a) : (b))
-#define FLOAT8_MIN(a,b)  (FLOAT8_LT(a, b) ? (a) : (b))
-
 
 /**************************************************
  * Box ops
  **************************************************/
 
 /*
  * Calculates union of two boxes, a and b. The result is stored in *n.
  */
 static void
 rt_box_union(BOX *n, const BOX *a, const BOX *b)
 {
-	n->high.x = FLOAT8_MAX(a->high.x, b->high.x);
-	n->high.y = FLOAT8_MAX(a->high.y, b->high.y);
-	n->low.x = FLOAT8_MIN(a->low.x, b->low.x);
-	n->low.y = FLOAT8_MIN(a->low.y, b->low.y);
+	n->high.x = float8_max(a->high.x, b->high.x);
+	n->high.y = float8_max(a->high.y, b->high.y);
+	n->low.x = float8_min(a->low.x, b->low.x);
+	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
 static double
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
-	if (FLOAT8_LE(box->high.x, box->low.x) ||
-		FLOAT8_LE(box->high.y, box->low.y))
+	if (float8_le(box->high.x, box->low.x) ||
+		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
 	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
@@ -137,27 +128,27 @@ gist_box_consistent(PG_FUNCTION_ARGS)
 												 query,
 												 strategy));
 }
 
 /*
  * Increase BOX b to include addon.
  */
 static void
 adjustBox(BOX *b, const BOX *addon)
 {
-	if (FLOAT8_LT(b->high.x, addon->high.x))
+	if (float8_lt(b->high.x, addon->high.x))
 		b->high.x = addon->high.x;
-	if (FLOAT8_GT(b->low.x, addon->low.x))
+	if (float8_gt(b->low.x, addon->low.x))
 		b->low.x = addon->low.x;
-	if (FLOAT8_LT(b->high.y, addon->high.y))
+	if (float8_lt(b->high.y, addon->high.y))
 		b->high.y = addon->high.y;
-	if (FLOAT8_GT(b->low.y, addon->low.y))
+	if (float8_gt(b->low.y, addon->low.y))
 		b->low.y = addon->low.y;
 }
 
 /*
  * The GiST Union method for boxes
  *
  * returns the minimal bounding box that encloses all the entries in entryvec
  */
 Datum
 gist_box_union(PG_FUNCTION_ARGS)
@@ -637,36 +628,36 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		i1 = 0;
 		i2 = 0;
 		rightLower = intervalsLower[i1].lower;
 		leftUpper = intervalsUpper[i2].lower;
 		while (true)
 		{
 			/*
 			 * Find next lower bound of right group.
 			 */
 			while (i1 < nentries &&
-				   FLOAT8_EQ(rightLower, intervalsLower[i1].lower))
+				   float8_eq(rightLower, intervalsLower[i1].lower))
 			{
-				if (FLOAT8_LT(leftUpper, intervalsLower[i1].upper))
+				if (float8_lt(leftUpper, intervalsLower[i1].upper))
 					leftUpper = intervalsLower[i1].upper;
 				i1++;
 			}
 			if (i1 >= nentries)
 				break;
 			rightLower = intervalsLower[i1].lower;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * left group.
 			 */
 			while (i2 < nentries &&
-				   FLOAT8_LE(intervalsUpper[i2].upper, leftUpper))
+				   float8_le(intervalsUpper[i2].upper, leftUpper))
 				i2++;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim, rightLower, i1, leftUpper, i2);
 		}
 
 		/*
 		 * Iterate over upper bound of left group finding greatest possible
@@ -674,35 +665,35 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		 */
 		i1 = nentries - 1;
 		i2 = nentries - 1;
 		rightLower = intervalsLower[i1].upper;
 		leftUpper = intervalsUpper[i2].upper;
 		while (true)
 		{
 			/*
 			 * Find next upper bound of left group.
 			 */
-			while (i2 >= 0 && FLOAT8_EQ(leftUpper, intervalsUpper[i2].upper))
+			while (i2 >= 0 && float8_eq(leftUpper, intervalsUpper[i2].upper))
 			{
-				if (FLOAT8_GT(rightLower, intervalsUpper[i2].lower))
+				if (float8_gt(rightLower, intervalsUpper[i2].lower))
 					rightLower = intervalsUpper[i2].lower;
 				i2--;
 			}
 			if (i2 < 0)
 				break;
 			leftUpper = intervalsUpper[i2].upper;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * right group.
 			 */
-			while (i1 >= 0 && FLOAT8_GE(intervalsLower[i1].lower, rightLower))
+			while (i1 >= 0 && float8_ge(intervalsLower[i1].lower, rightLower))
 				i1--;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim,
 								 rightLower, i1 + 1, leftUpper, i2 + 1);
 		}
 	}
 
@@ -776,42 +767,42 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
 		}
 		else
 		{
 			lower = box->low.y;
 			upper = box->high.y;
 		}
 
-		if (FLOAT8_LE(upper, context.leftUpper))
+		if (float8_le(upper, context.leftUpper))
 		{
 			/* Fits to the left group */
-			if (FLOAT8_GE(lower, context.rightLower))
+			if (float8_ge(lower, context.rightLower))
 			{
 				/* Fits also to the right group, so "common entry" */
 				commonEntries[commonEntriesCount++].index = i;
 			}
 			else
 			{
 				/* Doesn't fit to the right group, so join to the left group */
 				PLACE_LEFT(box, i);
 			}
 		}
 		else
 		{
 			/*
 			 * Each entry should fit on either left or right group. Since this
 			 * entry didn't fit on the left group, it better fit in the right
 			 * group.
 			 */
-			Assert(FLOAT8_GE(lower, context.rightLower));
+			Assert(float8_ge(lower, context.rightLower));
 
 			/* Doesn't fit to the left group, so join to the right group */
 			PLACE_RIGHT(box, i);
 		}
 	}
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
@@ -881,24 +872,24 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
  * equivalent to box_same().
  */
 Datum
 gist_box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *b1 = PG_GETARG_BOX_P(0);
 	BOX		   *b2 = PG_GETARG_BOX_P(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
 	if (b1 && b2)
-		*result = (FLOAT8_EQ(b1->low.x, b2->low.x) &&
-				   FLOAT8_EQ(b1->low.y, b2->low.y) &&
-				   FLOAT8_EQ(b1->high.x, b2->high.x) &&
-				   FLOAT8_EQ(b1->high.y, b2->high.y));
+		*result = (float8_eq(b1->low.x, b2->low.x) &&
+				   float8_eq(b1->low.y, b2->low.y) &&
+				   float8_eq(b1->high.x, b2->high.x) &&
+				   float8_eq(b1->high.y, b2->high.y));
 	else
 		*result = (b1 == NULL && b2 == NULL);
 	PG_RETURN_POINTER(result);
 }
 
 /*
  * Leaf-level consistency for boxes: just apply the query operator
  */
 static bool
 gist_box_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy)
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index b6ccc1a66a..8792257c01 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -15,21 +15,21 @@
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist_private.h"
 #include "access/htup_details.h"
 #include "access/reloptions.h"
 #include "catalog/pg_opclass.h"
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/syscache.h"
 
 
 /*
  * Write itup vector to page, has no control of free space.
  */
 void
 gistfillbuffer(Page page, IndexTuple *itup, int len, OffsetNumber off)
 {
 	OffsetNumber l = InvalidOffsetNumber;
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index 18b3b949ac..7359278737 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -15,62 +15,25 @@
 #include "postgres.h"
 
 #include <ctype.h>
 #include <float.h>
 #include <math.h>
 #include <limits.h>
 
 #include "catalog/pg_type.h"
 #include "libpq/pqformat.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/sortsupport.h"
 
 
-#ifndef M_PI
-/* from my RH5.2 gcc math.h file - thomas 2000-04-03 */
-#define M_PI 3.14159265358979323846
-#endif
-
-/* Radians per degree, a.k.a. PI / 180 */
-#define RADIANS_PER_DEGREE 0.0174532925199432957692
-
-/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0.  NAN definition from
- * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfNotNumberNANItems.asp
- */
-#if defined(WIN32) && !defined(NAN)
-static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
-
-#define NAN (*(const double *) nan)
-#endif
-
-/* not sure what the following should be, but better to make it over-sufficient */
-#define MAXFLOATWIDTH	64
-#define MAXDOUBLEWIDTH	128
-
-/*
- * check to see if a float4/8 val has underflowed or overflowed
- */
-#define CHECKFLOATVAL(val, inf_is_valid, zero_is_valid)			\
-do {															\
-	if (isinf(val) && !(inf_is_valid))							\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		  errmsg("value out of range: overflow")));				\
-																\
-	if ((val) == 0.0 && !(zero_is_valid))						\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		 errmsg("value out of range: underflow")));				\
-} while(0)
-
-
 /* Configurable GUC parameter */
 int			extra_float_digits = 0; /* Added to DBL_DIG or FLT_DIG */
 
 /* Cached constants for degree-based trig functions */
 static bool degree_consts_set = false;
 static float8 sin_30 = 0;
 static float8 one_minus_cos_60 = 0;
 static float8 asin_0_5 = 0;
 static float8 acos_0_5 = 0;
 static float8 atan_1_0 = 0;
@@ -102,100 +65,20 @@ static void init_degree_constants(void);
  * their compilers spit up at the mismatch between extern declaration
  * and static definition.  We work around that here by the expedient
  * of a #define to make the actual name of the static function different.
  */
 #define cbrt my_cbrt
 static double cbrt(double x);
 #endif							/* HAVE_CBRT */
 
 
 /*
- * Routines to provide reasonably platform-independent handling of
- * infinity and NaN.  We assume that isinf() and isnan() are available
- * and work per spec.  (On some platforms, we have to supply our own;
- * see src/port.)  However, generating an Infinity or NaN in the first
- * place is less well standardized; pre-C99 systems tend not to have C99's
- * INFINITY and NAN macros.  We centralize our workarounds for this here.
- */
-
-double
-get_float8_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (double) INFINITY;
-#else
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (double) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-/*
-* The funny placements of the two #pragmas is necessary because of a
-* long lived bug in the Microsoft compilers.
-* See http://support.microsoft.com/kb/120968/en-us for details
-*/
-#if (_MSC_VER >= 1800)
-#pragma warning(disable:4756)
-#endif
-float
-get_float4_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (float) INFINITY;
-#else
-#if (_MSC_VER >= 1800)
-#pragma warning(default:4756)
-#endif
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (float) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-double
-get_float8_nan(void)
-{
-	/* (double) NAN doesn't work on some NetBSD/MIPS releases */
-#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
-	/* C99 standard way */
-	return (double) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (double) (0.0 / 0.0);
-#endif
-}
-
-float
-get_float4_nan(void)
-{
-#ifdef NAN
-	/* C99 standard way */
-	return (float) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (float) (0.0 / 0.0);
-#endif
-}
-
-
-/*
  * Returns -1 if 'val' represents negative infinity, 1 if 'val'
  * represents (positive) infinity, and 0 otherwise. On some platforms,
  * this is equivalent to the isinf() macro, but not everywhere: C99
  * does not specify that isinf() needs to distinguish between positive
  * and negative infinity.
  */
 int
 is_infinite(double val)
 {
 	int			inf = isinf(val);
@@ -339,21 +222,21 @@ float4in(PG_FUNCTION_ARGS)
 	if (*endptr != '\0')
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"real", orig_num)));
 
 	/*
 	 * if we get here, we have a legal double, still need to check to see if
 	 * it's a legal float4
 	 */
-	CHECKFLOATVAL((float4) val, isinf(val), val == 0);
+	check_float4_val((float4) val, isinf(val), val == 0);
 
 	PG_RETURN_FLOAT4((float4) val);
 }
 
 /*
  *		float4out		- converts a float4 number to a string
  *						  using a standard output format
  */
 Datum
 float4out(PG_FUNCTION_ARGS)
@@ -689,35 +572,35 @@ float4up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT4(arg);
 }
 
 Datum
 float4larger(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) > 0)
+	if (float4_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 Datum
 float4smaller(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) < 0)
+	if (float4_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 /*
  *		======================
  *		FLOAT8 BASE OPERATIONS
  *		======================
@@ -756,35 +639,35 @@ float8up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT8(arg);
 }
 
 Datum
 float8larger(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) > 0)
+	if (float8_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 Datum
 float8smaller(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) < 0)
+	if (float8_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		====================
  *		ARITHMETIC OPERATORS
@@ -795,234 +678,165 @@ float8smaller(PG_FUNCTION_ARGS)
  *		float4pl		- returns arg1 + arg2
  *		float4mi		- returns arg1 - arg2
  *		float4mul		- returns arg1 * arg2
  *		float4div		- returns arg1 / arg2
  */
 Datum
 float4pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 + arg2;
-
-	/*
-	 * There isn't any way to check for underflow of addition/subtraction
-	 * because numbers near the underflow value have already been rounded to
-	 * the point where we can't detect that the two values were originally
-	 * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
-	 * 1.4013e-45.
-	 */
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_pl(arg1, arg2));
 }
 
 Datum
 float4mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mi(arg1, arg2));
 }
 
 Datum
 float4mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mul(arg1, arg2));
 }
 
 Datum
 float4div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_div(arg1, arg2));
 }
 
 /*
  *		float8pl		- returns arg1 + arg2
  *		float8mi		- returns arg1 - arg2
  *		float8mul		- returns arg1 * arg2
  *		float8div		- returns arg1 / arg2
  */
 Datum
 float8pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 + arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, arg2));
 }
 
 Datum
 float8mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 - arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, arg2));
 }
 
 Datum
 float8mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 * arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, arg2));
 }
 
 Datum
 float8div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, arg2));
 }
 
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float4{eq,ne,lt,le,gt,ge}		- float4/float4 comparison operations
  */
 int
 float4_cmp_internal(float4 a, float4 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float4_gt(a, b))
+		return 1;
+	if (float4_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
 float4eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float4_eq(arg1, arg2));
 }
 
 Datum
 float4ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float4_ne(arg1, arg2));
 }
 
 Datum
 float4lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float4_lt(arg1, arg2));
 }
 
 Datum
 float4le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float4_le(arg1, arg2));
 }
 
 Datum
 float4gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float4_gt(arg1, arg2));
 }
 
 Datum
 float4ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float4_ge(arg1, arg2));
 }
 
 Datum
 btfloat4cmp(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
 	PG_RETURN_INT32(float4_cmp_internal(arg1, arg2));
 }
@@ -1044,99 +858,79 @@ btfloat4sortsupport(PG_FUNCTION_ARGS)
 	ssup->comparator = btfloat4fastcmp;
 	PG_RETURN_VOID();
 }
 
 /*
  *		float8{eq,ne,lt,le,gt,ge}		- float8/float8 comparison operations
  */
 int
 float8_cmp_internal(float8 a, float8 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float8_gt(a, b))
+		return 1;
+	if (float8_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
 float8eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, arg2));
 }
 
 Datum
 float8ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, arg2));
 }
 
 Datum
 float8lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, arg2));
 }
 
 Datum
 float8le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, arg2));
 }
 
 Datum
 float8gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, arg2));
 }
 
 Datum
 float8ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, arg2));
 }
 
 Datum
 btfloat8cmp(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
 	PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
 }
@@ -1199,21 +993,21 @@ ftod(PG_FUNCTION_ARGS)
 
 
 /*
  *		dtof			- converts a float8 number to a float4 number
  */
 Datum
 dtof(PG_FUNCTION_ARGS)
 {
 	float8		num = PG_GETARG_FLOAT8(0);
 
-	CHECKFLOATVAL((float4) num, isinf(num), num == 0);
+	check_float4_val((float4) num, isinf(num), num == 0);
 
 	PG_RETURN_FLOAT4((float4) num);
 }
 
 
 /*
  *		dtoi4			- converts a float8 number to an int4 number
  */
 Datum
 dtoi4(PG_FUNCTION_ARGS)
@@ -1424,36 +1218,36 @@ dsqrt(PG_FUNCTION_ARGS)
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
 				 errmsg("cannot take square root of a negative number")));
 
 	result = sqrt(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcbrt			- returns cube root of arg1
  */
 Datum
 dcbrt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	result = cbrt(arg1);
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dpow			- returns pow(arg1,arg2)
  */
 Datum
 dpow(PG_FUNCTION_ARGS)
 {
@@ -1492,40 +1286,40 @@ dpow(PG_FUNCTION_ARGS)
 			/* The sign of Inf is not significant in this case. */
 			result = get_float8_infinity();
 		else if (fabs(arg1) != 1)
 			result = 0;
 		else
 			result = 1;
 	}
 	else if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
+	check_float8_val(result, isinf(arg1) || isinf(arg2), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dexp			- returns the exponential function of arg1
  */
 Datum
 dexp(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	errno = 0;
 	result = exp(arg1);
 	if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1), false);
+	check_float8_val(result, isinf(arg1), false);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dlog1			- returns the natural logarithm of arg1
  */
 Datum
 dlog1(PG_FUNCTION_ARGS)
 {
@@ -1540,21 +1334,21 @@ dlog1(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of zero")));
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of a negative number")));
 
 	result = log(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dlog10			- returns the base 10 logarithm of arg1
  */
 Datum
 dlog10(PG_FUNCTION_ARGS)
 {
@@ -1570,21 +1364,21 @@ dlog10(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of zero")));
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of a negative number")));
 
 	result = log10(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dacos			- returns the arccos of arg1 (radians)
  */
 Datum
 dacos(PG_FUNCTION_ARGS)
 {
@@ -1600,21 +1394,21 @@ dacos(PG_FUNCTION_ARGS)
 	 * range [-1, 1] to values in the range [0, Pi], so we should reject any
 	 * inputs outside that range and the result will always be finite.
 	 */
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = acos(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dasin			- returns the arcsin of arg1 (radians)
  */
 Datum
 dasin(PG_FUNCTION_ARGS)
 {
@@ -1630,21 +1424,21 @@ dasin(PG_FUNCTION_ARGS)
 	 * range [-1, 1] to values in the range [-Pi/2, Pi/2], so we should reject
 	 * any inputs outside that range and the result will always be finite.
 	 */
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = asin(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		datan			- returns the arctan of arg1 (radians)
  */
 Datum
 datan(PG_FUNCTION_ARGS)
 {
@@ -1655,21 +1449,21 @@ datan(PG_FUNCTION_ARGS)
 	if (isnan(arg1))
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/*
 	 * The principal branch of the inverse tangent function maps all inputs to
 	 * values in the range [-Pi/2, Pi/2], so the result should always be
 	 * finite, even if the input is infinite.
 	 */
 	result = atan(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		atan2			- returns the arctan of arg1/arg2 (radians)
  */
 Datum
 datan2(PG_FUNCTION_ARGS)
 {
@@ -1680,21 +1474,21 @@ datan2(PG_FUNCTION_ARGS)
 	/* Per the POSIX spec, return NaN if either input is NaN */
 	if (isnan(arg1) || isnan(arg2))
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/*
 	 * atan2 maps all inputs to values in the range [-Pi, Pi], so the result
 	 * should always be finite, even if the inputs are infinite.
 	 */
 	result = atan2(arg1, arg2);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcos			- returns the cosine of arg1 (radians)
  */
 Datum
 dcos(PG_FUNCTION_ARGS)
 {
@@ -1720,21 +1514,21 @@ dcos(PG_FUNCTION_ARGS)
 	 * platform reports via errno, so also explicitly test for infinite
 	 * inputs.
 	 */
 	errno = 0;
 	result = cos(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcot			- returns the cotangent of arg1 (radians)
  */
 Datum
 dcot(PG_FUNCTION_ARGS)
 {
@@ -1747,21 +1541,21 @@ dcot(PG_FUNCTION_ARGS)
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = tan(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = 1.0 / result;
-	CHECKFLOATVAL(result, true /* cot(0) == Inf */ , true);
+	check_float8_val(result, true /* cot(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dsin			- returns the sine of arg1 (radians)
  */
 Datum
 dsin(PG_FUNCTION_ARGS)
 {
@@ -1773,21 +1567,21 @@ dsin(PG_FUNCTION_ARGS)
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = sin(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dtan			- returns the tangent of arg1 (radians)
  */
 Datum
 dtan(PG_FUNCTION_ARGS)
 {
@@ -1799,21 +1593,21 @@ dtan(PG_FUNCTION_ARGS)
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = tan(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, true /* tan(pi/2) == Inf */ , true);
+	check_float8_val(result, true /* tan(pi/2) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /* ========== DEGREE-BASED TRIGONOMETRIC FUNCTIONS ========== */
 
 
 /*
  * Initialize the cached constants declared at the head of this file
  * (sin_30 etc).  The fact that we need those at all, let alone need this
@@ -1951,21 +1745,21 @@ dacosd(PG_FUNCTION_ARGS)
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	if (arg1 >= 0.0)
 		result = acosd_q1(arg1);
 	else
 		result = 90.0 + asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dasind			- returns the arcsin of arg1 (degrees)
  */
 Datum
 dasind(PG_FUNCTION_ARGS)
 {
@@ -1986,21 +1780,21 @@ dasind(PG_FUNCTION_ARGS)
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	if (arg1 >= 0.0)
 		result = asind_q1(arg1);
 	else
 		result = -asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		datand			- returns the arctan of arg1 (degrees)
  */
 Datum
 datand(PG_FUNCTION_ARGS)
 {
@@ -2016,21 +1810,21 @@ datand(PG_FUNCTION_ARGS)
 
 	/*
 	 * The principal branch of the inverse tangent function maps all inputs to
 	 * values in the range [-90, 90], so the result should always be finite,
 	 * even if the input is infinite.  Additionally, we take care to ensure
 	 * than when arg1 is 1, the result is exactly 45.
 	 */
 	atan_arg1 = atan(arg1);
 	result = (atan_arg1 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		atan2d			- returns the arctan of arg1/arg2 (degrees)
  */
 Datum
 datan2d(PG_FUNCTION_ARGS)
 {
@@ -2050,21 +1844,21 @@ datan2d(PG_FUNCTION_ARGS)
 	 * result should always be finite, even if the inputs are infinite.
 	 *
 	 * Note: this coding assumes that atan(1.0) is a suitable scaling constant
 	 * to get an exact result from atan2().  This might well fail on us at
 	 * some point, requiring us to decide exactly what inputs we think we're
 	 * going to guarantee an exact result for.
 	 */
 	atan2_arg1_arg2 = atan2(arg1, arg2);
 	result = (atan2_arg1_arg2 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		sind_0_to_30	- returns the sine of an angle that lies between 0 and
  *						  30 degrees.  This will return exactly 0 when x is 0,
  *						  and exactly 0.5 when x is 30 degrees.
  */
 static double
@@ -2171,21 +1965,21 @@ dcosd(PG_FUNCTION_ARGS)
 
 	if (arg1 > 90.0)
 	{
 		/* cosd(180-x) = -cosd(x) */
 		arg1 = 180.0 - arg1;
 		sign = -sign;
 	}
 
 	result = sign * cosd_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcotd			- returns the cotangent of arg1 (degrees)
  */
 Datum
 dcotd(PG_FUNCTION_ARGS)
 {
@@ -2236,21 +2030,21 @@ dcotd(PG_FUNCTION_ARGS)
 	result = sign * (cot_arg1 / cot_45);
 
 	/*
 	 * On some machines we get cotd(270) = minus zero, but this isn't always
 	 * true.  For portability, and because the user constituency for this
 	 * function probably doesn't want minus zero, force it to plain zero.
 	 */
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* cotd(0) == Inf */ , true);
+	check_float8_val(result, true /* cotd(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dsind			- returns the sine of arg1 (degrees)
  */
 Datum
 dsind(PG_FUNCTION_ARGS)
 {
@@ -2290,21 +2084,21 @@ dsind(PG_FUNCTION_ARGS)
 	}
 
 	if (arg1 > 90.0)
 	{
 		/* sind(180-x) = sind(x) */
 		arg1 = 180.0 - arg1;
 	}
 
 	result = sign * sind_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dtand			- returns the tangent of arg1 (degrees)
  */
 Datum
 dtand(PG_FUNCTION_ARGS)
 {
@@ -2355,64 +2149,56 @@ dtand(PG_FUNCTION_ARGS)
 	result = sign * (tan_arg1 / tan_45);
 
 	/*
 	 * On some machines we get tand(180) = minus zero, but this isn't always
 	 * true.  For portability, and because the user constituency for this
 	 * function probably doesn't want minus zero, force it to plain zero.
 	 */
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* tand(90) == Inf */ , true);
+	check_float8_val(result, true /* tand(90) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		degrees		- returns degrees converted from radians
  */
 Datum
 degrees(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
 
-	result = arg1 / RADIANS_PER_DEGREE;
-
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, RADIANS_PER_DEGREE));
 }
 
 
 /*
  *		dpi				- returns the constant PI
  */
 Datum
 dpi(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_FLOAT8(M_PI);
 }
 
 
 /*
  *		radians		- returns radians converted from degrees
  */
 Datum
 radians(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
 
-	result = arg1 * RADIANS_PER_DEGREE;
-
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, RADIANS_PER_DEGREE));
 }
 
 
 /*
  *		drandom		- returns a random number
  */
 Datum
 drandom(PG_FUNCTION_ARGS)
 {
 	float8		result;
@@ -2490,144 +2276,105 @@ check_float8_array(ArrayType *transarray, const char *caller, int n)
  * This function is used only in two stage aggregation and
  * shouldn't be called outside aggregate context.
  */
 Datum
 float8_combine(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_combine", 3);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-
 	transvalues2 = check_float8_array(transarray2, "float8_combine", 3);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
 
 Datum
 float8_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8		newval = PG_GETARG_FLOAT8(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float8_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
 	else
 	{
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
 								 sizeof(float8), FLOAT8PASSBYVAL, 'd');
 
 		PG_RETURN_ARRAYTYPE_P(result);
 	}
 }
 
 Datum
 float4_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 
 	/* do computations as float8 */
 	float8		newval = PG_GETARG_FLOAT4(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float4_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
 	else
 	{
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
 								 sizeof(float8), FLOAT8PASSBYVAL, 'd');
 
 		PG_RETURN_ARRAYTYPE_P(result);
 	}
 }
 
 Datum
@@ -2663,21 +2410,21 @@ float8_var_pop(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_var_pop", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Population variance is undefined when N is 0, so return NULL */
 	if (N == 0.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / (N * N));
 }
 
 Datum
 float8_var_samp(PG_FUNCTION_ARGS)
@@ -2692,21 +2439,21 @@ float8_var_samp(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_var_samp", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Sample variance is undefined when N is 0 or 1, so return NULL */
 	if (N <= 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
 }
 
 Datum
 float8_stddev_pop(PG_FUNCTION_ARGS)
@@ -2721,21 +2468,21 @@ float8_stddev_pop(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_stddev_pop", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Population stddev is undefined when N is 0, so return NULL */
 	if (N == 0.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(sqrt(numerator / (N * N)));
 }
 
 Datum
 float8_stddev_samp(PG_FUNCTION_ARGS)
@@ -2750,21 +2497,21 @@ float8_stddev_samp(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_stddev_samp", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Sample stddev is undefined when N is 0 or 1, so return NULL */
 	if (N <= 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(sqrt(numerator / (N * (N - 1.0))));
 }
 
 /*
  *		=========================
@@ -2799,30 +2546,30 @@ float8_regr_accum(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_accum", 6);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	N += 1.0;
 	sumX += newvalX;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
+	check_float8_val(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
 	sumX2 += newvalX * newvalX;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
+	check_float8_val(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
 	sumY += newvalY;
-	CHECKFLOATVAL(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
+	check_float8_val(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
 	sumY2 += newvalY * newvalY;
-	CHECKFLOATVAL(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
+	check_float8_val(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
 	sumXY += newvalX * newvalY;
-	CHECKFLOATVAL(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
-				  isinf(newvalY), true);
+	check_float8_val(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
+					 isinf(newvalY), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
 		transvalues[0] = N;
 		transvalues[1] = sumX;
@@ -2861,63 +2608,33 @@ float8_regr_accum(PG_FUNCTION_ARGS)
  * This function is used only in two stage aggregation and
  * shouldn't be called outside aggregate context.
  */
 Datum
 float8_regr_combine(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2,
-				sumY,
-				sumY2,
-				sumXY;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_regr_combine", 6);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-	sumY = transvalues1[3];
-	sumY2 = transvalues1[4];
-	sumXY = transvalues1[5];
-
 	transvalues2 = check_float8_array(transarray2, "float8_regr_combine", 6);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-	sumY += transvalues2[3];
-	CHECKFLOATVAL(sumY, isinf(transvalues1[3]) || isinf(transvalues2[3]),
-				  true);
-	sumY2 += transvalues2[4];
-	CHECKFLOATVAL(sumY2, isinf(transvalues1[4]) || isinf(transvalues2[4]),
-				  true);
-	sumXY += transvalues2[5];
-	CHECKFLOATVAL(sumXY, isinf(transvalues1[5]) || isinf(transvalues2[5]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
-	transvalues1[3] = sumY;
-	transvalues1[4] = sumY2;
-	transvalues1[5] = sumXY;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
+	transvalues1[3] = float8_pl(transvalues1[3], transvalues2[3]);
+	transvalues1[4] = float8_pl(transvalues1[4], transvalues2[4]);
+	transvalues1[5] = float8_pl(transvalues1[5], transvalues2[5]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
 
 
 Datum
 float8_regr_sxx(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
@@ -2929,21 +2646,21 @@ float8_regr_sxx(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_sxx", 6);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_syy(PG_FUNCTION_ARGS)
@@ -2958,21 +2675,21 @@ float8_regr_syy(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_syy", 6);
 	N = transvalues[0];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumY2) || isinf(sumY), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_sxy(PG_FUNCTION_ARGS)
@@ -2989,22 +2706,22 @@ float8_regr_sxy(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	/* A negative result is valid here */
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_avgx(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3057,22 +2774,22 @@ float8_covar_pop(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * N));
 }
 
 Datum
 float8_covar_samp(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
 	float8		N,
@@ -3085,22 +2802,22 @@ float8_covar_samp(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is <= 1 we should return NULL */
 	if (N < 2.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
 }
 
 Datum
 float8_corr(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
 	float8		N,
@@ -3119,26 +2836,26 @@ float8_corr(PG_FUNCTION_ARGS)
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0 || numeratorY <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXY / sqrt(numeratorX * numeratorY));
 }
 
 Datum
 float8_regr_r2(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3159,26 +2876,26 @@ float8_regr_r2(PG_FUNCTION_ARGS)
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 	/* per spec, horizontal line produces 1.0 */
 	if (numeratorY <= 0)
 		PG_RETURN_FLOAT8(1.0);
 
 	PG_RETURN_FLOAT8((numeratorXY * numeratorXY) /
 					 (numeratorX * numeratorY));
 }
 
@@ -3200,24 +2917,24 @@ float8_regr_slope(PG_FUNCTION_ARGS)
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXY / numeratorX);
 }
 
 Datum
 float8_regr_intercept(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3235,24 +2952,24 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXXY = sumY * sumX2 - sumX * sumXY;
-	CHECKFLOATVAL(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
-				  isinf(sumX) || isinf(sumXY), true);
+	check_float8_val(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
+					 isinf(sumX) || isinf(sumXY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXXY / numeratorX);
 }
 
 
 /*
  *		====================================
  *		MIXED-PRECISION ARITHMETIC OPERATORS
@@ -3263,251 +2980,211 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
  *		float48pl		- returns arg1 + arg2
  *		float48mi		- returns arg1 - arg2
  *		float48mul		- returns arg1 * arg2
  *		float48div		- returns arg1 / arg2
  */
 Datum
 float48pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 + arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl((float8) arg1, arg2));
 }
 
 Datum
 float48mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi((float8) arg1, arg2));
 }
 
 Datum
 float48mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul((float8) arg1, arg2));
 }
 
 Datum
 float48div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div((float8) arg1, arg2));
 }
 
 /*
  *		float84pl		- returns arg1 + arg2
  *		float84mi		- returns arg1 - arg2
  *		float84mul		- returns arg1 * arg2
  *		float84div		- returns arg1 / arg2
  */
 Datum
 float84pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 + arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, (float8) arg2));
 }
 
 Datum
 float84mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 - arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, (float8) arg2));
 }
 
 Datum
 float84mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 * arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, (float8) arg2));
 }
 
 Datum
 float84div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, (float8) arg2));
 }
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float48{eq,ne,lt,le,gt,ge}		- float4/float8 comparison operations
  */
 Datum
 float48eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq((float8) arg1, arg2));
 }
 
 Datum
 float48ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne((float8) arg1, arg2));
 }
 
 Datum
 float48lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt((float8) arg1, arg2));
 }
 
 Datum
 float48le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le((float8) arg1, arg2));
 }
 
 Datum
 float48gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt((float8) arg1, arg2));
 }
 
 Datum
 float48ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge((float8) arg1, arg2));
 }
 
 /*
  *		float84{eq,ne,lt,le,gt,ge}		- float8/float4 comparison operations
  */
 Datum
 float84eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, (float8) arg2));
 }
 
 Datum
 float84ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, (float8) arg2));
 }
 
 Datum
 float84lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, (float8) arg2));
 }
 
 Datum
 float84le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, (float8) arg2));
 }
 
 Datum
 float84gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, (float8) arg2));
 }
 
 Datum
 float84ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, (float8) arg2));
 }
 
 /*
  * Implements the float8 version of the width_bucket() function
  * defined by SQL2003. See also width_bucket_numeric().
  *
  * 'bound1' and 'bound2' are the lower and upper bounds of the
  * histogram's range, respectively. 'count' is the number of buckets
  * in the histogram. width_bucket() returns an integer indicating the
  * bucket number that 'operand' belongs to in an equiwidth histogram
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c
index 46f45f6654..a10007196e 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -84,20 +84,21 @@
 
 #ifdef USE_ICU
 #include <unicode/ustring.h>
 #endif
 
 #include "catalog/pg_collation.h"
 #include "mb/pg_wchar.h"
 #include "utils/builtins.h"
 #include "utils/date.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 #include "utils/formatting.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/pg_locale.h"
 
 /* ----------
  * Routines type
  * ----------
  */
 #define DCH_TYPE		1		/* DATE-TIME version	*/
@@ -110,27 +111,20 @@
 #define KeyWord_INDEX_SIZE		('~' - ' ')
 #define KeyWord_INDEX_FILTER(_c)	((_c) <= ' ' || (_c) >= '~' ? 0 : 1)
 
 /* ----------
  * Maximal length of one node
  * ----------
  */
 #define DCH_MAX_ITEM_SIZ	   12	/* max localized day name		*/
 #define NUM_MAX_ITEM_SIZ		8	/* roman number (RN has 15 chars)	*/
 
-/* ----------
- * More is in float.c
- * ----------
- */
-#define MAXFLOATWIDTH	60
-#define MAXDOUBLEWIDTH	500
-
 
 /* ----------
  * Format parser structs
  * ----------
  */
 typedef struct
 {
 	char	   *name;			/* suffix string		*/
 	int			len,			/* suffix length		*/
 				id,				/* used in node->suffix */
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index c43d02ac14..865698738e 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -14,27 +14,23 @@
  */
 #include "postgres.h"
 
 #include <math.h>
 #include <limits.h>
 #include <float.h>
 #include <ctype.h>
 
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
-#include "utils/builtins.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index f6334bae14..c800bb1338 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -69,21 +69,21 @@
  *			src/backend/utils/adt/geo_spgist.c
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
 
 #include "access/spgist.h"
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
  * is going only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index bc01f3c284..482631f34d 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -28,20 +28,21 @@
 
 #include "access/hash.h"
 #include "catalog/pg_type.h"
 #include "funcapi.h"
 #include "lib/hyperloglog.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/sortsupport.h"
 
 /* ----------
  * Uncomment the following to enable compilation of dump_numeric()
  * and dump_var() and to get a dump of any result produced by make_result().
  * ----------
 #define NUMERIC_DEBUG
diff --git a/src/backend/utils/adt/rangetypes_gist.c b/src/backend/utils/adt/rangetypes_gist.c
index a1f4f4d372..f416a1f654 100644
--- a/src/backend/utils/adt/rangetypes_gist.c
+++ b/src/backend/utils/adt/rangetypes_gist.c
@@ -9,21 +9,22 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_gist.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/gist.h"
 #include "access/stratnum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/datum.h"
 #include "utils/rangetypes.h"
 
 
 /*
  * Range class properties used to segregate different classes of ranges in
  * GiST.  Each unique combination of properties is a class.  CLS_EMPTY cannot
  * be combined with anything else.
  */
 #define CLS_NORMAL			0	/* Ordinary finite range (no bits set) */
diff --git a/src/backend/utils/adt/rangetypes_selfuncs.c b/src/backend/utils/adt/rangetypes_selfuncs.c
index ed13c27fcb..756c553627 100644
--- a/src/backend/utils/adt/rangetypes_selfuncs.c
+++ b/src/backend/utils/adt/rangetypes_selfuncs.c
@@ -14,21 +14,22 @@
  *	  src/backend/utils/adt/rangetypes_selfuncs.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/htup_details.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 #include "utils/selfuncs.h"
 #include "utils/typcache.h"
 
 static double calc_rangesel(TypeCacheEntry *typcache, VariableStatData *vardata,
 			  RangeType *constval, Oid operator);
 static double default_range_selectivity(Oid operator);
 static double calc_hist_selectivity(TypeCacheEntry *typcache,
 					  VariableStatData *vardata, RangeType *constval,
diff --git a/src/backend/utils/adt/rangetypes_typanalyze.c b/src/backend/utils/adt/rangetypes_typanalyze.c
index 324bbe48e5..58bcd3c035 100644
--- a/src/backend/utils/adt/rangetypes_typanalyze.c
+++ b/src/backend/utils/adt/rangetypes_typanalyze.c
@@ -19,21 +19,22 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_typanalyze.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "catalog/pg_operator.h"
 #include "commands/vacuum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 
 static int	float8_qsort_cmp(const void *a1, const void *a2);
 static int	range_bound_qsort_cmp(const void *a1, const void *a2, void *arg);
 static void compute_range_stats(VacAttrStats *stats,
 					AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows);
 
 /*
  * range_typanalyze -- typanalyze function for range columns
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index b11d452fc8..3df4010b97 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -27,20 +27,21 @@
 #include "common/int128.h"
 #include "funcapi.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
 #include "parser/scansup.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 /*
  * gcc's -ffast-math switch breaks routines that expect exact results from
  * expressions like timeval / SECS_PER_HOUR, where timeval is double.
  */
 #ifdef __FAST_MATH__
 #error -ffast-math is known to break this code
 #endif
 
 #define SAMESIGN(a,b)	(((a) < 0) == ((b) < 0))
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 246fea8693..c22669772a 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -72,20 +72,21 @@
 #include "storage/standby.h"
 #include "storage/fd.h"
 #include "storage/pg_shmem.h"
 #include "storage/proc.h"
 #include "storage/predicate.h"
 #include "tcop/tcopprot.h"
 #include "tsearch/ts_cache.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/guc_tables.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/pg_locale.h"
 #include "utils/plancache.h"
 #include "utils/portal.h"
 #include "utils/ps_status.h"
 #include "utils/rls.h"
 #include "utils/snapmgr.h"
 #include "utils/tzparser.h"
 #include "utils/varlena.h"
 #include "utils/xml.h"
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 762532f636..668e037737 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -43,34 +43,20 @@ extern int	namestrcmp(Name name, const char *str);
 
 /* numutils.c */
 extern int32 pg_atoi(const char *s, int size, int c);
 extern void pg_itoa(int16 i, char *a);
 extern void pg_ltoa(int32 l, char *a);
 extern void pg_lltoa(int64 ll, char *a);
 extern char *pg_ltostr_zeropad(char *str, int32 value, int32 minwidth);
 extern char *pg_ltostr(char *str, int32 value);
 extern uint64 pg_strtouint64(const char *str, char **endptr, int base);
 
-/* float.c */
-extern PGDLLIMPORT int extra_float_digits;
-
-extern double get_float8_infinity(void);
-extern float get_float4_infinity(void);
-extern double get_float8_nan(void);
-extern float get_float4_nan(void);
-extern int	is_infinite(double val);
-extern double float8in_internal(char *num, char **endptr_p,
-				  const char *type_name, const char *orig_string);
-extern char *float8out_internal(double num);
-extern int	float4_cmp_internal(float4 a, float4 b);
-extern int	float8_cmp_internal(float8 a, float8 b);
-
 /* oid.c */
 extern oidvector *buildoidvector(const Oid *oids, int n);
 extern Oid	oidparse(Node *node);
 extern int	oid_cmp(const void *p1, const void *p2);
 
 /* regexp.c */
 extern char *regexp_fixed_prefix(text *text_re, bool case_insensitive,
 					Oid collation, bool *exact);
 
 /* ruleutils.c */
diff --git a/src/include/utils/float.h b/src/include/utils/float.h
new file mode 100644
index 0000000000..c26de1cca4
--- /dev/null
+++ b/src/include/utils/float.h
@@ -0,0 +1,383 @@
+/*-------------------------------------------------------------------------
+ *
+ * float.h
+ *	  Definitions for the built-in floating-point types
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/include/utils/float.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef FLOAT_H
+#define FLOAT_H
+
+#include <math.h>
+
+#ifndef M_PI
+/* From my RH5.2 gcc math.h file - thomas 2000-04-03 */
+#define M_PI 3.14159265358979323846
+#endif
+
+/* Radians per degree, a.k.a. PI / 180 */
+#define RADIANS_PER_DEGREE 0.0174532925199432957692
+
+/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0.  NAN definition from
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfNotNumberNANItems.asp
+ */
+#if defined(WIN32) && !defined(NAN)
+static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
+
+#define NAN (*(const float8 *) nan)
+#endif
+
+/*
+ * We are not sure what the following should be, but better to make it
+ * over-sufficient.
+ */
+#define MAXFLOATWIDTH	64
+#define MAXDOUBLEWIDTH	128
+
+extern PGDLLIMPORT int extra_float_digits;
+
+/*
+ * Utility functions in float.c
+ */
+extern int	is_infinite(float8 val);
+extern float8 float8in_internal(char *num, char **endptr_p,
+				  const char *type_name, const char *orig_string);
+extern char *float8out_internal(float8 num);
+extern int	float4_cmp_internal(float4 a, float4 b);
+extern int	float8_cmp_internal(float8 a, float8 b);
+
+/*
+ * Routines to provide reasonably platform-independent handling of
+ * infinity and NaN
+ *
+ * We assume that isinf() and isnan() are available and work per spec.
+ * (On some platforms, we have to supply our own; see src/port.)  However,
+ * generating an Infinity or NaN in the first place is less well standardized;
+ * pre-C99 systems tend not to have C99's INFINITY and NAN macros.  We
+ * centralize our workarounds for this here.
+ */
+
+/*
+* The funny placements of the two #pragmas is necessary because of a
+* long lived bug in the Microsoft compilers.
+* See http://support.microsoft.com/kb/120968/en-us for details
+*/
+#if (_MSC_VER >= 1800)
+#pragma warning(disable:4756)
+#endif
+static inline float
+get_float4_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float) INFINITY;
+#else
+#if (_MSC_VER >= 1800)
+#pragma warning(default:4756)
+#endif
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float8
+get_float8_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float8) INFINITY;
+#else
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float8) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float4
+get_float4_nan(void)
+{
+#ifdef NAN
+	/* C99 standard way */
+	return (float) NAN;
+#else
+	/* Assume we can get a NAN via zero divide */
+	return (float) (0.0 / 0.0);
+#endif
+}
+
+static inline float8
+get_float8_nan(void)
+{
+	/* (float8) NAN doesn't work on some NetBSD/MIPS releases */
+#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
+	/* C99 standard way */
+	return (float8) NAN;
+#else
+	/* Assume we can get a NAN via zero divide */
+	return (float8) (0.0 / 0.0);
+#endif
+}
+
+/*
+ * Checks to see if a float4/8 val has underflowed or overflowed
+ */
+
+static inline void
+check_float4_val(float4 val, bool inf_is_valid, bool zero_is_valid)
+{
+	if (isinf(val) && !(inf_is_valid))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if ((val) == 0.0 && !(zero_is_valid))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+static inline void
+check_float8_val(float8 val, bool inf_is_valid, bool zero_is_valid)
+{
+	if (isinf(val) && !(inf_is_valid))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if ((val) == 0.0 && !(zero_is_valid))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+/*
+ * Routines for operations with the checks above
+ *
+ * There isn't any way to check for underflow of addition/subtraction
+ * because numbers near the underflow value have already been rounded to
+ * the point where we can't detect that the two values were originally
+ * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
+ * 1.4013e-45.
+ */
+
+static inline float4
+float4_pl(float4 val1, float4 val2)
+{
+	float4		result;
+
+	result = val1 + val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_pl(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = val1 + val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mi(float4 val1, float4 val2)
+{
+	float4		result;
+
+	result = val1 - val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_mi(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = val1 - val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mul(float4 val1, float4 val2)
+{
+	float4		result;
+
+	result = val1 * val2;
+	check_float4_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0f || val2 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_mul(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = val1 * val2;
+	check_float8_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0 || val2 == 0.0);
+
+	return result;
+}
+
+static inline float4
+float4_div(float4 val1, float4 val2)
+{
+	float4		result;
+
+	if (val2 == 0.0f)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), val1 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_div(float8 val1, float8 val2)
+{
+	float8		result;
+
+	if (val2 == 0.0)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
+
+	return result;
+}
+
+/*
+ * Routines for NaN-aware comparisons
+ *
+ * We consider all NANs to be equal and larger than any non-NAN. This is
+ * somewhat arbitrary; the important thing is to have a consistent sort
+ * order.
+ */
+
+static inline bool
+float4_eq(float4 val1, float4 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float8_eq(float8 val1, float8 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float4_ne(float4 val1, float4 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float8_ne(float8 val1, float8 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float4_lt(float4 val1, float4 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float8_lt(float8 val1, float8 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float4_le(float4 val1, float4 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float8_le(float8 val1, float8 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float4_gt(float4 val1, float4 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float8_gt(float8 val1, float8 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float4_ge(float4 val1, float4 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline bool
+float8_ge(float8 val1, float8 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline float4
+float4_min(float4 val1, float4 val2)
+{
+	return float4_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_min(float8 val1, float8 val2)
+{
+	return float8_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float4
+float4_max(float4 val1, float4 val2)
+{
+	return float4_gt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_max(float8 val1, float8 val2)
+{
+	return float8_gt(val1, val2) ? val1 : val2;
+}
+
+#endif   /* FLOAT_H */
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 90119a0158..f845dffcb7 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -17,20 +17,21 @@
  *		and data types. There are still some more to do. - tgl 97/04/19
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEO_DECLS_H
 #define GEO_DECLS_H
 
 #include <math.h>
 
 #include "fmgr.h"
+#include "utils/float.h"
 
 /*--------------------------------------------------------------------
  * Useful floating point utilities and constants.
  *-------------------------------------------------------------------*/
 
 
 #define EPSILON					1.0E-06
 
 #ifdef EPSILON
 #define FPzero(A)				(fabs(A) <= EPSILON)
-- 
2.11.0 (Apple Git-81)

0003-geo-float-v2.patchapplication/octet-stream; name=0003-geo-float-v2.patchDownload
From e4a1939dc75fb607245643fb928db508746f7bc2 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 27 May 2017 16:17:42 -0400
Subject: [PATCH 3/4] geo-float-v2

Use the built-in float datatype to implement geometric types

This will provide:

* Check for underflow and overflow
* Check for division by zero
* Handle NaNs consistently

The patch also replaces all occurrences of "double" as "float8".  They
are the same, but were randomly spread on the same file.
---
 src/backend/access/gist/gistproc.c | 156 +++++------
 src/backend/utils/adt/geo_ops.c    | 546 +++++++++++++++++++------------------
 src/backend/utils/adt/geo_spgist.c |  36 +--
 src/include/utils/float.h          |  13 +
 src/include/utils/geo_decls.h      |  40 ++-
 5 files changed, 412 insertions(+), 379 deletions(-)

diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index c1ea88f90d..3dbd4aaa36 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -16,20 +16,21 @@
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/geo_decls.h"
 
 
 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
 						 StrategyNumber strategy);
 static bool rtree_internal_consistent(BOX *key, BOX *query,
 						  StrategyNumber strategy);
 
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
@@ -48,55 +49,56 @@ rt_box_union(BOX *n, const BOX *a, const BOX *b)
 	n->high.x = float8_max(a->high.x, b->high.x);
 	n->high.y = float8_max(a->high.y, b->high.y);
 	n->low.x = float8_min(a->low.x, b->low.x);
 	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
 	if (float8_le(box->high.x, box->low.x) ||
 		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
-	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
+	return float8_mul(float8_mi(box->high.x, box->low.x),
+					  float8_mi(box->high.y, box->low.y));
 }
 
 /*
  * Return amount by which the union of the two boxes is larger than
  * the original BOX's area.  The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 box_penalty(const BOX *original, const BOX *new)
 {
 	BOX			unionbox;
 
 	rt_box_union(&unionbox, original, new);
-	return size_box(&unionbox) - size_box(original);
+	return float8_mi(size_box(&unionbox), size_box(original));
 }
 
 /*
  * The GiST Consistent method for boxes
  *
  * Should return false if for all data items x below entry,
  * the predicate x op query must be FALSE, where op is the oper
  * corresponding to strategy in the pg_amop table.
  */
 Datum
@@ -284,74 +286,74 @@ fallbackSplit(GistEntryVector *entryvec, GIST_SPLITVEC *v)
 
 /*
  * Represents information about an entry that can be placed to either group
  * without affecting overlap over selected axis ("common entry").
  */
 typedef struct
 {
 	/* Index of entry in the initial array */
 	int			index;
 	/* Delta between penalties of entry insertion into different groups */
-	double		delta;
+	float8		delta;
 } CommonEntry;
 
 /*
  * Context for g_box_consider_split. Contains information about currently
  * selected split and some general information.
  */
 typedef struct
 {
 	int			entriesCount;	/* total number of entries being split */
 	BOX			boundingBox;	/* minimum bounding box across all entries */
 
 	/* Information about currently selected split follows */
 
 	bool		first;			/* true if no split was selected yet */
 
-	double		leftUpper;		/* upper bound of left interval */
-	double		rightLower;		/* lower bound of right interval */
+	float8		leftUpper;		/* upper bound of left interval */
+	float8		rightLower;		/* lower bound of right interval */
 
 	float4		ratio;
 	float4		overlap;
 	int			dim;			/* axis of this split */
-	double		range;			/* width of general MBR projection to the
+	float8		range;			/* width of general MBR projection to the
 								 * selected axis */
 } ConsiderSplitContext;
 
 /*
  * Interval represents projection of box to axis.
  */
 typedef struct
 {
-	double		lower,
+	float8		lower,
 				upper;
 } SplitInterval;
 
 /*
  * Interval comparison function by lower bound of the interval;
  */
 static int
 interval_cmp_lower(const void *i1, const void *i2)
 {
-	double		lower1 = ((const SplitInterval *) i1)->lower,
+	float8		lower1 = ((const SplitInterval *) i1)->lower,
 				lower2 = ((const SplitInterval *) i2)->lower;
 
 	return float8_cmp_internal(lower1, lower2);
 }
 
 /*
  * Interval comparison function by upper bound of the interval;
  */
 static int
 interval_cmp_upper(const void *i1, const void *i2)
 {
-	double		upper1 = ((const SplitInterval *) i1)->upper,
+	float8		upper1 = ((const SplitInterval *) i1)->upper,
 				upper2 = ((const SplitInterval *) i2)->upper;
 
 	return float8_cmp_internal(upper1, upper2);
 }
 
 /*
  * Replace negative (or NaN) value with zero.
  */
 static inline float
 non_negative(float val)
@@ -360,28 +362,28 @@ non_negative(float val)
 		return val;
 	else
 		return 0.0f;
 }
 
 /*
  * Consider replacement of currently selected split with the better one.
  */
 static inline void
 g_box_consider_split(ConsiderSplitContext *context, int dimNum,
-					 double rightLower, int minLeftCount,
-					 double leftUpper, int maxLeftCount)
+					 float8 rightLower, int minLeftCount,
+					 float8 leftUpper, int maxLeftCount)
 {
 	int			leftCount,
 				rightCount;
 	float4		ratio,
 				overlap;
-	double		range;
+	float8		range;
 
 	/*
 	 * Calculate entries distribution ratio assuming most uniform distribution
 	 * of common entries.
 	 */
 	if (minLeftCount >= (context->entriesCount + 1) / 2)
 	{
 		leftCount = minLeftCount;
 	}
 	else
@@ -390,52 +392,54 @@ g_box_consider_split(ConsiderSplitContext *context, int dimNum,
 			leftCount = maxLeftCount;
 		else
 			leftCount = context->entriesCount / 2;
 	}
 	rightCount = context->entriesCount - leftCount;
 
 	/*
 	 * Ratio of split - quotient between size of lesser group and total
 	 * entries count.
 	 */
-	ratio = ((float4) Min(leftCount, rightCount)) /
-		((float4) context->entriesCount);
+	ratio = float4_div(Min(leftCount, rightCount), context->entriesCount);
 
-	if (ratio > LIMIT_RATIO)
+	if (float4_gt(ratio, LIMIT_RATIO))
 	{
 		bool		selectthis = false;
 
 		/*
 		 * The ratio is acceptable, so compare current split with previously
 		 * selected one. Between splits of one dimension we search for minimal
 		 * overlap (allowing negative values) and minimal ration (between same
 		 * overlaps. We switch dimension if find less overlap (non-negative)
 		 * or less range with same overlap.
 		 */
 		if (dimNum == 0)
-			range = context->boundingBox.high.x - context->boundingBox.low.x;
+			range = float8_mi(context->boundingBox.high.x,
+							  context->boundingBox.low.x);
 		else
-			range = context->boundingBox.high.y - context->boundingBox.low.y;
+			range = float8_mi(context->boundingBox.high.y,
+							  context->boundingBox.low.y);
 
-		overlap = (leftUpper - rightLower) / range;
+		overlap = float8_div(float8_mi(leftUpper, rightLower), range);
 
 		/* If there is no previous selection, select this */
 		if (context->first)
 			selectthis = true;
 		else if (context->dim == dimNum)
 		{
 			/*
 			 * Within the same dimension, choose the new split if it has a
 			 * smaller overlap, or same overlap but better ratio.
 			 */
-			if (overlap < context->overlap ||
-				(overlap == context->overlap && ratio > context->ratio))
+			if (float4_lt(overlap, context->overlap) ||
+				(float4_eq(overlap, context->overlap) &&
+				 float4_gt(ratio, context->ratio)))
 				selectthis = true;
 		}
 		else
 		{
 			/*
 			 * Across dimensions, choose the new split if it has a smaller
 			 * *non-negative* overlap, or same *non-negative* overlap but
 			 * bigger range. This condition differs from the one described in
 			 * the article. On the datasets where leaf MBRs don't overlap
 			 * themselves, non-overlapping splits (i.e. splits which have zero
@@ -444,55 +448,49 @@ g_box_consider_split(ConsiderSplitContext *context, int dimNum,
 			 * non-overlapping splits (i.e. having lowest negative overlap)
 			 * appears to be in the same dimension as in the previous split.
 			 * Therefore MBRs appear to be very prolonged along another
 			 * dimension, which leads to bad search performance. Using range
 			 * as the second split criteria makes MBRs more quadratic. Using
 			 * *non-negative* overlap instead of overlap as the first split
 			 * criteria gives to range criteria a chance to matter, because
 			 * non-overlapping splits are equivalent in this criteria.
 			 */
 			if (non_negative(overlap) < non_negative(context->overlap) ||
-				(range > context->range &&
+				(float4_gt(range, context->range) &&
 				 non_negative(overlap) <= non_negative(context->overlap)))
 				selectthis = true;
 		}
 
 		if (selectthis)
 		{
 			/* save information about selected split */
 			context->first = false;
 			context->ratio = ratio;
 			context->range = range;
 			context->overlap = overlap;
 			context->rightLower = rightLower;
 			context->leftUpper = leftUpper;
 			context->dim = dimNum;
 		}
 	}
 }
 
 /*
  * Compare common entries by their deltas.
- * (We assume the deltas can't be NaN.)
  */
 static int
 common_entry_cmp(const void *i1, const void *i2)
 {
-	double		delta1 = ((const CommonEntry *) i1)->delta,
+	float8		delta1 = ((const CommonEntry *) i1)->delta,
 				delta2 = ((const CommonEntry *) i2)->delta;
 
-	if (delta1 < delta2)
-		return -1;
-	else if (delta1 > delta2)
-		return 1;
-	else
-		return 0;
+	return float8_cmp_internal(delta1, delta2);
 }
 
 /*
  * --------------------------------------------------------------------------
  * Double sorting split algorithm. This is used for both boxes and points.
  *
  * The algorithm finds split of boxes by considering splits along each axis.
  * Each entry is first projected as an interval on the X-axis, and different
  * ways to split the intervals into two groups are considered, trying to
  * minimize the overlap of the groups. Then the same is repeated for the
@@ -552,21 +550,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		else
 			adjustBox(&context.boundingBox, box);
 	}
 
 	/*
 	 * Iterate over axes for optimal split searching.
 	 */
 	context.first = true;		/* nothing selected yet */
 	for (dim = 0; dim < 2; dim++)
 	{
-		double		leftUpper,
+		float8		leftUpper,
 					rightLower;
 		int			i1,
 					i2;
 
 		/* Project each entry as an interval on the selected axis. */
 		for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 		{
 			box = DatumGetBoxP(entryvec->vector[i].key);
 			if (dim == 0)
 			{
@@ -749,21 +747,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 			*rightBox = *(box);					\
 		v->spl_right[v->spl_nright++] = off;	\
 	} while(0)
 
 	/*
 	 * Distribute entries which can be distributed unambiguously, and collect
 	 * common entries.
 	 */
 	for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 	{
-		double		lower,
+		float8		lower,
 					upper;
 
 		/*
 		 * Get upper and lower bounds along selected axis.
 		 */
 		box = DatumGetBoxP(entryvec->vector[i].key);
 		if (context.dim == 0)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
@@ -804,31 +802,31 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
 	{
 		/*
 		 * Calculate minimum number of entries that must be placed in both
 		 * groups, to reach LIMIT_RATIO.
 		 */
-		int			m = ceil(LIMIT_RATIO * (double) nentries);
+		int			m = ceil(LIMIT_RATIO * (float8) nentries);
 
 		/*
 		 * Calculate delta between penalties of join "common entries" to
 		 * different groups.
 		 */
 		for (i = 0; i < commonEntriesCount; i++)
 		{
 			box = DatumGetBoxP(entryvec->vector[commonEntries[i].index].key);
-			commonEntries[i].delta = Abs(box_penalty(leftBox, box) -
-										 box_penalty(rightBox, box));
+			commonEntries[i].delta = Abs(float8_mi(box_penalty(leftBox, box),
+												   box_penalty(rightBox, box)));
 		}
 
 		/*
 		 * Sort "common entries" by calculated deltas in order to distribute
 		 * the most ambiguous entries first.
 		 */
 		qsort(commonEntries, commonEntriesCount, sizeof(CommonEntry), common_entry_cmp);
 
 		/*
 		 * Distribute "common entries" between groups.
@@ -1128,24 +1126,24 @@ gist_circle_compress(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	GISTENTRY  *retval;
 
 	if (entry->leafkey)
 	{
 		CIRCLE	   *in = DatumGetCircleP(entry->key);
 		BOX		   *r;
 
 		r = (BOX *) palloc(sizeof(BOX));
-		r->high.x = in->center.x + in->radius;
-		r->low.x = in->center.x - in->radius;
-		r->high.y = in->center.y + in->radius;
-		r->low.y = in->center.y - in->radius;
+		r->high.x = float8_pl(in->center.x, in->radius);
+		r->low.x = float8_mi(in->center.x, in->radius);
+		r->high.y = float8_pl(in->center.y, in->radius);
+		r->low.y = float8_mi(in->center.y, in->radius);
 
 		retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
 		gistentryinit(*retval, PointerGetDatum(r),
 					  entry->rel, entry->page,
 					  entry->offset, FALSE);
 	}
 	else
 		retval = entry;
 	PG_RETURN_POINTER(retval);
 }
@@ -1169,24 +1167,24 @@ gist_circle_consistent(PG_FUNCTION_ARGS)
 	*recheck = true;
 
 	if (DatumGetBoxP(entry->key) == NULL || query == NULL)
 		PG_RETURN_BOOL(FALSE);
 
 	/*
 	 * Since the operators require recheck anyway, we can just use
 	 * rtree_internal_consistent even at leaf nodes.  (This works in part
 	 * because the index entries are bounding boxes not circles.)
 	 */
-	bbox.high.x = query->center.x + query->radius;
-	bbox.low.x = query->center.x - query->radius;
-	bbox.high.y = query->center.y + query->radius;
-	bbox.low.y = query->center.y - query->radius;
+	bbox.high.x = float8_pl(query->center.x, query->radius);
+	bbox.low.x = float8_mi(query->center.x, query->radius);
+	bbox.high.y = float8_pl(query->center.y, query->radius);
+	bbox.low.y = float8_mi(query->center.y, query->radius);
 
 	result = rtree_internal_consistent(DatumGetBoxP(entry->key),
 									   &bbox, strategy);
 
 	PG_RETURN_BOOL(result);
 }
 
 /**************************************************
  * Point ops
  **************************************************/
@@ -1237,80 +1235,84 @@ gist_point_fetch(PG_FUNCTION_ARGS)
 				  entry->offset, FALSE);
 
 	PG_RETURN_POINTER(retval);
 }
 
 
 #define point_point_distance(p1,p2) \
 	DatumGetFloat8(DirectFunctionCall2(point_distance, \
 									   PointPGetDatum(p1), PointPGetDatum(p2)))
 
-static double
+static float8
 computeDistance(bool isLeaf, BOX *box, Point *point)
 {
-	double		result = 0.0;
+	float8		result = 0.0;
 
 	if (isLeaf)
 	{
 		/* simple point to point distance */
 		result = point_point_distance(point, &box->low);
 	}
-	else if (point->x <= box->high.x && point->x >= box->low.x &&
-			 point->y <= box->high.y && point->y >= box->low.y)
+	else if (float8_le(point->x, box->high.x) &&
+			 float8_ge(point->x, box->low.x) &&
+			 float8_le(point->y, box->high.y) &&
+			 float8_ge(point->y, box->low.y))
 	{
 		/* point inside the box */
 		result = 0.0;
 	}
-	else if (point->x <= box->high.x && point->x >= box->low.x)
+	else if (float8_le(point->x, box->high.x) &&
+			 float8_ge(point->x, box->low.x))
 	{
 		/* point is over or below box */
-		Assert(box->low.y <= box->high.y);
-		if (point->y > box->high.y)
-			result = point->y - box->high.y;
-		else if (point->y < box->low.y)
-			result = box->low.y - point->y;
+		Assert(float8_le(box->low.y, box->high.y));
+		if (float8_gt(point->y, box->high.y))
+			result = float8_mi(point->y, box->high.y);
+		else if (float8_lt(point->y, box->low.y))
+			result = float8_mi(box->low.y, point->y);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
-	else if (point->y <= box->high.y && point->y >= box->low.y)
+	else if (float8_le(point->y, box->high.y) &&
+			 float8_ge(point->y, box->low.y))
 	{
 		/* point is to left or right of box */
-		Assert(box->low.x <= box->high.x);
-		if (point->x > box->high.x)
-			result = point->x - box->high.x;
-		else if (point->x < box->low.x)
-			result = box->low.x - point->x;
+		Assert(float8_lt(box->low.x, box->high.x));
+		if (float8_gt(point->x, box->high.x))
+			result = float8_mi(point->x, box->high.x);
+		else if (float8_lt(point->x, box->low.x))
+			result = float8_mi(box->low.x, point->x);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
 	else
 	{
 		/* closest point will be a vertex */
 		Point		p;
-		double		subresult;
+		float8		subresult;
 
 		result = point_point_distance(point, &box->low);
 
 		subresult = point_point_distance(point, &box->high);
-		if (result > subresult)
+		if (float8_gt(result, subresult))
 			result = subresult;
 
 		p.x = box->low.x;
 		p.y = box->high.y;
 		subresult = point_point_distance(point, &p);
-		if (result > subresult)
+		if (float8_gt(result, subresult))
 			result = subresult;
 
 		p.x = box->high.x;
 		p.y = box->low.y;
 		subresult = point_point_distance(point, &p);
-		if (result > subresult)
+		if (float8_gt(result, subresult))
 			result = subresult;
 	}
 
 	return result;
 }
 
 static bool
 gist_point_consistent_internal(StrategyNumber strategy,
 							   bool isLeaf, BOX *key, Point *query)
 {
@@ -1391,24 +1393,24 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 				 * Instead we write a non-fuzzy overlap test.  The same code
 				 * will also serve for leaf-page tests, since leaf keys have
 				 * high == low.
 				 */
 				BOX		   *query,
 						   *key;
 
 				query = PG_GETARG_BOX_P(1);
 				key = DatumGetBoxP(entry->key);
 
-				result = (key->high.x >= query->low.x &&
-						  key->low.x <= query->high.x &&
-						  key->high.y >= query->low.y &&
-						  key->low.y <= query->high.y);
+				result = (float8_ge(key->high.x, query->low.x) &&
+						  float8_le(key->low.x, query->high.x) &&
+						  float8_ge(key->high.y, query->low.y) &&
+						  float8_le(key->low.y, query->high.y));
 				*recheck = false;
 			}
 			break;
 		case PolygonStrategyNumberGroup:
 			{
 				POLYGON    *query = PG_GETARG_POLYGON_P(1);
 
 				result = DatumGetBool(DirectFunctionCall5(
 														  gist_poly_consistent,
 														  PointerGetDatum(entry),
@@ -1417,22 +1419,22 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 														  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);
+					Assert(float8_eq(box->high.x, box->low.x) &&
+						   float8_eq(box->high.y, box->low.y));
 					result = DatumGetBool(DirectFunctionCall2(
 															  poly_contain_pt,
 															  PolygonPGetDatum(query),
 															  PointPGetDatum(&box->high)));
 					*recheck = false;
 				}
 			}
 			break;
 		case CircleStrategyNumberGroup:
 			{
@@ -1446,22 +1448,22 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 														  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);
+					Assert(float8_eq(box->high.x, box->low.x) &&
+						   float8_eq(box->high.y, box->low.y));
 					result = DatumGetBool(DirectFunctionCall2(
 															  circle_contain_pt,
 															  CirclePGetDatum(query),
 															  PointPGetDatum(&box->high)));
 					*recheck = false;
 				}
 			}
 			break;
 		default:
 			elog(ERROR, "unrecognized strategy number: %d", strategy);
@@ -1470,21 +1472,21 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 	}
 
 	PG_RETURN_BOOL(result);
 }
 
 Datum
 gist_point_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(GIST_LEAF(entry),
 									   DatumGetBoxP(entry->key),
 									   PG_GETARG_POINT_P(1));
 			break;
 		default:
@@ -1499,25 +1501,25 @@ gist_point_distance(PG_FUNCTION_ARGS)
 /*
  * The inexact GiST distance method for geometric types that store bounding
  * boxes.
  *
  * Compute lossy distance from point to index entries.  The result is inexact
  * because index entries are bounding boxes, not the exact shapes of the
  * indexed geometric types.  We use distance from point to MBR of index entry.
  * This is a lower bound estimate of distance from point to indexed geometric
  * type.
  */
-static double
+static float8
 gist_bbox_distance(GISTENTRY *entry, Datum query,
 				   StrategyNumber strategy, bool *recheck)
 {
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	/* Bounding box distance is always inexact. */
 	*recheck = true;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(false,
 									   DatumGetBoxP(entry->key),
@@ -1533,32 +1535,32 @@ gist_bbox_distance(GISTENTRY *entry, Datum query,
 
 Datum
 gist_circle_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
 
 Datum
 gist_poly_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 865698738e..dbff7abf64 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -41,55 +41,55 @@ static void point_sub_internal(Point *result, Point *pt1, Point *pt2);
 static void point_mul_internal(Point *result, Point *pt1, Point *pt2);
 static void point_div_internal(Point *result, Point *pt1, Point *pt2);
 static bool point_eq_internal(Point *pt1, Point *pt2);
 static float8 point_dt(Point *pt1, Point *pt2);
 static float8 point_sl(Point *pt1, Point *pt2);
 static int	point_inside(Point *p, int npts, Point *plist);
 /* Methods on box */
 static void box_construct(BOX *result, float8 x1, float8 x2, float8 y1, float8 y2);
 static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
-static double box_ar(BOX *box);
-static double box_ht(BOX *box);
-static double box_wd(BOX *box);
+static float8 box_ar(BOX *box);
+static float8 box_ht(BOX *box);
+static float8 box_wd(BOX *box);
 /* Methods on circle */
-static double circle_ar(CIRCLE *circle);
+static float8 circle_ar(CIRCLE *circle);
 /* Methods on line */
 static void line_construct_pm(LINE *result, Point *pt, float8 m);
 static void line_construct_pts(LINE *line, Point *pt1, Point *pt2);
 static bool line_interpt_internal(Point *result, LINE *l1, LINE *l2);
 static float8 line_calculate_point(LINE *line, Point *pt);
 /* Methods on line segment */
 static bool lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line);
 static bool lseg_interpt_internal(Point *result, LSEG *l1, LSEG *l2);
 static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
 static float8 lseg_dt(LSEG *l1, LSEG *l2);
-static int	lseg_crossing(double x, double y, double px, double py);
+static int	lseg_crossing(float8 x, float8 y, float8 px, float8 py);
 /* Others */
 static bool on_ps_internal(Point *pt, LSEG *lseg);
 static void make_bound_box(POLYGON *poly);
 static bool plist_same(int npts, Point *p1, Point *p2);
-static double single_decode(char *num, char **endptr_p,
+static float8 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
-static void pair_decode(char *str, double *x, double *y, char **endptr_p,
+static void pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
 static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
 static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
-static double dist_pl_internal(Point *pt, LINE *line);
-static double dist_ps_internal(Point *pt, LSEG *lseg);
-static double dist_ppoly_internal(Point *pt, POLYGON *poly);
+static float8 dist_pl_internal(Point *pt, LINE *line);
+static float8 dist_ps_internal(Point *pt, LSEG *lseg);
+static float8 dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 
 /*
  * Delimiters for input and output strings.
  * LDELIM, RDELIM, and DELIM are left, right, and separator delimiters, respectively.
  * LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints.
  */
 
 #define LDELIM			'('
 #define RDELIM			')'
@@ -118,38 +118,38 @@ static double dist_ppoly_internal(Point *pt, POLYGON *poly);
  *
  * For boxes, the points are opposite corners with the first point at the top right.
  * For closed paths and polygons, the points should be reordered to allow
  *	fast and correct equality comparisons.
  *
  * XXX perhaps points in complex shapes should be reordered internally
  *	to allow faster internal operations, but should keep track of input order
  *	and restore that order for text output - tgl 97/01/16
  */
 
-static double
+static float8
 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string)
 {
 	return float8in_internal(num, endptr_p, type_name, orig_string);
 }								/* single_decode() */
 
 static void
 single_encode(float8 x, StringInfo str)
 {
 	char	   *xstr = float8out_internal(x);
 
 	appendStringInfoString(str, xstr);
 	pfree(xstr);
 }								/* single_encode() */
 
 static void
-pair_decode(char *str, double *x, double *y, char **endptr_p,
+pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string)
 {
 	bool		has_delim;
 
 	while (isspace((unsigned char) *str))
 		str++;
 	if ((has_delim = (*str == LDELIM)))
 		str++;
 
 	*x = float8in_internal(str, &str, type_name, orig_string);
@@ -351,33 +351,33 @@ pair_count(char *s, char delim)
  *		External format: (two corners of box)
  *				"(f8, f8), (f8, f8)"
  *				also supports the older style "(f8, f8, f8, f8)"
  */
 Datum
 box_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	BOX		   *box = (BOX *) palloc(sizeof(BOX));
 	bool		isopen;
-	double		x,
+	float8		x,
 				y;
 
 	path_decode(str, false, 2, &(box->high), &isopen, NULL, "box", str);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*		box_out -		convert a box to external form.
@@ -391,38 +391,38 @@ box_out(PG_FUNCTION_ARGS)
 }
 
 /*
  *		box_recv			- converts external binary format to box
  */
 Datum
 box_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	BOX		   *box;
-	double		x,
+	float8		x,
 				y;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
 	box->high.x = pq_getmsgfloat8(buf);
 	box->high.y = pq_getmsgfloat8(buf);
 	box->low.x = pq_getmsgfloat8(buf);
 	box->low.y = pq_getmsgfloat8(buf);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*
@@ -441,31 +441,31 @@ box_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, box->low.y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*		box_construct	-		fill in a new box.
  */
 static void
 box_construct(BOX *result, float8 x1, float8 x2, float8 y1, float8 y2)
 {
-	if (x1 > x2)
+	if (float8_gt(x1, x2))
 	{
 		result->high.x = x1;
 		result->low.x = x2;
 	}
 	else
 	{
 		result->high.x = x2;
 		result->low.x = x1;
 	}
-	if (y1 > y2)
+	if (float8_gt(y1, y2))
 	{
 		result->high.y = y1;
 		result->low.y = y2;
 	}
 	else
 	{
 		result->high.y = y2;
 		result->low.y = y1;
 	}
 }
@@ -777,54 +777,54 @@ box_center(PG_FUNCTION_ARGS)
 	Point	   *result = (Point *) palloc(sizeof(Point));
 
 	box_cn(result, box);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		box_ar	-		returns the area of the box.
  */
-static double
+static float8
 box_ar(BOX *box)
 {
-	return box_wd(box) * box_ht(box);
+	return float8_mul(box_wd(box), box_ht(box));
 }
 
 
 /*		box_cn	-		stores the centerpoint of the box into *center.
  */
 static void
 box_cn(Point *center, BOX *box)
 {
-	center->x = (box->high.x + box->low.x) / 2.0;
-	center->y = (box->high.y + box->low.y) / 2.0;
+	center->x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	center->y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 }
 
 
 /*		box_wd	-		returns the width (length) of the box
  *								  (horizontal magnitude).
  */
-static double
+static float8
 box_wd(BOX *box)
 {
-	return box->high.x - box->low.x;
+	return float8_mi(box->high.x, box->low.x);
 }
 
 
 /*		box_ht	-		returns the height of the box
  *								  (vertical magnitude).
  */
-static double
+static float8
 box_ht(BOX *box)
 {
-	return box->high.y - box->low.y;
+	return float8_mi(box->high.y, box->low.y);
 }
 
 
 /*----------------------------------------------------------
  *	Funky operations.
  *---------------------------------------------------------*/
 
 /*		box_intersect	-
  *				returns the overlapping portion of two boxes,
  *				  or NULL if they do not intersect.
@@ -834,24 +834,24 @@ box_intersect(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 	BOX		   *result;
 
 	if (!box_ov(box1, box2))
 		PG_RETURN_NULL();
 
 	result = (BOX *) palloc(sizeof(BOX));
 
-	result->high.x = Min(box1->high.x, box2->high.x);
-	result->low.x = Max(box1->low.x, box2->low.x);
-	result->high.y = Min(box1->high.y, box2->high.y);
-	result->low.y = Max(box1->low.y, box2->low.y);
+	result->high.x = float8_min(box1->high.x, box2->high.x);
+	result->low.x = float8_max(box1->low.x, box2->low.x);
+	result->high.y = float8_min(box1->high.y, box2->high.y);
+	result->low.y = float8_max(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(result);
 }
 
 
 /*		box_diagonal	-
  *				returns a line segment which happens to be the
  *				  positive-slope diagonal of "box".
  */
 Datum
@@ -982,65 +982,65 @@ line_send(PG_FUNCTION_ARGS)
 
 /* line_construct_pm()
  * point-slope
  */
 static void
 line_construct_pm(LINE *result, Point *pt, float8 m)
 {
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
-		result->A = -1;
-		result->B = 0;
+		result->A = -1.0;
+		result->B = 0.0;
 		result->C = pt->x;
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
-		result->C = pt->y - m * pt->x;
+		result->C = float8_mi(pt->y, float8_mul(m, pt->x));
 	}
 }
 
 /*
  * Fill already-allocated LINE struct from two points on the line
  */
 static void
 line_construct_pts(LINE *line, Point *pt1, Point *pt2)
 {
 	if (FPeq(pt1->x, pt2->x))
 	{							/* vertical */
 		/* use "x = C" */
-		line->A = -1;
-		line->B = 0;
+		line->A = -1.0;
+		line->B = 0.0;
 		line->C = pt1->x;
 #ifdef GEODEBUG
 		printf("line_construct_pts- line is vertical\n");
 #endif
 	}
 	else if (FPeq(pt1->y, pt2->y))
 	{							/* horizontal */
 		/* use "y = C" */
-		line->A = 0;
-		line->B = -1;
+		line->A = 0.0;
+		line->B = -1.0;
 		line->C = pt1->y;
 #ifdef GEODEBUG
 		printf("line_construct_pts- line is horizontal\n");
 #endif
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		line->A = point_sl(pt2, pt1);
 		line->B = -1.0;
-		line->C = pt1->y - line->A * pt1->x;
+		line->C = float8_mi(pt1->y, float8_mul(line->A, pt1->x));
 		/* on some platforms, the preceding expression tends to produce -0 */
 		if (line->C == 0.0)
 			line->C = 0.0;
 #ifdef GEODEBUG
 		printf("line_construct_pts- line is neither vertical nor horizontal (diffs x=%.*g, y=%.*g\n",
 			   DBL_DIG, (pt2->x - pt1->x), DBL_DIG, (pt2->y - pt1->y));
 #endif
 	}
 }
 
@@ -1060,21 +1060,22 @@ line_construct_pp(PG_FUNCTION_ARGS)
 
 /*
  * Calculate the line equation for a point
  *
  * This returns the result of the line equation Ax + By + C.  The result
  * needs to be 0 for the point to be on the line.
  */
 static float8
 line_calculate_point(LINE *line, Point *pt)
 {
-	return line->A * pt->x + line->B * pt->y + line->C;
+	return float8_pl(float8_pl(float8_mul(line->A, pt->x),
+							   float8_mul(line->B, pt->y)), line->C);
 }
 
 
 /*----------------------------------------------------------
  *	Relative position routines.
  *---------------------------------------------------------*/
 
 Datum
 line_intersect(PG_FUNCTION_ARGS)
 {
@@ -1097,21 +1098,22 @@ Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
 	else if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
 
-	PG_RETURN_BOOL(FPeq(((l1->A * l2->B) / (l1->B * l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
+								   float8_mul(l1->B, l2->A)), -1.0));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
@@ -1121,34 +1123,34 @@ line_horizontal(PG_FUNCTION_ARGS)
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->A));
 }
 
 Datum
 line_eq(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	double		k;
+	float8		ratio;
 
 	if (!FPzero(l2->A))
-		k = l1->A / l2->A;
+		ratio = float8_div(l1->A, l2->A);
 	else if (!FPzero(l2->B))
-		k = l1->B / l2->B;
+		ratio = float8_div(l1->B, l2->B);
 	else if (!FPzero(l2->C))
-		k = l1->C / l2->C;
+		ratio = float8_div(l1->C, l2->C);
 	else
-		k = 1.0;
+		ratio = 1.0;
 
-	PG_RETURN_BOOL(FPeq(l1->A, k * l2->A) &&
-				   FPeq(l1->B, k * l2->B) &&
-				   FPeq(l1->C, k * l2->C));
+	PG_RETURN_BOOL(FPeq(l1->A, float8_mul(ratio, l2->A)) &&
+				   FPeq(l1->B, float8_mul(ratio, l2->B)) &&
+				   FPeq(l1->C, float8_mul(ratio, l2->C)));
 }
 
 
 /*----------------------------------------------------------
  *	Line arithmetic routines.
  *---------------------------------------------------------*/
 
 /* line_distance()
  * Distance between two lines.
  */
@@ -1156,21 +1158,21 @@ Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
 	Point		tmp;
 
 	if (line_interpt_internal(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
+		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
 	point_construct(&tmp, 0.0, l1->C);
 	result = dist_pl_internal(&tmp, l2);
 	PG_RETURN_FLOAT8(result);
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
@@ -1193,41 +1195,41 @@ line_interpt(PG_FUNCTION_ARGS)
  * parallel), false if they do not.  This also sets the intersection point
  * to *result, if it is not NULL.
  *
  * NOTE: If the lines are identical then we will find they are parallel
  * and report "no intersection".  This is a little weird, but since
  * there's no *unique* intersection, maybe it's appropriate behavior.
  */
 static bool
 line_interpt_internal(Point *result, LINE *l1, LINE *l2)
 {
-	double		x,
+	float8		x,
 				y;
 
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
 		if (FPzero(l2->B))		/* l2 vertical? */
 			return false;
 
 		x = l1->C;
-		y = (l2->A * x + l2->C);
+		y = float8_pl(float8_mul(l2->A, x), l2->C);
 	}
 	else
 	{
-		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
 			return false;
 
 		if (FPzero(l2->B))
 			x = l2->C;
 		else
-			x = (l1->C - l2->C) / (l2->A - l1->A);
-		y = (l1->A * x + l1->C);
+			x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
+		y = float8_pl(float8_mul(l1->A, x), l1->C);
 	}
 	if (result != NULL)
 		point_construct(result, x, y);
 
 #ifdef GEODEBUG
 	printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
 		   DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
 	printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
 #endif
 
@@ -1254,36 +1256,35 @@ line_interpt_internal(Point *result, LINE *l1, LINE *l2)
  *				"(xcoord, ycoord),... "
  *				"[xcoord, ycoord,... ]"
  *		Also support older format:
  *				"(closed, npts, xcoord, ycoord,... )"
  *---------------------------------------------------------*/
 
 Datum
 path_area(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P(0);
-	double		area = 0.0;
+	float8		area = 0.0;
 	int			i,
 				j;
 
 	if (!path->closed)
 		PG_RETURN_NULL();
 
 	for (i = 0; i < path->npts; i++)
 	{
 		j = (i + 1) % path->npts;
-		area += path->p[i].x * path->p[j].y;
-		area -= path->p[i].y * path->p[j].x;
+		area = float8_pl(area, float8_mul(path->p[i].x, path->p[j].y));
+		area = float8_mi(area, float8_mul(path->p[i].y, path->p[j].x));
 	}
 
-	area *= 0.5;
-	PG_RETURN_FLOAT8(area < 0.0 ? -area : area);
+	PG_RETURN_FLOAT8(float8_div(fabs(area), 2.0));
 }
 
 
 Datum
 path_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	PATH	   *path;
 	bool		isopen;
 	char	   *s;
@@ -1500,31 +1501,31 @@ path_npoints(PG_FUNCTION_ARGS)
 
 	PG_RETURN_INT32(path->npts);
 }
 
 
 Datum
 path_close(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 
-	path->closed = TRUE;
+	path->closed = true;
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_open(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 
-	path->closed = FALSE;
+	path->closed = false;
 
 	PG_RETURN_PATH_P(path);
 }
 
 
 /* path_inter -
  *		Does p1 intersect p2 at any point?
  *		Use bounding boxes for a quick (O(n)) check, then do a
  *		O(n^2) iterative edge check.
  */
@@ -1540,33 +1541,33 @@ path_inter(PG_FUNCTION_ARGS)
 	LSEG		seg1,
 				seg2;
 
 	if (p1->npts <= 0 || p2->npts <= 0)
 		PG_RETURN_BOOL(false);
 
 	b1.high.x = b1.low.x = p1->p[0].x;
 	b1.high.y = b1.low.y = p1->p[0].y;
 	for (i = 1; i < p1->npts; i++)
 	{
-		b1.high.x = Max(p1->p[i].x, b1.high.x);
-		b1.high.y = Max(p1->p[i].y, b1.high.y);
-		b1.low.x = Min(p1->p[i].x, b1.low.x);
-		b1.low.y = Min(p1->p[i].y, b1.low.y);
+		b1.high.x = float8_max(p1->p[i].x, b1.high.x);
+		b1.high.y = float8_max(p1->p[i].y, b1.high.y);
+		b1.low.x = float8_min(p1->p[i].x, b1.low.x);
+		b1.low.y = float8_min(p1->p[i].y, b1.low.y);
 	}
 	b2.high.x = b2.low.x = p2->p[0].x;
 	b2.high.y = b2.low.y = p2->p[0].y;
 	for (i = 1; i < p2->npts; i++)
 	{
-		b2.high.x = Max(p2->p[i].x, b2.high.x);
-		b2.high.y = Max(p2->p[i].y, b2.high.y);
-		b2.low.x = Min(p2->p[i].x, b2.low.x);
-		b2.low.y = Min(p2->p[i].y, b2.low.y);
+		b2.high.x = float8_max(p2->p[i].x, b2.high.x);
+		b2.high.y = float8_max(p2->p[i].y, b2.high.y);
+		b2.low.x = float8_min(p2->p[i].x, b2.low.x);
+		b2.low.y = float8_min(p2->p[i].y, b2.low.y);
 	}
 	if (!box_ov(&b1, &b2))
 		PG_RETURN_BOOL(false);
 
 	/* pairwise check lseg intersections */
 	for (i = 0; i < p1->npts; i++)
 	{
 		int			iprev;
 
 		if (i > 0)
@@ -1642,21 +1643,21 @@ path_distance(PG_FUNCTION_ARGS)
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
 			tmp = lseg_dt(&seg1, &seg2);
-			if (!have_min || tmp < min)
+			if (!have_min || float8_lt(tmp, min))
 			{
 				min = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	if (!have_min)
 		PG_RETURN_NULL();
 
@@ -1681,21 +1682,21 @@ path_length(PG_FUNCTION_ARGS)
 
 		if (i > 0)
 			iprev = i - 1;
 		else
 		{
 			if (!path->closed)
 				continue;
 			iprev = path->npts - 1; /* include the closure segment */
 		}
 
-		result += point_dt(&path->p[iprev], &path->p[i]);
+		result = float8_pl(result, point_dt(&path->p[iprev], &path->p[i]));
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /***********************************************************************
  **
  **		Routines for 2D points.
  **
  ***********************************************************************/
@@ -1867,43 +1868,48 @@ point_distance(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
 static float8
 point_dt(Point *pt1, Point *pt2)
 {
+	float8		result;
+
+	result = float8_hypot(float8_mi(pt1->x, pt2->x), float8_mi(pt1->y, pt2->y));
+
 #ifdef GEODEBUG
 	printf("point_dt- segment (%f,%f),(%f,%f) length is %f\n",
-		   pt1->x, pt1->y, pt2->x, pt2->y, HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
+		   pt1->x, pt1->y, pt2->x, pt2->y, result);
 #endif
-	return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
+
+	return result;
 }
 
 Datum
 point_slope(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_sl(pt1, pt2));
 }
 
 
 static float8
 point_sl(Point *pt1, Point *pt2)
 {
-	return (FPeq(pt1->x, pt2->x)
-			? (double) DBL_MAX
-			: (pt1->y - pt2->y) / (pt1->x - pt2->x));
+	if (FPeq(pt1->x, pt2->x))
+		return DBL_MAX;
+	return float8_div(float8_mi(pt1->y, pt2->y), float8_mi(pt1->x, pt2->x));
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D line segments.
  **
  ***********************************************************************/
 
 /*----------------------------------------------------------
@@ -2043,35 +2049,35 @@ lseg_parallel(PG_FUNCTION_ARGS)
  *	'((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg
  * So, modified it to check explicitly for slope of vertical line
  *	returned by point_sl() and the results seem better.
  * - thomas 1998-01-31
  */
 Datum
 lseg_perp(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	double		m1,
+	float8		m1,
 				m2;
 
 	m1 = point_sl(&l1->p[0], &l1->p[1]);
 	m2 = point_sl(&l2->p[0], &l2->p[1]);
 
 #ifdef GEODEBUG
 	printf("lseg_perp- slopes are %g and %g\n", m1, m2);
 #endif
 	if (FPzero(m1))
 		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
 	else if (FPzero(m2))
 		PG_RETURN_BOOL(FPeq(m1, DBL_MAX));
 
-	PG_RETURN_BOOL(FPeq(m1 / m2, -1.0));
+	PG_RETURN_BOOL(FPeq(float8_div(m1, m2), -1.0));
 }
 
 Datum
 lseg_vertical(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 
 	PG_RETURN_BOOL(FPeq(lseg->p[0].x, lseg->p[1].x));
 }
 
@@ -2161,52 +2167,47 @@ lseg_distance(PG_FUNCTION_ARGS)
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_FLOAT8(lseg_dt(l1, l2));
 }
 
 /* lseg_dt()
  * Distance between two line segments.
  * Must check both sets of endpoints to ensure minimum distance is found.
  * - thomas 1998-02-01
  */
-static double
+static float8
 lseg_dt(LSEG *l1, LSEG *l2)
 {
-	double		result,
-				d;
+	float8		result;
 
 	if (lseg_interpt_internal(NULL, l1, l2))
 		return 0.0;
 
-	d = dist_ps_internal(&l1->p[0], l2);
-	result = d;
-	d = dist_ps_internal(&l1->p[1], l2);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[0], l1);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[1], l1);
-	result = Min(result, d);
+	result = dist_ps_internal(&l1->p[0], l2);
+	result = float8_min(result, dist_ps_internal(&l1->p[1], l2));
+	result = float8_min(result, dist_ps_internal(&l2->p[0], l1));
+	result = float8_min(result, dist_ps_internal(&l2->p[1], l1));
 
 	return result;
 }
 
 
 Datum
 lseg_center(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
-	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
+	result->x = float8_div(float8_pl(lseg->p[0].x, lseg->p[1].x), 2.0);
+	result->y = float8_div(float8_pl(lseg->p[0].y, lseg->p[1].y), 2.0);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static bool
 lseg_interpt_internal(Point *result, LSEG *l1, LSEG *l2)
 {
 	Point		interpt;
 	LINE		tmp1,
 				tmp2;
@@ -2290,58 +2291,58 @@ lseg_interpt(PG_FUNCTION_ARGS)
  */
 Datum
 dist_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
 	PG_RETURN_FLOAT8(dist_pl_internal(pt, line));
 }
 
-static double
+static float8
 dist_pl_internal(Point *pt, LINE *line)
 {
-	return fabs(line_calculate_point(line, pt) /
-				HYPOT(line->A, line->B));
+	return float8_div(fabs(line_calculate_point(line, pt)),
+					  float8_hypot(line->A, line->B));
 }
 
 /*
  * Distance from a point to a lseg
  */
 Datum
 dist_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_FLOAT8(dist_ps_internal(pt, lseg));
 }
 
-static double
+static float8
 dist_ps_internal(Point *pt, LSEG *lseg)
 {
-	double		m;				/* slope of perp. */
-	double		result,
+	float8		m;				/* slope of perp. */
+	float8		result,
 				tmpdist;
 	Point		interpt;
 	LINE		ln;
 
 	/*
 	 * Construct a line perpendicular to the input segment and through the
 	 * input point
 	 */
-	if (lseg->p[1].x == lseg->p[0].x)
-		m = 0;
-	else if (lseg->p[1].y == lseg->p[0].y)
-		m = (double) DBL_MAX;	/* slope is infinite */
+	if (float8_eq(lseg->p[0].x, lseg->p[1].x))
+		m = 0.0;
+	else if (float8_eq(lseg->p[0].y, lseg->p[1].y))
+		m = DBL_MAX;	/* slope is infinite */
 	else
-		m = -1.0 / point_sl(&lseg->p[0], &lseg->p[1]);
+		m = float8_div(-1.0, point_sl(&lseg->p[0], &lseg->p[1]));
 	line_construct_pm(&ln, pt, m);
 
 #ifdef GEODEBUG
 	printf("dist_ps- line is A=%g B=%g C=%g from (point) slope (%f,%f) %g\n",
 		   ln->A, ln->B, ln->C, pt->x, pt->y, m);
 #endif
 
 	/*
 	 * Calculate distance to the line segment or to the nearest endpoint of
 	 * the segment.
@@ -2353,24 +2354,22 @@ dist_ps_internal(Point *pt, LSEG *lseg)
 		/* yes, so use distance to the intersection point */
 		result = point_dt(pt, &interpt);
 #ifdef GEODEBUG
 		printf("dist_ps- distance is %f to intersection point is (%f,%f)\n",
 			   result, tmp.x, tmp.y);
 #endif
 	}
 	else
 	{
 		/* no, so use distance to the nearer endpoint */
-		result = point_dt(pt, &lseg->p[0]);
-		tmpdist = point_dt(pt, &lseg->p[1]);
-		if (tmpdist < result)
-			result = tmpdist;
+		result = float8_min(point_dt(pt, &lseg->p[0]),
+							point_dt(pt, &lseg->p[1]));
 	}
 
 	return result;
 }
 
 /*
  * Distance from a point to a path
  */
 Datum
 dist_ppath(PG_FUNCTION_ARGS)
@@ -2408,21 +2407,21 @@ dist_ppath(PG_FUNCTION_ARGS)
 					iprev = i - 1;
 				else
 				{
 					if (!path->closed)
 						continue;
 					iprev = path->npts - 1; /* include the closure segment */
 				}
 
 				statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
 				tmp = dist_ps_internal(pt, &lseg);
-				if (!have_min || tmp < result)
+				if (!have_min || float8_lt(tmp, result))
 				{
 					result = tmp;
 					have_min = true;
 				}
 			}
 			break;
 	}
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -2446,33 +2445,28 @@ dist_pb(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
-	float8		result,
-				d2;
+	float8		result;
 
 	if (lseg_interpt_line_internal(NULL, lseg, line))
 		result = 0.0;
 	else
-	{
-		result = dist_pl_internal(&lseg->p[0], line);
-		d2 = dist_pl_internal(&lseg->p[1], line);
 		/* XXX shouldn't we take the min not max? */
-		if (d2 > result)
-			result = d2;
-	}
+		result = float8_max(dist_pl_internal(&lseg->p[0], line),
+							dist_pl_internal(&lseg->p[1], line));
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
@@ -2514,25 +2508,22 @@ dist_lb(PG_FUNCTION_ARGS)
  * Distance from a circle to a polygon
  */
 Datum
 dist_cpoly(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	POLYGON    *poly = PG_GETARG_POLYGON_P(1);
 	float8		result;
 
 	/* calculate distance to center, and subtract radius */
-	result = dist_ppoly_internal(&circle->center, poly);
-
-	result -= circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_min(float8_mi(dist_ppoly_internal(&circle->center, poly),
+								  circle->radius), 0.0);
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a point to a polygon
  */
 Datum
 dist_ppoly(PG_FUNCTION_ARGS)
 {
@@ -2550,21 +2541,21 @@ dist_polyp(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	float8		result;
 
 	result = dist_ppoly_internal(point, poly);
 
 	PG_RETURN_FLOAT8(result);
 }
 
-static double
+static float8
 dist_ppoly_internal(Point *pt, POLYGON *poly)
 {
 	float8		result;
 	float8		d;
 	int			i;
 	LSEG		seg;
 
 	if (point_inside(pt, poly->npts, poly->p) != 0)
 	{
 #ifdef GEODEBUG
@@ -2587,21 +2578,21 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
 	for (i = 0; (i < poly->npts - 1); i++)
 	{
 		seg.p[0].x = poly->p[i].x;
 		seg.p[0].y = poly->p[i].y;
 		seg.p[1].x = poly->p[i + 1].x;
 		seg.p[1].y = poly->p[i + 1].y;
 		d = dist_ps_internal(pt, &seg);
 #ifdef GEODEBUG
 		printf("dist_ppoly_internal- segment %d distance is %f\n", (i + 1), d);
 #endif
-		if (d < result)
+		if (float8_lt(d, result))
 			result = d;
 	}
 
 	return result;
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
  *				Intersection point of objects.
@@ -2655,41 +2646,41 @@ lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line)
 /* close_pl -
  *		The intersection point of a perpendicular of the line
  *		through the point.
  */
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
-	double		invm;
+	float8		invm;
 	LINE		tmp;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (FPzero(line->B))		/* vertical? */
 	{
 		result->x = line->C;
 		result->y = pt->y;
 		PG_RETURN_POINT_P(result);
 	}
 	if (FPzero(line->A))		/* horizontal? */
 	{
 		result->x = pt->x;
 		result->y = line->C;
 		PG_RETURN_POINT_P(result);
 	}
 	/* drop a perpendicular and find the intersection point */
 
 	/* invert and flip the sign on the slope to get a perpendicular */
-	invm = line->B / line->A;
+	invm = float8_div(line->B, line->A);
 	line_construct_pm(&tmp, pt, invm);
 	line_interpt_internal(result, &tmp, line);
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_ps()
  * Closest point on line segment to specified point.
  * Take the closest endpoint if the point is left, right,
  *	above, or below the segment, otherwise find the intersection
@@ -2698,21 +2689,21 @@ close_pl(PG_FUNCTION_ARGS)
  * Some tricky code here, relying on boolean expressions
  *	evaluating to only zero or one to use as an array index.
  *		bug fixes by gthaker@atl.lmco.com; May 1, 1998
  */
 Datum
 close_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
-	double		invm;
+	float8		invm;
 	int			xh,
 				yh;
 	LINE		tmp;
 
 	result = (Point *) palloc(sizeof(Point));
 
 #ifdef GEODEBUG
 	printf("close_sp:pt->x %f pt->y %f\nlseg(0).x %f lseg(0).y %f  lseg(1).x %f lseg(1).y %f\n",
 		   pt->x, pt->y, lseg->p[0].x, lseg->p[0].y,
 		   lseg->p[1].x, lseg->p[1].y);
@@ -2754,35 +2745,35 @@ close_ps(PG_FUNCTION_ARGS)
 			point_construct(result, pt->x, lseg->p[0].y);
 
 		PG_RETURN_POINT_P(result);
 	}
 
 	/*
 	 * vert. and horiz. cases are down, now check if the closest point is one
 	 * of the end points or someplace on the lseg.
 	 */
 
-	invm = -1.0 / point_sl(&(lseg->p[0]), &(lseg->p[1]));
+	invm = float8_div(-1.0, point_sl(&lseg->p[0], &lseg->p[1]));
 	line_construct_pm(&tmp, &lseg->p[!yh], invm);	/* lower edge of the
 													 * "band" */
-	if (pt->y < (tmp.A * pt->x + tmp.C))
+	if (pt->y < float8_pl(float8_mul(tmp.A, pt->x), tmp.C))
 	{							/* we are below the lower edge */
 		*result = lseg->p[!yh];	/* below the lseg, take lower end pt */
 #ifdef GEODEBUG
 		printf("close_ps below: tmp A %f  B %f   C %f\n",
 			   tmp->A, tmp->B, tmp->C);
 #endif
 		PG_RETURN_POINT_P(result);
 	}
 	line_construct_pm(&tmp, &lseg->p[yh], invm);	/* upper edge of the
 													 * "band" */
-	if (pt->y > (tmp.A * pt->x + tmp.C))
+	if (pt->y > float8_pl(float8_mul(tmp.A, pt->x), tmp.C))
 	{							/* we are below the lower edge */
 		*result = lseg->p[yh];	/* above the lseg, take higher end pt */
 #ifdef GEODEBUG
 		printf("close_ps above: tmp A %f  B %f   C %f\n",
 			   tmp->A, tmp->B, tmp->C);
 #endif
 		PG_RETURN_POINT_P(result);
 	}
 
 	/*
@@ -2818,32 +2809,32 @@ close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 	double		dist,
 				dist0,
 				dist1;
 
 	dist0 = dist_ps_internal(&l1->p[0], l2);
 	dist1 = dist_ps_internal(&l1->p[1], l2);
-	dist = Min(dist0, dist1);
+	dist = float8_min(dist0, dist1);
 
-	if (dist_ps_internal(&l2->p[0], l1) < dist)
+	if (float8_lt(dist_ps_internal(&l2->p[0], l1), dist))
 	{
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(&l2->p[0]),
 													LsegPGetDatum(l1)));
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(result),
 													LsegPGetDatum(l2)));
 	}
-	else if (dist_ps_internal(&l2->p[1], l1) < dist)
+	else if (float8_lt(dist_ps_internal(&l2->p[1], l1), dist))
 	{
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(&l2->p[1]),
 													LsegPGetDatum(l1)));
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(result),
 													LsegPGetDatum(l2)));
 	}
 	else
 	{
@@ -2858,52 +2849,55 @@ close_lseg(PG_FUNCTION_ARGS)
  * Closest point on or in box to specified point.
  */
 Datum
 close_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	LSEG		lseg,
 				seg;
 	Point		point;
-	double		dist,
+	float8		dist,
 				d;
 
 	if (DatumGetBool(DirectFunctionCall2(on_pb,
 										 PointPGetDatum(pt),
 										 BoxPGetDatum(box))))
 		PG_RETURN_POINT_P(pt);
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&lseg, &box->low, &point);
 	dist = dist_ps_internal(pt, &lseg);
 
 	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	d = dist_ps_internal(pt, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&lseg, &seg, sizeof(lseg));
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&seg, &box->low, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	d = dist_ps_internal(pt, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&lseg, &seg, sizeof(lseg));
 	}
 
 	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	d = dist_ps_internal(pt, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&lseg, &seg, sizeof(lseg));
 	}
 
 	PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
 										PointPGetDatum(pt),
 										LsegPGetDatum(&lseg)));
 }
 
@@ -2926,21 +2920,21 @@ close_sl(PG_FUNCTION_ARGS)
 	float8		d1,
 				d2;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (lseg_interpt_line_internal(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = dist_pl_internal(&lseg->p[0], line);
 	d2 = dist_pl_internal(&lseg->p[1], line);
-	if (d1 < d2)
+	if (float8_lt(d1, d2))
 		*result = lseg->p[0];
 	else
 		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
 
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_sl\" not implemented")));
@@ -2960,77 +2954,80 @@ close_ls(PG_FUNCTION_ARGS)
 	float8		d1,
 				d2;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (lseg_interpt_line_internal(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = dist_pl_internal(&lseg->p[0], line);
 	d2 = dist_pl_internal(&lseg->p[1], line);
-	if (d1 < d2)
+	if (float8_lt(d1, d2))
 		*result = lseg->p[0];
 	else
 		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 }
 
 /* close_sb()
  * Closest point on or in box to line segment.
  */
 Datum
 close_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	Point		point;
 	LSEG		bseg,
 				seg;
-	double		dist,
+	float8		dist,
 				d;
 
 	/* segment intersects box? then just return closest point to center */
 	if (DatumGetBool(DirectFunctionCall2(inter_sb,
 										 LsegPGetDatum(lseg),
 										 BoxPGetDatum(box))))
 	{
 		box_cn(&point, box);
 		PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
 											PointPGetDatum(&point),
 											LsegPGetDatum(lseg)));
 	}
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
 	dist = lseg_dt(lseg, &bseg);
 
 	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	d = lseg_dt(lseg, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&bseg, &seg, sizeof(bseg));
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&seg, &box->low, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	d = lseg_dt(lseg, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&bseg, &seg, sizeof(bseg));
 	}
 
 	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	d = lseg_dt(lseg, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&bseg, &seg, sizeof(bseg));
 	}
 
 	/* OK, we now have the closest line segment on the box boundary */
 	PG_RETURN_DATUM(DirectFunctionCall2(close_lseg,
 										LsegPGetDatum(lseg),
 										LsegPGetDatum(&bseg)));
 }
@@ -3078,75 +3075,80 @@ on_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_BOOL(on_ps_internal(pt, lseg));
 }
 
 static bool
 on_ps_internal(Point *pt, LSEG *lseg)
 {
-	return FPeq(point_dt(pt, &lseg->p[0]) + point_dt(pt, &lseg->p[1]),
+	return FPeq(float8_pl(point_dt(pt, &lseg->p[0]),
+						  point_dt(pt, &lseg->p[1])),
 				point_dt(&lseg->p[0], &lseg->p[1]));
 }
 
+
 Datum
 on_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_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);
+	PG_RETURN_BOOL(float8_le(pt->x, box->high.x) &&
+				   float8_ge(pt->x, box->low.x) &&
+				   float8_le(pt->y, box->high.y) &&
+				   float8_ge(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);
+	PG_RETURN_BOOL(float8_le(pt->x, box->high.x) &&
+				   float8_ge(pt->x, box->low.x) &&
+				   float8_le(pt->y, box->high.y) &&
+				   float8_ge(pt->y, box->low.y));
 }
 
 /* on_ppath -
  *		Whether a point lies within (on) a polyline.
  *		If open, we have to (groan) check each segment.
  * (uses same algorithm as for point intersecting segment - tgl 1997-07-09)
  *		If closed, we use the old O(n) ray method for point-in-polygon.
  *				The ray is horizontal, from pt out to the right.
  *				Each segment that crosses the ray counts as an
  *				intersection; note that an endpoint or edge may touch
  *				but not cross.
  *				(we can do p-in-p in lg(n), but it takes preprocessing)
  */
 Datum
 on_ppath(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	PATH	   *path = PG_GETARG_PATH_P(1);
 	int			i,
 				n;
-	double		a,
+	float8		a,
 				b;
 
 	/*-- OPEN --*/
 	if (!path->closed)
 	{
 		n = path->npts - 1;
 		a = point_dt(pt, &path->p[0]);
 		for (i = 0; i < n; i++)
 		{
 			b = point_dt(pt, &path->p[i + 1]);
-			if (FPeq(a + b,
-					 point_dt(&path->p[i], &path->p[i + 1])))
+			if (FPeq(float8_pl(a, b), point_dt(&path->p[i], &path->p[i + 1])))
 				PG_RETURN_BOOL(true);
 			a = b;
 		}
 		PG_RETURN_BOOL(false);
 	}
 
 	/*-- CLOSED --*/
 	PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
 }
 
@@ -3204,24 +3206,24 @@ inter_sl(PG_FUNCTION_ARGS)
  */
 Datum
 inter_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	BOX			lbox;
 	LSEG		bseg;
 	Point		point;
 
-	lbox.low.x = Min(lseg->p[0].x, lseg->p[1].x);
-	lbox.low.y = Min(lseg->p[0].y, lseg->p[1].y);
-	lbox.high.x = Max(lseg->p[0].x, lseg->p[1].x);
-	lbox.high.y = Max(lseg->p[0].y, lseg->p[1].y);
+	lbox.low.x = float8_min(lseg->p[0].x, lseg->p[1].x);
+	lbox.low.y = float8_min(lseg->p[0].y, lseg->p[1].y);
+	lbox.high.x = float8_max(lseg->p[0].x, lseg->p[1].x);
+	lbox.high.y = float8_max(lseg->p[0].y, lseg->p[1].y);
 
 	/* nothing close to overlap? then not going to intersect */
 	if (!box_ov(&lbox, box))
 		PG_RETURN_BOOL(false);
 
 	/* an endpoint of segment is inside box? then clearly intersects */
 	if (DatumGetBool(DirectFunctionCall2(on_pb,
 										 PointPGetDatum(&lseg->p[0]),
 										 BoxPGetDatum(box))) ||
 		DatumGetBool(DirectFunctionCall2(on_pb,
@@ -3302,38 +3304,38 @@ inter_lb(PG_FUNCTION_ARGS)
  * make_bound_box - create the bounding box for the input polygon
  *------------------------------------------------------------------*/
 
 /*---------------------------------------------------------------------
  * Make the smallest bounding box for the given polygon.
  *---------------------------------------------------------------------*/
 static void
 make_bound_box(POLYGON *poly)
 {
 	int			i;
-	double		x1,
+	float8		x1,
 				y1,
 				x2,
 				y2;
 
 	if (poly->npts > 0)
 	{
 		x2 = x1 = poly->p[0].x;
 		y2 = y1 = poly->p[0].y;
 		for (i = 1; i < poly->npts; i++)
 		{
-			if (poly->p[i].x < x1)
+			if (float8_lt(poly->p[i].x, x1))
 				x1 = poly->p[i].x;
-			if (poly->p[i].x > x2)
+			if (float8_gt(poly->p[i].x, x2))
 				x2 = poly->p[i].x;
-			if (poly->p[i].y < y1)
+			if (float8_lt(poly->p[i].y, y1))
 				y1 = poly->p[i].y;
-			if (poly->p[i].y > y2)
+			if (float8_gt(poly->p[i].y, y2))
 				y2 = poly->p[i].y;
 		}
 
 		box_construct(&poly->boundbox, x1, x2, y1, y2);
 	}
 	else
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("cannot create bounding box for empty polygon")));
 }
@@ -3461,21 +3463,21 @@ poly_send(PG_FUNCTION_ARGS)
  * the right most point of A left of the left most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_left(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.high.x < polyb->boundbox.low.x;
+	result = float8_lt(polya->boundbox.high.x, polyb->boundbox.low.x);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3484,21 +3486,21 @@ poly_left(PG_FUNCTION_ARGS)
  * the right most point of A at or left of the right most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_overleft(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.high.x <= polyb->boundbox.high.x;
+	result = float8_le(polya->boundbox.high.x, polyb->boundbox.high.x);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3507,21 +3509,21 @@ poly_overleft(PG_FUNCTION_ARGS)
  * the left most point of A right of the right most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_right(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.low.x > polyb->boundbox.high.x;
+	result = float8_gt(polya->boundbox.low.x, polyb->boundbox.high.x);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3530,21 +3532,21 @@ poly_right(PG_FUNCTION_ARGS)
  * the left most point of A at or right of the left most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_overright(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.low.x >= polyb->boundbox.low.x;
+	result = float8_ge(polya->boundbox.low.x, polyb->boundbox.low.x);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3553,21 +3555,21 @@ poly_overright(PG_FUNCTION_ARGS)
  * the upper most point of A below the lower most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_below(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.high.y < polyb->boundbox.low.y;
+	result = float8_lt(polya->boundbox.high.y, polyb->boundbox.low.y);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3576,21 +3578,21 @@ poly_below(PG_FUNCTION_ARGS)
  * the upper most point of A at or below the upper most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_overbelow(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.high.y <= polyb->boundbox.high.y;
+	result = float8_le(polya->boundbox.high.y, polyb->boundbox.high.y);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3599,21 +3601,21 @@ poly_overbelow(PG_FUNCTION_ARGS)
  * the lower most point of A above the upper most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_above(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.low.y > polyb->boundbox.high.y;
+	result = float8_gt(polya->boundbox.low.y, polyb->boundbox.high.y);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3622,21 +3624,21 @@ poly_above(PG_FUNCTION_ARGS)
  * the lower most point of A at or above the lower most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_overabove(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.low.y >= polyb->boundbox.low.y;
+	result = float8_ge(polya->boundbox.low.y, polyb->boundbox.low.y);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3833,22 +3835,22 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 	}
 
 	if (res && !intersection)
 	{
 		Point		p;
 
 		/*
 		 * if X-intersection wasn't found  then check central point of tested
 		 * segment. In opposite case we already check all subsegments
 		 */
-		p.x = (t.p[0].x + t.p[1].x) / 2.0;
-		p.y = (t.p[0].y + t.p[1].y) / 2.0;
+		p.x = float8_div(float8_pl(t.p[0].x, t.p[1].x), 2.0);
+		p.y = float8_div(float8_pl(t.p[0].y, t.p[1].y), 2.0);
 
 		res = point_inside(&p, poly->npts, poly->p);
 	}
 
 	return res;
 }
 
 /*-----------------------------------------------------------------
  * Determine if polygon A contains polygon B.
  *-----------------------------------------------------------------*/
@@ -3975,66 +3977,68 @@ point_add(PG_FUNCTION_ARGS)
 
 	point_add_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static void
 point_add_internal(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x + pt2->x,
-					pt1->y + pt2->y);
+					float8_pl(pt1->x, pt2->x),
+					float8_pl(pt1->y, pt2->y));
 }
 
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	point_sub_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static void
 point_sub_internal(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x - pt2->x,
-					pt1->y - pt2->y);
+					float8_mi(pt1->x, pt2->x),
+					float8_mi(pt1->y, pt2->y));
 }
 
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	point_mul_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static void
 point_mul_internal(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					(pt1->x * pt2->x) - (pt1->y * pt2->y),
-					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+					float8_mi(float8_mul(pt1->x, pt2->x),
+							  float8_mul(pt1->y, pt2->y)),
+					float8_pl(float8_mul(pt1->x, pt2->y),
+							  float8_mul(pt1->y, pt2->x)));
 }
 
 Datum
 point_div(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -4042,24 +4046,26 @@ point_div(PG_FUNCTION_ARGS)
 	point_div_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static void
 point_div_internal(Point *result, Point *pt1, Point *pt2)
 {
 	float8		div;
 
-	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
+	div = float8_pl(float8_mul(pt2->x, pt2->x), float8_mul(pt2->y, pt2->y));
 	point_construct(result,
-					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
-					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+					float8_div(float8_pl(float8_mul(pt1->x, pt2->x),
+										 float8_mul(pt1->y, pt2->y)), div),
+					float8_div(float8_mi(float8_mul(pt1->y, pt2->x),
+										 float8_mul(pt1->x, pt2->y)), div));
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D boxes.
  **
  ***********************************************************************/
 
 Datum
@@ -4168,24 +4174,24 @@ point_box(PG_FUNCTION_ARGS)
  */
 Datum
 boxes_bound_box(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0),
 			   *box2 = PG_GETARG_BOX_P(1),
 			   *container;
 
 	container = (BOX *) palloc(sizeof(BOX));
 
-	container->high.x = Max(box1->high.x, box2->high.x);
-	container->low.x = Min(box1->low.x, box2->low.x);
-	container->high.y = Max(box1->high.y, box2->high.y);
-	container->low.y = Min(box1->low.y, box2->low.y);
+	container->high.x = float8_max(box1->high.x, box2->high.x);
+	container->low.x = float8_min(box1->low.x, box2->low.x);
+	container->high.y = float8_max(box1->high.y, box2->high.y);
+	container->low.y = float8_min(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(container);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D paths.
  **
  ***********************************************************************/
@@ -4495,21 +4501,21 @@ circle_in(PG_FUNCTION_ARGS)
 		if (*cp == LDELIM)
 			s = cp;
 	}
 
 	pair_decode(s, &circle->center.x, &circle->center.y, &s, "circle", str);
 
 	if (*s == DELIM)
 		s++;
 
 	circle->radius = single_decode(s, &s, "circle", str);
-	if (circle->radius < 0)
+	if (float8_lt(circle->radius, 0.0))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
 
 	while (depth > 0)
 	{
 		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
@@ -4562,21 +4568,21 @@ circle_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	circle->center.x = pq_getmsgfloat8(buf);
 	circle->center.y = pq_getmsgfloat8(buf);
 	circle->radius = pq_getmsgfloat8(buf);
 
-	if (circle->radius < 0)
+	if (float8_lt(circle->radius, 0.0))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
 				 errmsg("invalid radius in external \"circle\" value")));
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 /*
  *		circle_send			- converts circle to binary format
  */
@@ -4613,144 +4619,146 @@ circle_same(PG_FUNCTION_ARGS)
 
 /*		circle_overlap	-		does circle1 overlap circle2?
  */
 Datum
 circle_overlap(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle1->radius + circle2->radius));
+						float8_pl(circle1->radius, circle2->radius)));
 }
 
 /*		circle_overleft -		is the right edge of circle1 at or left of
  *								the right edge of circle2?
  */
 Datum
 circle_overleft(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.x + circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_left		-		is circle1 strictly left of circle2?
  */
 Datum
 circle_left(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.x + circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_right	-		is circle1 strictly right of circle2?
  */
 Datum
 circle_right(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.x - circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_overright	-	is the left edge of circle1 at or right of
  *								the left edge of circle2?
  */
 Datum
 circle_overright(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.x - circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_contained		-		is circle1 contained by circle2?
  */
 Datum
 circle_contained(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle1->radius), circle2->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						float8_mi(circle2->radius, circle1->radius)));
 }
 
 /*		circle_contain	-		does circle1 contain circle2?
  */
 Datum
 circle_contain(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle2->radius), circle1->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						float8_mi(circle1->radius, circle2->radius)));
 }
 
 
 /*		circle_below		-		is circle1 strictly below circle2?
  */
 Datum
 circle_below(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.y + circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_above	-		is circle1 strictly above circle2?
  */
 Datum
 circle_above(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.y - circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overbelow -		is the upper edge of circle1 at or below
  *								the upper edge of circle2?
  */
 Datum
 circle_overbelow(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.y + circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overabove	-	is the lower edge of circle1 at or above
  *								the lower edge of circle2?
  */
 Datum
 circle_overabove(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.y - circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 
 /*		circle_relop	-		is area(circle1) relop area(circle2), within
  *								our accuracy constraint?
  */
 Datum
 circle_eq(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
@@ -4849,36 +4857,38 @@ circle_sub_pt(PG_FUNCTION_ARGS)
 Datum
 circle_mul_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_mul_internal(&result->center, &circle->center, point);
-	result->radius *= HYPOT(point->x, point->y);
+	result->radius = float8_mul(circle->radius,
+								float8_hypot(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_div_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_div_internal(&result->center, &circle->center, point);
-	result->radius /= HYPOT(point->x, point->y);
+	result->radius = float8_div(circle->radius,
+								float8_hypot(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /*		circle_area		-		returns the area of the circle.
  */
 Datum
 circle_area(PG_FUNCTION_ARGS)
 {
@@ -4888,21 +4898,21 @@ circle_area(PG_FUNCTION_ARGS)
 }
 
 
 /*		circle_diameter -		returns the diameter of the circle.
  */
 Datum
 circle_diameter(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
-	PG_RETURN_FLOAT8(2 * circle->radius);
+	PG_RETURN_FLOAT8(float8_mul(circle->radius, 2.0));
 }
 
 
 /*		circle_radius	-		returns the radius of the circle.
  */
 Datum
 circle_radius(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
@@ -4913,81 +4923,84 @@ circle_radius(PG_FUNCTION_ARGS)
 /*		circle_distance -		returns the distance between
  *								  two circles.
  */
 Datum
 circle_distance(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(&circle1->center, &circle2->center)
-		- (circle1->radius + circle2->radius);
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(&circle1->center, &circle2->center),
+					   float8_pl(circle1->radius, circle2->radius));
+	if (float8_lt(result, 0.0))
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 
 Datum
 circle_contain_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
-	PG_RETURN_BOOL(d <= circle->radius);
+	PG_RETURN_BOOL(float8_le(d, circle->radius));
 }
 
 
 Datum
 pt_contained_circle(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
-	PG_RETURN_BOOL(d <= circle->radius);
+	PG_RETURN_BOOL(float8_le(d, circle->radius));
 }
 
 
 /*		dist_pc -		returns the distance between
  *						  a point and a circle.
  */
 Datum
 dist_pc(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center), circle->radius);
+	if (float8_lt(result, 0.0))
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a circle to a point
  */
 Datum
 dist_cpoint(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center), circle->radius);
+	if (float8_lt(result, 0.0))
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*		circle_center	-		returns the center point of the circle.
  */
 Datum
 circle_center(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *result;
@@ -4995,24 +5008,24 @@ circle_center(PG_FUNCTION_ARGS)
 	result = (Point *) palloc(sizeof(Point));
 	result->x = circle->center.x;
 	result->y = circle->center.y;
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		circle_ar		-		returns the area of the circle.
  */
-static double
+static float8
 circle_ar(CIRCLE *circle)
 {
-	return M_PI * (circle->radius * circle->radius);
+	return float8_mul(float8_mul(circle->radius, circle->radius), M_PI);
 }
 
 
 /*----------------------------------------------------------
  *	Conversion operators.
  *---------------------------------------------------------*/
 
 Datum
 cr_circle(PG_FUNCTION_ARGS)
 {
@@ -5027,65 +5040,65 @@ cr_circle(PG_FUNCTION_ARGS)
 	result->radius = radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_box(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	BOX		   *box;
-	double		delta;
+	float8		delta;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
-	delta = circle->radius / sqrt(2.0);
+	delta = float8_div(circle->radius, sqrt(2.0));
 
-	box->high.x = circle->center.x + delta;
-	box->low.x = circle->center.x - delta;
-	box->high.y = circle->center.y + delta;
-	box->low.y = circle->center.y - delta;
+	box->high.x = float8_pl(circle->center.x, delta);
+	box->low.x = float8_mi(circle->center.x, delta);
+	box->high.y = float8_pl(circle->center.y, delta);
+	box->low.y = float8_mi(circle->center.y, delta);
 
 	PG_RETURN_BOX_P(box);
 }
 
 /* box_circle()
  * Convert a box to a circle.
  */
 Datum
 box_circle(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	circle->center.x = (box->high.x + box->low.x) / 2;
-	circle->center.y = (box->high.y + box->low.y) / 2;
+	circle->center.x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	circle->center.y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 
 	circle->radius = point_dt(&circle->center, &box->high);
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 
 Datum
 circle_poly(PG_FUNCTION_ARGS)
 {
 	int32		npts = PG_GETARG_INT32(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	POLYGON    *poly;
 	int			base_size,
 				size;
 	int			i;
-	double		angle;
-	double		anglestep;
+	float8		angle;
+	float8		anglestep;
 
 	if (FPzero(circle->radius))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("cannot convert circle with radius zero to polygon")));
 
 	if (npts < 2)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("must request at least 2 points")));
@@ -5096,27 +5109,30 @@ circle_poly(PG_FUNCTION_ARGS)
 	/* Check for integer overflow */
 	if (base_size / npts != sizeof(poly->p[0]) || size <= base_size)
 		ereport(ERROR,
 				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 				 errmsg("too many points requested")));
 
 	poly = (POLYGON *) palloc0(size);	/* zero any holes */
 	SET_VARSIZE(poly, size);
 	poly->npts = npts;
 
-	anglestep = (2.0 * M_PI) / npts;
+	anglestep = float8_div(2.0 * M_PI, npts);
 
 	for (i = 0; i < npts; i++)
 	{
-		angle = i * anglestep;
-		poly->p[i].x = circle->center.x - (circle->radius * cos(angle));
-		poly->p[i].y = circle->center.y + (circle->radius * sin(angle));
+		angle = float8_mul(anglestep, i);
+
+		poly->p[i].x = float8_mi(circle->center.x,
+								 float8_mul(circle->radius, cos(angle)));
+		poly->p[i].y = float8_pl(circle->center.y,
+								 float8_mul(circle->radius, sin(angle)));
 	}
 
 	make_bound_box(poly);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
 /*		poly_circle		- convert polygon to circle
  *
  * XXX This algorithm should use weighted means of line segments
@@ -5135,29 +5151,30 @@ poly_circle(PG_FUNCTION_ARGS)
 				 errmsg("cannot convert empty polygon to circle")));
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	circle->center.x = 0;
 	circle->center.y = 0;
 	circle->radius = 0;
 
 	for (i = 0; i < poly->npts; i++)
 	{
-		circle->center.x += poly->p[i].x;
-		circle->center.y += poly->p[i].y;
+		circle->center.x = float8_pl(circle->center.x, poly->p[i].x);
+		circle->center.y = float8_pl(circle->center.y, poly->p[i].y);
 	}
-	circle->center.x /= poly->npts;
-	circle->center.y /= poly->npts;
+	circle->center.x = float8_div(circle->center.x, poly->npts);
+	circle->center.y = float8_div(circle->center.y, poly->npts);
 
 	for (i = 0; i < poly->npts; i++)
-		circle->radius += point_dt(&poly->p[i], &circle->center);
-	circle->radius /= poly->npts;
+		circle->radius = float8_pl(circle->radius, point_dt(&poly->p[i],
+															&circle->center));
+	circle->radius = float8_div(circle->radius, poly->npts);
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 
 /***********************************************************************
  **
  **		Private routines for multiple types.
  **
  ***********************************************************************/
@@ -5171,45 +5188,45 @@ poly_circle(PG_FUNCTION_ARGS)
  *	http://hopf.math.northwestern.edu/index.html
  *	Description of algorithm:  http://www.linuxjournal.com/article/2197
  *							   http://www.linuxjournal.com/article/2029
  */
 
 #define POINT_ON_POLYGON INT_MAX
 
 static int
 point_inside(Point *p, int npts, Point *plist)
 {
-	double		x0,
+	float8		x0,
 				y0;
-	double		prev_x,
+	float8		prev_x,
 				prev_y;
 	int			i = 0;
-	double		x,
+	float8		x,
 				y;
 	int			cross,
 				total_cross = 0;
 
 	if (npts <= 0)
 		return 0;
 
 	/* compute first polygon point relative to single point */
-	x0 = plist[0].x - p->x;
-	y0 = plist[0].y - p->y;
+	x0 = float8_mi(plist[0].x, p->x);
+	y0 = float8_mi(plist[0].y, p->y);
 
 	prev_x = x0;
 	prev_y = y0;
 	/* loop over polygon points and aggregate total_cross */
 	for (i = 1; i < npts; i++)
 	{
 		/* compute next polygon point relative to single point */
-		x = plist[i].x - p->x;
-		y = plist[i].y - p->y;
+		x = float8_mi(plist[i].x, p->x);
+		y = float8_mi(plist[i].y, p->y);
 
 		/* compute previous to current point crossing */
 		if ((cross = lseg_crossing(x, y, prev_x, prev_y)) == POINT_ON_POLYGON)
 			return 2;
 		total_cross += cross;
 
 		prev_x = x;
 		prev_y = y;
 	}
 
@@ -5227,69 +5244,74 @@ point_inside(Point *p, int npts, Point *plist)
 /* lseg_crossing()
  * Returns +/-2 if line segment crosses the positive X-axis in a +/- direction.
  * Returns +/-1 if one point is on the positive X-axis.
  * Returns 0 if both points are on the positive X-axis, or there is no crossing.
  * Returns POINT_ON_POLYGON if the segment contains (0,0).
  * Wow, that is one confusing API, but it is used above, and when summed,
  * can tell is if a point is in a polygon.
  */
 
 static int
-lseg_crossing(double x, double y, double prev_x, double prev_y)
+lseg_crossing(float8 x, float8 y, float8 prev_x, float8 prev_y)
 {
-	double		z;
+	float8		z;
 	int			y_sign;
 
 	if (FPzero(y))
 	{							/* y == 0, on X axis */
 		if (FPzero(x))			/* (x,y) is (0,0)? */
 			return POINT_ON_POLYGON;
 		else if (FPgt(x, 0))
 		{						/* x > 0 */
 			if (FPzero(prev_y)) /* y and prev_y are zero */
 				/* prev_x > 0? */
-				return FPgt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
-			return FPlt(prev_y, 0) ? 1 : -1;
+				return FPgt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
+			return FPlt(prev_y, 0.0) ? 1 : -1;
 		}
 		else
 		{						/* x < 0, x not on positive X axis */
 			if (FPzero(prev_y))
 				/* prev_x < 0? */
-				return FPlt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
+				return FPlt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
 			return 0;
 		}
 	}
 	else
 	{							/* y != 0 */
 		/* compute y crossing direction from previous point */
-		y_sign = FPgt(y, 0) ? 1 : -1;
+		y_sign = FPgt(y, 0.0) ? 1 : -1;
 
 		if (FPzero(prev_y))
 			/* previous point was on X axis, so new point is either off or on */
-			return FPlt(prev_x, 0) ? 0 : y_sign;
-		else if (FPgt(y_sign * prev_y, 0))
+			return FPlt(prev_x, 0.0) ? 0 : y_sign;
+		else if ((y_sign < 0 && FPlt(prev_y, 0.0)) ||
+			(y_sign > 0 && FPgt(prev_y, 0.0)))
 			/* both above or below X axis */
 			return 0;			/* same sign */
 		else
 		{						/* y and prev_y cross X-axis */
-			if (FPge(x, 0) && FPgt(prev_x, 0))
+			if (FPge(x, 0.0) && FPgt(prev_x, 0.0))
 				/* both non-negative so cross positive X-axis */
 				return 2 * y_sign;
-			if (FPlt(x, 0) && FPle(prev_x, 0))
+			if (FPlt(x, 0.0) && FPle(prev_x, 0.0))
 				/* both non-positive so do not cross positive X-axis */
 				return 0;
 
 			/* x and y cross axises, see URL above point_inside() */
-			z = (x - prev_x) * y - (y - prev_y) * x;
+			z = float8_mi(float8_mul(float8_mi(x, prev_x), y),
+						  float8_mul(float8_mi(y, prev_y), x));
 			if (FPzero(z))
 				return POINT_ON_POLYGON;
-			return FPgt((y_sign * z), 0) ? 0 : 2 * y_sign;
+			if ((y_sign < 0 && FPlt(z, 0.0)) ||
+				(y_sign > 0 && FPgt(z, 0.0)))
+				return 0;
+			return 2 * y_sign;
 		}
 	}
 }
 
 
 static bool
 plist_same(int npts, Point *p1, Point *p2)
 {
 	int			i,
 				ii,
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index c800bb1338..f62be1061e 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -76,38 +76,38 @@
 #include "access/spgist.h"
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
 #include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
- * is going only going to be used in a place to effect the performance
+ * is only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
 compareDoubles(const void *a, const void *b)
 {
-	double		x = *(double *) a;
-	double		y = *(double *) b;
+	float8		x = *(float8 *) a;
+	float8		y = *(float8 *) b;
 
 	if (x == y)
 		return 0;
 	return (x > y) ? 1 : -1;
 }
 
 typedef struct
 {
-	double		low;
-	double		high;
+	float8		low;
+	float8		high;
 } Range;
 
 typedef struct
 {
 	Range		left;
 	Range		right;
 } RangeBox;
 
 typedef struct
 {
@@ -121,30 +121,30 @@ typedef struct
  * The quadrant is 8 bit unsigned integer with 4 least bits in use.
  * This function accepts BOXes as input.  They are not casted to
  * RangeBoxes, yet.  All 4 bits are set by comparing a corner of the box.
  * This makes 16 quadrants in total.
  */
 static uint8
 getQuadrant(BOX *centroid, BOX *inBox)
 {
 	uint8		quadrant = 0;
 
-	if (inBox->low.x > centroid->low.x)
+	if (float8_gt(inBox->low.x, centroid->low.x))
 		quadrant |= 0x8;
 
-	if (inBox->high.x > centroid->high.x)
+	if (float8_gt(inBox->high.x, centroid->high.x))
 		quadrant |= 0x4;
 
-	if (inBox->low.y > centroid->low.y)
+	if (float8_gt(inBox->low.y, centroid->low.y))
 		quadrant |= 0x2;
 
-	if (inBox->high.y > centroid->high.y)
+	if (float8_gt(inBox->high.y, centroid->high.y))
 		quadrant |= 0x1;
 
 	return quadrant;
 }
 
 /*
  * Get RangeBox using BOX
  *
  * We are turning the BOX to our structures to emphasize their function
  * of representing points in 4D space.  It also is more convenient to
@@ -167,21 +167,21 @@ getRangeBox(BOX *box)
 /*
  * Initialize the traversal value
  *
  * In the beginning, we don't have any restrictions.  We have to
  * initialize the struct to cover the whole 4D space.
  */
 static RectBox *
 initRectBox(void)
 {
 	RectBox    *rect_box = (RectBox *) palloc(sizeof(RectBox));
-	double		infinity = get_float8_infinity();
+	float8		infinity = get_float8_infinity();
 
 	rect_box->range_box_x.left.low = -infinity;
 	rect_box->range_box_x.left.high = infinity;
 
 	rect_box->range_box_x.right.low = -infinity;
 	rect_box->range_box_x.right.high = infinity;
 
 	rect_box->range_box_y.left.low = -infinity;
 	rect_box->range_box_y.left.high = infinity;
 
@@ -410,40 +410,40 @@ spg_box_quad_choose(PG_FUNCTION_ARGS)
  * point as the median of the coordinates of the boxes.
  */
 Datum
 spg_box_quad_picksplit(PG_FUNCTION_ARGS)
 {
 	spgPickSplitIn *in = (spgPickSplitIn *) PG_GETARG_POINTER(0);
 	spgPickSplitOut *out = (spgPickSplitOut *) PG_GETARG_POINTER(1);
 	BOX		   *centroid;
 	int			median,
 				i;
-	double	   *lowXs = palloc(sizeof(double) * in->nTuples);
-	double	   *highXs = palloc(sizeof(double) * in->nTuples);
-	double	   *lowYs = palloc(sizeof(double) * in->nTuples);
-	double	   *highYs = palloc(sizeof(double) * in->nTuples);
+	float8	   *lowXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *lowYs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highYs = palloc(sizeof(float8) * in->nTuples);
 
 	/* Calculate median of all 4D coordinates */
 	for (i = 0; i < in->nTuples; i++)
 	{
 		BOX		   *box = DatumGetBoxP(in->datums[i]);
 
 		lowXs[i] = box->low.x;
 		highXs[i] = box->high.x;
 		lowYs[i] = box->low.y;
 		highYs[i] = box->high.y;
 	}
 
-	qsort(lowXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(lowYs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highYs, in->nTuples, sizeof(double), compareDoubles);
+	qsort(lowXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(lowYs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highYs, in->nTuples, sizeof(float8), compareDoubles);
 
 	median = in->nTuples / 2;
 
 	centroid = palloc(sizeof(BOX));
 
 	centroid->low.x = lowXs[median];
 	centroid->high.x = highXs[median];
 	centroid->low.y = lowYs[median];
 	centroid->high.y = highYs[median];
 
diff --git a/src/include/utils/float.h b/src/include/utils/float.h
index c26de1cca4..c893f79a4d 100644
--- a/src/include/utils/float.h
+++ b/src/include/utils/float.h
@@ -269,20 +269,33 @@ float8_div(float8 val1, float8 val2)
 		ereport(ERROR,
 				(errcode(ERRCODE_DIVISION_BY_ZERO),
 				 errmsg("division by zero")));
 
 	result = val1 / val2;
 	check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
 
 	return result;
 }
 
+static inline float8
+float8_hypot(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = hypot(val1, val2);
+	check_float8_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0 && val2 == 0.0);
+	Assert(isinf(result) || result >= 0.0);
+
+	return result;
+}
+
 /*
  * Routines for NaN-aware comparisons
  *
  * We consider all NANs to be equal and larger than any non-NAN. This is
  * somewhat arbitrary; the important thing is to have a consistent sort
  * order.
  */
 
 static inline bool
 float4_eq(float4 val1, float4 val2)
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index f845dffcb7..527036f1fc 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -1,23 +1,20 @@
 /*-------------------------------------------------------------------------
  *
  * geo_decls.h - Declarations for various 2D constructs.
  *
  *
  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * src/include/utils/geo_decls.h
  *
- * NOTE
- *	  These routines do *not* use the float types from adt/.
- *
  *	  XXX These routines were not written by a numerical analyst.
  *
  *	  XXX I have made some attempt to flesh out the operators
  *		and data types. There are still some more to do. - tgl 97/04/19
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEO_DECLS_H
 #define GEO_DECLS_H
 
@@ -28,44 +25,43 @@
 
 /*--------------------------------------------------------------------
  * Useful floating point utilities and constants.
  *-------------------------------------------------------------------*/
 
 
 #define EPSILON					1.0E-06
 
 #ifdef EPSILON
 #define FPzero(A)				(fabs(A) <= EPSILON)
-#define FPeq(A,B)				(fabs((A) - (B)) <= EPSILON)
-#define FPne(A,B)				(fabs((A) - (B)) > EPSILON)
-#define FPlt(A,B)				((B) - (A) > EPSILON)
-#define FPle(A,B)				((A) - (B) <= EPSILON)
-#define FPgt(A,B)				((A) - (B) > EPSILON)
-#define FPge(A,B)				((B) - (A) <= EPSILON)
+#define FPeq(A, B)				(float8_le(fabs(float8_mi(A, B)), EPSILON))
+#define FPne(A, B)				(float8_gt(fabs(float8_mi(A, B)), EPSILON))
+#define FPlt(A, B)				(float8_gt(float8_mi(B, A), EPSILON))
+#define FPle(A, B)				(float8_le(float8_mi(A, B), EPSILON))
+#define FPgt(A, B)				(float8_gt(float8_mi(A, B), EPSILON))
+#define FPge(A, B)				(float8_le(float8_mi(B, A), EPSILON))
 #else
-#define FPzero(A)				((A) == 0)
-#define FPeq(A,B)				((A) == (B))
-#define FPne(A,B)				((A) != (B))
-#define FPlt(A,B)				((A) < (B))
-#define FPle(A,B)				((A) <= (B))
-#define FPgt(A,B)				((A) > (B))
-#define FPge(A,B)				((A) >= (B))
+#define FPzero(A)				((A) == 0.0)
+#define FPeq(A, B)				(float8_eq(A, B))
+#define FPne(A, B)				(float8_ne(A, B))
+#define FPlt(A, B)				(float8_lt(A, B))
+#define FPle(A, B)				(float8_le(A, B))
+#define FPgt(A, B)				(float8_gt(A, B))
+#define FPge(A, B)				(float8_ge(A, B))
 #endif
 
-#define HYPOT(A, B)				hypot(A, B)
 
 /*---------------------------------------------------------------------
  * Point - (x,y)
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		x,
+	float8		x,
 				y;
 } Point;
 
 
 /*---------------------------------------------------------------------
  * LSEG - A straight line, specified by endpoints.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		p[2];
@@ -73,66 +69,66 @@ typedef struct
 
 
 /*---------------------------------------------------------------------
  * PATH - Specified by vertex points.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	int32		vl_len_;		/* varlena header (do not touch directly!) */
 	int32		npts;
 	int32		closed;			/* is this a closed polygon? */
-	int32		dummy;			/* padding to make it double align */
+	int32		dummy;			/* padding to make it float8 align */
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } PATH;
 
 
 /*---------------------------------------------------------------------
  * LINE - Specified by its general equation (Ax+By+C=0).
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		A,
+	float8		A,
 				B,
 				C;
 } LINE;
 
 
 /*---------------------------------------------------------------------
  * BOX	- Specified by two corner points, which are
  *		 sorted to save calculation time later.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		high,
 				low;			/* corner POINTs */
 } BOX;
 
 /*---------------------------------------------------------------------
- * POLYGON - Specified by an array of doubles defining the points,
+ * POLYGON - Specified by an array of float8s defining the points,
  *		keeping the number of points and the bounding box for
  *		speed purposes.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	int32		vl_len_;		/* varlena header (do not touch directly!) */
 	int32		npts;
 	BOX			boundbox;
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } POLYGON;
 
 /*---------------------------------------------------------------------
  * CIRCLE - Specified by a center point and radius.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		center;
-	double		radius;
+	float8		radius;
 } CIRCLE;
 
 /*
  * fmgr interface macros
  *
  * Path and Polygon are toastable varlena types, the others are just
  * fixed-size pass-by-reference types.
  */
 
 #define DatumGetPointP(X)	 ((Point *) DatumGetPointer(X))
-- 
2.11.0 (Apple Git-81)

0004-line-fixes-v2.patchapplication/octet-stream; name=0004-line-fixes-v2.patchDownload
From cc522ff02152d465b72d305af4110d0156b57c80 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sun, 28 May 2017 11:35:17 +0200
Subject: [PATCH 4/4] line-fixes-v2

Fix obvious problems around the line datatype

I have noticed some line operators retuning wrong results, and Tom Lane
spotted similar problems on more places.  Source history reveals that
during 1990s, the internal format of the line datatype is changed, but
most functions haven't got the hint.  The fixes include:

* Reject invalid specification A=B=0 on receive
* Avoid division by zero on perpendicular operator
* Fix intersection and distance operators when neither A nor B are 1
* Avoid point distance operator crashing on float precision loss
* Fix line segment distance by getting the minimum as the comment suggested

The changes are also aiming make line operators more symmetric.  Changing
results for same lines in different order are surely not expected.

Previous discussion:
https://www.postgresql.org/message-id/flat/CAE2gYzw_-z%3DV2kh8QqFjenu%3D8MJXzOP44wRW%3DAzzeamrmTT1%3DQ%40mail.gmail.com
---
 src/backend/utils/adt/geo_ops.c | 115 +++++++++++++++++++++++++++-------------
 1 file changed, 77 insertions(+), 38 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index dbff7abf64..e3f9cbebbf 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -948,20 +948,25 @@ line_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LINE	   *line;
 
 	line = (LINE *) palloc(sizeof(LINE));
 
 	line->A = pq_getmsgfloat8(buf);
 	line->B = pq_getmsgfloat8(buf);
 	line->C = pq_getmsgfloat8(buf);
 
+	if (line->A == 0.0 && line->B == 0.0)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+		 errmsg("invalid line specification: A and B cannot both be zero")));
+
 	PG_RETURN_LINE_P(line);
 }
 
 /*
  *		line_send			- converts line to binary format
  */
 Datum
 line_send(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -1095,25 +1100,28 @@ line_parallel(PG_FUNCTION_ARGS)
 }
 
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
-	else if (FPzero(l1->B))
+	if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
+	if (FPzero(l2->A))
+		PG_RETURN_BOOL(FPzero(l1->B));
+	if (FPzero(l2->B))
+		PG_RETURN_BOOL(FPzero(l1->A));
 
-	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
-								   float8_mul(l1->B, l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(float8_mul(l1->A, l2->B), -float8_mul(l1->B, l2->A)));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
@@ -1125,20 +1133,21 @@ line_horizontal(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(FPzero(line->A));
 }
 
 Datum
 line_eq(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		ratio;
 
+	/* A and B cannot be both 0, but we never really know with the EPSILON. */
 	if (!FPzero(l2->A))
 		ratio = float8_div(l1->A, l2->A);
 	else if (!FPzero(l2->B))
 		ratio = float8_div(l1->B, l2->B);
 	else if (!FPzero(l2->C))
 		ratio = float8_div(l1->C, l2->C);
 	else
 		ratio = 1.0;
 
 	PG_RETURN_BOOL(FPeq(l1->A, float8_mul(ratio, l2->A)) &&
@@ -1152,30 +1161,36 @@ line_eq(PG_FUNCTION_ARGS)
  *---------------------------------------------------------*/
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	float8		result;
-	Point		tmp;
+	float8		ratio;
 
 	if (line_interpt_internal(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
-	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
-	point_construct(&tmp, 0.0, l1->C);
-	result = dist_pl_internal(&tmp, l2);
-	PG_RETURN_FLOAT8(result);
+
+	/* A and B cannot be both 0, but we never really know with the EPSILON. */
+	if (!FPzero(l2->A))
+		ratio = float8_div(l1->A, l2->A);
+	else if (!FPzero(l2->B))
+		ratio = float8_div(l1->B, l2->B);
+	else
+		ratio = 1.0;
+
+	PG_RETURN_FLOAT8(float8_div(fabs(float8_mi(l1->C,
+											   float8_mul(ratio, l2->C))),
+								float8_hypot(l1->A, l1->B)));
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
@@ -1198,38 +1213,62 @@ line_interpt(PG_FUNCTION_ARGS)
  * NOTE: If the lines are identical then we will find they are parallel
  * and report "no intersection".  This is a little weird, but since
  * there's no *unique* intersection, maybe it's appropriate behavior.
  */
 static bool
 line_interpt_internal(Point *result, LINE *l1, LINE *l2)
 {
 	float8		x,
 				y;
 
-	if (FPzero(l1->B))			/* l1 vertical? */
+	if (FPzero(l1->A))			/* l1 horizontal? */
+	{
+		if (FPzero(l2->A))		/* l2 horizontal? */
+			return false;
+
+		y = float8_div(-l1->C, l1->B);
+		x = float8_div(-float8_pl(float8_mul(l2->B, y), l2->C), l2->A);
+	}
+	else if (FPzero(l1->B))		/* l1 vertical? */
 	{
 		if (FPzero(l2->B))		/* l2 vertical? */
 			return false;
 
-		x = l1->C;
-		y = float8_pl(float8_mul(l2->A, x), l2->C);
+		x = float8_div(-l1->C, l1->A);
+		y = float8_div(-float8_pl(float8_mul(l2->A, x), l2->C), l2->B);
+	}
+	else if (FPzero(l2->A))		/* l2 horizontal? */
+	{
+		if (FPzero(l1->A))		/* l1 horizontal? */
+			return false;
+
+		y = float8_div(-l2->C, l2->B);
+		x = float8_div(-float8_pl(float8_mul(l1->B, y), l1->C), l1->A);
+	}
+	else if (FPzero(l2->B))		/* l2 vertical? */
+	{
+		if (FPzero(l1->B))		/* l1 vertical? */
+			return false;
+
+		x = float8_div(-l2->C, l2->A);
+		y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
 	}
 	else
 	{
-		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
+		if (FPeq(float8_mul(l1->A, l2->B), float8_mul(l2->A, l1->B)))
 			return false;
 
-		if (FPzero(l2->B))
-			x = l2->C;
-		else
-			x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
-		y = float8_pl(float8_mul(l1->A, x), l1->C);
+		x = float8_div(float8_mi(float8_mul(l1->B, l2->C),
+								 float8_mul(l2->B, l1->C)),
+					   float8_mi(float8_mul(l1->A, l2->B),
+								 float8_mul(l2->A, l1->B)));
+		y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
 	}
 	if (result != NULL)
 		point_construct(result, x, y);
 
 #ifdef GEODEBUG
 	printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
 		   DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
 	printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
 #endif
 
@@ -2450,22 +2489,21 @@ dist_pb(PG_FUNCTION_ARGS)
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	float8		result;
 
 	if (lseg_interpt_line_internal(NULL, lseg, line))
 		result = 0.0;
 	else
-		/* XXX shouldn't we take the min not max? */
-		result = float8_max(dist_pl_internal(&lseg->p[0], line),
+		result = float8_min(dist_pl_internal(&lseg->p[0], line),
 							dist_pl_internal(&lseg->p[1], line));
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
@@ -2646,43 +2684,44 @@ lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line)
 /* close_pl -
  *		The intersection point of a perpendicular of the line
  *		through the point.
  */
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
-	float8		invm;
-	LINE		tmp;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (FPzero(line->B))		/* vertical? */
+		point_construct(result, float8_div(-line->C, line->A), pt->y);
+	else if (FPzero(line->A))	/* horizontal? */
+		point_construct(result, pt->x, float8_div(-line->C, line->B));
+	else
 	{
-		result->x = line->C;
-		result->y = pt->y;
-		PG_RETURN_POINT_P(result);
-	}
-	if (FPzero(line->A))		/* horizontal? */
-	{
-		result->x = pt->x;
-		result->y = line->C;
-		PG_RETURN_POINT_P(result);
-	}
-	/* drop a perpendicular and find the intersection point */
+		LINE		perp;
+
+		/*
+		 * Drop a perpendicular and find the intersection point
+		 *
+		 * We need to invert and flip the sign on the slope to get the
+		 * perpendicular.  We might lose some precision on the division.
+		 * It shouldn't be as much to turn the line.  If it happens anyway,
+		 * we will assume the point it on the line.
+		 */
+		line_construct_pm(&perp, pt, float8_div(line->B, line->A));
+		if (!line_interpt_internal(result, &perp, line))
+			*result = *pt;
+	}
 
-	/* invert and flip the sign on the slope to get a perpendicular */
-	invm = float8_div(line->B, line->A);
-	line_construct_pm(&tmp, pt, invm);
-	line_interpt_internal(result, &tmp, line);
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_ps()
  * Closest point on line segment to specified point.
  * Take the closest endpoint if the point is left, right,
  *	above, or below the segment, otherwise find the intersection
  *	point of the segment and its perpendicular through the point.
  *
-- 
2.11.0 (Apple Git-81)

#4Aleksander Alekseev
a.alekseev@postgrespro.ru
In reply to: Emre Hasegeli (#3)
Re: [PATCH] Improve geometric types

The following review has been posted through the commitfest application:
make installcheck-world: tested, failed
Implements feature: not tested
Spec compliant: not tested
Documentation: not tested

PostgreSQL fails with SIGSEGV during `make check-world`.

Backtrace: http://afiskon.ru/s/d4/f3dc17838a_sigsegv.txt
regression.diffs (not very useful): http://afiskon.ru/s/ac/ac5294656c_regression.diffs.txt
regression.out: http://afiskon.ru/s/70/39d872e2b8_regression.out.txt
How to reproduce: https://github.com/afiskon/pgscripts/blob/master/full-build.sh

The environment is Arch Linux x64, gcc 7.1.1

The new status of this patch is: Waiting on Author

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

#5Emre Hasegeli
emre@hasegeli.com
In reply to: Aleksander Alekseev (#4)
4 attachment(s)
Re: [PATCH] Improve geometric types

PostgreSQL fails with SIGSEGV during `make check-world`.

Fixed. I am sorry for not running "check-world" before.

Attachments:

0001-geo-funcs-v2.patchapplication/octet-stream; name=0001-geo-funcs-v2.patchDownload
From a9a82d5e67f89d3466841ffc34719e0e1861050f Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 27 May 2017 11:27:18 -0400
Subject: [PATCH 1/4] geo-funcs-v2

Refactor geometric functions and operators code

Most of the geometric types were not using functions of each other's.
I believe the reason behind this is simpler types line point and line
being developed after more complicated ones.  This patch reduces duplicate
code and makes functions of different datatypes more compatible.  We can
do better than that, but it would require touching many more lines.
The changes can be summarised as:

* Re-use more functions to implement others
* Unify *_construct and *_interpt_internal functions to obtain
  pre-allocated memory
* Remove private functions from geo_decls.h
* Switch using C11 hypot() as the comment suggested
---
 src/backend/utils/adt/geo_ops.c | 810 +++++++++++++++++-----------------------
 src/include/utils/geo_decls.h   |  14 +-
 src/test/regress/regress.c      |  11 +-
 3 files changed, 346 insertions(+), 489 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 0348855b11..c43d02ac14 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -31,60 +31,68 @@
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
+/* Methods on point */
+static void point_construct(Point *result, float8 x, float8 y);
+static void point_add_internal(Point *result, Point *pt1, Point *pt2);
+static void point_sub_internal(Point *result, Point *pt1, Point *pt2);
+static void point_mul_internal(Point *result, Point *pt1, Point *pt2);
+static void point_div_internal(Point *result, Point *pt1, Point *pt2);
+static bool point_eq_internal(Point *pt1, Point *pt2);
+static float8 point_dt(Point *pt1, Point *pt2);
+static float8 point_sl(Point *pt1, Point *pt2);
 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);
+/* Methods on box */
+static void box_construct(BOX *result, float8 x1, float8 x2, float8 y1, float8 y2);
+static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
+static double box_ar(BOX *box);
 static double box_ht(BOX *box);
 static double box_wd(BOX *box);
+/* Methods on circle */
 static double circle_ar(CIRCLE *circle);
-static CIRCLE *circle_copy(CIRCLE *circle);
-static LINE *line_construct_pm(Point *pt, double m);
+/* Methods on line */
+static void line_construct_pm(LINE *result, Point *pt, float8 m);
 static void line_construct_pts(LINE *line, Point *pt1, Point *pt2);
-static bool lseg_intersect_internal(LSEG *l1, LSEG *l2);
-static double lseg_dt(LSEG *l1, LSEG *l2);
+static bool line_interpt_internal(Point *result, LINE *l1, LINE *l2);
+static float8 line_calculate_point(LINE *line, Point *pt);
+/* Methods on line segment */
+static bool lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line);
+static bool lseg_interpt_internal(Point *result, LSEG *l1, LSEG *l2);
+static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
+static float8 lseg_dt(LSEG *l1, LSEG *l2);
+static int	lseg_crossing(double x, double y, double px, double py);
+/* Others */
 static bool on_ps_internal(Point *pt, LSEG *lseg);
 static void make_bound_box(POLYGON *poly);
 static bool plist_same(int npts, Point *p1, Point *p2);
-static Point *point_construct(double x, double y);
-static Point *point_copy(Point *pt);
 static double single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
 static void pair_decode(char *str, double *x, double *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
 static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
 static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
-static double box_ar(BOX *box);
-static void box_cn(Point *center, BOX *box);
-static Point *interpt_sl(LSEG *lseg, LINE *line);
-static bool has_interpt_sl(LSEG *lseg, LINE *line);
 static double dist_pl_internal(Point *pt, LINE *line);
 static double dist_ps_internal(Point *pt, LSEG *lseg);
-static Point *line_interpt_internal(LINE *l1, LINE *l2);
-static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
-static Point *lseg_interpt_internal(LSEG *l1, LSEG *l2);
 static double dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 
 /*
  * Delimiters for input and output strings.
  * LDELIM, RDELIM, and DELIM are left, right, and separator delimiters, respectively.
  * LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints.
  */
 
 #define LDELIM			'('
@@ -434,33 +442,22 @@ box_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, box->high.x);
 	pq_sendfloat8(&buf, box->high.y);
 	pq_sendfloat8(&buf, box->low.x);
 	pq_sendfloat8(&buf, box->low.y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*		box_construct	-		fill in a new box.
  */
-static BOX *
-box_construct(double x1, double x2, double y1, double y2)
-{
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	return box_fill(result, x1, x2, y1, y2);
-}
-
-
-/*		box_fill		-		fill in a given box struct
- */
-static BOX *
-box_fill(BOX *result, double x1, double x2, double y1, double y2)
+static void
+box_construct(BOX *result, float8 x1, float8 x2, float8 y1, float8 y2)
 {
 	if (x1 > x2)
 	{
 		result->high.x = x1;
 		result->low.x = x2;
 	}
 	else
 	{
 		result->high.x = x2;
 		result->low.x = x1;
@@ -468,55 +465,38 @@ box_fill(BOX *result, double x1, double x2, double y1, double y2)
 	if (y1 > y2)
 	{
 		result->high.y = y1;
 		result->low.y = y2;
 	}
 	else
 	{
 		result->high.y = y2;
 		result->low.y = y1;
 	}
-
-	return result;
-}
-
-
-/*		box_copy		-		copy a box
- */
-static BOX *
-box_copy(BOX *box)
-{
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	memcpy((char *) result, (char *) box, sizeof(BOX));
-
-	return result;
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for BOXes.
  *		<, >, <=, >=, and == are based on box area.
  *---------------------------------------------------------*/
 
 /*		box_same		-		are two boxes identical?
  */
 Datum
 box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPeq(box1->high.x, box2->high.x) &&
-				   FPeq(box1->low.x, box2->low.x) &&
-				   FPeq(box1->high.y, box2->high.y) &&
-				   FPeq(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(point_eq_internal(&box1->high, &box2->high) &&
+				   point_eq_internal(&box1->low, &box2->low));
 }
 
 /*		box_overlap		-		does box1 overlap box2?
  */
 Datum
 box_overlap(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
@@ -751,51 +731,51 @@ box_area(PG_FUNCTION_ARGS)
 
 
 /*		box_width		-		returns the width of the box
  *								  (horizontal magnitude).
  */
 Datum
 box_width(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.x - box->low.x);
+	PG_RETURN_FLOAT8(box_wd(box));
 }
 
 
 /*		box_height		-		returns the height of the box
  *								  (vertical magnitude).
  */
 Datum
 box_height(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.y - box->low.y);
+	PG_RETURN_FLOAT8(box_ht(box));
 }
 
 
 /*		box_distance	-		returns the distance between the
  *								  center points of two boxes.
  */
 Datum
 box_distance(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 	Point		a,
 				b;
 
 	box_cn(&a, box1);
 	box_cn(&b, box2);
 
-	PG_RETURN_FLOAT8(HYPOT(a.x - b.x, a.y - b.y));
+	PG_RETURN_FLOAT8(point_dt(&a, &b));
 }
 
 
 /*		box_center		-		returns the center point of the box.
  */
 Datum
 box_center(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *result = (Point *) palloc(sizeof(Point));
@@ -934,22 +914,22 @@ line_in(PG_FUNCTION_ARGS)
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
 							"line", str)));
 		if (FPzero(line->A) && FPzero(line->B))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: A and B cannot both be zero")));
 	}
 	else
 	{
-		path_decode(s, true, 2, &(lseg.p[0]), &isopen, NULL, "line", str);
-		if (FPeq(lseg.p[0].x, lseg.p[1].x) && FPeq(lseg.p[0].y, lseg.p[1].y))
+		path_decode(s, true, 2, &lseg.p[0], &isopen, NULL, "line", str);
+		if (point_eq_internal(&lseg.p[0], &lseg.p[1]))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: must be two distinct points")));
 		line_construct_pts(line, &lseg.p[0], &lseg.p[1]);
 	}
 
 	PG_RETURN_LINE_P(line);
 }
 
 
@@ -1000,41 +980,37 @@ line_send(PG_FUNCTION_ARGS)
 
 
 /*----------------------------------------------------------
  *	Conversion routines from one line formula to internal.
  *		Internal form:	Ax+By+C=0
  *---------------------------------------------------------*/
 
 /* line_construct_pm()
  * point-slope
  */
-static LINE *
-line_construct_pm(Point *pt, double m)
+static void
+line_construct_pm(LINE *result, Point *pt, float8 m)
 {
-	LINE	   *result = (LINE *) palloc(sizeof(LINE));
-
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
 		result->A = -1;
 		result->B = 0;
 		result->C = pt->x;
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
 		result->C = pt->y - m * pt->x;
 	}
-
-	return result;
 }
 
 /*
  * Fill already-allocated LINE struct from two points on the line
  */
 static void
 line_construct_pts(LINE *line, Point *pt1, Point *pt2)
 {
 	if (FPeq(pt1->x, pt2->x))
 	{							/* vertical */
@@ -1052,21 +1028,21 @@ line_construct_pts(LINE *line, Point *pt1, Point *pt2)
 		line->A = 0;
 		line->B = -1;
 		line->C = pt1->y;
 #ifdef GEODEBUG
 		printf("line_construct_pts- line is horizontal\n");
 #endif
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
-		line->A = (pt2->y - pt1->y) / (pt2->x - pt1->x);
+		line->A = point_sl(pt2, pt1);
 		line->B = -1.0;
 		line->C = pt1->y - line->A * pt1->x;
 		/* on some platforms, the preceding expression tends to produce -0 */
 		if (line->C == 0.0)
 			line->C = 0.0;
 #ifdef GEODEBUG
 		printf("line_construct_pts- line is neither vertical nor horizontal (diffs x=%.*g, y=%.*g\n",
 			   DBL_DIG, (pt2->x - pt1->x), DBL_DIG, (pt2->y - pt1->y));
 #endif
 	}
@@ -1079,46 +1055,53 @@ Datum
 line_construct_pp(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 	LINE	   *result = (LINE *) palloc(sizeof(LINE));
 
 	line_construct_pts(result, pt1, pt2);
 	PG_RETURN_LINE_P(result);
 }
 
+/*
+ * Calculate the line equation for a point
+ *
+ * This returns the result of the line equation Ax + By + C.  The result
+ * needs to be 0 for the point to be on the line.
+ */
+static float8
+line_calculate_point(LINE *line, Point *pt)
+{
+	return line->A * pt->x + line->B * pt->y + line->C;
+}
+
 
 /*----------------------------------------------------------
  *	Relative position routines.
  *---------------------------------------------------------*/
 
 Datum
 line_intersect(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(!DatumGetBool(DirectFunctionCall2(line_parallel,
-													 LinePGetDatum(l1),
-													 LinePGetDatum(l2))));
+	PG_RETURN_BOOL(line_interpt_internal(NULL, l1, l2));
 }
 
 Datum
 line_parallel(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
-	if (FPzero(l1->B))
-		PG_RETURN_BOOL(FPzero(l2->B));
-
-	PG_RETURN_BOOL(FPeq(l2->A, l1->A * (l2->B / l1->B)));
+	PG_RETURN_BOOL(!line_interpt_internal(NULL, l1, l2));
 }
 
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
@@ -1172,96 +1155,94 @@ line_eq(PG_FUNCTION_ARGS)
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
-	Point	   *tmp;
+	Point		tmp;
 
-	if (!DatumGetBool(DirectFunctionCall2(line_parallel,
-										  LinePGetDatum(l1),
-										  LinePGetDatum(l2))))
+	if (line_interpt_internal(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
 		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
-	tmp = point_construct(0.0, l1->C);
-	result = dist_pl_internal(tmp, l2);
+	point_construct(&tmp, 0.0, l1->C);
+	result = dist_pl_internal(&tmp, l2);
 	PG_RETURN_FLOAT8(result);
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
-	result = line_interpt_internal(l1, l2);
+	result = (Point *) palloc(sizeof(Point));
 
-	if (result == NULL)
+	if (!line_interpt_internal(result, l1, l2))
 		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
 
 /*
  * Internal version of line_interpt
  *
- * returns a NULL pointer if no intersection point
+ * This returns true if two lines intersect (they do, if they are not
+ * parallel), false if they do not.  This also sets the intersection point
+ * to *result, if it is not NULL.
+ *
+ * NOTE: If the lines are identical then we will find they are parallel
+ * and report "no intersection".  This is a little weird, but since
+ * there's no *unique* intersection, maybe it's appropriate behavior.
  */
-static Point *
-line_interpt_internal(LINE *l1, LINE *l2)
+static bool
+line_interpt_internal(Point *result, LINE *l1, LINE *l2)
 {
-	Point	   *result;
 	double		x,
 				y;
 
-	/*
-	 * NOTE: if the lines are identical then we will find they are parallel
-	 * and report "no intersection".  This is a little weird, but since
-	 * there's no *unique* intersection, maybe it's appropriate behavior.
-	 */
-	if (DatumGetBool(DirectFunctionCall2(line_parallel,
-										 LinePGetDatum(l1),
-										 LinePGetDatum(l2))))
-		return NULL;
-
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
+		if (FPzero(l2->B))		/* l2 vertical? */
+			return false;
+
 		x = l1->C;
 		y = (l2->A * x + l2->C);
 	}
-	else if (FPzero(l2->B))		/* l2 vertical? */
-	{
-		x = l2->C;
-		y = (l1->A * x + l1->C);
-	}
 	else
 	{
-		x = (l1->C - l2->C) / (l2->A - l1->A);
+		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+			return false;
+
+		if (FPzero(l2->B))
+			x = l2->C;
+		else
+			x = (l1->C - l2->C) / (l2->A - l1->A);
 		y = (l1->A * x + l1->C);
 	}
-	result = point_construct(x, y);
+	if (result != NULL)
+		point_construct(result, x, y);
 
 #ifdef GEODEBUG
 	printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
 		   DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
 	printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
 #endif
 
-	return result;
+	return true;
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D paths (sequences of line segments, also
  **				called `polylines').
  **
  **				This is not a general package for geometric paths,
  **				which of course include polygons; the emphasis here
@@ -1609,21 +1590,21 @@ path_inter(PG_FUNCTION_ARGS)
 				jprev = j - 1;
 			else
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
-			if (lseg_intersect_internal(&seg1, &seg2))
+			if (lseg_interpt_internal(NULL, &seg1, &seg2))
 				PG_RETURN_BOOL(true);
 		}
 	}
 
 	/* if we dropped through, no two segs intersected */
 	PG_RETURN_BOOL(false);
 }
 
 /* path_distance()
  * This essentially does a cartesian product of the lsegs in the
@@ -1664,23 +1645,21 @@ path_distance(PG_FUNCTION_ARGS)
 			else
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
-			tmp = DatumGetFloat8(DirectFunctionCall2(lseg_distance,
-													 LsegPGetDatum(&seg1),
-													 LsegPGetDatum(&seg2)));
+			tmp = lseg_dt(&seg1, &seg2);
 			if (!have_min || tmp < min)
 			{
 				min = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	if (!have_min)
 		PG_RETURN_NULL();
@@ -1773,45 +1752,31 @@ point_send(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	StringInfoData buf;
 
 	pq_begintypsend(&buf);
 	pq_sendfloat8(&buf, pt->x);
 	pq_sendfloat8(&buf, pt->y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
-
-static Point *
-point_construct(double x, double y)
+/*
+ * Initialize a point
+ *
+ * This function is over-simple, but it is, at least, useful when the new
+ * point is calculated using the existing one.
+ */
+static void
+point_construct(Point *result, float8 x, float8 y)
 {
-	Point	   *result = (Point *) palloc(sizeof(Point));
-
 	result->x = x;
 	result->y = y;
-	return result;
-}
-
-
-static Point *
-point_copy(Point *pt)
-{
-	Point	   *result;
-
-	if (!PointerIsValid(pt))
-		return NULL;
-
-	result = (Point *) palloc(sizeof(Point));
-
-	result->x = pt->x;
-	result->y = pt->y;
-	return result;
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for Points.
  *		Since we do have a sense of coordinates being
  *		"equal" to a given accuracy (point_vert, point_horiz),
  *		the other ops must preserve that sense.  This means
  *		that results may, strictly speaking, be a lie (unless
  *		EPSILON = 0.0).
@@ -1870,66 +1835,74 @@ point_horiz(PG_FUNCTION_ARGS)
 
 	PG_RETURN_BOOL(FPeq(pt1->y, pt2->y));
 }
 
 Datum
 point_eq(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y));
+	PG_RETURN_BOOL(point_eq_internal(pt1, pt2));
 }
 
 Datum
 point_ne(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPne(pt1->x, pt2->x) || FPne(pt1->y, pt2->y));
+	PG_RETURN_BOOL(!point_eq_internal(pt1, pt2));
 }
 
+
+static bool
+point_eq_internal(Point *pt1, Point *pt2)
+{
+	return FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y);
+}
+
+
 /*----------------------------------------------------------
  *	"Arithmetic" operators on points.
  *---------------------------------------------------------*/
 
 Datum
 point_distance(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_FLOAT8(HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
+	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
-double
+static float8
 point_dt(Point *pt1, Point *pt2)
 {
 #ifdef GEODEBUG
 	printf("point_dt- segment (%f,%f),(%f,%f) length is %f\n",
 		   pt1->x, pt1->y, pt2->x, pt2->y, HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
 #endif
 	return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
 }
 
 Datum
 point_slope(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_sl(pt1, pt2));
 }
 
 
-double
+static float8
 point_sl(Point *pt1, Point *pt2)
 {
 	return (FPeq(pt1->x, pt2->x)
 			? (double) DBL_MAX
 			: (pt1->y - pt2->y) / (pt1->x - pt2->x));
 }
 
 
 /***********************************************************************
  **
@@ -1946,31 +1919,31 @@ point_sl(Point *pt1, Point *pt2)
  *		(old form)		"(x1, y1, x2, y2)"
  *---------------------------------------------------------*/
 
 Datum
 lseg_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	LSEG	   *lseg = (LSEG *) palloc(sizeof(LSEG));
 	bool		isopen;
 
-	path_decode(str, true, 2, &(lseg->p[0]), &isopen, NULL, "lseg", str);
+	path_decode(str, true, 2, &lseg->p[0], &isopen, NULL, "lseg", str);
 	PG_RETURN_LSEG_P(lseg);
 }
 
 
 Datum
 lseg_out(PG_FUNCTION_ARGS)
 {
 	LSEG	   *ls = PG_GETARG_LSEG_P(0);
 
-	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, (Point *) &(ls->p[0])));
+	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, &ls->p[0]));
 }
 
 /*
  *		lseg_recv			- converts external binary format to lseg
  */
 Datum
 lseg_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LSEG	   *lseg;
@@ -2046,39 +2019,23 @@ lseg_length(PG_FUNCTION_ARGS)
 /*
  **  find intersection of the two lines, and see if it falls on
  **  both segments.
  */
 Datum
 lseg_intersect(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(lseg_intersect_internal(l1, l2));
+	PG_RETURN_BOOL(lseg_interpt_internal(NULL, l1, l2));
 }
 
-static bool
-lseg_intersect_internal(LSEG *l1, LSEG *l2)
-{
-	LINE		ln;
-	Point	   *interpt;
-	bool		retval;
-
-	line_construct_pts(&ln, &l2->p[0], &l2->p[1]);
-	interpt = interpt_sl(l1, &ln);
-
-	if (interpt != NULL && on_ps_internal(interpt, l2))
-		retval = true;			/* interpt on l1 and l2 */
-	else
-		retval = false;
-	return retval;
-}
 
 Datum
 lseg_parallel(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_BOOL(FPeq(point_sl(&l1->p[0], &l1->p[1]),
 						point_sl(&l2->p[0], &l2->p[1])));
 }
@@ -2093,22 +2050,22 @@ lseg_parallel(PG_FUNCTION_ARGS)
  * - thomas 1998-01-31
  */
 Datum
 lseg_perp(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	double		m1,
 				m2;
 
-	m1 = point_sl(&(l1->p[0]), &(l1->p[1]));
-	m2 = point_sl(&(l2->p[0]), &(l2->p[1]));
+	m1 = point_sl(&l1->p[0], &l1->p[1]);
+	m2 = point_sl(&l2->p[0], &l2->p[1]);
 
 #ifdef GEODEBUG
 	printf("lseg_perp- slopes are %g and %g\n", m1, m2);
 #endif
 	if (FPzero(m1))
 		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
 	else if (FPzero(m2))
 		PG_RETURN_BOOL(FPeq(m1, DBL_MAX));
 
 	PG_RETURN_BOOL(FPeq(m1 / m2, -1.0));
@@ -2130,36 +2087,32 @@ lseg_horizontal(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(FPeq(lseg->p[0].y, lseg->p[1].y));
 }
 
 
 Datum
 lseg_eq(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPeq(l1->p[0].x, l2->p[0].x) &&
-				   FPeq(l1->p[0].y, l2->p[0].y) &&
-				   FPeq(l1->p[1].x, l2->p[1].x) &&
-				   FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(point_eq_internal(&l1->p[0], &l2->p[0]) &&
+				   point_eq_internal(&l1->p[1], &l2->p[1]));
 }
 
 Datum
 lseg_ne(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(!FPeq(l1->p[0].x, l2->p[0].x) ||
-				   !FPeq(l1->p[0].y, l2->p[0].y) ||
-				   !FPeq(l1->p[1].x, l2->p[1].x) ||
-				   !FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(!point_eq_internal(&l1->p[0], &l2->p[0]) ||
+				   !point_eq_internal(&l1->p[1], &l2->p[1]));
 }
 
 Datum
 lseg_lt(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_BOOL(FPlt(point_dt(&l1->p[0], &l1->p[1]),
 						point_dt(&l2->p[0], &l2->p[1])));
@@ -2218,21 +2171,21 @@ lseg_distance(PG_FUNCTION_ARGS)
  * Distance between two line segments.
  * Must check both sets of endpoints to ensure minimum distance is found.
  * - thomas 1998-02-01
  */
 static double
 lseg_dt(LSEG *l1, LSEG *l2)
 {
 	double		result,
 				d;
 
-	if (lseg_intersect_internal(l1, l2))
+	if (lseg_interpt_internal(NULL, l1, l2))
 		return 0.0;
 
 	d = dist_ps_internal(&l1->p[0], l2);
 	result = d;
 	d = dist_ps_internal(&l1->p[1], l2);
 	result = Min(result, d);
 	d = dist_ps_internal(&l2->p[0], l1);
 	result = Min(result, d);
 	d = dist_ps_internal(&l2->p[1], l1);
 	result = Min(result, d);
@@ -2248,82 +2201,86 @@ lseg_center(PG_FUNCTION_ARGS)
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
 	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
 
 	PG_RETURN_POINT_P(result);
 }
 
-static Point *
-lseg_interpt_internal(LSEG *l1, LSEG *l2)
+static bool
+lseg_interpt_internal(Point *result, LSEG *l1, LSEG *l2)
 {
-	Point	   *result;
+	Point		interpt;
 	LINE		tmp1,
 				tmp2;
 
 	/*
 	 * Find the intersection of the appropriate lines, if any.
 	 */
 	line_construct_pts(&tmp1, &l1->p[0], &l1->p[1]);
 	line_construct_pts(&tmp2, &l2->p[0], &l2->p[1]);
-	result = line_interpt_internal(&tmp1, &tmp2);
-	if (!PointerIsValid(result))
-		return NULL;
+	if (!line_interpt_internal(&interpt, &tmp1, &tmp2))
+		return false;
 
 	/*
 	 * If the line intersection point isn't within l1 (or equivalently l2),
 	 * there is no valid segment intersection point at all.
 	 */
-	if (!on_ps_internal(result, l1) ||
-		!on_ps_internal(result, l2))
-	{
-		pfree(result);
-		return NULL;
-	}
+	if (!on_ps_internal(&interpt, l1) ||
+		!on_ps_internal(&interpt, l2))
+		return false;
+
+	if (result == NULL)
+		return true;
 
 	/*
 	 * If there is an intersection, then check explicitly for matching
 	 * endpoints since there may be rounding effects with annoying lsb
 	 * residue. - tgl 1997-07-09
 	 */
 	if ((FPeq(l1->p[0].x, l2->p[0].x) && FPeq(l1->p[0].y, l2->p[0].y)) ||
 		(FPeq(l1->p[0].x, l2->p[1].x) && FPeq(l1->p[0].y, l2->p[1].y)))
 	{
 		result->x = l1->p[0].x;
 		result->y = l1->p[0].y;
 	}
 	else if ((FPeq(l1->p[1].x, l2->p[0].x) && FPeq(l1->p[1].y, l2->p[0].y)) ||
 			 (FPeq(l1->p[1].x, l2->p[1].x) && FPeq(l1->p[1].y, l2->p[1].y)))
 	{
 		result->x = l1->p[1].x;
 		result->y = l1->p[1].y;
 	}
+	else
+	{
+		result->x = interpt.x;
+		result->y = interpt.y;
+	}
 
-	return result;
+	return true;
 }
 
 /* lseg_interpt -
  *		Find the intersection point of two segments (if any).
  */
 Datum
 lseg_interpt(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
-	result = lseg_interpt_internal(l1, l2);
-	if (!PointerIsValid(result))
-		PG_RETURN_NULL();
+	result = (Point *) palloc(sizeof(Point));
 
+	if (!lseg_interpt_internal(result, l1, l2))
+		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
 
 /***********************************************************************
  **
  **		Routines for position comparisons of differently-typed
  **				2D objects.
  **
  ***********************************************************************/
 
@@ -2340,75 +2297,75 @@ dist_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
 	PG_RETURN_FLOAT8(dist_pl_internal(pt, line));
 }
 
 static double
 dist_pl_internal(Point *pt, LINE *line)
 {
-	return fabs((line->A * pt->x + line->B * pt->y + line->C) /
+	return fabs(line_calculate_point(line, pt) /
 				HYPOT(line->A, line->B));
 }
 
 /*
  * Distance from a point to a lseg
  */
 Datum
 dist_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_FLOAT8(dist_ps_internal(pt, lseg));
 }
 
 static double
 dist_ps_internal(Point *pt, LSEG *lseg)
 {
 	double		m;				/* slope of perp. */
-	LINE	   *ln;
 	double		result,
 				tmpdist;
-	Point	   *ip;
+	Point		interpt;
+	LINE		ln;
 
 	/*
 	 * Construct a line perpendicular to the input segment and through the
 	 * input point
 	 */
 	if (lseg->p[1].x == lseg->p[0].x)
 		m = 0;
 	else if (lseg->p[1].y == lseg->p[0].y)
 		m = (double) DBL_MAX;	/* slope is infinite */
 	else
-		m = (lseg->p[0].x - lseg->p[1].x) / (lseg->p[1].y - lseg->p[0].y);
-	ln = line_construct_pm(pt, m);
+		m = -1.0 / point_sl(&lseg->p[0], &lseg->p[1]);
+	line_construct_pm(&ln, pt, m);
 
 #ifdef GEODEBUG
 	printf("dist_ps- line is A=%g B=%g C=%g from (point) slope (%f,%f) %g\n",
 		   ln->A, ln->B, ln->C, pt->x, pt->y, m);
 #endif
 
 	/*
 	 * Calculate distance to the line segment or to the nearest endpoint of
 	 * the segment.
 	 */
 
 	/* intersection is on the line segment? */
-	if ((ip = interpt_sl(lseg, ln)) != NULL)
+	if (lseg_interpt_line_internal(&interpt, lseg, &ln))
 	{
 		/* yes, so use distance to the intersection point */
-		result = point_dt(pt, ip);
+		result = point_dt(pt, &interpt);
 #ifdef GEODEBUG
 		printf("dist_ps- distance is %f to intersection point is (%f,%f)\n",
-			   result, ip->x, ip->y);
+			   result, tmp.x, tmp.y);
 #endif
 	}
 	else
 	{
 		/* no, so use distance to the nearer endpoint */
 		result = point_dt(pt, &lseg->p[0]);
 		tmpdist = point_dt(pt, &lseg->p[1]);
 		if (tmpdist < result)
 			result = tmpdist;
 	}
@@ -2496,21 +2453,21 @@ dist_pb(PG_FUNCTION_ARGS)
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	float8		result,
 				d2;
 
-	if (has_interpt_sl(lseg, line))
+	if (lseg_interpt_line_internal(NULL, lseg, line))
 		result = 0.0;
 	else
 	{
 		result = dist_pl_internal(&lseg->p[0], line);
 		d2 = dist_pl_internal(&lseg->p[1], line);
 		/* XXX shouldn't we take the min not max? */
 		if (d2 > result)
 			result = d2;
 	}
 
@@ -2649,284 +2606,261 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
  *				Intersection point of objects.
  *				We choose to ignore the "point" of intersection between
  *				  lines and boxes, since there are typically two.
  *-------------------------------------------------------------------*/
 
-/* Get intersection point of lseg and line; returns NULL if no intersection */
-static Point *
-interpt_sl(LSEG *lseg, LINE *line)
+/*
+ * Check if the line segment intersects with the line
+ *
+ * It sets the intersection point to *result, if it is not NULL.
+ */
+static bool
+lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line)
 {
+	Point		interpt;
 	LINE		tmp;
-	Point	   *p;
 
 	line_construct_pts(&tmp, &lseg->p[0], &lseg->p[1]);
-	p = line_interpt_internal(&tmp, line);
 #ifdef GEODEBUG
-	printf("interpt_sl- segment is (%.*g %.*g) (%.*g %.*g)\n",
+	printf("lseg_interpt_line- segment is (%.*g %.*g) (%.*g %.*g)\n",
 		   DBL_DIG, lseg->p[0].x, DBL_DIG, lseg->p[0].y, DBL_DIG, lseg->p[1].x, DBL_DIG, lseg->p[1].y);
-	printf("interpt_sl- segment becomes line A=%.*g B=%.*g C=%.*g\n",
+	printf("lseg_interpt_line_- segment becomes line A=%.*g B=%.*g C=%.*g\n",
 		   DBL_DIG, tmp.A, DBL_DIG, tmp.B, DBL_DIG, tmp.C);
 #endif
-	if (PointerIsValid(p))
+	if (line_interpt_internal(&interpt, &tmp, line))
 	{
 #ifdef GEODEBUG
-		printf("interpt_sl- intersection point is (%.*g %.*g)\n", DBL_DIG, p->x, DBL_DIG, p->y);
+		printf("lseg_interpt_line- intersection point is (%.*g %.*g)\n", DBL_DIG, p->x, DBL_DIG, p->y);
 #endif
-		if (on_ps_internal(p, lseg))
+		if (on_ps_internal(&interpt, lseg))
 		{
 #ifdef GEODEBUG
-			printf("interpt_sl- intersection point is on segment\n");
+			printf("lseg_interpt_line- intersection point is on segment\n");
 #endif
+			if (result != NULL)
+				*result = interpt;
+			return true;
 		}
-		else
-			p = NULL;
 	}
 
-	return p;
-}
-
-/* variant: just indicate if intersection point exists */
-static bool
-has_interpt_sl(LSEG *lseg, LINE *line)
-{
-	Point	   *tmp;
-
-	tmp = interpt_sl(lseg, line);
-	if (tmp)
-		return true;
 	return false;
 }
 
+
 /*---------------------------------------------------------------------
  *		close_
  *				Point of closest proximity between objects.
  *-------------------------------------------------------------------*/
 
 /* close_pl -
  *		The intersection point of a perpendicular of the line
  *		through the point.
  */
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
-	LINE	   *tmp;
 	double		invm;
+	LINE		tmp;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (FPzero(line->B))		/* vertical? */
 	{
 		result->x = line->C;
 		result->y = pt->y;
 		PG_RETURN_POINT_P(result);
 	}
 	if (FPzero(line->A))		/* horizontal? */
 	{
 		result->x = pt->x;
 		result->y = line->C;
 		PG_RETURN_POINT_P(result);
 	}
 	/* drop a perpendicular and find the intersection point */
 
 	/* invert and flip the sign on the slope to get a perpendicular */
 	invm = line->B / line->A;
-	tmp = line_construct_pm(pt, invm);
-	result = line_interpt_internal(tmp, line);
-	Assert(result != NULL);
+	line_construct_pm(&tmp, pt, invm);
+	line_interpt_internal(result, &tmp, line);
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_ps()
  * Closest point on line segment to specified point.
  * Take the closest endpoint if the point is left, right,
  *	above, or below the segment, otherwise find the intersection
  *	point of the segment and its perpendicular through the point.
  *
  * Some tricky code here, relying on boolean expressions
  *	evaluating to only zero or one to use as an array index.
  *		bug fixes by gthaker@atl.lmco.com; May 1, 1998
  */
 Datum
 close_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
-	LINE	   *tmp;
+	Point	   *result;
 	double		invm;
 	int			xh,
 				yh;
+	LINE		tmp;
+
+	result = (Point *) palloc(sizeof(Point));
 
 #ifdef GEODEBUG
 	printf("close_sp:pt->x %f pt->y %f\nlseg(0).x %f lseg(0).y %f  lseg(1).x %f lseg(1).y %f\n",
 		   pt->x, pt->y, lseg->p[0].x, lseg->p[0].y,
 		   lseg->p[1].x, lseg->p[1].y);
 #endif
 
 	/* xh (or yh) is the index of upper x( or y) end point of lseg */
 	/* !xh (or !yh) is the index of lower x( or y) end point of lseg */
 	xh = lseg->p[0].x < lseg->p[1].x;
 	yh = lseg->p[0].y < lseg->p[1].y;
 
 	if (FPeq(lseg->p[0].x, lseg->p[1].x))	/* vertical? */
 	{
 #ifdef GEODEBUG
 		printf("close_ps- segment is vertical\n");
 #endif
 		/* first check if point is below or above the entire lseg. */
 		if (pt->y < lseg->p[!yh].y)
-			result = point_copy(&lseg->p[!yh]); /* below the lseg */
+			*result = lseg->p[!yh];		/* below the lseg */
 		else if (pt->y > lseg->p[yh].y)
-			result = point_copy(&lseg->p[yh]);	/* above the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
+			*result = lseg->p[yh];		/* above the lseg */
+		else
+			/* point lines along (to left or right) of the vertical lseg. */
+			point_construct(result, lseg->p[0].x, pt->y);
 
-		/* point lines along (to left or right) of the vertical lseg. */
-
-		result = (Point *) palloc(sizeof(Point));
-		result->x = lseg->p[0].x;
-		result->y = pt->y;
 		PG_RETURN_POINT_P(result);
 	}
 	else if (FPeq(lseg->p[0].y, lseg->p[1].y))	/* horizontal? */
 	{
 #ifdef GEODEBUG
 		printf("close_ps- segment is horizontal\n");
 #endif
 		/* first check if point is left or right of the entire lseg. */
 		if (pt->x < lseg->p[!xh].x)
-			result = point_copy(&lseg->p[!xh]); /* left of the lseg */
+			*result = lseg->p[!xh];		/* left of the lseg */
 		else if (pt->x > lseg->p[xh].x)
-			result = point_copy(&lseg->p[xh]);	/* right of the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
+			*result = lseg->p[xh];		/* right of the lseg */
+		else
+			/* point lines along (at top or below) the horiz. lseg. */
+			point_construct(result, pt->x, lseg->p[0].y);
 
-		/* point lines along (at top or below) the horiz. lseg. */
-		result = (Point *) palloc(sizeof(Point));
-		result->x = pt->x;
-		result->y = lseg->p[0].y;
 		PG_RETURN_POINT_P(result);
 	}
 
 	/*
 	 * vert. and horiz. cases are down, now check if the closest point is one
 	 * of the end points or someplace on the lseg.
 	 */
 
 	invm = -1.0 / point_sl(&(lseg->p[0]), &(lseg->p[1]));
-	tmp = line_construct_pm(&lseg->p[!yh], invm);	/* lower edge of the
+	line_construct_pm(&tmp, &lseg->p[!yh], invm);	/* lower edge of the
 													 * "band" */
-	if (pt->y < (tmp->A * pt->x + tmp->C))
+	if (pt->y < (tmp.A * pt->x + tmp.C))
 	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[!yh]); /* below the lseg, take lower end
-											 * pt */
+		*result = lseg->p[!yh];	/* below the lseg, take lower end pt */
 #ifdef GEODEBUG
 		printf("close_ps below: tmp A %f  B %f   C %f\n",
 			   tmp->A, tmp->B, tmp->C);
 #endif
 		PG_RETURN_POINT_P(result);
 	}
-	tmp = line_construct_pm(&lseg->p[yh], invm);	/* upper edge of the
+	line_construct_pm(&tmp, &lseg->p[yh], invm);	/* upper edge of the
 													 * "band" */
-	if (pt->y > (tmp->A * pt->x + tmp->C))
+	if (pt->y > (tmp.A * pt->x + tmp.C))
 	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[yh]);	/* above the lseg, take higher end
-											 * pt */
+		*result = lseg->p[yh];	/* above the lseg, take higher end pt */
 #ifdef GEODEBUG
 		printf("close_ps above: tmp A %f  B %f   C %f\n",
 			   tmp->A, tmp->B, tmp->C);
 #endif
 		PG_RETURN_POINT_P(result);
 	}
 
 	/*
 	 * at this point the "normal" from point will hit lseg. The closest point
 	 * will be somewhere on the lseg
 	 */
-	tmp = line_construct_pm(pt, invm);
+	line_construct_pm(&tmp, pt, invm);
 #ifdef GEODEBUG
 	printf("close_ps- tmp A %f  B %f   C %f\n",
 		   tmp->A, tmp->B, tmp->C);
 #endif
-	result = interpt_sl(lseg, tmp);
 
 	/*
 	 * ordinarily we should always find an intersection point, but that could
 	 * fail in the presence of NaN coordinates, and perhaps even from simple
 	 * roundoff issues.  Return a SQL NULL if so.
 	 */
-	if (result == NULL)
+	if (!lseg_interpt_line_internal(result, lseg, &tmp))
 		PG_RETURN_NULL();
 
 #ifdef GEODEBUG
 	printf("close_ps- result.x %f  result.y %f\n", result->x, result->y);
 #endif
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_lseg()
  * Closest point to l1 on l2.
  */
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
-	Point		point;
-	double		dist;
-	double		d;
+	Point	   *result;
+	double		dist,
+				dist0,
+				dist1;
 
-	d = dist_ps_internal(&l1->p[0], l2);
-	dist = d;
-	memcpy(&point, &l1->p[0], sizeof(Point));
-
-	if ((d = dist_ps_internal(&l1->p[1], l2)) < dist)
-	{
-		dist = d;
-		memcpy(&point, &l1->p[1], sizeof(Point));
-	}
+	dist0 = dist_ps_internal(&l1->p[0], l2);
+	dist1 = dist_ps_internal(&l1->p[1], l2);
+	dist = Min(dist0, dist1);
 
 	if (dist_ps_internal(&l2->p[0], l1) < dist)
 	{
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(&l2->p[0]),
 													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
+													PointPGetDatum(result),
 													LsegPGetDatum(l2)));
 	}
-
-	if (dist_ps_internal(&l2->p[1], l1) < dist)
+	else if (dist_ps_internal(&l2->p[1], l1) < dist)
 	{
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(&l2->p[1]),
 													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
+													PointPGetDatum(result),
 													LsegPGetDatum(l2)));
 	}
-
-	if (result == NULL)
-		result = point_copy(&point);
+	else
+	{
+		result = (Point *) palloc(sizeof(Point));
+		*result = l1->p[dist == dist0 ? 0 : 1];
+	}
 
 	PG_RETURN_POINT_P(result);
 }
 
 /* close_pb()
  * Closest point on or in box to specified point.
  */
 Datum
 close_pb(PG_FUNCTION_ARGS)
 {
@@ -2989,30 +2923,31 @@ close_pb(PG_FUNCTION_ARGS)
 Datum
 close_sl(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 	float8		d1,
 				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
+	result = (Point *) palloc(sizeof(Point));
+
+	if (lseg_interpt_line_internal(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = dist_pl_internal(&lseg->p[0], line);
 	d2 = dist_pl_internal(&lseg->p[1], line);
 	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
+		*result = lseg->p[0];
 	else
-		result = point_copy(&lseg->p[1]);
+		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
 
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_sl\" not implemented")));
 
 	PG_RETURN_NULL();
 }
@@ -3022,30 +2957,31 @@ close_sl(PG_FUNCTION_ARGS)
  */
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 	float8		d1,
 				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
+	result = (Point *) palloc(sizeof(Point));
+
+	if (lseg_interpt_line_internal(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = dist_pl_internal(&lseg->p[0], line);
 	d2 = dist_pl_internal(&lseg->p[1], line);
 	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
+		*result = lseg->p[0];
 	else
-		result = point_copy(&lseg->p[1]);
+		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 }
 
 /* close_sb()
  * Closest point on or in box to line segment.
  */
 Datum
 close_sb(PG_FUNCTION_ARGS)
 {
@@ -3126,21 +3062,21 @@ close_lb(PG_FUNCTION_ARGS)
 
 /* on_pl -
  *		Does the point satisfy the equation?
  */
 Datum
 on_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(FPzero(line->A * pt->x + line->B * pt->y + line->C));
+	PG_RETURN_BOOL(FPzero(line_calculate_point(line, pt)));
 }
 
 
 /* on_ps -
  *		Determine colinearity by detecting a triangle inequality.
  * This algorithm seems to behave nicely even with lsb residues - tgl 1997-07-09
  */
 Datum
 on_ps(PG_FUNCTION_ARGS)
 {
@@ -3250,21 +3186,21 @@ on_sb(PG_FUNCTION_ARGS)
  *		inter_
  *				Whether one object intersects another.
  *-------------------------------------------------------------------*/
 
 Datum
 inter_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(has_interpt_sl(lseg, line));
+	PG_RETURN_BOOL(lseg_interpt_line_internal(NULL, lseg, line));
 }
 
 /* inter_sb()
  * Do line segment and box intersect?
  *
  * Segment completely inside box counts as intersection.
  * If you want only segments crossing box boundaries,
  *	try converting box to path first.
  *
  * Optimize for non-intersection by checking for box intersection first.
@@ -3294,35 +3230,35 @@ inter_sb(PG_FUNCTION_ARGS)
 										 BoxPGetDatum(box))) ||
 		DatumGetBool(DirectFunctionCall2(on_pb,
 										 PointPGetDatum(&lseg->p[1]),
 										 BoxPGetDatum(box))))
 		PG_RETURN_BOOL(true);
 
 	/* pairwise check lseg intersections */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
+	if (lseg_interpt_internal(NULL, &bseg, lseg))
 		PG_RETURN_BOOL(true);
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
+	if (lseg_interpt_internal(NULL, &bseg, lseg))
 		PG_RETURN_BOOL(true);
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
+	if (lseg_interpt_internal(NULL, &bseg, lseg))
 		PG_RETURN_BOOL(true);
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
+	if (lseg_interpt_internal(NULL, &bseg, lseg))
 		PG_RETURN_BOOL(true);
 
 	/* if we dropped through, no two segs intersected */
 	PG_RETURN_BOOL(false);
 }
 
 /* inter_lb()
  * Do line and box intersect?
  */
 Datum
@@ -3333,36 +3269,36 @@ inter_lb(PG_FUNCTION_ARGS)
 	LSEG		bseg;
 	Point		p1,
 				p2;
 
 	/* pairwise check lseg intersections */
 	p1.x = box->low.x;
 	p1.y = box->low.y;
 	p2.x = box->low.x;
 	p2.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line_internal(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->high.x;
 	p1.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line_internal(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p2.x = box->high.x;
 	p2.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line_internal(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->low.x;
 	p1.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line_internal(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 
 	/* if we dropped through, no intersection */
 	PG_RETURN_BOOL(false);
 }
 
 /*------------------------------------------------------------------
  * The following routines define a data type and operator class for
  * POLYGONS .... Part of which (the polygon's bounding box) is built on
  * top of the BOX data type.
@@ -3391,21 +3327,21 @@ make_bound_box(POLYGON *poly)
 			if (poly->p[i].x < x1)
 				x1 = poly->p[i].x;
 			if (poly->p[i].x > x2)
 				x2 = poly->p[i].x;
 			if (poly->p[i].y < y1)
 				y1 = poly->p[i].y;
 			if (poly->p[i].y > y2)
 				y2 = poly->p[i].y;
 		}
 
-		box_fill(&(poly->boundbox), x1, x2, y1, y2);
+		box_construct(&poly->boundbox, x1, x2, y1, y2);
 	}
 	else
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("cannot create bounding box for empty polygon")));
 }
 
 /*------------------------------------------------------------------
  * poly_in - read in the polygon from a string specification
  *
@@ -3742,21 +3678,21 @@ poly_same(PG_FUNCTION_ARGS)
  *-----------------------------------------------------------------*/
 Datum
 poly_overlap(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
 	/* Quick check by bounding box */
 	result = (polya->npts > 0 && polyb->npts > 0 &&
-			  box_ov(&polya->boundbox, &polyb->boundbox)) ? true : false;
+			  box_ov(&polya->boundbox, &polyb->boundbox));
 
 	/*
 	 * Brute-force algorithm - try to find intersected edges, if so then
 	 * polygons are overlapped else check is one polygon inside other or not
 	 * by testing single point of them.
 	 */
 	if (result)
 	{
 		int			ia,
 					ib;
@@ -3771,34 +3707,33 @@ poly_overlap(PG_FUNCTION_ARGS)
 		{
 			/* Second point of polya's edge is a current one */
 			sa.p[1] = polya->p[ia];
 
 			/* Init first of polyb's edge with last point */
 			sb.p[0] = polyb->p[polyb->npts - 1];
 
 			for (ib = 0; ib < polyb->npts && result == false; ib++)
 			{
 				sb.p[1] = polyb->p[ib];
-				result = lseg_intersect_internal(&sa, &sb);
+				result = lseg_interpt_internal(NULL, &sa, &sb);
 				sb.p[0] = sb.p[1];
 			}
 
 			/*
 			 * move current endpoint to the first point of next edge
 			 */
 			sa.p[0] = sa.p[1];
 		}
 
 		if (result == false)
 		{
-			result = (point_inside(polya->p, polyb->npts, polyb->p)
-					  ||
+			result = (point_inside(polya->p, polyb->npts, polyb->p) ||
 					  point_inside(polyb->p, polya->npts, polya->p));
 		}
 	}
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
@@ -3818,27 +3753,26 @@ poly_overlap(PG_FUNCTION_ARGS)
 
 static bool
 touched_lseg_inside_poly(Point *a, Point *b, LSEG *s, POLYGON *poly, int start)
 {
 	/* point a is on s, b is not */
 	LSEG		t;
 
 	t.p[0] = *a;
 	t.p[1] = *b;
 
-#define POINTEQ(pt1, pt2)	(FPeq((pt1)->x, (pt2)->x) && FPeq((pt1)->y, (pt2)->y))
-	if (POINTEQ(a, s->p))
+	if (point_eq_internal(a, s->p))
 	{
 		if (on_ps_internal(s->p + 1, &t))
 			return lseg_inside_poly(b, s->p + 1, poly, start);
 	}
-	else if (POINTEQ(a, s->p + 1))
+	else if (point_eq_internal(a, s->p + 1))
 	{
 		if (on_ps_internal(s->p, &t))
 			return lseg_inside_poly(b, s->p, poly, start);
 	}
 	else if (on_ps_internal(s->p, &t))
 	{
 		return lseg_inside_poly(b, s->p, poly, start);
 	}
 	else if (on_ps_internal(s->p + 1, &t))
 	{
@@ -3861,50 +3795,49 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 	int			i;
 	bool		res = true,
 				intersection = false;
 
 	t.p[0] = *a;
 	t.p[1] = *b;
 	s.p[0] = poly->p[(start == 0) ? (poly->npts - 1) : (start - 1)];
 
 	for (i = start; i < poly->npts && res; i++)
 	{
-		Point	   *interpt;
+		Point		interpt;
 
 		CHECK_FOR_INTERRUPTS();
 
 		s.p[1] = poly->p[i];
 
 		if (on_ps_internal(t.p, &s))
 		{
 			if (on_ps_internal(t.p + 1, &s))
 				return true;	/* t is contained by s */
 
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p, t.p + 1, &s, poly, i + 1);
 		}
 		else if (on_ps_internal(t.p + 1, &s))
 		{
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p + 1, t.p, &s, poly, i + 1);
 		}
-		else if ((interpt = lseg_interpt_internal(&t, &s)) != NULL)
+		else if (lseg_interpt_internal(&interpt, &t, &s))
 		{
 			/*
 			 * segments are X-crossing, go to check each subsegment
 			 */
 
 			intersection = true;
-			res = lseg_inside_poly(t.p, interpt, poly, i + 1);
+			res = lseg_inside_poly(t.p, &interpt, poly, i + 1);
 			if (res)
-				res = lseg_inside_poly(t.p + 1, interpt, poly, i + 1);
-			pfree(interpt);
+				res = lseg_inside_poly(t.p + 1, &interpt, poly, i + 1);
 		}
 
 		s.p[0] = s.p[1];
 	}
 
 	if (res && !intersection)
 	{
 		Point		p;
 
 		/*
@@ -4019,170 +3952,205 @@ poly_distance(PG_FUNCTION_ARGS)
  **
  **		Routines for 2D points.
  **
  ***********************************************************************/
 
 Datum
 construct_point(PG_FUNCTION_ARGS)
 {
 	float8		x = PG_GETARG_FLOAT8(0);
 	float8		y = PG_GETARG_FLOAT8(1);
+	Point	   *result;
 
-	PG_RETURN_POINT_P(point_construct(x, y));
+	result = (Point *) palloc(sizeof(Point));
+
+	point_construct(result, x, y);
+
+	PG_RETURN_POINT_P(result);
 }
 
 Datum
 point_add(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x + p2->x);
-	result->y = (p1->y + p2->y);
+	point_add_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+static void
+point_add_internal(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x + pt2->x,
+					pt1->y + pt2->y);
+}
+
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x - p2->x);
-	result->y = (p1->y - p2->y);
+	point_sub_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+static void
+point_sub_internal(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x - pt2->x,
+					pt1->y - pt2->y);
+}
+
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x * p2->x) - (p1->y * p2->y);
-	result->y = (p1->x * p2->y) + (p1->y * p2->x);
+	point_mul_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+static void
+point_mul_internal(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					(pt1->x * pt2->x) - (pt1->y * pt2->y),
+					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+}
+
 Datum
 point_div(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
-	double		div;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	div = (p2->x * p2->x) + (p2->y * p2->y);
-
-	if (div == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result->x = ((p1->x * p2->x) + (p1->y * p2->y)) / div;
-	result->y = ((p2->x * p1->y) - (p2->y * p1->x)) / div;
+	point_div_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+static void
+point_div_internal(Point *result, Point *pt1, Point *pt2)
+{
+	float8		div;
+
+	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
+	point_construct(result,
+					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
+					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+}
+
 
 /***********************************************************************
  **
  **		Routines for 2D boxes.
  **
  ***********************************************************************/
 
 Datum
 points_box(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct(p1->x, p2->x, p1->y, p2->y));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	box_construct(result, p1->x, p2->x, p1->y, p2->y);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_add(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct((box->high.x + p->x),
-								  (box->low.x + p->x),
-								  (box->high.y + p->y),
-								  (box->low.y + p->y)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_add_internal(&result->high, &box->high, p);
+	point_add_internal(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_sub(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct((box->high.x - p->x),
-								  (box->low.x - p->x),
-								  (box->high.y - p->y),
-								  (box->low.y - p->y)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_sub_internal(&result->high, &box->high, p);
+	point_sub_internal(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_mul(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
 
-	high = DatumGetPointP(DirectFunctionCall2(point_mul,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_mul,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	result = (BOX *) palloc(sizeof(BOX));
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	point_mul_internal(&high, &box->high, p);
+	point_mul_internal(&low, &box->low, p);
+
+	box_construct(result, high.x, low.x, high.y, low.y);
 
 	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_div(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
 
-	high = DatumGetPointP(DirectFunctionCall2(point_div,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_div,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	result = (BOX *) palloc(sizeof(BOX));
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	point_div_internal(&high, &box->high, p);
+	point_div_internal(&low, &box->low, p);
+
+	box_construct(result, high.x, low.x, high.y, low.y);
 
 	PG_RETURN_BOX_P(result);
 }
 
 /*
  * Convert point to empty box
  */
 Datum
 point_box(PG_FUNCTION_ARGS)
 {
@@ -4278,83 +4246,63 @@ path_add(PG_FUNCTION_ARGS)
  * Translation operators.
  */
 Datum
 path_add_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x += point->x;
-		path->p[i].y += point->y;
-	}
+		point_add_internal(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_sub_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x -= point->x;
-		path->p[i].y -= point->y;
-	}
+		point_sub_internal(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 /* path_mul_pt()
  * Rotation and scaling operators.
  */
 Datum
 path_mul_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_mul,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_mul_internal(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_div_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_div,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_div_internal(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 
 Datum
 path_center(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	PATH	   *path = PG_GETARG_PATH_P(0);
@@ -4436,21 +4384,22 @@ poly_center(PG_FUNCTION_ARGS)
 
 Datum
 poly_box(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	BOX		   *box;
 
 	if (poly->npts < 1)
 		PG_RETURN_NULL();
 
-	box = box_copy(&poly->boundbox);
+	box = (BOX *) palloc(sizeof(BOX));
+	*box = poly->boundbox;
 
 	PG_RETURN_BOX_P(box);
 }
 
 
 /* box_poly()
  * Convert a box to a polygon.
  */
 Datum
 box_poly(PG_FUNCTION_ARGS)
@@ -4468,22 +4417,22 @@ box_poly(PG_FUNCTION_ARGS)
 
 	poly->p[0].x = box->low.x;
 	poly->p[0].y = box->low.y;
 	poly->p[1].x = box->low.x;
 	poly->p[1].y = box->high.y;
 	poly->p[2].x = box->high.x;
 	poly->p[2].y = box->high.y;
 	poly->p[3].x = box->high.x;
 	poly->p[3].y = box->low.y;
 
-	box_fill(&poly->boundbox, box->high.x, box->low.x,
-			 box->high.y, box->low.y);
+	box_construct(&poly->boundbox, box->high.x, box->low.x,
+				  box->high.y, box->low.y);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
 
 Datum
 poly_path(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	PATH	   *path;
@@ -4492,21 +4441,21 @@ poly_path(PG_FUNCTION_ARGS)
 
 	/*
 	 * Never overflows: the old size fit in MaxAllocSize, and the new size is
 	 * smaller by a small constant.
 	 */
 	size = offsetof(PATH, p) + sizeof(path->p[0]) * poly->npts;
 	path = (PATH *) palloc(size);
 
 	SET_VARSIZE(path, size);
 	path->npts = poly->npts;
-	path->closed = TRUE;
+	path->closed = true;
 	/* prevent instability in unused pad bytes */
 	path->dummy = 0;
 
 	for (i = 0; i < poly->npts; i++)
 	{
 		path->p[i].x = poly->p[i].x;
 		path->p[i].y = poly->p[i].y;
 	}
 
 	PG_RETURN_PATH_P(path);
@@ -4558,22 +4507,21 @@ circle_in(PG_FUNCTION_ARGS)
 
 	circle->radius = single_decode(s, &s, "circle", str);
 	if (circle->radius < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
 
 	while (depth > 0)
 	{
-		if ((*s == RDELIM)
-			|| ((*s == RDELIM_C) && (depth == 1)))
+		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
 			s++;
 			while (isspace((unsigned char) *s))
 				s++;
 		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
@@ -4657,22 +4605,21 @@ circle_send(PG_FUNCTION_ARGS)
 
 /*		circles identical?
  */
 Datum
 circle_same(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPeq(circle1->radius, circle2->radius) &&
-				   FPeq(circle1->center.x, circle2->center.x) &&
-				   FPeq(circle1->center.y, circle2->center.y));
+				   point_eq_internal(&circle1->center, &circle2->center));
 }
 
 /*		circle_overlap	-		does circle1 overlap circle2?
  */
 Datum
 circle_overlap(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
@@ -4859,106 +4806,82 @@ circle_ge(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPge(circle_ar(circle1), circle_ar(circle2)));
 }
 
 
 /*----------------------------------------------------------
  *	"Arithmetic" operators on circles.
  *---------------------------------------------------------*/
 
-static CIRCLE *
-circle_copy(CIRCLE *circle)
-{
-	CIRCLE	   *result;
-
-	if (!PointerIsValid(circle))
-		return NULL;
-
-	result = (CIRCLE *) palloc(sizeof(CIRCLE));
-	memcpy((char *) result, (char *) circle, sizeof(CIRCLE));
-	return result;
-}
-
-
 /* circle_add_pt()
  * Translation operator.
  */
 Datum
 circle_add_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x += point->x;
-	result->center.y += point->y;
+	point_add_internal(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_sub_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x -= point->x;
-	result->center.y -= point->y;
+	point_sub_internal(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /* circle_mul_pt()
  * Rotation and scaling operators.
  */
 Datum
 circle_mul_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_mul,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
+	point_mul_internal(&result->center, &circle->center, point);
 	result->radius *= HYPOT(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_div_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_div,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
+	point_div_internal(&result->center, &circle->center, point);
 	result->radius /= HYPOT(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /*		circle_area		-		returns the area of the circle.
  */
 Datum
 circle_area(PG_FUNCTION_ARGS)
@@ -5372,118 +5295,55 @@ lseg_crossing(double x, double y, double prev_x, double prev_y)
 static bool
 plist_same(int npts, Point *p1, Point *p2)
 {
 	int			i,
 				ii,
 				j;
 
 	/* find match for first point */
 	for (i = 0; i < npts; i++)
 	{
-		if ((FPeq(p2[i].x, p1[0].x))
-			&& (FPeq(p2[i].y, p1[0].y)))
+		if (point_eq_internal(&p2[i], &p1[0]))
 		{
 
 			/* match found? then look forward through remaining points */
 			for (ii = 1, j = i + 1; ii < npts; ii++, j++)
 			{
 				if (j >= npts)
 					j = 0;
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_internal(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed forward match with %d\n", j, ii);
 #endif
 					break;
 				}
 			}
 #ifdef GEODEBUG
 			printf("plist_same- ii = %d/%d after forward match\n", ii, npts);
 #endif
 			if (ii == npts)
-				return TRUE;
+				return true;
 
 			/* match not found forwards? then look backwards */
 			for (ii = 1, j = i - 1; ii < npts; ii++, j--)
 			{
 				if (j < 0)
 					j = (npts - 1);
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_internal(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed reverse match with %d\n", j, ii);
 #endif
 					break;
 				}
 			}
 #ifdef GEODEBUG
 			printf("plist_same- ii = %d/%d after reverse match\n", ii, npts);
 #endif
 			if (ii == npts)
-				return TRUE;
+				return true;
 		}
 	}
 
-	return FALSE;
-}
-
-
-/*-------------------------------------------------------------------------
- * Determine the hypotenuse.
- *
- * If required, x and y are swapped to make x the larger number. The
- * traditional formula of x^2+y^2 is rearranged to factor x outside the
- * sqrt. This allows computation of the hypotenuse for significantly
- * larger values, and with a higher precision than when using the naive
- * formula.  In particular, this cannot overflow unless the final result
- * would be out-of-range.
- *
- * sqrt( x^2 + y^2 ) = sqrt( x^2( 1 + y^2/x^2) )
- *					 = x * sqrt( 1 + y^2/x^2 )
- *					 = x * sqrt( 1 + y/x * y/x )
- *
- * It is expected that this routine will eventually be replaced with the
- * C99 hypot() function.
- *
- * This implementation conforms to IEEE Std 1003.1 and GLIBC, in that the
- * case of hypot(inf,nan) results in INF, and not NAN.
- *-----------------------------------------------------------------------
- */
-double
-pg_hypot(double x, double y)
-{
-	double		yx;
-
-	/* Handle INF and NaN properly */
-	if (isinf(x) || isinf(y))
-		return get_float8_infinity();
-
-	if (isnan(x) || isnan(y))
-		return get_float8_nan();
-
-	/* Else, drop any minus signs */
-	x = fabs(x);
-	y = fabs(y);
-
-	/* Swap x and y if needed to make x the larger one */
-	if (x < y)
-	{
-		double		temp = x;
-
-		x = y;
-		y = temp;
-	}
-
-	/*
-	 * If y is zero, the hypotenuse is x.  This test saves a few cycles in
-	 * such cases, but more importantly it also protects against
-	 * divide-by-zero errors, since now x >= y.
-	 */
-	if (y == 0.0)
-		return x;
-
-	/* Determine the hypotenuse */
-	yx = y / x;
-	return x * sqrt(1.0 + (yx * yx));
+	return false;
 }
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 44c6381b85..90119a0158 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -43,21 +43,21 @@
 #else
 #define FPzero(A)				((A) == 0)
 #define FPeq(A,B)				((A) == (B))
 #define FPne(A,B)				((A) != (B))
 #define FPlt(A,B)				((A) < (B))
 #define FPle(A,B)				((A) <= (B))
 #define FPgt(A,B)				((A) > (B))
 #define FPge(A,B)				((A) >= (B))
 #endif
 
-#define HYPOT(A, B)				pg_hypot(A, B)
+#define HYPOT(A, B)				hypot(A, B)
 
 /*---------------------------------------------------------------------
  * Point - (x,y)
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	double		x,
 				y;
 } Point;
 
@@ -166,21 +166,11 @@ typedef struct
 #define PolygonPGetDatum(X)			PointerGetDatum(X)
 #define PG_GETARG_POLYGON_P(n)		DatumGetPolygonP(PG_GETARG_DATUM(n))
 #define PG_GETARG_POLYGON_P_COPY(n) DatumGetPolygonPCopy(PG_GETARG_DATUM(n))
 #define PG_RETURN_POLYGON_P(x)		return PolygonPGetDatum(x)
 
 #define DatumGetCircleP(X)	  ((CIRCLE *) DatumGetPointer(X))
 #define CirclePGetDatum(X)	  PointerGetDatum(X)
 #define PG_GETARG_CIRCLE_P(n) DatumGetCircleP(PG_GETARG_DATUM(n))
 #define PG_RETURN_CIRCLE_P(x) return CirclePGetDatum(x)
 
-
-/*
- * 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 */
+#endif   /* GEO_DECLS_H */
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index 734947cc98..6988500067 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -62,21 +62,23 @@ regress_dist_ptpath(PG_FUNCTION_ARGS)
 	float8		result = 0.0;	/* keep compiler quiet */
 	float8		tmp;
 	int			i;
 	LSEG		lseg;
 
 	switch (path->npts)
 	{
 		case 0:
 			PG_RETURN_NULL();
 		case 1:
-			result = point_dt(pt, &path->p[0]);
+			result = DatumGetFloat8(DirectFunctionCall2(point_distance,
+														PointPGetDatum(pt),
+												PointPGetDatum(&path->p[0])));
 			break;
 		default:
 
 			/*
 			 * the distance from a point to a path is the smallest distance
 			 * from the point to any of its constituent segments.
 			 */
 			Assert(path->npts > 1);
 			for (i = 0; i < path->npts - 1; ++i)
 			{
@@ -280,22 +282,27 @@ widget_out(PG_FUNCTION_ARGS)
 	PG_RETURN_CSTRING(str);
 }
 
 PG_FUNCTION_INFO_V1(pt_in_widget);
 
 Datum
 pt_in_widget(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	WIDGET	   *widget = (WIDGET *) PG_GETARG_POINTER(1);
+	float8		distance;
 
-	PG_RETURN_BOOL(point_dt(point, &widget->center) < widget->radius);
+	distance = DatumGetFloat8(DirectFunctionCall2(point_distance,
+												  PointPGetDatum(point),
+											PointPGetDatum(&widget->center)));
+
+	PG_RETURN_BOOL(distance < widget->radius);
 }
 
 PG_FUNCTION_INFO_V1(boxarea);
 
 Datum
 boxarea(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	double		width,
 				height;
-- 
2.11.0 (Apple Git-81)

0002-float-header-v06.patchapplication/octet-stream; name=0002-float-header-v06.patchDownload
From 8d2df385e2f32cbcec1d8933844f9a48bed1e001 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 28 May 2016 18:16:05 +0200
Subject: [PATCH 2/4] float-header-v06

Provide header file for built-in float datatypes

Even though, some datatypes under adt/ have separate header files,
most of the simple ones do not.  Their public functions were on
the builtins.h.  We would need to make more functions of floats public
to let the geometric types built on top of them.  This is a good
opportunity to make a separate header file for floats.

1acf7572554515b99ef6e783750aaea8777524ec made _cmp functions public
to solve NaN problem locally for GiST indexes.  This patch reworks it
in favour of a more extensive API.  Kevin Grittner suggested to design
the API using inline functions.  They are easier to use compared
to macros, and avoid double-evaluation hazards.
---
 contrib/btree_gin/btree_gin.c                 |   2 +
 contrib/btree_gist/btree_ts.c                 |   1 +
 contrib/cube/cube.c                           |   2 +-
 contrib/cube/cubeparse.y                      |   2 +-
 contrib/postgres_fdw/postgres_fdw.c           |   1 +
 src/backend/access/gist/gistget.c             |   2 +-
 src/backend/access/gist/gistproc.c            |  55 +--
 src/backend/access/gist/gistutil.c            |   2 +-
 src/backend/utils/adt/float.c                 | 593 ++++++--------------------
 src/backend/utils/adt/formatting.c            |   8 +-
 src/backend/utils/adt/geo_ops.c               |   6 +-
 src/backend/utils/adt/geo_spgist.c            |   2 +-
 src/backend/utils/adt/numeric.c               |   1 +
 src/backend/utils/adt/rangetypes_gist.c       |   3 +-
 src/backend/utils/adt/rangetypes_selfuncs.c   |   3 +-
 src/backend/utils/adt/rangetypes_typanalyze.c |   3 +-
 src/backend/utils/adt/timestamp.c             |   1 +
 src/backend/utils/misc/guc.c                  |   1 +
 src/include/utils/builtins.h                  |  14 -
 src/include/utils/float.h                     | 383 +++++++++++++++++
 src/include/utils/geo_decls.h                 |   1 +
 21 files changed, 562 insertions(+), 524 deletions(-)
 create mode 100644 src/include/utils/float.h

diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index 2473f79ca1..c27eabc696 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -3,20 +3,22 @@
  */
 #include "postgres.h"
 
 #include <limits.h>
 
 #include "access/stratnum.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/cash.h"
 #include "utils/date.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/inet.h"
 #include "utils/numeric.h"
 #include "utils/timestamp.h"
 #include "utils/varbit.h"
 
 PG_MODULE_MAGIC;
 
 typedef struct QueryInfo
 {
 	StrategyNumber strategy;
diff --git a/contrib/btree_gist/btree_ts.c b/contrib/btree_gist/btree_ts.c
index 1582cff102..6e77ebab0d 100644
--- a/contrib/btree_gist/btree_ts.c
+++ b/contrib/btree_gist/btree_ts.c
@@ -2,20 +2,21 @@
  * contrib/btree_gist/btree_ts.c
  */
 #include "postgres.h"
 
 #include <limits.h>
 
 #include "btree_gist.h"
 #include "btree_utils_num.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 typedef struct
 {
 	Timestamp	lower;
 	Timestamp	upper;
 } tsKEY;
 
 /*
 ** timestamp ops
 */
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c
index 149558c763..c94fc93ffd 100644
--- a/contrib/cube/cube.c
+++ b/contrib/cube/cube.c
@@ -7,21 +7,21 @@
 ******************************************************************************/
 
 #include "postgres.h"
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 
 #include "cubedata.h"
 
 PG_MODULE_MAGIC;
 
 /*
  * Taken from the intarray contrib header
  */
 #define ARRPTR(x)  ( (double *) ARR_DATA_PTR(x) )
 #define ARRNELEMS(x)  ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x))
diff --git a/contrib/cube/cubeparse.y b/contrib/cube/cubeparse.y
index 1b65fa967c..deb2efdc0d 100644
--- a/contrib/cube/cubeparse.y
+++ b/contrib/cube/cubeparse.y
@@ -1,20 +1,20 @@
 %{
 /* contrib/cube/cubeparse.y */
 
 /* NdBox = [(lowerleft),(upperright)] */
 /* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */
 
 #include "postgres.h"
 
 #include "cubedata.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 
 /* All grammar constructs return strings */
 #define YYSTYPE char *
 
 /*
  * Bison doesn't allocate anything that needs to live across parser calls,
  * so we can easily have it use palloc instead of malloc.  This prevents
  * memory leaks if we error out during parsing.  Note this only works with
  * bison >= 2.0.  However, in bison 1.875 the default is to use alloca()
  * if possible, so there's not really much problem anyhow, at least if
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 32dc4e6301..d4dfa532a0 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -28,20 +28,21 @@
 #include "optimizer/cost.h"
 #include "optimizer/clauses.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
 #include "optimizer/planmain.h"
 #include "optimizer/restrictinfo.h"
 #include "optimizer/var.h"
 #include "optimizer/tlist.h"
 #include "parser/parsetree.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 #include "utils/sampling.h"
 #include "utils/selfuncs.h"
 
 PG_MODULE_MAGIC;
 
 /* Default CPU cost to start up a foreign query. */
diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c
index 760ea0c997..9828587add 100644
--- a/src/backend/access/gist/gistget.c
+++ b/src/backend/access/gist/gistget.c
@@ -13,21 +13,21 @@
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/gist_private.h"
 #include "access/relscan.h"
 #include "catalog/pg_type.h"
 #include "miscadmin.h"
 #include "pgstat.h"
 #include "lib/pairingheap.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 
 /*
  * gistkillitems() -- set LP_DEAD state for items an indexscan caller has
  * told us were killed.
  *
  * We re-read page here, so it's important to check page LSN. If the page
  * has been modified since the last read (as determined by LSN), we cannot
  * flag any entries because it is possible that the old entry was vacuumed
diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index 08990f5a1b..c1ea88f90d 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -27,62 +27,53 @@
 
 
 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
 						 StrategyNumber strategy);
 static bool rtree_internal_consistent(BOX *key, BOX *query,
 						  StrategyNumber strategy);
 
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
 
-/* Convenience macros for NaN-aware comparisons */
-#define FLOAT8_EQ(a,b)	(float8_cmp_internal(a, b) == 0)
-#define FLOAT8_LT(a,b)	(float8_cmp_internal(a, b) < 0)
-#define FLOAT8_LE(a,b)	(float8_cmp_internal(a, b) <= 0)
-#define FLOAT8_GT(a,b)	(float8_cmp_internal(a, b) > 0)
-#define FLOAT8_GE(a,b)	(float8_cmp_internal(a, b) >= 0)
-#define FLOAT8_MAX(a,b)  (FLOAT8_GT(a, b) ? (a) : (b))
-#define FLOAT8_MIN(a,b)  (FLOAT8_LT(a, b) ? (a) : (b))
-
 
 /**************************************************
  * Box ops
  **************************************************/
 
 /*
  * Calculates union of two boxes, a and b. The result is stored in *n.
  */
 static void
 rt_box_union(BOX *n, const BOX *a, const BOX *b)
 {
-	n->high.x = FLOAT8_MAX(a->high.x, b->high.x);
-	n->high.y = FLOAT8_MAX(a->high.y, b->high.y);
-	n->low.x = FLOAT8_MIN(a->low.x, b->low.x);
-	n->low.y = FLOAT8_MIN(a->low.y, b->low.y);
+	n->high.x = float8_max(a->high.x, b->high.x);
+	n->high.y = float8_max(a->high.y, b->high.y);
+	n->low.x = float8_min(a->low.x, b->low.x);
+	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
 static double
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
-	if (FLOAT8_LE(box->high.x, box->low.x) ||
-		FLOAT8_LE(box->high.y, box->low.y))
+	if (float8_le(box->high.x, box->low.x) ||
+		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
 	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
@@ -137,27 +128,27 @@ gist_box_consistent(PG_FUNCTION_ARGS)
 												 query,
 												 strategy));
 }
 
 /*
  * Increase BOX b to include addon.
  */
 static void
 adjustBox(BOX *b, const BOX *addon)
 {
-	if (FLOAT8_LT(b->high.x, addon->high.x))
+	if (float8_lt(b->high.x, addon->high.x))
 		b->high.x = addon->high.x;
-	if (FLOAT8_GT(b->low.x, addon->low.x))
+	if (float8_gt(b->low.x, addon->low.x))
 		b->low.x = addon->low.x;
-	if (FLOAT8_LT(b->high.y, addon->high.y))
+	if (float8_lt(b->high.y, addon->high.y))
 		b->high.y = addon->high.y;
-	if (FLOAT8_GT(b->low.y, addon->low.y))
+	if (float8_gt(b->low.y, addon->low.y))
 		b->low.y = addon->low.y;
 }
 
 /*
  * The GiST Union method for boxes
  *
  * returns the minimal bounding box that encloses all the entries in entryvec
  */
 Datum
 gist_box_union(PG_FUNCTION_ARGS)
@@ -637,36 +628,36 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		i1 = 0;
 		i2 = 0;
 		rightLower = intervalsLower[i1].lower;
 		leftUpper = intervalsUpper[i2].lower;
 		while (true)
 		{
 			/*
 			 * Find next lower bound of right group.
 			 */
 			while (i1 < nentries &&
-				   FLOAT8_EQ(rightLower, intervalsLower[i1].lower))
+				   float8_eq(rightLower, intervalsLower[i1].lower))
 			{
-				if (FLOAT8_LT(leftUpper, intervalsLower[i1].upper))
+				if (float8_lt(leftUpper, intervalsLower[i1].upper))
 					leftUpper = intervalsLower[i1].upper;
 				i1++;
 			}
 			if (i1 >= nentries)
 				break;
 			rightLower = intervalsLower[i1].lower;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * left group.
 			 */
 			while (i2 < nentries &&
-				   FLOAT8_LE(intervalsUpper[i2].upper, leftUpper))
+				   float8_le(intervalsUpper[i2].upper, leftUpper))
 				i2++;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim, rightLower, i1, leftUpper, i2);
 		}
 
 		/*
 		 * Iterate over upper bound of left group finding greatest possible
@@ -674,35 +665,35 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		 */
 		i1 = nentries - 1;
 		i2 = nentries - 1;
 		rightLower = intervalsLower[i1].upper;
 		leftUpper = intervalsUpper[i2].upper;
 		while (true)
 		{
 			/*
 			 * Find next upper bound of left group.
 			 */
-			while (i2 >= 0 && FLOAT8_EQ(leftUpper, intervalsUpper[i2].upper))
+			while (i2 >= 0 && float8_eq(leftUpper, intervalsUpper[i2].upper))
 			{
-				if (FLOAT8_GT(rightLower, intervalsUpper[i2].lower))
+				if (float8_gt(rightLower, intervalsUpper[i2].lower))
 					rightLower = intervalsUpper[i2].lower;
 				i2--;
 			}
 			if (i2 < 0)
 				break;
 			leftUpper = intervalsUpper[i2].upper;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * right group.
 			 */
-			while (i1 >= 0 && FLOAT8_GE(intervalsLower[i1].lower, rightLower))
+			while (i1 >= 0 && float8_ge(intervalsLower[i1].lower, rightLower))
 				i1--;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim,
 								 rightLower, i1 + 1, leftUpper, i2 + 1);
 		}
 	}
 
@@ -776,42 +767,42 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
 		}
 		else
 		{
 			lower = box->low.y;
 			upper = box->high.y;
 		}
 
-		if (FLOAT8_LE(upper, context.leftUpper))
+		if (float8_le(upper, context.leftUpper))
 		{
 			/* Fits to the left group */
-			if (FLOAT8_GE(lower, context.rightLower))
+			if (float8_ge(lower, context.rightLower))
 			{
 				/* Fits also to the right group, so "common entry" */
 				commonEntries[commonEntriesCount++].index = i;
 			}
 			else
 			{
 				/* Doesn't fit to the right group, so join to the left group */
 				PLACE_LEFT(box, i);
 			}
 		}
 		else
 		{
 			/*
 			 * Each entry should fit on either left or right group. Since this
 			 * entry didn't fit on the left group, it better fit in the right
 			 * group.
 			 */
-			Assert(FLOAT8_GE(lower, context.rightLower));
+			Assert(float8_ge(lower, context.rightLower));
 
 			/* Doesn't fit to the left group, so join to the right group */
 			PLACE_RIGHT(box, i);
 		}
 	}
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
@@ -881,24 +872,24 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
  * equivalent to box_same().
  */
 Datum
 gist_box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *b1 = PG_GETARG_BOX_P(0);
 	BOX		   *b2 = PG_GETARG_BOX_P(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
 	if (b1 && b2)
-		*result = (FLOAT8_EQ(b1->low.x, b2->low.x) &&
-				   FLOAT8_EQ(b1->low.y, b2->low.y) &&
-				   FLOAT8_EQ(b1->high.x, b2->high.x) &&
-				   FLOAT8_EQ(b1->high.y, b2->high.y));
+		*result = (float8_eq(b1->low.x, b2->low.x) &&
+				   float8_eq(b1->low.y, b2->low.y) &&
+				   float8_eq(b1->high.x, b2->high.x) &&
+				   float8_eq(b1->high.y, b2->high.y));
 	else
 		*result = (b1 == NULL && b2 == NULL);
 	PG_RETURN_POINTER(result);
 }
 
 /*
  * Leaf-level consistency for boxes: just apply the query operator
  */
 static bool
 gist_box_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy)
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index b6ccc1a66a..8792257c01 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -15,21 +15,21 @@
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist_private.h"
 #include "access/htup_details.h"
 #include "access/reloptions.h"
 #include "catalog/pg_opclass.h"
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/syscache.h"
 
 
 /*
  * Write itup vector to page, has no control of free space.
  */
 void
 gistfillbuffer(Page page, IndexTuple *itup, int len, OffsetNumber off)
 {
 	OffsetNumber l = InvalidOffsetNumber;
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index 18b3b949ac..7359278737 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -15,62 +15,25 @@
 #include "postgres.h"
 
 #include <ctype.h>
 #include <float.h>
 #include <math.h>
 #include <limits.h>
 
 #include "catalog/pg_type.h"
 #include "libpq/pqformat.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/sortsupport.h"
 
 
-#ifndef M_PI
-/* from my RH5.2 gcc math.h file - thomas 2000-04-03 */
-#define M_PI 3.14159265358979323846
-#endif
-
-/* Radians per degree, a.k.a. PI / 180 */
-#define RADIANS_PER_DEGREE 0.0174532925199432957692
-
-/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0.  NAN definition from
- * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfNotNumberNANItems.asp
- */
-#if defined(WIN32) && !defined(NAN)
-static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
-
-#define NAN (*(const double *) nan)
-#endif
-
-/* not sure what the following should be, but better to make it over-sufficient */
-#define MAXFLOATWIDTH	64
-#define MAXDOUBLEWIDTH	128
-
-/*
- * check to see if a float4/8 val has underflowed or overflowed
- */
-#define CHECKFLOATVAL(val, inf_is_valid, zero_is_valid)			\
-do {															\
-	if (isinf(val) && !(inf_is_valid))							\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		  errmsg("value out of range: overflow")));				\
-																\
-	if ((val) == 0.0 && !(zero_is_valid))						\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		 errmsg("value out of range: underflow")));				\
-} while(0)
-
-
 /* Configurable GUC parameter */
 int			extra_float_digits = 0; /* Added to DBL_DIG or FLT_DIG */
 
 /* Cached constants for degree-based trig functions */
 static bool degree_consts_set = false;
 static float8 sin_30 = 0;
 static float8 one_minus_cos_60 = 0;
 static float8 asin_0_5 = 0;
 static float8 acos_0_5 = 0;
 static float8 atan_1_0 = 0;
@@ -102,100 +65,20 @@ static void init_degree_constants(void);
  * their compilers spit up at the mismatch between extern declaration
  * and static definition.  We work around that here by the expedient
  * of a #define to make the actual name of the static function different.
  */
 #define cbrt my_cbrt
 static double cbrt(double x);
 #endif							/* HAVE_CBRT */
 
 
 /*
- * Routines to provide reasonably platform-independent handling of
- * infinity and NaN.  We assume that isinf() and isnan() are available
- * and work per spec.  (On some platforms, we have to supply our own;
- * see src/port.)  However, generating an Infinity or NaN in the first
- * place is less well standardized; pre-C99 systems tend not to have C99's
- * INFINITY and NAN macros.  We centralize our workarounds for this here.
- */
-
-double
-get_float8_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (double) INFINITY;
-#else
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (double) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-/*
-* The funny placements of the two #pragmas is necessary because of a
-* long lived bug in the Microsoft compilers.
-* See http://support.microsoft.com/kb/120968/en-us for details
-*/
-#if (_MSC_VER >= 1800)
-#pragma warning(disable:4756)
-#endif
-float
-get_float4_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (float) INFINITY;
-#else
-#if (_MSC_VER >= 1800)
-#pragma warning(default:4756)
-#endif
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (float) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-double
-get_float8_nan(void)
-{
-	/* (double) NAN doesn't work on some NetBSD/MIPS releases */
-#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
-	/* C99 standard way */
-	return (double) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (double) (0.0 / 0.0);
-#endif
-}
-
-float
-get_float4_nan(void)
-{
-#ifdef NAN
-	/* C99 standard way */
-	return (float) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (float) (0.0 / 0.0);
-#endif
-}
-
-
-/*
  * Returns -1 if 'val' represents negative infinity, 1 if 'val'
  * represents (positive) infinity, and 0 otherwise. On some platforms,
  * this is equivalent to the isinf() macro, but not everywhere: C99
  * does not specify that isinf() needs to distinguish between positive
  * and negative infinity.
  */
 int
 is_infinite(double val)
 {
 	int			inf = isinf(val);
@@ -339,21 +222,21 @@ float4in(PG_FUNCTION_ARGS)
 	if (*endptr != '\0')
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"real", orig_num)));
 
 	/*
 	 * if we get here, we have a legal double, still need to check to see if
 	 * it's a legal float4
 	 */
-	CHECKFLOATVAL((float4) val, isinf(val), val == 0);
+	check_float4_val((float4) val, isinf(val), val == 0);
 
 	PG_RETURN_FLOAT4((float4) val);
 }
 
 /*
  *		float4out		- converts a float4 number to a string
  *						  using a standard output format
  */
 Datum
 float4out(PG_FUNCTION_ARGS)
@@ -689,35 +572,35 @@ float4up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT4(arg);
 }
 
 Datum
 float4larger(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) > 0)
+	if (float4_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 Datum
 float4smaller(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) < 0)
+	if (float4_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 /*
  *		======================
  *		FLOAT8 BASE OPERATIONS
  *		======================
@@ -756,35 +639,35 @@ float8up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT8(arg);
 }
 
 Datum
 float8larger(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) > 0)
+	if (float8_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 Datum
 float8smaller(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) < 0)
+	if (float8_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		====================
  *		ARITHMETIC OPERATORS
@@ -795,234 +678,165 @@ float8smaller(PG_FUNCTION_ARGS)
  *		float4pl		- returns arg1 + arg2
  *		float4mi		- returns arg1 - arg2
  *		float4mul		- returns arg1 * arg2
  *		float4div		- returns arg1 / arg2
  */
 Datum
 float4pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 + arg2;
-
-	/*
-	 * There isn't any way to check for underflow of addition/subtraction
-	 * because numbers near the underflow value have already been rounded to
-	 * the point where we can't detect that the two values were originally
-	 * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
-	 * 1.4013e-45.
-	 */
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_pl(arg1, arg2));
 }
 
 Datum
 float4mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mi(arg1, arg2));
 }
 
 Datum
 float4mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mul(arg1, arg2));
 }
 
 Datum
 float4div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_div(arg1, arg2));
 }
 
 /*
  *		float8pl		- returns arg1 + arg2
  *		float8mi		- returns arg1 - arg2
  *		float8mul		- returns arg1 * arg2
  *		float8div		- returns arg1 / arg2
  */
 Datum
 float8pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 + arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, arg2));
 }
 
 Datum
 float8mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 - arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, arg2));
 }
 
 Datum
 float8mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 * arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, arg2));
 }
 
 Datum
 float8div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, arg2));
 }
 
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float4{eq,ne,lt,le,gt,ge}		- float4/float4 comparison operations
  */
 int
 float4_cmp_internal(float4 a, float4 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float4_gt(a, b))
+		return 1;
+	if (float4_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
 float4eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float4_eq(arg1, arg2));
 }
 
 Datum
 float4ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float4_ne(arg1, arg2));
 }
 
 Datum
 float4lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float4_lt(arg1, arg2));
 }
 
 Datum
 float4le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float4_le(arg1, arg2));
 }
 
 Datum
 float4gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float4_gt(arg1, arg2));
 }
 
 Datum
 float4ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float4_ge(arg1, arg2));
 }
 
 Datum
 btfloat4cmp(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
 	PG_RETURN_INT32(float4_cmp_internal(arg1, arg2));
 }
@@ -1044,99 +858,79 @@ btfloat4sortsupport(PG_FUNCTION_ARGS)
 	ssup->comparator = btfloat4fastcmp;
 	PG_RETURN_VOID();
 }
 
 /*
  *		float8{eq,ne,lt,le,gt,ge}		- float8/float8 comparison operations
  */
 int
 float8_cmp_internal(float8 a, float8 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float8_gt(a, b))
+		return 1;
+	if (float8_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
 float8eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, arg2));
 }
 
 Datum
 float8ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, arg2));
 }
 
 Datum
 float8lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, arg2));
 }
 
 Datum
 float8le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, arg2));
 }
 
 Datum
 float8gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, arg2));
 }
 
 Datum
 float8ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, arg2));
 }
 
 Datum
 btfloat8cmp(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
 	PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
 }
@@ -1199,21 +993,21 @@ ftod(PG_FUNCTION_ARGS)
 
 
 /*
  *		dtof			- converts a float8 number to a float4 number
  */
 Datum
 dtof(PG_FUNCTION_ARGS)
 {
 	float8		num = PG_GETARG_FLOAT8(0);
 
-	CHECKFLOATVAL((float4) num, isinf(num), num == 0);
+	check_float4_val((float4) num, isinf(num), num == 0);
 
 	PG_RETURN_FLOAT4((float4) num);
 }
 
 
 /*
  *		dtoi4			- converts a float8 number to an int4 number
  */
 Datum
 dtoi4(PG_FUNCTION_ARGS)
@@ -1424,36 +1218,36 @@ dsqrt(PG_FUNCTION_ARGS)
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
 				 errmsg("cannot take square root of a negative number")));
 
 	result = sqrt(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcbrt			- returns cube root of arg1
  */
 Datum
 dcbrt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	result = cbrt(arg1);
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dpow			- returns pow(arg1,arg2)
  */
 Datum
 dpow(PG_FUNCTION_ARGS)
 {
@@ -1492,40 +1286,40 @@ dpow(PG_FUNCTION_ARGS)
 			/* The sign of Inf is not significant in this case. */
 			result = get_float8_infinity();
 		else if (fabs(arg1) != 1)
 			result = 0;
 		else
 			result = 1;
 	}
 	else if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
+	check_float8_val(result, isinf(arg1) || isinf(arg2), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dexp			- returns the exponential function of arg1
  */
 Datum
 dexp(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	errno = 0;
 	result = exp(arg1);
 	if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1), false);
+	check_float8_val(result, isinf(arg1), false);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dlog1			- returns the natural logarithm of arg1
  */
 Datum
 dlog1(PG_FUNCTION_ARGS)
 {
@@ -1540,21 +1334,21 @@ dlog1(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of zero")));
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of a negative number")));
 
 	result = log(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dlog10			- returns the base 10 logarithm of arg1
  */
 Datum
 dlog10(PG_FUNCTION_ARGS)
 {
@@ -1570,21 +1364,21 @@ dlog10(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of zero")));
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of a negative number")));
 
 	result = log10(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dacos			- returns the arccos of arg1 (radians)
  */
 Datum
 dacos(PG_FUNCTION_ARGS)
 {
@@ -1600,21 +1394,21 @@ dacos(PG_FUNCTION_ARGS)
 	 * range [-1, 1] to values in the range [0, Pi], so we should reject any
 	 * inputs outside that range and the result will always be finite.
 	 */
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = acos(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dasin			- returns the arcsin of arg1 (radians)
  */
 Datum
 dasin(PG_FUNCTION_ARGS)
 {
@@ -1630,21 +1424,21 @@ dasin(PG_FUNCTION_ARGS)
 	 * range [-1, 1] to values in the range [-Pi/2, Pi/2], so we should reject
 	 * any inputs outside that range and the result will always be finite.
 	 */
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = asin(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		datan			- returns the arctan of arg1 (radians)
  */
 Datum
 datan(PG_FUNCTION_ARGS)
 {
@@ -1655,21 +1449,21 @@ datan(PG_FUNCTION_ARGS)
 	if (isnan(arg1))
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/*
 	 * The principal branch of the inverse tangent function maps all inputs to
 	 * values in the range [-Pi/2, Pi/2], so the result should always be
 	 * finite, even if the input is infinite.
 	 */
 	result = atan(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		atan2			- returns the arctan of arg1/arg2 (radians)
  */
 Datum
 datan2(PG_FUNCTION_ARGS)
 {
@@ -1680,21 +1474,21 @@ datan2(PG_FUNCTION_ARGS)
 	/* Per the POSIX spec, return NaN if either input is NaN */
 	if (isnan(arg1) || isnan(arg2))
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/*
 	 * atan2 maps all inputs to values in the range [-Pi, Pi], so the result
 	 * should always be finite, even if the inputs are infinite.
 	 */
 	result = atan2(arg1, arg2);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcos			- returns the cosine of arg1 (radians)
  */
 Datum
 dcos(PG_FUNCTION_ARGS)
 {
@@ -1720,21 +1514,21 @@ dcos(PG_FUNCTION_ARGS)
 	 * platform reports via errno, so also explicitly test for infinite
 	 * inputs.
 	 */
 	errno = 0;
 	result = cos(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcot			- returns the cotangent of arg1 (radians)
  */
 Datum
 dcot(PG_FUNCTION_ARGS)
 {
@@ -1747,21 +1541,21 @@ dcot(PG_FUNCTION_ARGS)
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = tan(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = 1.0 / result;
-	CHECKFLOATVAL(result, true /* cot(0) == Inf */ , true);
+	check_float8_val(result, true /* cot(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dsin			- returns the sine of arg1 (radians)
  */
 Datum
 dsin(PG_FUNCTION_ARGS)
 {
@@ -1773,21 +1567,21 @@ dsin(PG_FUNCTION_ARGS)
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = sin(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dtan			- returns the tangent of arg1 (radians)
  */
 Datum
 dtan(PG_FUNCTION_ARGS)
 {
@@ -1799,21 +1593,21 @@ dtan(PG_FUNCTION_ARGS)
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = tan(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, true /* tan(pi/2) == Inf */ , true);
+	check_float8_val(result, true /* tan(pi/2) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /* ========== DEGREE-BASED TRIGONOMETRIC FUNCTIONS ========== */
 
 
 /*
  * Initialize the cached constants declared at the head of this file
  * (sin_30 etc).  The fact that we need those at all, let alone need this
@@ -1951,21 +1745,21 @@ dacosd(PG_FUNCTION_ARGS)
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	if (arg1 >= 0.0)
 		result = acosd_q1(arg1);
 	else
 		result = 90.0 + asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dasind			- returns the arcsin of arg1 (degrees)
  */
 Datum
 dasind(PG_FUNCTION_ARGS)
 {
@@ -1986,21 +1780,21 @@ dasind(PG_FUNCTION_ARGS)
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	if (arg1 >= 0.0)
 		result = asind_q1(arg1);
 	else
 		result = -asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		datand			- returns the arctan of arg1 (degrees)
  */
 Datum
 datand(PG_FUNCTION_ARGS)
 {
@@ -2016,21 +1810,21 @@ datand(PG_FUNCTION_ARGS)
 
 	/*
 	 * The principal branch of the inverse tangent function maps all inputs to
 	 * values in the range [-90, 90], so the result should always be finite,
 	 * even if the input is infinite.  Additionally, we take care to ensure
 	 * than when arg1 is 1, the result is exactly 45.
 	 */
 	atan_arg1 = atan(arg1);
 	result = (atan_arg1 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		atan2d			- returns the arctan of arg1/arg2 (degrees)
  */
 Datum
 datan2d(PG_FUNCTION_ARGS)
 {
@@ -2050,21 +1844,21 @@ datan2d(PG_FUNCTION_ARGS)
 	 * result should always be finite, even if the inputs are infinite.
 	 *
 	 * Note: this coding assumes that atan(1.0) is a suitable scaling constant
 	 * to get an exact result from atan2().  This might well fail on us at
 	 * some point, requiring us to decide exactly what inputs we think we're
 	 * going to guarantee an exact result for.
 	 */
 	atan2_arg1_arg2 = atan2(arg1, arg2);
 	result = (atan2_arg1_arg2 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		sind_0_to_30	- returns the sine of an angle that lies between 0 and
  *						  30 degrees.  This will return exactly 0 when x is 0,
  *						  and exactly 0.5 when x is 30 degrees.
  */
 static double
@@ -2171,21 +1965,21 @@ dcosd(PG_FUNCTION_ARGS)
 
 	if (arg1 > 90.0)
 	{
 		/* cosd(180-x) = -cosd(x) */
 		arg1 = 180.0 - arg1;
 		sign = -sign;
 	}
 
 	result = sign * cosd_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcotd			- returns the cotangent of arg1 (degrees)
  */
 Datum
 dcotd(PG_FUNCTION_ARGS)
 {
@@ -2236,21 +2030,21 @@ dcotd(PG_FUNCTION_ARGS)
 	result = sign * (cot_arg1 / cot_45);
 
 	/*
 	 * On some machines we get cotd(270) = minus zero, but this isn't always
 	 * true.  For portability, and because the user constituency for this
 	 * function probably doesn't want minus zero, force it to plain zero.
 	 */
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* cotd(0) == Inf */ , true);
+	check_float8_val(result, true /* cotd(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dsind			- returns the sine of arg1 (degrees)
  */
 Datum
 dsind(PG_FUNCTION_ARGS)
 {
@@ -2290,21 +2084,21 @@ dsind(PG_FUNCTION_ARGS)
 	}
 
 	if (arg1 > 90.0)
 	{
 		/* sind(180-x) = sind(x) */
 		arg1 = 180.0 - arg1;
 	}
 
 	result = sign * sind_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dtand			- returns the tangent of arg1 (degrees)
  */
 Datum
 dtand(PG_FUNCTION_ARGS)
 {
@@ -2355,64 +2149,56 @@ dtand(PG_FUNCTION_ARGS)
 	result = sign * (tan_arg1 / tan_45);
 
 	/*
 	 * On some machines we get tand(180) = minus zero, but this isn't always
 	 * true.  For portability, and because the user constituency for this
 	 * function probably doesn't want minus zero, force it to plain zero.
 	 */
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* tand(90) == Inf */ , true);
+	check_float8_val(result, true /* tand(90) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		degrees		- returns degrees converted from radians
  */
 Datum
 degrees(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
 
-	result = arg1 / RADIANS_PER_DEGREE;
-
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, RADIANS_PER_DEGREE));
 }
 
 
 /*
  *		dpi				- returns the constant PI
  */
 Datum
 dpi(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_FLOAT8(M_PI);
 }
 
 
 /*
  *		radians		- returns radians converted from degrees
  */
 Datum
 radians(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
 
-	result = arg1 * RADIANS_PER_DEGREE;
-
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, RADIANS_PER_DEGREE));
 }
 
 
 /*
  *		drandom		- returns a random number
  */
 Datum
 drandom(PG_FUNCTION_ARGS)
 {
 	float8		result;
@@ -2490,144 +2276,105 @@ check_float8_array(ArrayType *transarray, const char *caller, int n)
  * This function is used only in two stage aggregation and
  * shouldn't be called outside aggregate context.
  */
 Datum
 float8_combine(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_combine", 3);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-
 	transvalues2 = check_float8_array(transarray2, "float8_combine", 3);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
 
 Datum
 float8_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8		newval = PG_GETARG_FLOAT8(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float8_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
 	else
 	{
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
 								 sizeof(float8), FLOAT8PASSBYVAL, 'd');
 
 		PG_RETURN_ARRAYTYPE_P(result);
 	}
 }
 
 Datum
 float4_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 
 	/* do computations as float8 */
 	float8		newval = PG_GETARG_FLOAT4(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float4_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
 	else
 	{
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
 								 sizeof(float8), FLOAT8PASSBYVAL, 'd');
 
 		PG_RETURN_ARRAYTYPE_P(result);
 	}
 }
 
 Datum
@@ -2663,21 +2410,21 @@ float8_var_pop(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_var_pop", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Population variance is undefined when N is 0, so return NULL */
 	if (N == 0.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / (N * N));
 }
 
 Datum
 float8_var_samp(PG_FUNCTION_ARGS)
@@ -2692,21 +2439,21 @@ float8_var_samp(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_var_samp", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Sample variance is undefined when N is 0 or 1, so return NULL */
 	if (N <= 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
 }
 
 Datum
 float8_stddev_pop(PG_FUNCTION_ARGS)
@@ -2721,21 +2468,21 @@ float8_stddev_pop(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_stddev_pop", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Population stddev is undefined when N is 0, so return NULL */
 	if (N == 0.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(sqrt(numerator / (N * N)));
 }
 
 Datum
 float8_stddev_samp(PG_FUNCTION_ARGS)
@@ -2750,21 +2497,21 @@ float8_stddev_samp(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_stddev_samp", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Sample stddev is undefined when N is 0 or 1, so return NULL */
 	if (N <= 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(sqrt(numerator / (N * (N - 1.0))));
 }
 
 /*
  *		=========================
@@ -2799,30 +2546,30 @@ float8_regr_accum(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_accum", 6);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	N += 1.0;
 	sumX += newvalX;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
+	check_float8_val(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
 	sumX2 += newvalX * newvalX;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
+	check_float8_val(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
 	sumY += newvalY;
-	CHECKFLOATVAL(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
+	check_float8_val(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
 	sumY2 += newvalY * newvalY;
-	CHECKFLOATVAL(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
+	check_float8_val(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
 	sumXY += newvalX * newvalY;
-	CHECKFLOATVAL(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
-				  isinf(newvalY), true);
+	check_float8_val(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
+					 isinf(newvalY), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
 		transvalues[0] = N;
 		transvalues[1] = sumX;
@@ -2861,63 +2608,33 @@ float8_regr_accum(PG_FUNCTION_ARGS)
  * This function is used only in two stage aggregation and
  * shouldn't be called outside aggregate context.
  */
 Datum
 float8_regr_combine(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2,
-				sumY,
-				sumY2,
-				sumXY;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_regr_combine", 6);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-	sumY = transvalues1[3];
-	sumY2 = transvalues1[4];
-	sumXY = transvalues1[5];
-
 	transvalues2 = check_float8_array(transarray2, "float8_regr_combine", 6);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-	sumY += transvalues2[3];
-	CHECKFLOATVAL(sumY, isinf(transvalues1[3]) || isinf(transvalues2[3]),
-				  true);
-	sumY2 += transvalues2[4];
-	CHECKFLOATVAL(sumY2, isinf(transvalues1[4]) || isinf(transvalues2[4]),
-				  true);
-	sumXY += transvalues2[5];
-	CHECKFLOATVAL(sumXY, isinf(transvalues1[5]) || isinf(transvalues2[5]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
-	transvalues1[3] = sumY;
-	transvalues1[4] = sumY2;
-	transvalues1[5] = sumXY;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
+	transvalues1[3] = float8_pl(transvalues1[3], transvalues2[3]);
+	transvalues1[4] = float8_pl(transvalues1[4], transvalues2[4]);
+	transvalues1[5] = float8_pl(transvalues1[5], transvalues2[5]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
 
 
 Datum
 float8_regr_sxx(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
@@ -2929,21 +2646,21 @@ float8_regr_sxx(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_sxx", 6);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_syy(PG_FUNCTION_ARGS)
@@ -2958,21 +2675,21 @@ float8_regr_syy(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_syy", 6);
 	N = transvalues[0];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumY2) || isinf(sumY), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_sxy(PG_FUNCTION_ARGS)
@@ -2989,22 +2706,22 @@ float8_regr_sxy(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	/* A negative result is valid here */
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_avgx(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3057,22 +2774,22 @@ float8_covar_pop(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * N));
 }
 
 Datum
 float8_covar_samp(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
 	float8		N,
@@ -3085,22 +2802,22 @@ float8_covar_samp(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is <= 1 we should return NULL */
 	if (N < 2.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
 }
 
 Datum
 float8_corr(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
 	float8		N,
@@ -3119,26 +2836,26 @@ float8_corr(PG_FUNCTION_ARGS)
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0 || numeratorY <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXY / sqrt(numeratorX * numeratorY));
 }
 
 Datum
 float8_regr_r2(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3159,26 +2876,26 @@ float8_regr_r2(PG_FUNCTION_ARGS)
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 	/* per spec, horizontal line produces 1.0 */
 	if (numeratorY <= 0)
 		PG_RETURN_FLOAT8(1.0);
 
 	PG_RETURN_FLOAT8((numeratorXY * numeratorXY) /
 					 (numeratorX * numeratorY));
 }
 
@@ -3200,24 +2917,24 @@ float8_regr_slope(PG_FUNCTION_ARGS)
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXY / numeratorX);
 }
 
 Datum
 float8_regr_intercept(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3235,24 +2952,24 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXXY = sumY * sumX2 - sumX * sumXY;
-	CHECKFLOATVAL(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
-				  isinf(sumX) || isinf(sumXY), true);
+	check_float8_val(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
+					 isinf(sumX) || isinf(sumXY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXXY / numeratorX);
 }
 
 
 /*
  *		====================================
  *		MIXED-PRECISION ARITHMETIC OPERATORS
@@ -3263,251 +2980,211 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
  *		float48pl		- returns arg1 + arg2
  *		float48mi		- returns arg1 - arg2
  *		float48mul		- returns arg1 * arg2
  *		float48div		- returns arg1 / arg2
  */
 Datum
 float48pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 + arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl((float8) arg1, arg2));
 }
 
 Datum
 float48mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi((float8) arg1, arg2));
 }
 
 Datum
 float48mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul((float8) arg1, arg2));
 }
 
 Datum
 float48div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div((float8) arg1, arg2));
 }
 
 /*
  *		float84pl		- returns arg1 + arg2
  *		float84mi		- returns arg1 - arg2
  *		float84mul		- returns arg1 * arg2
  *		float84div		- returns arg1 / arg2
  */
 Datum
 float84pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 + arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, (float8) arg2));
 }
 
 Datum
 float84mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 - arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, (float8) arg2));
 }
 
 Datum
 float84mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 * arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, (float8) arg2));
 }
 
 Datum
 float84div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, (float8) arg2));
 }
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float48{eq,ne,lt,le,gt,ge}		- float4/float8 comparison operations
  */
 Datum
 float48eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq((float8) arg1, arg2));
 }
 
 Datum
 float48ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne((float8) arg1, arg2));
 }
 
 Datum
 float48lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt((float8) arg1, arg2));
 }
 
 Datum
 float48le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le((float8) arg1, arg2));
 }
 
 Datum
 float48gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt((float8) arg1, arg2));
 }
 
 Datum
 float48ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge((float8) arg1, arg2));
 }
 
 /*
  *		float84{eq,ne,lt,le,gt,ge}		- float8/float4 comparison operations
  */
 Datum
 float84eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, (float8) arg2));
 }
 
 Datum
 float84ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, (float8) arg2));
 }
 
 Datum
 float84lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, (float8) arg2));
 }
 
 Datum
 float84le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, (float8) arg2));
 }
 
 Datum
 float84gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, (float8) arg2));
 }
 
 Datum
 float84ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, (float8) arg2));
 }
 
 /*
  * Implements the float8 version of the width_bucket() function
  * defined by SQL2003. See also width_bucket_numeric().
  *
  * 'bound1' and 'bound2' are the lower and upper bounds of the
  * histogram's range, respectively. 'count' is the number of buckets
  * in the histogram. width_bucket() returns an integer indicating the
  * bucket number that 'operand' belongs to in an equiwidth histogram
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c
index 46f45f6654..a10007196e 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -84,20 +84,21 @@
 
 #ifdef USE_ICU
 #include <unicode/ustring.h>
 #endif
 
 #include "catalog/pg_collation.h"
 #include "mb/pg_wchar.h"
 #include "utils/builtins.h"
 #include "utils/date.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 #include "utils/formatting.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/pg_locale.h"
 
 /* ----------
  * Routines type
  * ----------
  */
 #define DCH_TYPE		1		/* DATE-TIME version	*/
@@ -110,27 +111,20 @@
 #define KeyWord_INDEX_SIZE		('~' - ' ')
 #define KeyWord_INDEX_FILTER(_c)	((_c) <= ' ' || (_c) >= '~' ? 0 : 1)
 
 /* ----------
  * Maximal length of one node
  * ----------
  */
 #define DCH_MAX_ITEM_SIZ	   12	/* max localized day name		*/
 #define NUM_MAX_ITEM_SIZ		8	/* roman number (RN has 15 chars)	*/
 
-/* ----------
- * More is in float.c
- * ----------
- */
-#define MAXFLOATWIDTH	60
-#define MAXDOUBLEWIDTH	500
-
 
 /* ----------
  * Format parser structs
  * ----------
  */
 typedef struct
 {
 	char	   *name;			/* suffix string		*/
 	int			len,			/* suffix length		*/
 				id,				/* used in node->suffix */
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index c43d02ac14..865698738e 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -14,27 +14,23 @@
  */
 #include "postgres.h"
 
 #include <math.h>
 #include <limits.h>
 #include <float.h>
 #include <ctype.h>
 
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
-#include "utils/builtins.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index f6334bae14..c800bb1338 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -69,21 +69,21 @@
  *			src/backend/utils/adt/geo_spgist.c
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
 
 #include "access/spgist.h"
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
  * is going only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index bc01f3c284..482631f34d 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -28,20 +28,21 @@
 
 #include "access/hash.h"
 #include "catalog/pg_type.h"
 #include "funcapi.h"
 #include "lib/hyperloglog.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/sortsupport.h"
 
 /* ----------
  * Uncomment the following to enable compilation of dump_numeric()
  * and dump_var() and to get a dump of any result produced by make_result().
  * ----------
 #define NUMERIC_DEBUG
diff --git a/src/backend/utils/adt/rangetypes_gist.c b/src/backend/utils/adt/rangetypes_gist.c
index a1f4f4d372..f416a1f654 100644
--- a/src/backend/utils/adt/rangetypes_gist.c
+++ b/src/backend/utils/adt/rangetypes_gist.c
@@ -9,21 +9,22 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_gist.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/gist.h"
 #include "access/stratnum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/datum.h"
 #include "utils/rangetypes.h"
 
 
 /*
  * Range class properties used to segregate different classes of ranges in
  * GiST.  Each unique combination of properties is a class.  CLS_EMPTY cannot
  * be combined with anything else.
  */
 #define CLS_NORMAL			0	/* Ordinary finite range (no bits set) */
diff --git a/src/backend/utils/adt/rangetypes_selfuncs.c b/src/backend/utils/adt/rangetypes_selfuncs.c
index ed13c27fcb..756c553627 100644
--- a/src/backend/utils/adt/rangetypes_selfuncs.c
+++ b/src/backend/utils/adt/rangetypes_selfuncs.c
@@ -14,21 +14,22 @@
  *	  src/backend/utils/adt/rangetypes_selfuncs.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/htup_details.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 #include "utils/selfuncs.h"
 #include "utils/typcache.h"
 
 static double calc_rangesel(TypeCacheEntry *typcache, VariableStatData *vardata,
 			  RangeType *constval, Oid operator);
 static double default_range_selectivity(Oid operator);
 static double calc_hist_selectivity(TypeCacheEntry *typcache,
 					  VariableStatData *vardata, RangeType *constval,
diff --git a/src/backend/utils/adt/rangetypes_typanalyze.c b/src/backend/utils/adt/rangetypes_typanalyze.c
index 324bbe48e5..58bcd3c035 100644
--- a/src/backend/utils/adt/rangetypes_typanalyze.c
+++ b/src/backend/utils/adt/rangetypes_typanalyze.c
@@ -19,21 +19,22 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_typanalyze.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "catalog/pg_operator.h"
 #include "commands/vacuum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 
 static int	float8_qsort_cmp(const void *a1, const void *a2);
 static int	range_bound_qsort_cmp(const void *a1, const void *a2, void *arg);
 static void compute_range_stats(VacAttrStats *stats,
 					AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows);
 
 /*
  * range_typanalyze -- typanalyze function for range columns
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index b11d452fc8..3df4010b97 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -27,20 +27,21 @@
 #include "common/int128.h"
 #include "funcapi.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
 #include "parser/scansup.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 /*
  * gcc's -ffast-math switch breaks routines that expect exact results from
  * expressions like timeval / SECS_PER_HOUR, where timeval is double.
  */
 #ifdef __FAST_MATH__
 #error -ffast-math is known to break this code
 #endif
 
 #define SAMESIGN(a,b)	(((a) < 0) == ((b) < 0))
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 246fea8693..c22669772a 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -72,20 +72,21 @@
 #include "storage/standby.h"
 #include "storage/fd.h"
 #include "storage/pg_shmem.h"
 #include "storage/proc.h"
 #include "storage/predicate.h"
 #include "tcop/tcopprot.h"
 #include "tsearch/ts_cache.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/guc_tables.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/pg_locale.h"
 #include "utils/plancache.h"
 #include "utils/portal.h"
 #include "utils/ps_status.h"
 #include "utils/rls.h"
 #include "utils/snapmgr.h"
 #include "utils/tzparser.h"
 #include "utils/varlena.h"
 #include "utils/xml.h"
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 762532f636..668e037737 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -43,34 +43,20 @@ extern int	namestrcmp(Name name, const char *str);
 
 /* numutils.c */
 extern int32 pg_atoi(const char *s, int size, int c);
 extern void pg_itoa(int16 i, char *a);
 extern void pg_ltoa(int32 l, char *a);
 extern void pg_lltoa(int64 ll, char *a);
 extern char *pg_ltostr_zeropad(char *str, int32 value, int32 minwidth);
 extern char *pg_ltostr(char *str, int32 value);
 extern uint64 pg_strtouint64(const char *str, char **endptr, int base);
 
-/* float.c */
-extern PGDLLIMPORT int extra_float_digits;
-
-extern double get_float8_infinity(void);
-extern float get_float4_infinity(void);
-extern double get_float8_nan(void);
-extern float get_float4_nan(void);
-extern int	is_infinite(double val);
-extern double float8in_internal(char *num, char **endptr_p,
-				  const char *type_name, const char *orig_string);
-extern char *float8out_internal(double num);
-extern int	float4_cmp_internal(float4 a, float4 b);
-extern int	float8_cmp_internal(float8 a, float8 b);
-
 /* oid.c */
 extern oidvector *buildoidvector(const Oid *oids, int n);
 extern Oid	oidparse(Node *node);
 extern int	oid_cmp(const void *p1, const void *p2);
 
 /* regexp.c */
 extern char *regexp_fixed_prefix(text *text_re, bool case_insensitive,
 					Oid collation, bool *exact);
 
 /* ruleutils.c */
diff --git a/src/include/utils/float.h b/src/include/utils/float.h
new file mode 100644
index 0000000000..c26de1cca4
--- /dev/null
+++ b/src/include/utils/float.h
@@ -0,0 +1,383 @@
+/*-------------------------------------------------------------------------
+ *
+ * float.h
+ *	  Definitions for the built-in floating-point types
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/include/utils/float.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef FLOAT_H
+#define FLOAT_H
+
+#include <math.h>
+
+#ifndef M_PI
+/* From my RH5.2 gcc math.h file - thomas 2000-04-03 */
+#define M_PI 3.14159265358979323846
+#endif
+
+/* Radians per degree, a.k.a. PI / 180 */
+#define RADIANS_PER_DEGREE 0.0174532925199432957692
+
+/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0.  NAN definition from
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfNotNumberNANItems.asp
+ */
+#if defined(WIN32) && !defined(NAN)
+static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
+
+#define NAN (*(const float8 *) nan)
+#endif
+
+/*
+ * We are not sure what the following should be, but better to make it
+ * over-sufficient.
+ */
+#define MAXFLOATWIDTH	64
+#define MAXDOUBLEWIDTH	128
+
+extern PGDLLIMPORT int extra_float_digits;
+
+/*
+ * Utility functions in float.c
+ */
+extern int	is_infinite(float8 val);
+extern float8 float8in_internal(char *num, char **endptr_p,
+				  const char *type_name, const char *orig_string);
+extern char *float8out_internal(float8 num);
+extern int	float4_cmp_internal(float4 a, float4 b);
+extern int	float8_cmp_internal(float8 a, float8 b);
+
+/*
+ * Routines to provide reasonably platform-independent handling of
+ * infinity and NaN
+ *
+ * We assume that isinf() and isnan() are available and work per spec.
+ * (On some platforms, we have to supply our own; see src/port.)  However,
+ * generating an Infinity or NaN in the first place is less well standardized;
+ * pre-C99 systems tend not to have C99's INFINITY and NAN macros.  We
+ * centralize our workarounds for this here.
+ */
+
+/*
+* The funny placements of the two #pragmas is necessary because of a
+* long lived bug in the Microsoft compilers.
+* See http://support.microsoft.com/kb/120968/en-us for details
+*/
+#if (_MSC_VER >= 1800)
+#pragma warning(disable:4756)
+#endif
+static inline float
+get_float4_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float) INFINITY;
+#else
+#if (_MSC_VER >= 1800)
+#pragma warning(default:4756)
+#endif
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float8
+get_float8_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float8) INFINITY;
+#else
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float8) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float4
+get_float4_nan(void)
+{
+#ifdef NAN
+	/* C99 standard way */
+	return (float) NAN;
+#else
+	/* Assume we can get a NAN via zero divide */
+	return (float) (0.0 / 0.0);
+#endif
+}
+
+static inline float8
+get_float8_nan(void)
+{
+	/* (float8) NAN doesn't work on some NetBSD/MIPS releases */
+#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
+	/* C99 standard way */
+	return (float8) NAN;
+#else
+	/* Assume we can get a NAN via zero divide */
+	return (float8) (0.0 / 0.0);
+#endif
+}
+
+/*
+ * Checks to see if a float4/8 val has underflowed or overflowed
+ */
+
+static inline void
+check_float4_val(float4 val, bool inf_is_valid, bool zero_is_valid)
+{
+	if (isinf(val) && !(inf_is_valid))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if ((val) == 0.0 && !(zero_is_valid))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+static inline void
+check_float8_val(float8 val, bool inf_is_valid, bool zero_is_valid)
+{
+	if (isinf(val) && !(inf_is_valid))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if ((val) == 0.0 && !(zero_is_valid))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+/*
+ * Routines for operations with the checks above
+ *
+ * There isn't any way to check for underflow of addition/subtraction
+ * because numbers near the underflow value have already been rounded to
+ * the point where we can't detect that the two values were originally
+ * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
+ * 1.4013e-45.
+ */
+
+static inline float4
+float4_pl(float4 val1, float4 val2)
+{
+	float4		result;
+
+	result = val1 + val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_pl(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = val1 + val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mi(float4 val1, float4 val2)
+{
+	float4		result;
+
+	result = val1 - val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_mi(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = val1 - val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mul(float4 val1, float4 val2)
+{
+	float4		result;
+
+	result = val1 * val2;
+	check_float4_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0f || val2 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_mul(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = val1 * val2;
+	check_float8_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0 || val2 == 0.0);
+
+	return result;
+}
+
+static inline float4
+float4_div(float4 val1, float4 val2)
+{
+	float4		result;
+
+	if (val2 == 0.0f)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), val1 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_div(float8 val1, float8 val2)
+{
+	float8		result;
+
+	if (val2 == 0.0)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
+
+	return result;
+}
+
+/*
+ * Routines for NaN-aware comparisons
+ *
+ * We consider all NANs to be equal and larger than any non-NAN. This is
+ * somewhat arbitrary; the important thing is to have a consistent sort
+ * order.
+ */
+
+static inline bool
+float4_eq(float4 val1, float4 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float8_eq(float8 val1, float8 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float4_ne(float4 val1, float4 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float8_ne(float8 val1, float8 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float4_lt(float4 val1, float4 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float8_lt(float8 val1, float8 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float4_le(float4 val1, float4 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float8_le(float8 val1, float8 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float4_gt(float4 val1, float4 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float8_gt(float8 val1, float8 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float4_ge(float4 val1, float4 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline bool
+float8_ge(float8 val1, float8 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline float4
+float4_min(float4 val1, float4 val2)
+{
+	return float4_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_min(float8 val1, float8 val2)
+{
+	return float8_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float4
+float4_max(float4 val1, float4 val2)
+{
+	return float4_gt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_max(float8 val1, float8 val2)
+{
+	return float8_gt(val1, val2) ? val1 : val2;
+}
+
+#endif   /* FLOAT_H */
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 90119a0158..f845dffcb7 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -17,20 +17,21 @@
  *		and data types. There are still some more to do. - tgl 97/04/19
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEO_DECLS_H
 #define GEO_DECLS_H
 
 #include <math.h>
 
 #include "fmgr.h"
+#include "utils/float.h"
 
 /*--------------------------------------------------------------------
  * Useful floating point utilities and constants.
  *-------------------------------------------------------------------*/
 
 
 #define EPSILON					1.0E-06
 
 #ifdef EPSILON
 #define FPzero(A)				(fabs(A) <= EPSILON)
-- 
2.11.0 (Apple Git-81)

0003-geo-float-v3.patchapplication/octet-stream; name=0003-geo-float-v3.patchDownload
From eb0ae60e6db7fb8a6a0f394bbaec0a87ec2cb68c Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 27 May 2017 16:17:42 -0400
Subject: [PATCH 3/4] geo-float-v3

Use the built-in float datatype to implement geometric types

This will provide:

* Check for underflow and overflow
* Check for division by zero
* Handle NaNs consistently

The patch also replaces all occurrences of "double" as "float8".  They
are the same, but were randomly spread on the same file.
---
 src/backend/access/gist/gistproc.c | 156 +++++------
 src/backend/utils/adt/geo_ops.c    | 547 +++++++++++++++++++------------------
 src/backend/utils/adt/geo_spgist.c |  36 +--
 src/include/utils/float.h          |  13 +
 src/include/utils/geo_decls.h      |  40 ++-
 5 files changed, 412 insertions(+), 380 deletions(-)

diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index c1ea88f90d..3dbd4aaa36 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -16,20 +16,21 @@
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/geo_decls.h"
 
 
 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
 						 StrategyNumber strategy);
 static bool rtree_internal_consistent(BOX *key, BOX *query,
 						  StrategyNumber strategy);
 
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
@@ -48,55 +49,56 @@ rt_box_union(BOX *n, const BOX *a, const BOX *b)
 	n->high.x = float8_max(a->high.x, b->high.x);
 	n->high.y = float8_max(a->high.y, b->high.y);
 	n->low.x = float8_min(a->low.x, b->low.x);
 	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
 	if (float8_le(box->high.x, box->low.x) ||
 		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
-	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
+	return float8_mul(float8_mi(box->high.x, box->low.x),
+					  float8_mi(box->high.y, box->low.y));
 }
 
 /*
  * Return amount by which the union of the two boxes is larger than
  * the original BOX's area.  The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 box_penalty(const BOX *original, const BOX *new)
 {
 	BOX			unionbox;
 
 	rt_box_union(&unionbox, original, new);
-	return size_box(&unionbox) - size_box(original);
+	return float8_mi(size_box(&unionbox), size_box(original));
 }
 
 /*
  * The GiST Consistent method for boxes
  *
  * Should return false if for all data items x below entry,
  * the predicate x op query must be FALSE, where op is the oper
  * corresponding to strategy in the pg_amop table.
  */
 Datum
@@ -284,74 +286,74 @@ fallbackSplit(GistEntryVector *entryvec, GIST_SPLITVEC *v)
 
 /*
  * Represents information about an entry that can be placed to either group
  * without affecting overlap over selected axis ("common entry").
  */
 typedef struct
 {
 	/* Index of entry in the initial array */
 	int			index;
 	/* Delta between penalties of entry insertion into different groups */
-	double		delta;
+	float8		delta;
 } CommonEntry;
 
 /*
  * Context for g_box_consider_split. Contains information about currently
  * selected split and some general information.
  */
 typedef struct
 {
 	int			entriesCount;	/* total number of entries being split */
 	BOX			boundingBox;	/* minimum bounding box across all entries */
 
 	/* Information about currently selected split follows */
 
 	bool		first;			/* true if no split was selected yet */
 
-	double		leftUpper;		/* upper bound of left interval */
-	double		rightLower;		/* lower bound of right interval */
+	float8		leftUpper;		/* upper bound of left interval */
+	float8		rightLower;		/* lower bound of right interval */
 
 	float4		ratio;
 	float4		overlap;
 	int			dim;			/* axis of this split */
-	double		range;			/* width of general MBR projection to the
+	float8		range;			/* width of general MBR projection to the
 								 * selected axis */
 } ConsiderSplitContext;
 
 /*
  * Interval represents projection of box to axis.
  */
 typedef struct
 {
-	double		lower,
+	float8		lower,
 				upper;
 } SplitInterval;
 
 /*
  * Interval comparison function by lower bound of the interval;
  */
 static int
 interval_cmp_lower(const void *i1, const void *i2)
 {
-	double		lower1 = ((const SplitInterval *) i1)->lower,
+	float8		lower1 = ((const SplitInterval *) i1)->lower,
 				lower2 = ((const SplitInterval *) i2)->lower;
 
 	return float8_cmp_internal(lower1, lower2);
 }
 
 /*
  * Interval comparison function by upper bound of the interval;
  */
 static int
 interval_cmp_upper(const void *i1, const void *i2)
 {
-	double		upper1 = ((const SplitInterval *) i1)->upper,
+	float8		upper1 = ((const SplitInterval *) i1)->upper,
 				upper2 = ((const SplitInterval *) i2)->upper;
 
 	return float8_cmp_internal(upper1, upper2);
 }
 
 /*
  * Replace negative (or NaN) value with zero.
  */
 static inline float
 non_negative(float val)
@@ -360,28 +362,28 @@ non_negative(float val)
 		return val;
 	else
 		return 0.0f;
 }
 
 /*
  * Consider replacement of currently selected split with the better one.
  */
 static inline void
 g_box_consider_split(ConsiderSplitContext *context, int dimNum,
-					 double rightLower, int minLeftCount,
-					 double leftUpper, int maxLeftCount)
+					 float8 rightLower, int minLeftCount,
+					 float8 leftUpper, int maxLeftCount)
 {
 	int			leftCount,
 				rightCount;
 	float4		ratio,
 				overlap;
-	double		range;
+	float8		range;
 
 	/*
 	 * Calculate entries distribution ratio assuming most uniform distribution
 	 * of common entries.
 	 */
 	if (minLeftCount >= (context->entriesCount + 1) / 2)
 	{
 		leftCount = minLeftCount;
 	}
 	else
@@ -390,52 +392,54 @@ g_box_consider_split(ConsiderSplitContext *context, int dimNum,
 			leftCount = maxLeftCount;
 		else
 			leftCount = context->entriesCount / 2;
 	}
 	rightCount = context->entriesCount - leftCount;
 
 	/*
 	 * Ratio of split - quotient between size of lesser group and total
 	 * entries count.
 	 */
-	ratio = ((float4) Min(leftCount, rightCount)) /
-		((float4) context->entriesCount);
+	ratio = float4_div(Min(leftCount, rightCount), context->entriesCount);
 
-	if (ratio > LIMIT_RATIO)
+	if (float4_gt(ratio, LIMIT_RATIO))
 	{
 		bool		selectthis = false;
 
 		/*
 		 * The ratio is acceptable, so compare current split with previously
 		 * selected one. Between splits of one dimension we search for minimal
 		 * overlap (allowing negative values) and minimal ration (between same
 		 * overlaps. We switch dimension if find less overlap (non-negative)
 		 * or less range with same overlap.
 		 */
 		if (dimNum == 0)
-			range = context->boundingBox.high.x - context->boundingBox.low.x;
+			range = float8_mi(context->boundingBox.high.x,
+							  context->boundingBox.low.x);
 		else
-			range = context->boundingBox.high.y - context->boundingBox.low.y;
+			range = float8_mi(context->boundingBox.high.y,
+							  context->boundingBox.low.y);
 
-		overlap = (leftUpper - rightLower) / range;
+		overlap = float8_div(float8_mi(leftUpper, rightLower), range);
 
 		/* If there is no previous selection, select this */
 		if (context->first)
 			selectthis = true;
 		else if (context->dim == dimNum)
 		{
 			/*
 			 * Within the same dimension, choose the new split if it has a
 			 * smaller overlap, or same overlap but better ratio.
 			 */
-			if (overlap < context->overlap ||
-				(overlap == context->overlap && ratio > context->ratio))
+			if (float4_lt(overlap, context->overlap) ||
+				(float4_eq(overlap, context->overlap) &&
+				 float4_gt(ratio, context->ratio)))
 				selectthis = true;
 		}
 		else
 		{
 			/*
 			 * Across dimensions, choose the new split if it has a smaller
 			 * *non-negative* overlap, or same *non-negative* overlap but
 			 * bigger range. This condition differs from the one described in
 			 * the article. On the datasets where leaf MBRs don't overlap
 			 * themselves, non-overlapping splits (i.e. splits which have zero
@@ -444,55 +448,49 @@ g_box_consider_split(ConsiderSplitContext *context, int dimNum,
 			 * non-overlapping splits (i.e. having lowest negative overlap)
 			 * appears to be in the same dimension as in the previous split.
 			 * Therefore MBRs appear to be very prolonged along another
 			 * dimension, which leads to bad search performance. Using range
 			 * as the second split criteria makes MBRs more quadratic. Using
 			 * *non-negative* overlap instead of overlap as the first split
 			 * criteria gives to range criteria a chance to matter, because
 			 * non-overlapping splits are equivalent in this criteria.
 			 */
 			if (non_negative(overlap) < non_negative(context->overlap) ||
-				(range > context->range &&
+				(float4_gt(range, context->range) &&
 				 non_negative(overlap) <= non_negative(context->overlap)))
 				selectthis = true;
 		}
 
 		if (selectthis)
 		{
 			/* save information about selected split */
 			context->first = false;
 			context->ratio = ratio;
 			context->range = range;
 			context->overlap = overlap;
 			context->rightLower = rightLower;
 			context->leftUpper = leftUpper;
 			context->dim = dimNum;
 		}
 	}
 }
 
 /*
  * Compare common entries by their deltas.
- * (We assume the deltas can't be NaN.)
  */
 static int
 common_entry_cmp(const void *i1, const void *i2)
 {
-	double		delta1 = ((const CommonEntry *) i1)->delta,
+	float8		delta1 = ((const CommonEntry *) i1)->delta,
 				delta2 = ((const CommonEntry *) i2)->delta;
 
-	if (delta1 < delta2)
-		return -1;
-	else if (delta1 > delta2)
-		return 1;
-	else
-		return 0;
+	return float8_cmp_internal(delta1, delta2);
 }
 
 /*
  * --------------------------------------------------------------------------
  * Double sorting split algorithm. This is used for both boxes and points.
  *
  * The algorithm finds split of boxes by considering splits along each axis.
  * Each entry is first projected as an interval on the X-axis, and different
  * ways to split the intervals into two groups are considered, trying to
  * minimize the overlap of the groups. Then the same is repeated for the
@@ -552,21 +550,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		else
 			adjustBox(&context.boundingBox, box);
 	}
 
 	/*
 	 * Iterate over axes for optimal split searching.
 	 */
 	context.first = true;		/* nothing selected yet */
 	for (dim = 0; dim < 2; dim++)
 	{
-		double		leftUpper,
+		float8		leftUpper,
 					rightLower;
 		int			i1,
 					i2;
 
 		/* Project each entry as an interval on the selected axis. */
 		for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 		{
 			box = DatumGetBoxP(entryvec->vector[i].key);
 			if (dim == 0)
 			{
@@ -749,21 +747,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 			*rightBox = *(box);					\
 		v->spl_right[v->spl_nright++] = off;	\
 	} while(0)
 
 	/*
 	 * Distribute entries which can be distributed unambiguously, and collect
 	 * common entries.
 	 */
 	for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 	{
-		double		lower,
+		float8		lower,
 					upper;
 
 		/*
 		 * Get upper and lower bounds along selected axis.
 		 */
 		box = DatumGetBoxP(entryvec->vector[i].key);
 		if (context.dim == 0)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
@@ -804,31 +802,31 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
 	{
 		/*
 		 * Calculate minimum number of entries that must be placed in both
 		 * groups, to reach LIMIT_RATIO.
 		 */
-		int			m = ceil(LIMIT_RATIO * (double) nentries);
+		int			m = ceil(LIMIT_RATIO * (float8) nentries);
 
 		/*
 		 * Calculate delta between penalties of join "common entries" to
 		 * different groups.
 		 */
 		for (i = 0; i < commonEntriesCount; i++)
 		{
 			box = DatumGetBoxP(entryvec->vector[commonEntries[i].index].key);
-			commonEntries[i].delta = Abs(box_penalty(leftBox, box) -
-										 box_penalty(rightBox, box));
+			commonEntries[i].delta = Abs(float8_mi(box_penalty(leftBox, box),
+												   box_penalty(rightBox, box)));
 		}
 
 		/*
 		 * Sort "common entries" by calculated deltas in order to distribute
 		 * the most ambiguous entries first.
 		 */
 		qsort(commonEntries, commonEntriesCount, sizeof(CommonEntry), common_entry_cmp);
 
 		/*
 		 * Distribute "common entries" between groups.
@@ -1128,24 +1126,24 @@ gist_circle_compress(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	GISTENTRY  *retval;
 
 	if (entry->leafkey)
 	{
 		CIRCLE	   *in = DatumGetCircleP(entry->key);
 		BOX		   *r;
 
 		r = (BOX *) palloc(sizeof(BOX));
-		r->high.x = in->center.x + in->radius;
-		r->low.x = in->center.x - in->radius;
-		r->high.y = in->center.y + in->radius;
-		r->low.y = in->center.y - in->radius;
+		r->high.x = float8_pl(in->center.x, in->radius);
+		r->low.x = float8_mi(in->center.x, in->radius);
+		r->high.y = float8_pl(in->center.y, in->radius);
+		r->low.y = float8_mi(in->center.y, in->radius);
 
 		retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
 		gistentryinit(*retval, PointerGetDatum(r),
 					  entry->rel, entry->page,
 					  entry->offset, FALSE);
 	}
 	else
 		retval = entry;
 	PG_RETURN_POINTER(retval);
 }
@@ -1169,24 +1167,24 @@ gist_circle_consistent(PG_FUNCTION_ARGS)
 	*recheck = true;
 
 	if (DatumGetBoxP(entry->key) == NULL || query == NULL)
 		PG_RETURN_BOOL(FALSE);
 
 	/*
 	 * Since the operators require recheck anyway, we can just use
 	 * rtree_internal_consistent even at leaf nodes.  (This works in part
 	 * because the index entries are bounding boxes not circles.)
 	 */
-	bbox.high.x = query->center.x + query->radius;
-	bbox.low.x = query->center.x - query->radius;
-	bbox.high.y = query->center.y + query->radius;
-	bbox.low.y = query->center.y - query->radius;
+	bbox.high.x = float8_pl(query->center.x, query->radius);
+	bbox.low.x = float8_mi(query->center.x, query->radius);
+	bbox.high.y = float8_pl(query->center.y, query->radius);
+	bbox.low.y = float8_mi(query->center.y, query->radius);
 
 	result = rtree_internal_consistent(DatumGetBoxP(entry->key),
 									   &bbox, strategy);
 
 	PG_RETURN_BOOL(result);
 }
 
 /**************************************************
  * Point ops
  **************************************************/
@@ -1237,80 +1235,84 @@ gist_point_fetch(PG_FUNCTION_ARGS)
 				  entry->offset, FALSE);
 
 	PG_RETURN_POINTER(retval);
 }
 
 
 #define point_point_distance(p1,p2) \
 	DatumGetFloat8(DirectFunctionCall2(point_distance, \
 									   PointPGetDatum(p1), PointPGetDatum(p2)))
 
-static double
+static float8
 computeDistance(bool isLeaf, BOX *box, Point *point)
 {
-	double		result = 0.0;
+	float8		result = 0.0;
 
 	if (isLeaf)
 	{
 		/* simple point to point distance */
 		result = point_point_distance(point, &box->low);
 	}
-	else if (point->x <= box->high.x && point->x >= box->low.x &&
-			 point->y <= box->high.y && point->y >= box->low.y)
+	else if (float8_le(point->x, box->high.x) &&
+			 float8_ge(point->x, box->low.x) &&
+			 float8_le(point->y, box->high.y) &&
+			 float8_ge(point->y, box->low.y))
 	{
 		/* point inside the box */
 		result = 0.0;
 	}
-	else if (point->x <= box->high.x && point->x >= box->low.x)
+	else if (float8_le(point->x, box->high.x) &&
+			 float8_ge(point->x, box->low.x))
 	{
 		/* point is over or below box */
-		Assert(box->low.y <= box->high.y);
-		if (point->y > box->high.y)
-			result = point->y - box->high.y;
-		else if (point->y < box->low.y)
-			result = box->low.y - point->y;
+		Assert(float8_le(box->low.y, box->high.y));
+		if (float8_gt(point->y, box->high.y))
+			result = float8_mi(point->y, box->high.y);
+		else if (float8_lt(point->y, box->low.y))
+			result = float8_mi(box->low.y, point->y);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
-	else if (point->y <= box->high.y && point->y >= box->low.y)
+	else if (float8_le(point->y, box->high.y) &&
+			 float8_ge(point->y, box->low.y))
 	{
 		/* point is to left or right of box */
-		Assert(box->low.x <= box->high.x);
-		if (point->x > box->high.x)
-			result = point->x - box->high.x;
-		else if (point->x < box->low.x)
-			result = box->low.x - point->x;
+		Assert(float8_lt(box->low.x, box->high.x));
+		if (float8_gt(point->x, box->high.x))
+			result = float8_mi(point->x, box->high.x);
+		else if (float8_lt(point->x, box->low.x))
+			result = float8_mi(box->low.x, point->x);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
 	else
 	{
 		/* closest point will be a vertex */
 		Point		p;
-		double		subresult;
+		float8		subresult;
 
 		result = point_point_distance(point, &box->low);
 
 		subresult = point_point_distance(point, &box->high);
-		if (result > subresult)
+		if (float8_gt(result, subresult))
 			result = subresult;
 
 		p.x = box->low.x;
 		p.y = box->high.y;
 		subresult = point_point_distance(point, &p);
-		if (result > subresult)
+		if (float8_gt(result, subresult))
 			result = subresult;
 
 		p.x = box->high.x;
 		p.y = box->low.y;
 		subresult = point_point_distance(point, &p);
-		if (result > subresult)
+		if (float8_gt(result, subresult))
 			result = subresult;
 	}
 
 	return result;
 }
 
 static bool
 gist_point_consistent_internal(StrategyNumber strategy,
 							   bool isLeaf, BOX *key, Point *query)
 {
@@ -1391,24 +1393,24 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 				 * Instead we write a non-fuzzy overlap test.  The same code
 				 * will also serve for leaf-page tests, since leaf keys have
 				 * high == low.
 				 */
 				BOX		   *query,
 						   *key;
 
 				query = PG_GETARG_BOX_P(1);
 				key = DatumGetBoxP(entry->key);
 
-				result = (key->high.x >= query->low.x &&
-						  key->low.x <= query->high.x &&
-						  key->high.y >= query->low.y &&
-						  key->low.y <= query->high.y);
+				result = (float8_ge(key->high.x, query->low.x) &&
+						  float8_le(key->low.x, query->high.x) &&
+						  float8_ge(key->high.y, query->low.y) &&
+						  float8_le(key->low.y, query->high.y));
 				*recheck = false;
 			}
 			break;
 		case PolygonStrategyNumberGroup:
 			{
 				POLYGON    *query = PG_GETARG_POLYGON_P(1);
 
 				result = DatumGetBool(DirectFunctionCall5(
 														  gist_poly_consistent,
 														  PointerGetDatum(entry),
@@ -1417,22 +1419,22 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 														  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);
+					Assert(float8_eq(box->high.x, box->low.x) &&
+						   float8_eq(box->high.y, box->low.y));
 					result = DatumGetBool(DirectFunctionCall2(
 															  poly_contain_pt,
 															  PolygonPGetDatum(query),
 															  PointPGetDatum(&box->high)));
 					*recheck = false;
 				}
 			}
 			break;
 		case CircleStrategyNumberGroup:
 			{
@@ -1446,22 +1448,22 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 														  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);
+					Assert(float8_eq(box->high.x, box->low.x) &&
+						   float8_eq(box->high.y, box->low.y));
 					result = DatumGetBool(DirectFunctionCall2(
 															  circle_contain_pt,
 															  CirclePGetDatum(query),
 															  PointPGetDatum(&box->high)));
 					*recheck = false;
 				}
 			}
 			break;
 		default:
 			elog(ERROR, "unrecognized strategy number: %d", strategy);
@@ -1470,21 +1472,21 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 	}
 
 	PG_RETURN_BOOL(result);
 }
 
 Datum
 gist_point_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(GIST_LEAF(entry),
 									   DatumGetBoxP(entry->key),
 									   PG_GETARG_POINT_P(1));
 			break;
 		default:
@@ -1499,25 +1501,25 @@ gist_point_distance(PG_FUNCTION_ARGS)
 /*
  * The inexact GiST distance method for geometric types that store bounding
  * boxes.
  *
  * Compute lossy distance from point to index entries.  The result is inexact
  * because index entries are bounding boxes, not the exact shapes of the
  * indexed geometric types.  We use distance from point to MBR of index entry.
  * This is a lower bound estimate of distance from point to indexed geometric
  * type.
  */
-static double
+static float8
 gist_bbox_distance(GISTENTRY *entry, Datum query,
 				   StrategyNumber strategy, bool *recheck)
 {
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	/* Bounding box distance is always inexact. */
 	*recheck = true;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(false,
 									   DatumGetBoxP(entry->key),
@@ -1533,32 +1535,32 @@ gist_bbox_distance(GISTENTRY *entry, Datum query,
 
 Datum
 gist_circle_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
 
 Datum
 gist_poly_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 865698738e..0af71aa818 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -41,55 +41,55 @@ static void point_sub_internal(Point *result, Point *pt1, Point *pt2);
 static void point_mul_internal(Point *result, Point *pt1, Point *pt2);
 static void point_div_internal(Point *result, Point *pt1, Point *pt2);
 static bool point_eq_internal(Point *pt1, Point *pt2);
 static float8 point_dt(Point *pt1, Point *pt2);
 static float8 point_sl(Point *pt1, Point *pt2);
 static int	point_inside(Point *p, int npts, Point *plist);
 /* Methods on box */
 static void box_construct(BOX *result, float8 x1, float8 x2, float8 y1, float8 y2);
 static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
-static double box_ar(BOX *box);
-static double box_ht(BOX *box);
-static double box_wd(BOX *box);
+static float8 box_ar(BOX *box);
+static float8 box_ht(BOX *box);
+static float8 box_wd(BOX *box);
 /* Methods on circle */
-static double circle_ar(CIRCLE *circle);
+static float8 circle_ar(CIRCLE *circle);
 /* Methods on line */
 static void line_construct_pm(LINE *result, Point *pt, float8 m);
 static void line_construct_pts(LINE *line, Point *pt1, Point *pt2);
 static bool line_interpt_internal(Point *result, LINE *l1, LINE *l2);
 static float8 line_calculate_point(LINE *line, Point *pt);
 /* Methods on line segment */
 static bool lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line);
 static bool lseg_interpt_internal(Point *result, LSEG *l1, LSEG *l2);
 static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
 static float8 lseg_dt(LSEG *l1, LSEG *l2);
-static int	lseg_crossing(double x, double y, double px, double py);
+static int	lseg_crossing(float8 x, float8 y, float8 px, float8 py);
 /* Others */
 static bool on_ps_internal(Point *pt, LSEG *lseg);
 static void make_bound_box(POLYGON *poly);
 static bool plist_same(int npts, Point *p1, Point *p2);
-static double single_decode(char *num, char **endptr_p,
+static float8 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
-static void pair_decode(char *str, double *x, double *y, char **endptr_p,
+static void pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
 static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
 static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
-static double dist_pl_internal(Point *pt, LINE *line);
-static double dist_ps_internal(Point *pt, LSEG *lseg);
-static double dist_ppoly_internal(Point *pt, POLYGON *poly);
+static float8 dist_pl_internal(Point *pt, LINE *line);
+static float8 dist_ps_internal(Point *pt, LSEG *lseg);
+static float8 dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 
 /*
  * Delimiters for input and output strings.
  * LDELIM, RDELIM, and DELIM are left, right, and separator delimiters, respectively.
  * LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints.
  */
 
 #define LDELIM			'('
 #define RDELIM			')'
@@ -118,38 +118,38 @@ static double dist_ppoly_internal(Point *pt, POLYGON *poly);
  *
  * For boxes, the points are opposite corners with the first point at the top right.
  * For closed paths and polygons, the points should be reordered to allow
  *	fast and correct equality comparisons.
  *
  * XXX perhaps points in complex shapes should be reordered internally
  *	to allow faster internal operations, but should keep track of input order
  *	and restore that order for text output - tgl 97/01/16
  */
 
-static double
+static float8
 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string)
 {
 	return float8in_internal(num, endptr_p, type_name, orig_string);
 }								/* single_decode() */
 
 static void
 single_encode(float8 x, StringInfo str)
 {
 	char	   *xstr = float8out_internal(x);
 
 	appendStringInfoString(str, xstr);
 	pfree(xstr);
 }								/* single_encode() */
 
 static void
-pair_decode(char *str, double *x, double *y, char **endptr_p,
+pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string)
 {
 	bool		has_delim;
 
 	while (isspace((unsigned char) *str))
 		str++;
 	if ((has_delim = (*str == LDELIM)))
 		str++;
 
 	*x = float8in_internal(str, &str, type_name, orig_string);
@@ -351,33 +351,33 @@ pair_count(char *s, char delim)
  *		External format: (two corners of box)
  *				"(f8, f8), (f8, f8)"
  *				also supports the older style "(f8, f8, f8, f8)"
  */
 Datum
 box_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	BOX		   *box = (BOX *) palloc(sizeof(BOX));
 	bool		isopen;
-	double		x,
+	float8		x,
 				y;
 
 	path_decode(str, false, 2, &(box->high), &isopen, NULL, "box", str);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*		box_out -		convert a box to external form.
@@ -391,38 +391,38 @@ box_out(PG_FUNCTION_ARGS)
 }
 
 /*
  *		box_recv			- converts external binary format to box
  */
 Datum
 box_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	BOX		   *box;
-	double		x,
+	float8		x,
 				y;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
 	box->high.x = pq_getmsgfloat8(buf);
 	box->high.y = pq_getmsgfloat8(buf);
 	box->low.x = pq_getmsgfloat8(buf);
 	box->low.y = pq_getmsgfloat8(buf);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*
@@ -441,31 +441,31 @@ box_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, box->low.y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*		box_construct	-		fill in a new box.
  */
 static void
 box_construct(BOX *result, float8 x1, float8 x2, float8 y1, float8 y2)
 {
-	if (x1 > x2)
+	if (float8_gt(x1, x2))
 	{
 		result->high.x = x1;
 		result->low.x = x2;
 	}
 	else
 	{
 		result->high.x = x2;
 		result->low.x = x1;
 	}
-	if (y1 > y2)
+	if (float8_gt(y1, y2))
 	{
 		result->high.y = y1;
 		result->low.y = y2;
 	}
 	else
 	{
 		result->high.y = y2;
 		result->low.y = y1;
 	}
 }
@@ -777,54 +777,54 @@ box_center(PG_FUNCTION_ARGS)
 	Point	   *result = (Point *) palloc(sizeof(Point));
 
 	box_cn(result, box);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		box_ar	-		returns the area of the box.
  */
-static double
+static float8
 box_ar(BOX *box)
 {
-	return box_wd(box) * box_ht(box);
+	return float8_mul(box_wd(box), box_ht(box));
 }
 
 
 /*		box_cn	-		stores the centerpoint of the box into *center.
  */
 static void
 box_cn(Point *center, BOX *box)
 {
-	center->x = (box->high.x + box->low.x) / 2.0;
-	center->y = (box->high.y + box->low.y) / 2.0;
+	center->x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	center->y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 }
 
 
 /*		box_wd	-		returns the width (length) of the box
  *								  (horizontal magnitude).
  */
-static double
+static float8
 box_wd(BOX *box)
 {
-	return box->high.x - box->low.x;
+	return float8_mi(box->high.x, box->low.x);
 }
 
 
 /*		box_ht	-		returns the height of the box
  *								  (vertical magnitude).
  */
-static double
+static float8
 box_ht(BOX *box)
 {
-	return box->high.y - box->low.y;
+	return float8_mi(box->high.y, box->low.y);
 }
 
 
 /*----------------------------------------------------------
  *	Funky operations.
  *---------------------------------------------------------*/
 
 /*		box_intersect	-
  *				returns the overlapping portion of two boxes,
  *				  or NULL if they do not intersect.
@@ -834,24 +834,24 @@ box_intersect(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 	BOX		   *result;
 
 	if (!box_ov(box1, box2))
 		PG_RETURN_NULL();
 
 	result = (BOX *) palloc(sizeof(BOX));
 
-	result->high.x = Min(box1->high.x, box2->high.x);
-	result->low.x = Max(box1->low.x, box2->low.x);
-	result->high.y = Min(box1->high.y, box2->high.y);
-	result->low.y = Max(box1->low.y, box2->low.y);
+	result->high.x = float8_min(box1->high.x, box2->high.x);
+	result->low.x = float8_max(box1->low.x, box2->low.x);
+	result->high.y = float8_min(box1->high.y, box2->high.y);
+	result->low.y = float8_max(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(result);
 }
 
 
 /*		box_diagonal	-
  *				returns a line segment which happens to be the
  *				  positive-slope diagonal of "box".
  */
 Datum
@@ -982,65 +982,65 @@ line_send(PG_FUNCTION_ARGS)
 
 /* line_construct_pm()
  * point-slope
  */
 static void
 line_construct_pm(LINE *result, Point *pt, float8 m)
 {
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
-		result->A = -1;
-		result->B = 0;
+		result->A = -1.0;
+		result->B = 0.0;
 		result->C = pt->x;
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
-		result->C = pt->y - m * pt->x;
+		result->C = float8_mi(pt->y, float8_mul(m, pt->x));
 	}
 }
 
 /*
  * Fill already-allocated LINE struct from two points on the line
  */
 static void
 line_construct_pts(LINE *line, Point *pt1, Point *pt2)
 {
 	if (FPeq(pt1->x, pt2->x))
 	{							/* vertical */
 		/* use "x = C" */
-		line->A = -1;
-		line->B = 0;
+		line->A = -1.0;
+		line->B = 0.0;
 		line->C = pt1->x;
 #ifdef GEODEBUG
 		printf("line_construct_pts- line is vertical\n");
 #endif
 	}
 	else if (FPeq(pt1->y, pt2->y))
 	{							/* horizontal */
 		/* use "y = C" */
-		line->A = 0;
-		line->B = -1;
+		line->A = 0.0;
+		line->B = -1.0;
 		line->C = pt1->y;
 #ifdef GEODEBUG
 		printf("line_construct_pts- line is horizontal\n");
 #endif
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		line->A = point_sl(pt2, pt1);
 		line->B = -1.0;
-		line->C = pt1->y - line->A * pt1->x;
+		line->C = float8_mi(pt1->y, float8_mul(line->A, pt1->x));
 		/* on some platforms, the preceding expression tends to produce -0 */
 		if (line->C == 0.0)
 			line->C = 0.0;
 #ifdef GEODEBUG
 		printf("line_construct_pts- line is neither vertical nor horizontal (diffs x=%.*g, y=%.*g\n",
 			   DBL_DIG, (pt2->x - pt1->x), DBL_DIG, (pt2->y - pt1->y));
 #endif
 	}
 }
 
@@ -1060,21 +1060,22 @@ line_construct_pp(PG_FUNCTION_ARGS)
 
 /*
  * Calculate the line equation for a point
  *
  * This returns the result of the line equation Ax + By + C.  The result
  * needs to be 0 for the point to be on the line.
  */
 static float8
 line_calculate_point(LINE *line, Point *pt)
 {
-	return line->A * pt->x + line->B * pt->y + line->C;
+	return float8_pl(float8_pl(float8_mul(line->A, pt->x),
+							   float8_mul(line->B, pt->y)), line->C);
 }
 
 
 /*----------------------------------------------------------
  *	Relative position routines.
  *---------------------------------------------------------*/
 
 Datum
 line_intersect(PG_FUNCTION_ARGS)
 {
@@ -1097,21 +1098,22 @@ Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
 	else if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
 
-	PG_RETURN_BOOL(FPeq(((l1->A * l2->B) / (l1->B * l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
+								   float8_mul(l1->B, l2->A)), -1.0));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
@@ -1121,34 +1123,34 @@ line_horizontal(PG_FUNCTION_ARGS)
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->A));
 }
 
 Datum
 line_eq(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	double		k;
+	float8		ratio;
 
 	if (!FPzero(l2->A))
-		k = l1->A / l2->A;
+		ratio = float8_div(l1->A, l2->A);
 	else if (!FPzero(l2->B))
-		k = l1->B / l2->B;
+		ratio = float8_div(l1->B, l2->B);
 	else if (!FPzero(l2->C))
-		k = l1->C / l2->C;
+		ratio = float8_div(l1->C, l2->C);
 	else
-		k = 1.0;
+		ratio = 1.0;
 
-	PG_RETURN_BOOL(FPeq(l1->A, k * l2->A) &&
-				   FPeq(l1->B, k * l2->B) &&
-				   FPeq(l1->C, k * l2->C));
+	PG_RETURN_BOOL(FPeq(l1->A, float8_mul(ratio, l2->A)) &&
+				   FPeq(l1->B, float8_mul(ratio, l2->B)) &&
+				   FPeq(l1->C, float8_mul(ratio, l2->C)));
 }
 
 
 /*----------------------------------------------------------
  *	Line arithmetic routines.
  *---------------------------------------------------------*/
 
 /* line_distance()
  * Distance between two lines.
  */
@@ -1156,21 +1158,21 @@ Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
 	Point		tmp;
 
 	if (line_interpt_internal(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
+		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
 	point_construct(&tmp, 0.0, l1->C);
 	result = dist_pl_internal(&tmp, l2);
 	PG_RETURN_FLOAT8(result);
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
@@ -1193,41 +1195,41 @@ line_interpt(PG_FUNCTION_ARGS)
  * parallel), false if they do not.  This also sets the intersection point
  * to *result, if it is not NULL.
  *
  * NOTE: If the lines are identical then we will find they are parallel
  * and report "no intersection".  This is a little weird, but since
  * there's no *unique* intersection, maybe it's appropriate behavior.
  */
 static bool
 line_interpt_internal(Point *result, LINE *l1, LINE *l2)
 {
-	double		x,
+	float8		x,
 				y;
 
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
 		if (FPzero(l2->B))		/* l2 vertical? */
 			return false;
 
 		x = l1->C;
-		y = (l2->A * x + l2->C);
+		y = float8_pl(float8_mul(l2->A, x), l2->C);
 	}
 	else
 	{
-		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
 			return false;
 
 		if (FPzero(l2->B))
 			x = l2->C;
 		else
-			x = (l1->C - l2->C) / (l2->A - l1->A);
-		y = (l1->A * x + l1->C);
+			x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
+		y = float8_pl(float8_mul(l1->A, x), l1->C);
 	}
 	if (result != NULL)
 		point_construct(result, x, y);
 
 #ifdef GEODEBUG
 	printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
 		   DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
 	printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
 #endif
 
@@ -1254,36 +1256,35 @@ line_interpt_internal(Point *result, LINE *l1, LINE *l2)
  *				"(xcoord, ycoord),... "
  *				"[xcoord, ycoord,... ]"
  *		Also support older format:
  *				"(closed, npts, xcoord, ycoord,... )"
  *---------------------------------------------------------*/
 
 Datum
 path_area(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P(0);
-	double		area = 0.0;
+	float8		area = 0.0;
 	int			i,
 				j;
 
 	if (!path->closed)
 		PG_RETURN_NULL();
 
 	for (i = 0; i < path->npts; i++)
 	{
 		j = (i + 1) % path->npts;
-		area += path->p[i].x * path->p[j].y;
-		area -= path->p[i].y * path->p[j].x;
+		area = float8_pl(area, float8_mul(path->p[i].x, path->p[j].y));
+		area = float8_mi(area, float8_mul(path->p[i].y, path->p[j].x));
 	}
 
-	area *= 0.5;
-	PG_RETURN_FLOAT8(area < 0.0 ? -area : area);
+	PG_RETURN_FLOAT8(float8_div(fabs(area), 2.0));
 }
 
 
 Datum
 path_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	PATH	   *path;
 	bool		isopen;
 	char	   *s;
@@ -1500,31 +1501,31 @@ path_npoints(PG_FUNCTION_ARGS)
 
 	PG_RETURN_INT32(path->npts);
 }
 
 
 Datum
 path_close(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 
-	path->closed = TRUE;
+	path->closed = true;
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_open(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 
-	path->closed = FALSE;
+	path->closed = false;
 
 	PG_RETURN_PATH_P(path);
 }
 
 
 /* path_inter -
  *		Does p1 intersect p2 at any point?
  *		Use bounding boxes for a quick (O(n)) check, then do a
  *		O(n^2) iterative edge check.
  */
@@ -1540,33 +1541,33 @@ path_inter(PG_FUNCTION_ARGS)
 	LSEG		seg1,
 				seg2;
 
 	if (p1->npts <= 0 || p2->npts <= 0)
 		PG_RETURN_BOOL(false);
 
 	b1.high.x = b1.low.x = p1->p[0].x;
 	b1.high.y = b1.low.y = p1->p[0].y;
 	for (i = 1; i < p1->npts; i++)
 	{
-		b1.high.x = Max(p1->p[i].x, b1.high.x);
-		b1.high.y = Max(p1->p[i].y, b1.high.y);
-		b1.low.x = Min(p1->p[i].x, b1.low.x);
-		b1.low.y = Min(p1->p[i].y, b1.low.y);
+		b1.high.x = float8_max(p1->p[i].x, b1.high.x);
+		b1.high.y = float8_max(p1->p[i].y, b1.high.y);
+		b1.low.x = float8_min(p1->p[i].x, b1.low.x);
+		b1.low.y = float8_min(p1->p[i].y, b1.low.y);
 	}
 	b2.high.x = b2.low.x = p2->p[0].x;
 	b2.high.y = b2.low.y = p2->p[0].y;
 	for (i = 1; i < p2->npts; i++)
 	{
-		b2.high.x = Max(p2->p[i].x, b2.high.x);
-		b2.high.y = Max(p2->p[i].y, b2.high.y);
-		b2.low.x = Min(p2->p[i].x, b2.low.x);
-		b2.low.y = Min(p2->p[i].y, b2.low.y);
+		b2.high.x = float8_max(p2->p[i].x, b2.high.x);
+		b2.high.y = float8_max(p2->p[i].y, b2.high.y);
+		b2.low.x = float8_min(p2->p[i].x, b2.low.x);
+		b2.low.y = float8_min(p2->p[i].y, b2.low.y);
 	}
 	if (!box_ov(&b1, &b2))
 		PG_RETURN_BOOL(false);
 
 	/* pairwise check lseg intersections */
 	for (i = 0; i < p1->npts; i++)
 	{
 		int			iprev;
 
 		if (i > 0)
@@ -1642,21 +1643,21 @@ path_distance(PG_FUNCTION_ARGS)
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
 			tmp = lseg_dt(&seg1, &seg2);
-			if (!have_min || tmp < min)
+			if (!have_min || float8_lt(tmp, min))
 			{
 				min = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	if (!have_min)
 		PG_RETURN_NULL();
 
@@ -1681,21 +1682,21 @@ path_length(PG_FUNCTION_ARGS)
 
 		if (i > 0)
 			iprev = i - 1;
 		else
 		{
 			if (!path->closed)
 				continue;
 			iprev = path->npts - 1; /* include the closure segment */
 		}
 
-		result += point_dt(&path->p[iprev], &path->p[i]);
+		result = float8_pl(result, point_dt(&path->p[iprev], &path->p[i]));
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /***********************************************************************
  **
  **		Routines for 2D points.
  **
  ***********************************************************************/
@@ -1867,43 +1868,48 @@ point_distance(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
 static float8
 point_dt(Point *pt1, Point *pt2)
 {
+	float8		result;
+
+	result = float8_hypot(float8_mi(pt1->x, pt2->x), float8_mi(pt1->y, pt2->y));
+
 #ifdef GEODEBUG
 	printf("point_dt- segment (%f,%f),(%f,%f) length is %f\n",
-		   pt1->x, pt1->y, pt2->x, pt2->y, HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
+		   pt1->x, pt1->y, pt2->x, pt2->y, result);
 #endif
-	return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
+
+	return result;
 }
 
 Datum
 point_slope(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_sl(pt1, pt2));
 }
 
 
 static float8
 point_sl(Point *pt1, Point *pt2)
 {
-	return (FPeq(pt1->x, pt2->x)
-			? (double) DBL_MAX
-			: (pt1->y - pt2->y) / (pt1->x - pt2->x));
+	if (FPeq(pt1->x, pt2->x))
+		return DBL_MAX;
+	return float8_div(float8_mi(pt1->y, pt2->y), float8_mi(pt1->x, pt2->x));
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D line segments.
  **
  ***********************************************************************/
 
 /*----------------------------------------------------------
@@ -2043,35 +2049,35 @@ lseg_parallel(PG_FUNCTION_ARGS)
  *	'((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg
  * So, modified it to check explicitly for slope of vertical line
  *	returned by point_sl() and the results seem better.
  * - thomas 1998-01-31
  */
 Datum
 lseg_perp(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	double		m1,
+	float8		m1,
 				m2;
 
 	m1 = point_sl(&l1->p[0], &l1->p[1]);
 	m2 = point_sl(&l2->p[0], &l2->p[1]);
 
 #ifdef GEODEBUG
 	printf("lseg_perp- slopes are %g and %g\n", m1, m2);
 #endif
 	if (FPzero(m1))
 		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
 	else if (FPzero(m2))
 		PG_RETURN_BOOL(FPeq(m1, DBL_MAX));
 
-	PG_RETURN_BOOL(FPeq(m1 / m2, -1.0));
+	PG_RETURN_BOOL(FPeq(float8_div(m1, m2), -1.0));
 }
 
 Datum
 lseg_vertical(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 
 	PG_RETURN_BOOL(FPeq(lseg->p[0].x, lseg->p[1].x));
 }
 
@@ -2161,52 +2167,47 @@ lseg_distance(PG_FUNCTION_ARGS)
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_FLOAT8(lseg_dt(l1, l2));
 }
 
 /* lseg_dt()
  * Distance between two line segments.
  * Must check both sets of endpoints to ensure minimum distance is found.
  * - thomas 1998-02-01
  */
-static double
+static float8
 lseg_dt(LSEG *l1, LSEG *l2)
 {
-	double		result,
-				d;
+	float8		result;
 
 	if (lseg_interpt_internal(NULL, l1, l2))
 		return 0.0;
 
-	d = dist_ps_internal(&l1->p[0], l2);
-	result = d;
-	d = dist_ps_internal(&l1->p[1], l2);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[0], l1);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[1], l1);
-	result = Min(result, d);
+	result = dist_ps_internal(&l1->p[0], l2);
+	result = float8_min(result, dist_ps_internal(&l1->p[1], l2));
+	result = float8_min(result, dist_ps_internal(&l2->p[0], l1));
+	result = float8_min(result, dist_ps_internal(&l2->p[1], l1));
 
 	return result;
 }
 
 
 Datum
 lseg_center(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
-	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
+	result->x = float8_div(float8_pl(lseg->p[0].x, lseg->p[1].x), 2.0);
+	result->y = float8_div(float8_pl(lseg->p[0].y, lseg->p[1].y), 2.0);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static bool
 lseg_interpt_internal(Point *result, LSEG *l1, LSEG *l2)
 {
 	Point		interpt;
 	LINE		tmp1,
 				tmp2;
@@ -2290,58 +2291,57 @@ lseg_interpt(PG_FUNCTION_ARGS)
  */
 Datum
 dist_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
 	PG_RETURN_FLOAT8(dist_pl_internal(pt, line));
 }
 
-static double
+static float8
 dist_pl_internal(Point *pt, LINE *line)
 {
-	return fabs(line_calculate_point(line, pt) /
-				HYPOT(line->A, line->B));
+	return float8_div(fabs(line_calculate_point(line, pt)),
+					  float8_hypot(line->A, line->B));
 }
 
 /*
  * Distance from a point to a lseg
  */
 Datum
 dist_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_FLOAT8(dist_ps_internal(pt, lseg));
 }
 
-static double
+static float8
 dist_ps_internal(Point *pt, LSEG *lseg)
 {
-	double		m;				/* slope of perp. */
-	double		result,
-				tmpdist;
+	float8		m;				/* slope of perp. */
+	float8		result;
 	Point		interpt;
 	LINE		ln;
 
 	/*
 	 * Construct a line perpendicular to the input segment and through the
 	 * input point
 	 */
-	if (lseg->p[1].x == lseg->p[0].x)
-		m = 0;
-	else if (lseg->p[1].y == lseg->p[0].y)
-		m = (double) DBL_MAX;	/* slope is infinite */
+	if (float8_eq(lseg->p[0].x, lseg->p[1].x))
+		m = 0.0;
+	else if (float8_eq(lseg->p[0].y, lseg->p[1].y))
+		m = DBL_MAX;	/* slope is infinite */
 	else
-		m = -1.0 / point_sl(&lseg->p[0], &lseg->p[1]);
+		m = float8_div(-1.0, point_sl(&lseg->p[0], &lseg->p[1]));
 	line_construct_pm(&ln, pt, m);
 
 #ifdef GEODEBUG
 	printf("dist_ps- line is A=%g B=%g C=%g from (point) slope (%f,%f) %g\n",
 		   ln->A, ln->B, ln->C, pt->x, pt->y, m);
 #endif
 
 	/*
 	 * Calculate distance to the line segment or to the nearest endpoint of
 	 * the segment.
@@ -2353,24 +2353,22 @@ dist_ps_internal(Point *pt, LSEG *lseg)
 		/* yes, so use distance to the intersection point */
 		result = point_dt(pt, &interpt);
 #ifdef GEODEBUG
 		printf("dist_ps- distance is %f to intersection point is (%f,%f)\n",
 			   result, tmp.x, tmp.y);
 #endif
 	}
 	else
 	{
 		/* no, so use distance to the nearer endpoint */
-		result = point_dt(pt, &lseg->p[0]);
-		tmpdist = point_dt(pt, &lseg->p[1]);
-		if (tmpdist < result)
-			result = tmpdist;
+		result = float8_min(point_dt(pt, &lseg->p[0]),
+							point_dt(pt, &lseg->p[1]));
 	}
 
 	return result;
 }
 
 /*
  * Distance from a point to a path
  */
 Datum
 dist_ppath(PG_FUNCTION_ARGS)
@@ -2408,21 +2406,21 @@ dist_ppath(PG_FUNCTION_ARGS)
 					iprev = i - 1;
 				else
 				{
 					if (!path->closed)
 						continue;
 					iprev = path->npts - 1; /* include the closure segment */
 				}
 
 				statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
 				tmp = dist_ps_internal(pt, &lseg);
-				if (!have_min || tmp < result)
+				if (!have_min || float8_lt(tmp, result))
 				{
 					result = tmp;
 					have_min = true;
 				}
 			}
 			break;
 	}
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -2446,33 +2444,28 @@ dist_pb(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
-	float8		result,
-				d2;
+	float8		result;
 
 	if (lseg_interpt_line_internal(NULL, lseg, line))
 		result = 0.0;
 	else
-	{
-		result = dist_pl_internal(&lseg->p[0], line);
-		d2 = dist_pl_internal(&lseg->p[1], line);
 		/* XXX shouldn't we take the min not max? */
-		if (d2 > result)
-			result = d2;
-	}
+		result = float8_max(dist_pl_internal(&lseg->p[0], line),
+							dist_pl_internal(&lseg->p[1], line));
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
@@ -2514,25 +2507,22 @@ dist_lb(PG_FUNCTION_ARGS)
  * Distance from a circle to a polygon
  */
 Datum
 dist_cpoly(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	POLYGON    *poly = PG_GETARG_POLYGON_P(1);
 	float8		result;
 
 	/* calculate distance to center, and subtract radius */
-	result = dist_ppoly_internal(&circle->center, poly);
-
-	result -= circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_min(float8_mi(dist_ppoly_internal(&circle->center, poly),
+								  circle->radius), 0.0);
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a point to a polygon
  */
 Datum
 dist_ppoly(PG_FUNCTION_ARGS)
 {
@@ -2550,21 +2540,21 @@ dist_polyp(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	float8		result;
 
 	result = dist_ppoly_internal(point, poly);
 
 	PG_RETURN_FLOAT8(result);
 }
 
-static double
+static float8
 dist_ppoly_internal(Point *pt, POLYGON *poly)
 {
 	float8		result;
 	float8		d;
 	int			i;
 	LSEG		seg;
 
 	if (point_inside(pt, poly->npts, poly->p) != 0)
 	{
 #ifdef GEODEBUG
@@ -2587,21 +2577,21 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
 	for (i = 0; (i < poly->npts - 1); i++)
 	{
 		seg.p[0].x = poly->p[i].x;
 		seg.p[0].y = poly->p[i].y;
 		seg.p[1].x = poly->p[i + 1].x;
 		seg.p[1].y = poly->p[i + 1].y;
 		d = dist_ps_internal(pt, &seg);
 #ifdef GEODEBUG
 		printf("dist_ppoly_internal- segment %d distance is %f\n", (i + 1), d);
 #endif
-		if (d < result)
+		if (float8_lt(d, result))
 			result = d;
 	}
 
 	return result;
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
  *				Intersection point of objects.
@@ -2655,41 +2645,41 @@ lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line)
 /* close_pl -
  *		The intersection point of a perpendicular of the line
  *		through the point.
  */
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
-	double		invm;
+	float8		invm;
 	LINE		tmp;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (FPzero(line->B))		/* vertical? */
 	{
 		result->x = line->C;
 		result->y = pt->y;
 		PG_RETURN_POINT_P(result);
 	}
 	if (FPzero(line->A))		/* horizontal? */
 	{
 		result->x = pt->x;
 		result->y = line->C;
 		PG_RETURN_POINT_P(result);
 	}
 	/* drop a perpendicular and find the intersection point */
 
 	/* invert and flip the sign on the slope to get a perpendicular */
-	invm = line->B / line->A;
+	invm = float8_div(line->B, line->A);
 	line_construct_pm(&tmp, pt, invm);
 	line_interpt_internal(result, &tmp, line);
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_ps()
  * Closest point on line segment to specified point.
  * Take the closest endpoint if the point is left, right,
  *	above, or below the segment, otherwise find the intersection
@@ -2698,21 +2688,21 @@ close_pl(PG_FUNCTION_ARGS)
  * Some tricky code here, relying on boolean expressions
  *	evaluating to only zero or one to use as an array index.
  *		bug fixes by gthaker@atl.lmco.com; May 1, 1998
  */
 Datum
 close_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
-	double		invm;
+	float8		invm;
 	int			xh,
 				yh;
 	LINE		tmp;
 
 	result = (Point *) palloc(sizeof(Point));
 
 #ifdef GEODEBUG
 	printf("close_sp:pt->x %f pt->y %f\nlseg(0).x %f lseg(0).y %f  lseg(1).x %f lseg(1).y %f\n",
 		   pt->x, pt->y, lseg->p[0].x, lseg->p[0].y,
 		   lseg->p[1].x, lseg->p[1].y);
@@ -2754,35 +2744,35 @@ close_ps(PG_FUNCTION_ARGS)
 			point_construct(result, pt->x, lseg->p[0].y);
 
 		PG_RETURN_POINT_P(result);
 	}
 
 	/*
 	 * vert. and horiz. cases are down, now check if the closest point is one
 	 * of the end points or someplace on the lseg.
 	 */
 
-	invm = -1.0 / point_sl(&(lseg->p[0]), &(lseg->p[1]));
+	invm = float8_div(-1.0, point_sl(&lseg->p[0], &lseg->p[1]));
 	line_construct_pm(&tmp, &lseg->p[!yh], invm);	/* lower edge of the
 													 * "band" */
-	if (pt->y < (tmp.A * pt->x + tmp.C))
+	if (pt->y < float8_pl(float8_mul(tmp.A, pt->x), tmp.C))
 	{							/* we are below the lower edge */
 		*result = lseg->p[!yh];	/* below the lseg, take lower end pt */
 #ifdef GEODEBUG
 		printf("close_ps below: tmp A %f  B %f   C %f\n",
 			   tmp->A, tmp->B, tmp->C);
 #endif
 		PG_RETURN_POINT_P(result);
 	}
 	line_construct_pm(&tmp, &lseg->p[yh], invm);	/* upper edge of the
 													 * "band" */
-	if (pt->y > (tmp.A * pt->x + tmp.C))
+	if (pt->y > float8_pl(float8_mul(tmp.A, pt->x), tmp.C))
 	{							/* we are below the lower edge */
 		*result = lseg->p[yh];	/* above the lseg, take higher end pt */
 #ifdef GEODEBUG
 		printf("close_ps above: tmp A %f  B %f   C %f\n",
 			   tmp->A, tmp->B, tmp->C);
 #endif
 		PG_RETURN_POINT_P(result);
 	}
 
 	/*
@@ -2818,32 +2808,32 @@ close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 	double		dist,
 				dist0,
 				dist1;
 
 	dist0 = dist_ps_internal(&l1->p[0], l2);
 	dist1 = dist_ps_internal(&l1->p[1], l2);
-	dist = Min(dist0, dist1);
+	dist = float8_min(dist0, dist1);
 
-	if (dist_ps_internal(&l2->p[0], l1) < dist)
+	if (float8_lt(dist_ps_internal(&l2->p[0], l1), dist))
 	{
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(&l2->p[0]),
 													LsegPGetDatum(l1)));
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(result),
 													LsegPGetDatum(l2)));
 	}
-	else if (dist_ps_internal(&l2->p[1], l1) < dist)
+	else if (float8_lt(dist_ps_internal(&l2->p[1], l1), dist))
 	{
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(&l2->p[1]),
 													LsegPGetDatum(l1)));
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(result),
 													LsegPGetDatum(l2)));
 	}
 	else
 	{
@@ -2858,52 +2848,55 @@ close_lseg(PG_FUNCTION_ARGS)
  * Closest point on or in box to specified point.
  */
 Datum
 close_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	LSEG		lseg,
 				seg;
 	Point		point;
-	double		dist,
+	float8		dist,
 				d;
 
 	if (DatumGetBool(DirectFunctionCall2(on_pb,
 										 PointPGetDatum(pt),
 										 BoxPGetDatum(box))))
 		PG_RETURN_POINT_P(pt);
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&lseg, &box->low, &point);
 	dist = dist_ps_internal(pt, &lseg);
 
 	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	d = dist_ps_internal(pt, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&lseg, &seg, sizeof(lseg));
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&seg, &box->low, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	d = dist_ps_internal(pt, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&lseg, &seg, sizeof(lseg));
 	}
 
 	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	d = dist_ps_internal(pt, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&lseg, &seg, sizeof(lseg));
 	}
 
 	PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
 										PointPGetDatum(pt),
 										LsegPGetDatum(&lseg)));
 }
 
@@ -2926,21 +2919,21 @@ close_sl(PG_FUNCTION_ARGS)
 	float8		d1,
 				d2;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (lseg_interpt_line_internal(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = dist_pl_internal(&lseg->p[0], line);
 	d2 = dist_pl_internal(&lseg->p[1], line);
-	if (d1 < d2)
+	if (float8_lt(d1, d2))
 		*result = lseg->p[0];
 	else
 		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
 
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_sl\" not implemented")));
@@ -2960,77 +2953,80 @@ close_ls(PG_FUNCTION_ARGS)
 	float8		d1,
 				d2;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (lseg_interpt_line_internal(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = dist_pl_internal(&lseg->p[0], line);
 	d2 = dist_pl_internal(&lseg->p[1], line);
-	if (d1 < d2)
+	if (float8_lt(d1, d2))
 		*result = lseg->p[0];
 	else
 		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 }
 
 /* close_sb()
  * Closest point on or in box to line segment.
  */
 Datum
 close_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	Point		point;
 	LSEG		bseg,
 				seg;
-	double		dist,
+	float8		dist,
 				d;
 
 	/* segment intersects box? then just return closest point to center */
 	if (DatumGetBool(DirectFunctionCall2(inter_sb,
 										 LsegPGetDatum(lseg),
 										 BoxPGetDatum(box))))
 	{
 		box_cn(&point, box);
 		PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
 											PointPGetDatum(&point),
 											LsegPGetDatum(lseg)));
 	}
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
 	dist = lseg_dt(lseg, &bseg);
 
 	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	d = lseg_dt(lseg, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&bseg, &seg, sizeof(bseg));
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&seg, &box->low, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	d = lseg_dt(lseg, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&bseg, &seg, sizeof(bseg));
 	}
 
 	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	d = lseg_dt(lseg, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&bseg, &seg, sizeof(bseg));
 	}
 
 	/* OK, we now have the closest line segment on the box boundary */
 	PG_RETURN_DATUM(DirectFunctionCall2(close_lseg,
 										LsegPGetDatum(lseg),
 										LsegPGetDatum(&bseg)));
 }
@@ -3078,75 +3074,80 @@ on_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_BOOL(on_ps_internal(pt, lseg));
 }
 
 static bool
 on_ps_internal(Point *pt, LSEG *lseg)
 {
-	return FPeq(point_dt(pt, &lseg->p[0]) + point_dt(pt, &lseg->p[1]),
+	return FPeq(float8_pl(point_dt(pt, &lseg->p[0]),
+						  point_dt(pt, &lseg->p[1])),
 				point_dt(&lseg->p[0], &lseg->p[1]));
 }
 
+
 Datum
 on_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_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);
+	PG_RETURN_BOOL(float8_le(pt->x, box->high.x) &&
+				   float8_ge(pt->x, box->low.x) &&
+				   float8_le(pt->y, box->high.y) &&
+				   float8_ge(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);
+	PG_RETURN_BOOL(float8_le(pt->x, box->high.x) &&
+				   float8_ge(pt->x, box->low.x) &&
+				   float8_le(pt->y, box->high.y) &&
+				   float8_ge(pt->y, box->low.y));
 }
 
 /* on_ppath -
  *		Whether a point lies within (on) a polyline.
  *		If open, we have to (groan) check each segment.
  * (uses same algorithm as for point intersecting segment - tgl 1997-07-09)
  *		If closed, we use the old O(n) ray method for point-in-polygon.
  *				The ray is horizontal, from pt out to the right.
  *				Each segment that crosses the ray counts as an
  *				intersection; note that an endpoint or edge may touch
  *				but not cross.
  *				(we can do p-in-p in lg(n), but it takes preprocessing)
  */
 Datum
 on_ppath(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	PATH	   *path = PG_GETARG_PATH_P(1);
 	int			i,
 				n;
-	double		a,
+	float8		a,
 				b;
 
 	/*-- OPEN --*/
 	if (!path->closed)
 	{
 		n = path->npts - 1;
 		a = point_dt(pt, &path->p[0]);
 		for (i = 0; i < n; i++)
 		{
 			b = point_dt(pt, &path->p[i + 1]);
-			if (FPeq(a + b,
-					 point_dt(&path->p[i], &path->p[i + 1])))
+			if (FPeq(float8_pl(a, b), point_dt(&path->p[i], &path->p[i + 1])))
 				PG_RETURN_BOOL(true);
 			a = b;
 		}
 		PG_RETURN_BOOL(false);
 	}
 
 	/*-- CLOSED --*/
 	PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
 }
 
@@ -3204,24 +3205,24 @@ inter_sl(PG_FUNCTION_ARGS)
  */
 Datum
 inter_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	BOX			lbox;
 	LSEG		bseg;
 	Point		point;
 
-	lbox.low.x = Min(lseg->p[0].x, lseg->p[1].x);
-	lbox.low.y = Min(lseg->p[0].y, lseg->p[1].y);
-	lbox.high.x = Max(lseg->p[0].x, lseg->p[1].x);
-	lbox.high.y = Max(lseg->p[0].y, lseg->p[1].y);
+	lbox.low.x = float8_min(lseg->p[0].x, lseg->p[1].x);
+	lbox.low.y = float8_min(lseg->p[0].y, lseg->p[1].y);
+	lbox.high.x = float8_max(lseg->p[0].x, lseg->p[1].x);
+	lbox.high.y = float8_max(lseg->p[0].y, lseg->p[1].y);
 
 	/* nothing close to overlap? then not going to intersect */
 	if (!box_ov(&lbox, box))
 		PG_RETURN_BOOL(false);
 
 	/* an endpoint of segment is inside box? then clearly intersects */
 	if (DatumGetBool(DirectFunctionCall2(on_pb,
 										 PointPGetDatum(&lseg->p[0]),
 										 BoxPGetDatum(box))) ||
 		DatumGetBool(DirectFunctionCall2(on_pb,
@@ -3302,38 +3303,38 @@ inter_lb(PG_FUNCTION_ARGS)
  * make_bound_box - create the bounding box for the input polygon
  *------------------------------------------------------------------*/
 
 /*---------------------------------------------------------------------
  * Make the smallest bounding box for the given polygon.
  *---------------------------------------------------------------------*/
 static void
 make_bound_box(POLYGON *poly)
 {
 	int			i;
-	double		x1,
+	float8		x1,
 				y1,
 				x2,
 				y2;
 
 	if (poly->npts > 0)
 	{
 		x2 = x1 = poly->p[0].x;
 		y2 = y1 = poly->p[0].y;
 		for (i = 1; i < poly->npts; i++)
 		{
-			if (poly->p[i].x < x1)
+			if (float8_lt(poly->p[i].x, x1))
 				x1 = poly->p[i].x;
-			if (poly->p[i].x > x2)
+			if (float8_gt(poly->p[i].x, x2))
 				x2 = poly->p[i].x;
-			if (poly->p[i].y < y1)
+			if (float8_lt(poly->p[i].y, y1))
 				y1 = poly->p[i].y;
-			if (poly->p[i].y > y2)
+			if (float8_gt(poly->p[i].y, y2))
 				y2 = poly->p[i].y;
 		}
 
 		box_construct(&poly->boundbox, x1, x2, y1, y2);
 	}
 	else
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("cannot create bounding box for empty polygon")));
 }
@@ -3461,21 +3462,21 @@ poly_send(PG_FUNCTION_ARGS)
  * the right most point of A left of the left most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_left(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.high.x < polyb->boundbox.low.x;
+	result = float8_lt(polya->boundbox.high.x, polyb->boundbox.low.x);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3484,21 +3485,21 @@ poly_left(PG_FUNCTION_ARGS)
  * the right most point of A at or left of the right most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_overleft(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.high.x <= polyb->boundbox.high.x;
+	result = float8_le(polya->boundbox.high.x, polyb->boundbox.high.x);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3507,21 +3508,21 @@ poly_overleft(PG_FUNCTION_ARGS)
  * the left most point of A right of the right most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_right(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.low.x > polyb->boundbox.high.x;
+	result = float8_gt(polya->boundbox.low.x, polyb->boundbox.high.x);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3530,21 +3531,21 @@ poly_right(PG_FUNCTION_ARGS)
  * the left most point of A at or right of the left most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_overright(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.low.x >= polyb->boundbox.low.x;
+	result = float8_ge(polya->boundbox.low.x, polyb->boundbox.low.x);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3553,21 +3554,21 @@ poly_overright(PG_FUNCTION_ARGS)
  * the upper most point of A below the lower most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_below(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.high.y < polyb->boundbox.low.y;
+	result = float8_lt(polya->boundbox.high.y, polyb->boundbox.low.y);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3576,21 +3577,21 @@ poly_below(PG_FUNCTION_ARGS)
  * the upper most point of A at or below the upper most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_overbelow(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.high.y <= polyb->boundbox.high.y;
+	result = float8_le(polya->boundbox.high.y, polyb->boundbox.high.y);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3599,21 +3600,21 @@ poly_overbelow(PG_FUNCTION_ARGS)
  * the lower most point of A above the upper most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_above(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.low.y > polyb->boundbox.high.y;
+	result = float8_gt(polya->boundbox.low.y, polyb->boundbox.high.y);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3622,21 +3623,21 @@ poly_above(PG_FUNCTION_ARGS)
  * the lower most point of A at or above the lower most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_overabove(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.low.y >= polyb->boundbox.low.y;
+	result = float8_ge(polya->boundbox.low.y, polyb->boundbox.low.y);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3833,22 +3834,22 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 	}
 
 	if (res && !intersection)
 	{
 		Point		p;
 
 		/*
 		 * if X-intersection wasn't found  then check central point of tested
 		 * segment. In opposite case we already check all subsegments
 		 */
-		p.x = (t.p[0].x + t.p[1].x) / 2.0;
-		p.y = (t.p[0].y + t.p[1].y) / 2.0;
+		p.x = float8_div(float8_pl(t.p[0].x, t.p[1].x), 2.0);
+		p.y = float8_div(float8_pl(t.p[0].y, t.p[1].y), 2.0);
 
 		res = point_inside(&p, poly->npts, poly->p);
 	}
 
 	return res;
 }
 
 /*-----------------------------------------------------------------
  * Determine if polygon A contains polygon B.
  *-----------------------------------------------------------------*/
@@ -3975,66 +3976,68 @@ point_add(PG_FUNCTION_ARGS)
 
 	point_add_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static void
 point_add_internal(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x + pt2->x,
-					pt1->y + pt2->y);
+					float8_pl(pt1->x, pt2->x),
+					float8_pl(pt1->y, pt2->y));
 }
 
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	point_sub_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static void
 point_sub_internal(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x - pt2->x,
-					pt1->y - pt2->y);
+					float8_mi(pt1->x, pt2->x),
+					float8_mi(pt1->y, pt2->y));
 }
 
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	point_mul_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static void
 point_mul_internal(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					(pt1->x * pt2->x) - (pt1->y * pt2->y),
-					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+					float8_mi(float8_mul(pt1->x, pt2->x),
+							  float8_mul(pt1->y, pt2->y)),
+					float8_pl(float8_mul(pt1->x, pt2->y),
+							  float8_mul(pt1->y, pt2->x)));
 }
 
 Datum
 point_div(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -4042,24 +4045,26 @@ point_div(PG_FUNCTION_ARGS)
 	point_div_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static void
 point_div_internal(Point *result, Point *pt1, Point *pt2)
 {
 	float8		div;
 
-	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
+	div = float8_pl(float8_mul(pt2->x, pt2->x), float8_mul(pt2->y, pt2->y));
 	point_construct(result,
-					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
-					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+					float8_div(float8_pl(float8_mul(pt1->x, pt2->x),
+										 float8_mul(pt1->y, pt2->y)), div),
+					float8_div(float8_mi(float8_mul(pt1->y, pt2->x),
+										 float8_mul(pt1->x, pt2->y)), div));
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D boxes.
  **
  ***********************************************************************/
 
 Datum
@@ -4168,24 +4173,24 @@ point_box(PG_FUNCTION_ARGS)
  */
 Datum
 boxes_bound_box(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0),
 			   *box2 = PG_GETARG_BOX_P(1),
 			   *container;
 
 	container = (BOX *) palloc(sizeof(BOX));
 
-	container->high.x = Max(box1->high.x, box2->high.x);
-	container->low.x = Min(box1->low.x, box2->low.x);
-	container->high.y = Max(box1->high.y, box2->high.y);
-	container->low.y = Min(box1->low.y, box2->low.y);
+	container->high.x = float8_max(box1->high.x, box2->high.x);
+	container->low.x = float8_min(box1->low.x, box2->low.x);
+	container->high.y = float8_max(box1->high.y, box2->high.y);
+	container->low.y = float8_min(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(container);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D paths.
  **
  ***********************************************************************/
@@ -4495,21 +4500,21 @@ circle_in(PG_FUNCTION_ARGS)
 		if (*cp == LDELIM)
 			s = cp;
 	}
 
 	pair_decode(s, &circle->center.x, &circle->center.y, &s, "circle", str);
 
 	if (*s == DELIM)
 		s++;
 
 	circle->radius = single_decode(s, &s, "circle", str);
-	if (circle->radius < 0)
+	if (float8_lt(circle->radius, 0.0))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
 
 	while (depth > 0)
 	{
 		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
@@ -4562,21 +4567,21 @@ circle_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	circle->center.x = pq_getmsgfloat8(buf);
 	circle->center.y = pq_getmsgfloat8(buf);
 	circle->radius = pq_getmsgfloat8(buf);
 
-	if (circle->radius < 0)
+	if (float8_lt(circle->radius, 0.0))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
 				 errmsg("invalid radius in external \"circle\" value")));
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 /*
  *		circle_send			- converts circle to binary format
  */
@@ -4613,144 +4618,146 @@ circle_same(PG_FUNCTION_ARGS)
 
 /*		circle_overlap	-		does circle1 overlap circle2?
  */
 Datum
 circle_overlap(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle1->radius + circle2->radius));
+						float8_pl(circle1->radius, circle2->radius)));
 }
 
 /*		circle_overleft -		is the right edge of circle1 at or left of
  *								the right edge of circle2?
  */
 Datum
 circle_overleft(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.x + circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_left		-		is circle1 strictly left of circle2?
  */
 Datum
 circle_left(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.x + circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_right	-		is circle1 strictly right of circle2?
  */
 Datum
 circle_right(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.x - circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_overright	-	is the left edge of circle1 at or right of
  *								the left edge of circle2?
  */
 Datum
 circle_overright(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.x - circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_contained		-		is circle1 contained by circle2?
  */
 Datum
 circle_contained(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle1->radius), circle2->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						float8_mi(circle2->radius, circle1->radius)));
 }
 
 /*		circle_contain	-		does circle1 contain circle2?
  */
 Datum
 circle_contain(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle2->radius), circle1->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						float8_mi(circle1->radius, circle2->radius)));
 }
 
 
 /*		circle_below		-		is circle1 strictly below circle2?
  */
 Datum
 circle_below(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.y + circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_above	-		is circle1 strictly above circle2?
  */
 Datum
 circle_above(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.y - circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overbelow -		is the upper edge of circle1 at or below
  *								the upper edge of circle2?
  */
 Datum
 circle_overbelow(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.y + circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overabove	-	is the lower edge of circle1 at or above
  *								the lower edge of circle2?
  */
 Datum
 circle_overabove(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.y - circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 
 /*		circle_relop	-		is area(circle1) relop area(circle2), within
  *								our accuracy constraint?
  */
 Datum
 circle_eq(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
@@ -4849,36 +4856,38 @@ circle_sub_pt(PG_FUNCTION_ARGS)
 Datum
 circle_mul_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_mul_internal(&result->center, &circle->center, point);
-	result->radius *= HYPOT(point->x, point->y);
+	result->radius = float8_mul(circle->radius,
+								float8_hypot(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_div_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_div_internal(&result->center, &circle->center, point);
-	result->radius /= HYPOT(point->x, point->y);
+	result->radius = float8_div(circle->radius,
+								float8_hypot(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /*		circle_area		-		returns the area of the circle.
  */
 Datum
 circle_area(PG_FUNCTION_ARGS)
 {
@@ -4888,21 +4897,21 @@ circle_area(PG_FUNCTION_ARGS)
 }
 
 
 /*		circle_diameter -		returns the diameter of the circle.
  */
 Datum
 circle_diameter(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
-	PG_RETURN_FLOAT8(2 * circle->radius);
+	PG_RETURN_FLOAT8(float8_mul(circle->radius, 2.0));
 }
 
 
 /*		circle_radius	-		returns the radius of the circle.
  */
 Datum
 circle_radius(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
@@ -4913,81 +4922,84 @@ circle_radius(PG_FUNCTION_ARGS)
 /*		circle_distance -		returns the distance between
  *								  two circles.
  */
 Datum
 circle_distance(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(&circle1->center, &circle2->center)
-		- (circle1->radius + circle2->radius);
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(&circle1->center, &circle2->center),
+					   float8_pl(circle1->radius, circle2->radius));
+	if (float8_lt(result, 0.0))
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 
 Datum
 circle_contain_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
-	PG_RETURN_BOOL(d <= circle->radius);
+	PG_RETURN_BOOL(float8_le(d, circle->radius));
 }
 
 
 Datum
 pt_contained_circle(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
-	PG_RETURN_BOOL(d <= circle->radius);
+	PG_RETURN_BOOL(float8_le(d, circle->radius));
 }
 
 
 /*		dist_pc -		returns the distance between
  *						  a point and a circle.
  */
 Datum
 dist_pc(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center), circle->radius);
+	if (float8_lt(result, 0.0))
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a circle to a point
  */
 Datum
 dist_cpoint(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center), circle->radius);
+	if (float8_lt(result, 0.0))
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*		circle_center	-		returns the center point of the circle.
  */
 Datum
 circle_center(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *result;
@@ -4995,24 +5007,24 @@ circle_center(PG_FUNCTION_ARGS)
 	result = (Point *) palloc(sizeof(Point));
 	result->x = circle->center.x;
 	result->y = circle->center.y;
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		circle_ar		-		returns the area of the circle.
  */
-static double
+static float8
 circle_ar(CIRCLE *circle)
 {
-	return M_PI * (circle->radius * circle->radius);
+	return float8_mul(float8_mul(circle->radius, circle->radius), M_PI);
 }
 
 
 /*----------------------------------------------------------
  *	Conversion operators.
  *---------------------------------------------------------*/
 
 Datum
 cr_circle(PG_FUNCTION_ARGS)
 {
@@ -5027,65 +5039,65 @@ cr_circle(PG_FUNCTION_ARGS)
 	result->radius = radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_box(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	BOX		   *box;
-	double		delta;
+	float8		delta;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
-	delta = circle->radius / sqrt(2.0);
+	delta = float8_div(circle->radius, sqrt(2.0));
 
-	box->high.x = circle->center.x + delta;
-	box->low.x = circle->center.x - delta;
-	box->high.y = circle->center.y + delta;
-	box->low.y = circle->center.y - delta;
+	box->high.x = float8_pl(circle->center.x, delta);
+	box->low.x = float8_mi(circle->center.x, delta);
+	box->high.y = float8_pl(circle->center.y, delta);
+	box->low.y = float8_mi(circle->center.y, delta);
 
 	PG_RETURN_BOX_P(box);
 }
 
 /* box_circle()
  * Convert a box to a circle.
  */
 Datum
 box_circle(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	circle->center.x = (box->high.x + box->low.x) / 2;
-	circle->center.y = (box->high.y + box->low.y) / 2;
+	circle->center.x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	circle->center.y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 
 	circle->radius = point_dt(&circle->center, &box->high);
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 
 Datum
 circle_poly(PG_FUNCTION_ARGS)
 {
 	int32		npts = PG_GETARG_INT32(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	POLYGON    *poly;
 	int			base_size,
 				size;
 	int			i;
-	double		angle;
-	double		anglestep;
+	float8		angle;
+	float8		anglestep;
 
 	if (FPzero(circle->radius))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("cannot convert circle with radius zero to polygon")));
 
 	if (npts < 2)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("must request at least 2 points")));
@@ -5096,27 +5108,30 @@ circle_poly(PG_FUNCTION_ARGS)
 	/* Check for integer overflow */
 	if (base_size / npts != sizeof(poly->p[0]) || size <= base_size)
 		ereport(ERROR,
 				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 				 errmsg("too many points requested")));
 
 	poly = (POLYGON *) palloc0(size);	/* zero any holes */
 	SET_VARSIZE(poly, size);
 	poly->npts = npts;
 
-	anglestep = (2.0 * M_PI) / npts;
+	anglestep = float8_div(2.0 * M_PI, npts);
 
 	for (i = 0; i < npts; i++)
 	{
-		angle = i * anglestep;
-		poly->p[i].x = circle->center.x - (circle->radius * cos(angle));
-		poly->p[i].y = circle->center.y + (circle->radius * sin(angle));
+		angle = float8_mul(anglestep, i);
+
+		poly->p[i].x = float8_mi(circle->center.x,
+								 float8_mul(circle->radius, cos(angle)));
+		poly->p[i].y = float8_pl(circle->center.y,
+								 float8_mul(circle->radius, sin(angle)));
 	}
 
 	make_bound_box(poly);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
 /*		poly_circle		- convert polygon to circle
  *
  * XXX This algorithm should use weighted means of line segments
@@ -5135,29 +5150,30 @@ poly_circle(PG_FUNCTION_ARGS)
 				 errmsg("cannot convert empty polygon to circle")));
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	circle->center.x = 0;
 	circle->center.y = 0;
 	circle->radius = 0;
 
 	for (i = 0; i < poly->npts; i++)
 	{
-		circle->center.x += poly->p[i].x;
-		circle->center.y += poly->p[i].y;
+		circle->center.x = float8_pl(circle->center.x, poly->p[i].x);
+		circle->center.y = float8_pl(circle->center.y, poly->p[i].y);
 	}
-	circle->center.x /= poly->npts;
-	circle->center.y /= poly->npts;
+	circle->center.x = float8_div(circle->center.x, poly->npts);
+	circle->center.y = float8_div(circle->center.y, poly->npts);
 
 	for (i = 0; i < poly->npts; i++)
-		circle->radius += point_dt(&poly->p[i], &circle->center);
-	circle->radius /= poly->npts;
+		circle->radius = float8_pl(circle->radius, point_dt(&poly->p[i],
+															&circle->center));
+	circle->radius = float8_div(circle->radius, poly->npts);
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 
 /***********************************************************************
  **
  **		Private routines for multiple types.
  **
  ***********************************************************************/
@@ -5171,45 +5187,45 @@ poly_circle(PG_FUNCTION_ARGS)
  *	http://hopf.math.northwestern.edu/index.html
  *	Description of algorithm:  http://www.linuxjournal.com/article/2197
  *							   http://www.linuxjournal.com/article/2029
  */
 
 #define POINT_ON_POLYGON INT_MAX
 
 static int
 point_inside(Point *p, int npts, Point *plist)
 {
-	double		x0,
+	float8		x0,
 				y0;
-	double		prev_x,
+	float8		prev_x,
 				prev_y;
 	int			i = 0;
-	double		x,
+	float8		x,
 				y;
 	int			cross,
 				total_cross = 0;
 
 	if (npts <= 0)
 		return 0;
 
 	/* compute first polygon point relative to single point */
-	x0 = plist[0].x - p->x;
-	y0 = plist[0].y - p->y;
+	x0 = float8_mi(plist[0].x, p->x);
+	y0 = float8_mi(plist[0].y, p->y);
 
 	prev_x = x0;
 	prev_y = y0;
 	/* loop over polygon points and aggregate total_cross */
 	for (i = 1; i < npts; i++)
 	{
 		/* compute next polygon point relative to single point */
-		x = plist[i].x - p->x;
-		y = plist[i].y - p->y;
+		x = float8_mi(plist[i].x, p->x);
+		y = float8_mi(plist[i].y, p->y);
 
 		/* compute previous to current point crossing */
 		if ((cross = lseg_crossing(x, y, prev_x, prev_y)) == POINT_ON_POLYGON)
 			return 2;
 		total_cross += cross;
 
 		prev_x = x;
 		prev_y = y;
 	}
 
@@ -5227,69 +5243,74 @@ point_inside(Point *p, int npts, Point *plist)
 /* lseg_crossing()
  * Returns +/-2 if line segment crosses the positive X-axis in a +/- direction.
  * Returns +/-1 if one point is on the positive X-axis.
  * Returns 0 if both points are on the positive X-axis, or there is no crossing.
  * Returns POINT_ON_POLYGON if the segment contains (0,0).
  * Wow, that is one confusing API, but it is used above, and when summed,
  * can tell is if a point is in a polygon.
  */
 
 static int
-lseg_crossing(double x, double y, double prev_x, double prev_y)
+lseg_crossing(float8 x, float8 y, float8 prev_x, float8 prev_y)
 {
-	double		z;
+	float8		z;
 	int			y_sign;
 
 	if (FPzero(y))
 	{							/* y == 0, on X axis */
 		if (FPzero(x))			/* (x,y) is (0,0)? */
 			return POINT_ON_POLYGON;
 		else if (FPgt(x, 0))
 		{						/* x > 0 */
 			if (FPzero(prev_y)) /* y and prev_y are zero */
 				/* prev_x > 0? */
-				return FPgt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
-			return FPlt(prev_y, 0) ? 1 : -1;
+				return FPgt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
+			return FPlt(prev_y, 0.0) ? 1 : -1;
 		}
 		else
 		{						/* x < 0, x not on positive X axis */
 			if (FPzero(prev_y))
 				/* prev_x < 0? */
-				return FPlt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
+				return FPlt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
 			return 0;
 		}
 	}
 	else
 	{							/* y != 0 */
 		/* compute y crossing direction from previous point */
-		y_sign = FPgt(y, 0) ? 1 : -1;
+		y_sign = FPgt(y, 0.0) ? 1 : -1;
 
 		if (FPzero(prev_y))
 			/* previous point was on X axis, so new point is either off or on */
-			return FPlt(prev_x, 0) ? 0 : y_sign;
-		else if (FPgt(y_sign * prev_y, 0))
+			return FPlt(prev_x, 0.0) ? 0 : y_sign;
+		else if ((y_sign < 0 && FPlt(prev_y, 0.0)) ||
+			(y_sign > 0 && FPgt(prev_y, 0.0)))
 			/* both above or below X axis */
 			return 0;			/* same sign */
 		else
 		{						/* y and prev_y cross X-axis */
-			if (FPge(x, 0) && FPgt(prev_x, 0))
+			if (FPge(x, 0.0) && FPgt(prev_x, 0.0))
 				/* both non-negative so cross positive X-axis */
 				return 2 * y_sign;
-			if (FPlt(x, 0) && FPle(prev_x, 0))
+			if (FPlt(x, 0.0) && FPle(prev_x, 0.0))
 				/* both non-positive so do not cross positive X-axis */
 				return 0;
 
 			/* x and y cross axises, see URL above point_inside() */
-			z = (x - prev_x) * y - (y - prev_y) * x;
+			z = float8_mi(float8_mul(float8_mi(x, prev_x), y),
+						  float8_mul(float8_mi(y, prev_y), x));
 			if (FPzero(z))
 				return POINT_ON_POLYGON;
-			return FPgt((y_sign * z), 0) ? 0 : 2 * y_sign;
+			if ((y_sign < 0 && FPlt(z, 0.0)) ||
+				(y_sign > 0 && FPgt(z, 0.0)))
+				return 0;
+			return 2 * y_sign;
 		}
 	}
 }
 
 
 static bool
 plist_same(int npts, Point *p1, Point *p2)
 {
 	int			i,
 				ii,
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index c800bb1338..f62be1061e 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -76,38 +76,38 @@
 #include "access/spgist.h"
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
 #include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
- * is going only going to be used in a place to effect the performance
+ * is only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
 compareDoubles(const void *a, const void *b)
 {
-	double		x = *(double *) a;
-	double		y = *(double *) b;
+	float8		x = *(float8 *) a;
+	float8		y = *(float8 *) b;
 
 	if (x == y)
 		return 0;
 	return (x > y) ? 1 : -1;
 }
 
 typedef struct
 {
-	double		low;
-	double		high;
+	float8		low;
+	float8		high;
 } Range;
 
 typedef struct
 {
 	Range		left;
 	Range		right;
 } RangeBox;
 
 typedef struct
 {
@@ -121,30 +121,30 @@ typedef struct
  * The quadrant is 8 bit unsigned integer with 4 least bits in use.
  * This function accepts BOXes as input.  They are not casted to
  * RangeBoxes, yet.  All 4 bits are set by comparing a corner of the box.
  * This makes 16 quadrants in total.
  */
 static uint8
 getQuadrant(BOX *centroid, BOX *inBox)
 {
 	uint8		quadrant = 0;
 
-	if (inBox->low.x > centroid->low.x)
+	if (float8_gt(inBox->low.x, centroid->low.x))
 		quadrant |= 0x8;
 
-	if (inBox->high.x > centroid->high.x)
+	if (float8_gt(inBox->high.x, centroid->high.x))
 		quadrant |= 0x4;
 
-	if (inBox->low.y > centroid->low.y)
+	if (float8_gt(inBox->low.y, centroid->low.y))
 		quadrant |= 0x2;
 
-	if (inBox->high.y > centroid->high.y)
+	if (float8_gt(inBox->high.y, centroid->high.y))
 		quadrant |= 0x1;
 
 	return quadrant;
 }
 
 /*
  * Get RangeBox using BOX
  *
  * We are turning the BOX to our structures to emphasize their function
  * of representing points in 4D space.  It also is more convenient to
@@ -167,21 +167,21 @@ getRangeBox(BOX *box)
 /*
  * Initialize the traversal value
  *
  * In the beginning, we don't have any restrictions.  We have to
  * initialize the struct to cover the whole 4D space.
  */
 static RectBox *
 initRectBox(void)
 {
 	RectBox    *rect_box = (RectBox *) palloc(sizeof(RectBox));
-	double		infinity = get_float8_infinity();
+	float8		infinity = get_float8_infinity();
 
 	rect_box->range_box_x.left.low = -infinity;
 	rect_box->range_box_x.left.high = infinity;
 
 	rect_box->range_box_x.right.low = -infinity;
 	rect_box->range_box_x.right.high = infinity;
 
 	rect_box->range_box_y.left.low = -infinity;
 	rect_box->range_box_y.left.high = infinity;
 
@@ -410,40 +410,40 @@ spg_box_quad_choose(PG_FUNCTION_ARGS)
  * point as the median of the coordinates of the boxes.
  */
 Datum
 spg_box_quad_picksplit(PG_FUNCTION_ARGS)
 {
 	spgPickSplitIn *in = (spgPickSplitIn *) PG_GETARG_POINTER(0);
 	spgPickSplitOut *out = (spgPickSplitOut *) PG_GETARG_POINTER(1);
 	BOX		   *centroid;
 	int			median,
 				i;
-	double	   *lowXs = palloc(sizeof(double) * in->nTuples);
-	double	   *highXs = palloc(sizeof(double) * in->nTuples);
-	double	   *lowYs = palloc(sizeof(double) * in->nTuples);
-	double	   *highYs = palloc(sizeof(double) * in->nTuples);
+	float8	   *lowXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *lowYs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highYs = palloc(sizeof(float8) * in->nTuples);
 
 	/* Calculate median of all 4D coordinates */
 	for (i = 0; i < in->nTuples; i++)
 	{
 		BOX		   *box = DatumGetBoxP(in->datums[i]);
 
 		lowXs[i] = box->low.x;
 		highXs[i] = box->high.x;
 		lowYs[i] = box->low.y;
 		highYs[i] = box->high.y;
 	}
 
-	qsort(lowXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(lowYs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highYs, in->nTuples, sizeof(double), compareDoubles);
+	qsort(lowXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(lowYs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highYs, in->nTuples, sizeof(float8), compareDoubles);
 
 	median = in->nTuples / 2;
 
 	centroid = palloc(sizeof(BOX));
 
 	centroid->low.x = lowXs[median];
 	centroid->high.x = highXs[median];
 	centroid->low.y = lowYs[median];
 	centroid->high.y = highYs[median];
 
diff --git a/src/include/utils/float.h b/src/include/utils/float.h
index c26de1cca4..c893f79a4d 100644
--- a/src/include/utils/float.h
+++ b/src/include/utils/float.h
@@ -269,20 +269,33 @@ float8_div(float8 val1, float8 val2)
 		ereport(ERROR,
 				(errcode(ERRCODE_DIVISION_BY_ZERO),
 				 errmsg("division by zero")));
 
 	result = val1 / val2;
 	check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
 
 	return result;
 }
 
+static inline float8
+float8_hypot(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = hypot(val1, val2);
+	check_float8_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0 && val2 == 0.0);
+	Assert(isinf(result) || result >= 0.0);
+
+	return result;
+}
+
 /*
  * Routines for NaN-aware comparisons
  *
  * We consider all NANs to be equal and larger than any non-NAN. This is
  * somewhat arbitrary; the important thing is to have a consistent sort
  * order.
  */
 
 static inline bool
 float4_eq(float4 val1, float4 val2)
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index f845dffcb7..527036f1fc 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -1,23 +1,20 @@
 /*-------------------------------------------------------------------------
  *
  * geo_decls.h - Declarations for various 2D constructs.
  *
  *
  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * src/include/utils/geo_decls.h
  *
- * NOTE
- *	  These routines do *not* use the float types from adt/.
- *
  *	  XXX These routines were not written by a numerical analyst.
  *
  *	  XXX I have made some attempt to flesh out the operators
  *		and data types. There are still some more to do. - tgl 97/04/19
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEO_DECLS_H
 #define GEO_DECLS_H
 
@@ -28,44 +25,43 @@
 
 /*--------------------------------------------------------------------
  * Useful floating point utilities and constants.
  *-------------------------------------------------------------------*/
 
 
 #define EPSILON					1.0E-06
 
 #ifdef EPSILON
 #define FPzero(A)				(fabs(A) <= EPSILON)
-#define FPeq(A,B)				(fabs((A) - (B)) <= EPSILON)
-#define FPne(A,B)				(fabs((A) - (B)) > EPSILON)
-#define FPlt(A,B)				((B) - (A) > EPSILON)
-#define FPle(A,B)				((A) - (B) <= EPSILON)
-#define FPgt(A,B)				((A) - (B) > EPSILON)
-#define FPge(A,B)				((B) - (A) <= EPSILON)
+#define FPeq(A, B)				(float8_le(fabs(float8_mi(A, B)), EPSILON))
+#define FPne(A, B)				(float8_gt(fabs(float8_mi(A, B)), EPSILON))
+#define FPlt(A, B)				(float8_gt(float8_mi(B, A), EPSILON))
+#define FPle(A, B)				(float8_le(float8_mi(A, B), EPSILON))
+#define FPgt(A, B)				(float8_gt(float8_mi(A, B), EPSILON))
+#define FPge(A, B)				(float8_le(float8_mi(B, A), EPSILON))
 #else
-#define FPzero(A)				((A) == 0)
-#define FPeq(A,B)				((A) == (B))
-#define FPne(A,B)				((A) != (B))
-#define FPlt(A,B)				((A) < (B))
-#define FPle(A,B)				((A) <= (B))
-#define FPgt(A,B)				((A) > (B))
-#define FPge(A,B)				((A) >= (B))
+#define FPzero(A)				((A) == 0.0)
+#define FPeq(A, B)				(float8_eq(A, B))
+#define FPne(A, B)				(float8_ne(A, B))
+#define FPlt(A, B)				(float8_lt(A, B))
+#define FPle(A, B)				(float8_le(A, B))
+#define FPgt(A, B)				(float8_gt(A, B))
+#define FPge(A, B)				(float8_ge(A, B))
 #endif
 
-#define HYPOT(A, B)				hypot(A, B)
 
 /*---------------------------------------------------------------------
  * Point - (x,y)
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		x,
+	float8		x,
 				y;
 } Point;
 
 
 /*---------------------------------------------------------------------
  * LSEG - A straight line, specified by endpoints.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		p[2];
@@ -73,66 +69,66 @@ typedef struct
 
 
 /*---------------------------------------------------------------------
  * PATH - Specified by vertex points.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	int32		vl_len_;		/* varlena header (do not touch directly!) */
 	int32		npts;
 	int32		closed;			/* is this a closed polygon? */
-	int32		dummy;			/* padding to make it double align */
+	int32		dummy;			/* padding to make it float8 align */
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } PATH;
 
 
 /*---------------------------------------------------------------------
  * LINE - Specified by its general equation (Ax+By+C=0).
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		A,
+	float8		A,
 				B,
 				C;
 } LINE;
 
 
 /*---------------------------------------------------------------------
  * BOX	- Specified by two corner points, which are
  *		 sorted to save calculation time later.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		high,
 				low;			/* corner POINTs */
 } BOX;
 
 /*---------------------------------------------------------------------
- * POLYGON - Specified by an array of doubles defining the points,
+ * POLYGON - Specified by an array of float8s defining the points,
  *		keeping the number of points and the bounding box for
  *		speed purposes.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	int32		vl_len_;		/* varlena header (do not touch directly!) */
 	int32		npts;
 	BOX			boundbox;
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } POLYGON;
 
 /*---------------------------------------------------------------------
  * CIRCLE - Specified by a center point and radius.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		center;
-	double		radius;
+	float8		radius;
 } CIRCLE;
 
 /*
  * fmgr interface macros
  *
  * Path and Polygon are toastable varlena types, the others are just
  * fixed-size pass-by-reference types.
  */
 
 #define DatumGetPointP(X)	 ((Point *) DatumGetPointer(X))
-- 
2.11.0 (Apple Git-81)

0004-line-fixes-v2.patchapplication/octet-stream; name=0004-line-fixes-v2.patchDownload
From fdd1d3ebbe03ef529b34328048c7ff9f95c18a80 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sun, 28 May 2017 11:35:17 +0200
Subject: [PATCH 4/4] line-fixes-v2

Fix obvious problems around the line datatype

I have noticed some line operators retuning wrong results, and Tom Lane
spotted similar problems on more places.  Source history reveals that
during 1990s, the internal format of the line datatype is changed, but
most functions haven't got the hint.  The fixes include:

* Reject invalid specification A=B=0 on receive
* Avoid division by zero on perpendicular operator
* Fix intersection and distance operators when neither A nor B are 1
* Avoid point distance operator crashing on float precision loss
* Fix line segment distance by getting the minimum as the comment suggested

The changes are also aiming make line operators more symmetric.  Changing
results for same lines in different order are surely not expected.

Previous discussion:
https://www.postgresql.org/message-id/flat/CAE2gYzw_-z%3DV2kh8QqFjenu%3D8MJXzOP44wRW%3DAzzeamrmTT1%3DQ%40mail.gmail.com
---
 src/backend/utils/adt/geo_ops.c | 115 +++++++++++++++++++++++++++-------------
 1 file changed, 77 insertions(+), 38 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 0af71aa818..d4f8fe9020 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -948,20 +948,25 @@ line_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LINE	   *line;
 
 	line = (LINE *) palloc(sizeof(LINE));
 
 	line->A = pq_getmsgfloat8(buf);
 	line->B = pq_getmsgfloat8(buf);
 	line->C = pq_getmsgfloat8(buf);
 
+	if (line->A == 0.0 && line->B == 0.0)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+		 errmsg("invalid line specification: A and B cannot both be zero")));
+
 	PG_RETURN_LINE_P(line);
 }
 
 /*
  *		line_send			- converts line to binary format
  */
 Datum
 line_send(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -1095,25 +1100,28 @@ line_parallel(PG_FUNCTION_ARGS)
 }
 
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
-	else if (FPzero(l1->B))
+	if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
+	if (FPzero(l2->A))
+		PG_RETURN_BOOL(FPzero(l1->B));
+	if (FPzero(l2->B))
+		PG_RETURN_BOOL(FPzero(l1->A));
 
-	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
-								   float8_mul(l1->B, l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(float8_mul(l1->A, l2->B), -float8_mul(l1->B, l2->A)));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
@@ -1125,20 +1133,21 @@ line_horizontal(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(FPzero(line->A));
 }
 
 Datum
 line_eq(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		ratio;
 
+	/* A and B cannot be both 0, but we never really know with the EPSILON. */
 	if (!FPzero(l2->A))
 		ratio = float8_div(l1->A, l2->A);
 	else if (!FPzero(l2->B))
 		ratio = float8_div(l1->B, l2->B);
 	else if (!FPzero(l2->C))
 		ratio = float8_div(l1->C, l2->C);
 	else
 		ratio = 1.0;
 
 	PG_RETURN_BOOL(FPeq(l1->A, float8_mul(ratio, l2->A)) &&
@@ -1152,30 +1161,36 @@ line_eq(PG_FUNCTION_ARGS)
  *---------------------------------------------------------*/
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	float8		result;
-	Point		tmp;
+	float8		ratio;
 
 	if (line_interpt_internal(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
-	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
-	point_construct(&tmp, 0.0, l1->C);
-	result = dist_pl_internal(&tmp, l2);
-	PG_RETURN_FLOAT8(result);
+
+	/* A and B cannot be both 0, but we never really know with the EPSILON. */
+	if (!FPzero(l2->A))
+		ratio = float8_div(l1->A, l2->A);
+	else if (!FPzero(l2->B))
+		ratio = float8_div(l1->B, l2->B);
+	else
+		ratio = 1.0;
+
+	PG_RETURN_FLOAT8(float8_div(fabs(float8_mi(l1->C,
+											   float8_mul(ratio, l2->C))),
+								float8_hypot(l1->A, l1->B)));
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
@@ -1198,38 +1213,62 @@ line_interpt(PG_FUNCTION_ARGS)
  * NOTE: If the lines are identical then we will find they are parallel
  * and report "no intersection".  This is a little weird, but since
  * there's no *unique* intersection, maybe it's appropriate behavior.
  */
 static bool
 line_interpt_internal(Point *result, LINE *l1, LINE *l2)
 {
 	float8		x,
 				y;
 
-	if (FPzero(l1->B))			/* l1 vertical? */
+	if (FPzero(l1->A))			/* l1 horizontal? */
+	{
+		if (FPzero(l2->A))		/* l2 horizontal? */
+			return false;
+
+		y = float8_div(-l1->C, l1->B);
+		x = float8_div(-float8_pl(float8_mul(l2->B, y), l2->C), l2->A);
+	}
+	else if (FPzero(l1->B))		/* l1 vertical? */
 	{
 		if (FPzero(l2->B))		/* l2 vertical? */
 			return false;
 
-		x = l1->C;
-		y = float8_pl(float8_mul(l2->A, x), l2->C);
+		x = float8_div(-l1->C, l1->A);
+		y = float8_div(-float8_pl(float8_mul(l2->A, x), l2->C), l2->B);
+	}
+	else if (FPzero(l2->A))		/* l2 horizontal? */
+	{
+		if (FPzero(l1->A))		/* l1 horizontal? */
+			return false;
+
+		y = float8_div(-l2->C, l2->B);
+		x = float8_div(-float8_pl(float8_mul(l1->B, y), l1->C), l1->A);
+	}
+	else if (FPzero(l2->B))		/* l2 vertical? */
+	{
+		if (FPzero(l1->B))		/* l1 vertical? */
+			return false;
+
+		x = float8_div(-l2->C, l2->A);
+		y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
 	}
 	else
 	{
-		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
+		if (FPeq(float8_mul(l1->A, l2->B), float8_mul(l2->A, l1->B)))
 			return false;
 
-		if (FPzero(l2->B))
-			x = l2->C;
-		else
-			x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
-		y = float8_pl(float8_mul(l1->A, x), l1->C);
+		x = float8_div(float8_mi(float8_mul(l1->B, l2->C),
+								 float8_mul(l2->B, l1->C)),
+					   float8_mi(float8_mul(l1->A, l2->B),
+								 float8_mul(l2->A, l1->B)));
+		y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
 	}
 	if (result != NULL)
 		point_construct(result, x, y);
 
 #ifdef GEODEBUG
 	printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
 		   DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
 	printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
 #endif
 
@@ -2449,22 +2488,21 @@ dist_pb(PG_FUNCTION_ARGS)
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	float8		result;
 
 	if (lseg_interpt_line_internal(NULL, lseg, line))
 		result = 0.0;
 	else
-		/* XXX shouldn't we take the min not max? */
-		result = float8_max(dist_pl_internal(&lseg->p[0], line),
+		result = float8_min(dist_pl_internal(&lseg->p[0], line),
 							dist_pl_internal(&lseg->p[1], line));
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
@@ -2645,43 +2683,44 @@ lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line)
 /* close_pl -
  *		The intersection point of a perpendicular of the line
  *		through the point.
  */
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
-	float8		invm;
-	LINE		tmp;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (FPzero(line->B))		/* vertical? */
+		point_construct(result, float8_div(-line->C, line->A), pt->y);
+	else if (FPzero(line->A))	/* horizontal? */
+		point_construct(result, pt->x, float8_div(-line->C, line->B));
+	else
 	{
-		result->x = line->C;
-		result->y = pt->y;
-		PG_RETURN_POINT_P(result);
-	}
-	if (FPzero(line->A))		/* horizontal? */
-	{
-		result->x = pt->x;
-		result->y = line->C;
-		PG_RETURN_POINT_P(result);
-	}
-	/* drop a perpendicular and find the intersection point */
+		LINE		perp;
+
+		/*
+		 * Drop a perpendicular and find the intersection point
+		 *
+		 * We need to invert and flip the sign on the slope to get the
+		 * perpendicular.  We might lose some precision on the division.
+		 * It shouldn't be as much to turn the line.  If it happens anyway,
+		 * we will assume the point it on the line.
+		 */
+		line_construct_pm(&perp, pt, float8_div(line->B, line->A));
+		if (!line_interpt_internal(result, &perp, line))
+			*result = *pt;
+	}
 
-	/* invert and flip the sign on the slope to get a perpendicular */
-	invm = float8_div(line->B, line->A);
-	line_construct_pm(&tmp, pt, invm);
-	line_interpt_internal(result, &tmp, line);
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_ps()
  * Closest point on line segment to specified point.
  * Take the closest endpoint if the point is left, right,
  *	above, or below the segment, otherwise find the intersection
  *	point of the segment and its perpendicular through the point.
  *
-- 
2.11.0 (Apple Git-81)

#6Aleksander Alekseev
a.alekseev@postgrespro.ru
In reply to: Emre Hasegeli (#5)
Re: [PATCH] Improve geometric types

The following review has been posted through the commitfest application:
make installcheck-world: tested, passed
Implements feature: tested, passed
Spec compliant: tested, passed
Documentation: tested, passed

LGTM.

The new status of this patch is: Ready for Committer

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

#7Kyotaro HORIGUCHI
horiguchi.kyotaro@lab.ntt.co.jp
In reply to: Aleksander Alekseev (#6)
Re: [PATCH] Improve geometric types

Hello, sorry to late for the party, but may I comment on this?

At Tue, 05 Sep 2017 13:18:12 +0000, Aleksander Alekseev <a.alekseev@postgrespro.ru> wrote in <20170905131812.18925.13551.pgcf@coridan.postgresql.org>

The following review has been posted through the commitfest application:
make installcheck-world: tested, passed
Implements feature: tested, passed
Spec compliant: tested, passed
Documentation: tested, passed

LGTM.

The new status of this patch is: Ready for Committer

The first patch reconstructs the operators in layers. These
functions are called very frequently when used. Some function are
already inlined in float.h but some static functions in float.h
also can be and are better be inlined. Some of *_internal,
point_construct, line_calculate_point and so on are the
candidates.

You removed some DirectFunctionCall to the functions within the
same file but other functions remain in the style,
ex. poly_center or on_sl. The function called from the former
seems large enough but the latter function calls a so small
function that it could be inlined. Would you like to make some
additional functions use C call (instead of DirectFunctionCall)
and inlining them?

This is not a fault of this patch, but some functions like on_pb
seems missing comment to describe what it is. Would you like to
add some?

In the second patch, the additional include fmgrprotos.h in
btree_gin.c seems needless. Some float[48] features were macros
so that they share the same expressions between float4 and
float8. They still seems sharing perfectly the same expressions
in float.h. Is there any reason for converting them into typed
inline functions?

In float.h, MAXDOUBLEWIDTH is redueced from 500 to 128, but the
exponent of double is up to 308 so it doesn't seem sufficient. On
the other hand we won't use non-scientific notation for extremely
large numbers and it requires (perhaps) up to 26 bytes in the
case. In the soruce code, most of them uses "%e" and one of them
uses '%g". %e always takes the format of
"-1.(17digits)e+308".. So it would be less than 26
characters.

=# set extra_float_digits to 3;
=# select -1.221423424320453e308::float8;
?column?
---------------------------
-1.22142342432045302e+308

man printf: (linux)

Style e is used if the exponent from its conversion is less than
-4 or greater than or equal to the precision.

So we should be safe to have a buffer with 26 byte length and 500
bytes will apparently too large and even 128 will be too loose in
most cases. So how about something like the following?

#define MINDOUBLEWIDTH 32
...
float4out@float.c<modified>:

int ndig = FLT_DIG + extra_float_digits;

if (ndig < 1)
ndig = 1;

len = snprintf(ascii, MINDOUBLEWIDTH + 1, "%+.*g", ndig, num);
if (len > MINDOUBLEWIDTH + 1)
{
ascii = (char *) repalloc(ascii, len);
if (snprintf(ascii, len, "%+.*e", ndig, num) > len)
error(ERROR, "something wrong happens...");
}

I don't think the if part can be used so there would be no
performance degradation, I believe.

----
I'd like to pause here.

regards,

--
Kyotaro Horiguchi
NTT Open Source Software Center

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

#8Emre Hasegeli
emre@hasegeli.com
In reply to: Kyotaro HORIGUCHI (#7)
Re: [PATCH] Improve geometric types

Hello, sorry to late for the party, but may I comment on this?

Thank you for picking this up again.

The first patch reconstructs the operators in layers. These
functions are called very frequently when used. Some function are
already inlined in float.h but some static functions in float.h
also can be and are better be inlined. Some of *_internal,
point_construct, line_calculate_point and so on are the
candidates.

They are static functions. I though compiler can decide to inline
them. Do you think adding "inline" to the function signatures are
necessary?

You removed some DirectFunctionCall to the functions within the
same file but other functions remain in the style,
ex. poly_center or on_sl. The function called from the former
seems large enough but the latter function calls a so small
function that it could be inlined. Would you like to make some
additional functions use C call (instead of DirectFunctionCall)
and inlining them?

I tried to minimise my changes to make reviewing easier. I can make
"_internal" functions for the remaining DirectFunctionCall()s, if you
find it necessary.

This is not a fault of this patch, but some functions like on_pb
seems missing comment to describe what it is. Would you like to
add some?

I will add some on the next version.

In the second patch, the additional include fmgrprotos.h in
btree_gin.c seems needless.

It must be something I missed on rebase. I will remove it.

Some float[48] features were macros
so that they share the same expressions between float4 and
float8. They still seems sharing perfectly the same expressions
in float.h. Is there any reason for converting them into typed
inline functions?

Kevin Grittner suggested using inline functions instead of macros.
They are easier to use compared to macros, and avoid double-evaluation
hazards.

In float.h, MAXDOUBLEWIDTH is redueced from 500 to 128, but the
exponent of double is up to 308 so it doesn't seem sufficient. On
the other hand we won't use non-scientific notation for extremely
large numbers and it requires (perhaps) up to 26 bytes in the
case. In the soruce code, most of them uses "%e" and one of them
uses '%g". %e always takes the format of
"-1.(17digits)e+308".. So it would be less than 26
characters.

=# set extra_float_digits to 3;
=# select -1.221423424320453e308::float8;
?column?
---------------------------
-1.22142342432045302e+308

man printf: (linux)

Style e is used if the exponent from its conversion is less than
-4 or greater than or equal to the precision.

So we should be safe to have a buffer with 26 byte length and 500
bytes will apparently too large and even 128 will be too loose in
most cases. So how about something like the following?

#define MINDOUBLEWIDTH 32

Should it be same for float4 and float8?

...
float4out@float.c<modified>:

int ndig = FLT_DIG + extra_float_digits;

if (ndig < 1)
ndig = 1;

len = snprintf(ascii, MINDOUBLEWIDTH + 1, "%+.*g", ndig, num);
if (len > MINDOUBLEWIDTH + 1)
{
ascii = (char *) repalloc(ascii, len);
if (snprintf(ascii, len, "%+.*e", ndig, num) > len)
error(ERROR, "something wrong happens...");
}

I don't think the if part can be used so there would be no
performance degradation, I believe.

Wouldn't this change the output of the float datatypes? That would be
a backwards incompatible change.

I'd like to pause here.

I will submit new versions after your are done with your review.

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

#9Kyotaro HORIGUCHI
horiguchi.kyotaro@lab.ntt.co.jp
In reply to: Emre Hasegeli (#8)
Re: [PATCH] Improve geometric types

At Tue, 12 Sep 2017 19:30:44 +0200, Emre Hasegeli <emre@hasegeli.com> wrote in <CAE2gYzxDRvNdhrWQa7ym423uvHLWJXkqx=BoJePYMdrKPR1Zhg@mail.gmail.com>

Hello, sorry to late for the party, but may I comment on this?

Thank you for picking this up again.

The first patch reconstructs the operators in layers. These
functions are called very frequently when used. Some function are
already inlined in float.h but some static functions in float.h
also can be and are better be inlined. Some of *_internal,
point_construct, line_calculate_point and so on are the
candidates.

They are static functions. I though compiler can decide to inline
them. Do you think adding "inline" to the function signatures are
necessary?

C++ surely make just static functions inlined but I'm not sure C
compiler does that. "static" is a scope modifier and "inline" is
not (what kind of modifier is it?). In regard to gcc,

https://gcc.gnu.org/onlinedocs/gcc-7.2.0/gcc/Inline.html#Inline

By declaring a function inline, you can direct GCC to make
calls to that function faster. <snip> You can also direct GCC
to try to integrate all “simple enough” functions into their
callers with the option -finline-functions.

I didn't find that postgresql uses the options so I think we
shouldn't expect that they are inlined automatically.

You removed some DirectFunctionCall to the functions within the
same file but other functions remain in the style,
ex. poly_center or on_sl. The function called from the former
seems large enough but the latter function calls a so small
function that it could be inlined. Would you like to make some
additional functions use C call (instead of DirectFunctionCall)
and inlining them?

I tried to minimise my changes to make reviewing easier. I can make
"_internal" functions for the remaining DirectFunctionCall()s, if you
find it necessary.

Ok, it would be another patch even if we need that.

This is not a fault of this patch, but some functions like on_pb
seems missing comment to describe what it is. Would you like to
add some?

I will add some on the next version.

In the second patch, the additional include fmgrprotos.h in
btree_gin.c seems needless.

It must be something I missed on rebase. I will remove it.

Some float[48] features were macros
so that they share the same expressions between float4 and
float8. They still seems sharing perfectly the same expressions
in float.h. Is there any reason for converting them into typed
inline functions?

Kevin Grittner suggested using inline functions instead of macros.
They are easier to use compared to macros, and avoid double-evaluation
hazards.

I recall a bit about the double-evaluation hazards. I think the
functions needs a comment describing the reasons so that anyone
kind won't try to merge them into a macro again.

In float.h, MAXDOUBLEWIDTH is redueced from 500 to 128, but the
exponent of double is up to 308 so it doesn't seem sufficient. On
the other hand we won't use non-scientific notation for extremely
large numbers and it requires (perhaps) up to 26 bytes in the
case. In the soruce code, most of them uses "%e" and one of them
uses '%g". %e always takes the format of
"-1.(17digits)e+308".. So it would be less than 26
characters.

=# set extra_float_digits to 3;
=# select -1.221423424320453e308::float8;
?column?
---------------------------
-1.22142342432045302e+308

man printf: (linux)

Style e is used if the exponent from its conversion is less than
-4 or greater than or equal to the precision.

So we should be safe to have a buffer with 26 byte length and 500
bytes will apparently too large and even 128 will be too loose in
most cases. So how about something like the following?

#define MINDOUBLEWIDTH 32

Should it be same for float4 and float8?

Strictly they are different each other but float8 needs 26 bytes
(additional 1 byte is the sign for expnent, which I forgot.) and
float4 needs 15 bytes so it could be reduced to 32 and 16
respectively.

| select -1.11111111111111111111111111e-38::float4;
| -1.11111113e-38
| select -1.11111111111111111111111111e-4::float4;
| -0.000111111112
| select -1.11111111111111111111111111e-5::float4;
| -1.11111112e-05

On the other hand float4 is anyway converted into double in
float4out and I'm not sure that the extension doesn't adds
spurious digits. Therefore I think it would be reasonable that
"%g" formatter requires up to 27 bytes (26 + terminating zero) so
it should use MINDOUBLEWIDTH regardless of the precision of the
value given to the formatter.

Addition to that if we are deliberately using %g in float4out, we
can use flot8out_internal instead of most of the stuff of
float4out.

| Datum
| float4out(PG_FUNCTION_ARGS)
| {
| float8 num = PG_GETARG_FLOAT4(0);
|
| PG_RETURN_CSTRING(float8out_internal(num));
| }

...
float4out@float.c<modified>:

int ndig = FLT_DIG + extra_float_digits;

if (ndig < 1)
ndig = 1;

len = snprintf(ascii, MINDOUBLEWIDTH + 1, "%+.*g", ndig, num);
if (len > MINDOUBLEWIDTH + 1)
{
ascii = (char *) repalloc(ascii, len);
if (snprintf(ascii, len, "%+.*e", ndig, num) > len)
error(ERROR, "something wrong happens...");
}

I don't think the if part can be used so there would be no
performance degradation, I believe.

Wouldn't this change the output of the float datatypes? That would be
a backwards incompatible change.

It just reduces the unused part after terminator \0, and we won't
get incompatible result.

I'd like to pause here.

I will submit new versions after your are done with your review.

regards,

--
Kyotaro Horiguchi
NTT Open Source Software Center

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

#10Robert Haas
robertmhaas@gmail.com
In reply to: Kyotaro HORIGUCHI (#9)
Re: [PATCH] Improve geometric types

On Thu, Sep 14, 2017 at 3:33 AM, Kyotaro HORIGUCHI
<horiguchi.kyotaro@lab.ntt.co.jp> wrote:

I recall a bit about the double-evaluation hazards. I think the
functions needs a comment describing the reasons so that anyone
kind won't try to merge them into a macro again.

I think we can count on PostgreSQL developers to understand the
advantages of an inline function over a macro. Even if they don't,
the solution can't be to put a comment in every place where an inline
function is used explaining it. That would be very repetitive.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

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

#11Kyotaro HORIGUCHI
horiguchi.kyotaro@lab.ntt.co.jp
In reply to: Robert Haas (#10)
Re: [PATCH] Improve geometric types

At Thu, 14 Sep 2017 16:19:13 -0400, Robert Haas <robertmhaas@gmail.com> wrote in <CA+TgmobinBA7uvQifYaYGdDUoF6VTo56dvoTT6nKSpJF-Zfv5A@mail.gmail.com>

On Thu, Sep 14, 2017 at 3:33 AM, Kyotaro HORIGUCHI
<horiguchi.kyotaro@lab.ntt.co.jp> wrote:

I recall a bit about the double-evaluation hazards. I think the
functions needs a comment describing the reasons so that anyone
kind won't try to merge them into a macro again.

I think we can count on PostgreSQL developers to understand the
advantages of an inline function over a macro. Even if they don't,
the solution can't be to put a comment in every place where an inline
function is used explaining it. That would be very repetitive.

Of course putting such a comment to all inline functions is
silly. The point here is that many pairs of two functions with
exactly the same shape but handle different types are defined
side by side. Such situation seems tempting to merge them into
single macros, as the previous author did there.

So a simple one like the following would be enough.

/* don't merge the following same functions with different types
into single macros so that double evaluation won't happen */

Is it still too verbose?

regards,

--
Kyotaro Horiguchi
NTT Open Source Software Center

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

#12Kyotaro HORIGUCHI
horiguchi.kyotaro@lab.ntt.co.jp
In reply to: Kyotaro HORIGUCHI (#11)
Re: [PATCH] Improve geometric types

At Fri, 15 Sep 2017 17:23:28 +0900 (Tokyo Standard Time), Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp> wrote in <20170915.172328.97446299.horiguchi.kyotaro@lab.ntt.co.jp>

At Thu, 14 Sep 2017 16:19:13 -0400, Robert Haas <robertmhaas@gmail.com> wrote in <CA+TgmobinBA7uvQifYaYGdDUoF6VTo56dvoTT6nKSpJF-Zfv5A@mail.gmail.com>

On Thu, Sep 14, 2017 at 3:33 AM, Kyotaro HORIGUCHI
<horiguchi.kyotaro@lab.ntt.co.jp> wrote:

I recall a bit about the double-evaluation hazards. I think the
functions needs a comment describing the reasons so that anyone
kind won't try to merge them into a macro again.

I think we can count on PostgreSQL developers to understand the
advantages of an inline function over a macro. Even if they don't,
the solution can't be to put a comment in every place where an inline
function is used explaining it. That would be very repetitive.

Of course putting such a comment to all inline functions is
silly. The point here is that many pairs of two functions with
exactly the same shape but handle different types are defined
side by side. Such situation seems tempting to merge them into
single macros, as the previous author did there.

So a simple one like the following would be enough.

/* don't merge the following same functions with different types
into single macros so that double evaluation won't happen */

Is it still too verbose?

That being said, I'm not stick on that if Robert or others think
it as needless.

regards,

--
Kyotaro Horiguchi
NTT Open Source Software Center

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

#13Kyotaro HORIGUCHI
horiguchi.kyotaro@lab.ntt.co.jp
In reply to: Kyotaro HORIGUCHI (#9)
Re: [PATCH] Improve geometric types

Hello, just one point on 0001.

The patch replace pg_hypot with hypot in libc. The man page says
as follows.

man 3 hypot

If the result overflows, a range error occurs, and the functions return
HUGE_VAL, HUGE_VALF, or HUGE_VALL, respectively.

..

ERRORS
See math_error(7) for information on how to determine whether an error
has occurred when calling these functions.

The following errors can occur:

Range error: result overflow
errno is set to ERANGE. An overflow floating-point exception
(FE_OVERFLOW) is raised.

Range error: result underflow
An underflow floating-point exception (FE_UNDERFLOW) is raised.

These functions do not set errno for this case.

So, the code seems to need some amendments following to this
spec.

regards,

--
Kyotaro Horiguchi
NTT Open Source Software Center

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

#14Robert Haas
robertmhaas@gmail.com
In reply to: Kyotaro HORIGUCHI (#11)
Re: [PATCH] Improve geometric types

On Fri, Sep 15, 2017 at 4:23 AM, Kyotaro HORIGUCHI
<horiguchi.kyotaro@lab.ntt.co.jp> wrote:

/* don't merge the following same functions with different types
into single macros so that double evaluation won't happen */

Is it still too verbose?

Personally, I don't think such a comment has much value, but I am not
going to spend a lot of time arguing about it. It's really up to the
eventual committer to decide, and that probably won't be me in this
case. My knowledge of the geometric types isn't great, and I am a tad
busy breaking^Wimproving things I do understand.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

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

#15Kyotaro HORIGUCHI
horiguchi.kyotaro@lab.ntt.co.jp
In reply to: Robert Haas (#14)
Re: [PATCH] Improve geometric types

At Fri, 15 Sep 2017 11:25:30 -0400, Robert Haas <robertmhaas@gmail.com> wrote in <CA+TgmoYgg8=m9+Y54Az1r+KBpMuiEOZM_DLDF04jMP4twGR3Ng@mail.gmail.com>

On Fri, Sep 15, 2017 at 4:23 AM, Kyotaro HORIGUCHI
<horiguchi.kyotaro@lab.ntt.co.jp> wrote:

/* don't merge the following same functions with different types
into single macros so that double evaluation won't happen */

Is it still too verbose?

Personally, I don't think such a comment has much value, but I am not
going to spend a lot of time arguing about it. It's really up to the
eventual committer to decide, and that probably won't be me in this
case. My knowledge of the geometric types isn't great, and I am a tad
busy breaking^Wimproving things I do understand.

Ok, I agree with you.

# Though it is not a issue of geometric types :p

I'll withdrow the comment. Maybe someone notices of that when
reviewing such a patch.

regards,

--
Kyotaro Horiguchi
NTT Open Source Software Center

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

#16Emre Hasegeli
emre@hasegeli.com
In reply to: Kyotaro HORIGUCHI (#9)
4 attachment(s)
Re: [PATCH] Improve geometric types

The new versions of the patches are attached addressing your comments.

C++ surely make just static functions inlined but I'm not sure C
compiler does that.

Thank you for your explanation. I marked the mentioned functions "inline".

So we should be safe to have a buffer with 26 byte length and 500
bytes will apparently too large and even 128 will be too loose in
most cases. So how about something like the following?

#define MINDOUBLEWIDTH 32

I left this part out for now. We can improve it separately.

Attachments:

0003-geo-float-v04.patchapplication/octet-stream; name=0003-geo-float-v04.patchDownload
From 28a3446aea2c1a3b4ed2f1123b7c1e1ff385712d Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 27 May 2017 16:17:42 -0400
Subject: [PATCH 3/4] geo-float-v04

Use the built-in float datatype to implement geometric types

This will provide:

* Check for underflow and overflow
* Check for division by zero
* Handle NaNs consistently

The patch also replaces all occurrences of "double" as "float8".  They
are the same, but were randomly spread on the same file.
---
 src/backend/access/gist/gistproc.c | 156 +++++------
 src/backend/utils/adt/geo_ops.c    | 533 ++++++++++++++++++++-----------------
 src/backend/utils/adt/geo_spgist.c |  36 +--
 src/include/utils/geo_decls.h      |  41 ++-
 4 files changed, 401 insertions(+), 365 deletions(-)

diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index 13524b4da0..6fa97602c5 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -16,20 +16,21 @@
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/geo_decls.h"
 
 
 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
 						 StrategyNumber strategy);
 static bool rtree_internal_consistent(BOX *key, BOX *query,
 						  StrategyNumber strategy);
 
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
@@ -48,55 +49,56 @@ rt_box_union(BOX *n, const BOX *a, const BOX *b)
 	n->high.x = float8_max(a->high.x, b->high.x);
 	n->high.y = float8_max(a->high.y, b->high.y);
 	n->low.x = float8_min(a->low.x, b->low.x);
 	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
 	if (float8_le(box->high.x, box->low.x) ||
 		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
-	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
+	return float8_mul(float8_mi(box->high.x, box->low.x),
+					  float8_mi(box->high.y, box->low.y));
 }
 
 /*
  * Return amount by which the union of the two boxes is larger than
  * the original BOX's area.  The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 box_penalty(const BOX *original, const BOX *new)
 {
 	BOX			unionbox;
 
 	rt_box_union(&unionbox, original, new);
-	return size_box(&unionbox) - size_box(original);
+	return float8_mi(size_box(&unionbox), size_box(original));
 }
 
 /*
  * The GiST Consistent method for boxes
  *
  * Should return false if for all data items x below entry,
  * the predicate x op query must be FALSE, where op is the oper
  * corresponding to strategy in the pg_amop table.
  */
 Datum
@@ -256,74 +258,74 @@ fallbackSplit(GistEntryVector *entryvec, GIST_SPLITVEC *v)
 
 /*
  * Represents information about an entry that can be placed to either group
  * without affecting overlap over selected axis ("common entry").
  */
 typedef struct
 {
 	/* Index of entry in the initial array */
 	int			index;
 	/* Delta between penalties of entry insertion into different groups */
-	double		delta;
+	float8		delta;
 } CommonEntry;
 
 /*
  * Context for g_box_consider_split. Contains information about currently
  * selected split and some general information.
  */
 typedef struct
 {
 	int			entriesCount;	/* total number of entries being split */
 	BOX			boundingBox;	/* minimum bounding box across all entries */
 
 	/* Information about currently selected split follows */
 
 	bool		first;			/* true if no split was selected yet */
 
-	double		leftUpper;		/* upper bound of left interval */
-	double		rightLower;		/* lower bound of right interval */
+	float8		leftUpper;		/* upper bound of left interval */
+	float8		rightLower;		/* lower bound of right interval */
 
 	float4		ratio;
 	float4		overlap;
 	int			dim;			/* axis of this split */
-	double		range;			/* width of general MBR projection to the
+	float8		range;			/* width of general MBR projection to the
 								 * selected axis */
 } ConsiderSplitContext;
 
 /*
  * Interval represents projection of box to axis.
  */
 typedef struct
 {
-	double		lower,
+	float8		lower,
 				upper;
 } SplitInterval;
 
 /*
  * Interval comparison function by lower bound of the interval;
  */
 static int
 interval_cmp_lower(const void *i1, const void *i2)
 {
-	double		lower1 = ((const SplitInterval *) i1)->lower,
+	float8		lower1 = ((const SplitInterval *) i1)->lower,
 				lower2 = ((const SplitInterval *) i2)->lower;
 
 	return float8_cmp_internal(lower1, lower2);
 }
 
 /*
  * Interval comparison function by upper bound of the interval;
  */
 static int
 interval_cmp_upper(const void *i1, const void *i2)
 {
-	double		upper1 = ((const SplitInterval *) i1)->upper,
+	float8		upper1 = ((const SplitInterval *) i1)->upper,
 				upper2 = ((const SplitInterval *) i2)->upper;
 
 	return float8_cmp_internal(upper1, upper2);
 }
 
 /*
  * Replace negative (or NaN) value with zero.
  */
 static inline float
 non_negative(float val)
@@ -332,28 +334,28 @@ non_negative(float val)
 		return val;
 	else
 		return 0.0f;
 }
 
 /*
  * Consider replacement of currently selected split with the better one.
  */
 static inline void
 g_box_consider_split(ConsiderSplitContext *context, int dimNum,
-					 double rightLower, int minLeftCount,
-					 double leftUpper, int maxLeftCount)
+					 float8 rightLower, int minLeftCount,
+					 float8 leftUpper, int maxLeftCount)
 {
 	int			leftCount,
 				rightCount;
 	float4		ratio,
 				overlap;
-	double		range;
+	float8		range;
 
 	/*
 	 * Calculate entries distribution ratio assuming most uniform distribution
 	 * of common entries.
 	 */
 	if (minLeftCount >= (context->entriesCount + 1) / 2)
 	{
 		leftCount = minLeftCount;
 	}
 	else
@@ -362,52 +364,54 @@ g_box_consider_split(ConsiderSplitContext *context, int dimNum,
 			leftCount = maxLeftCount;
 		else
 			leftCount = context->entriesCount / 2;
 	}
 	rightCount = context->entriesCount - leftCount;
 
 	/*
 	 * Ratio of split - quotient between size of lesser group and total
 	 * entries count.
 	 */
-	ratio = ((float4) Min(leftCount, rightCount)) /
-		((float4) context->entriesCount);
+	ratio = float4_div(Min(leftCount, rightCount), context->entriesCount);
 
-	if (ratio > LIMIT_RATIO)
+	if (float4_gt(ratio, LIMIT_RATIO))
 	{
 		bool		selectthis = false;
 
 		/*
 		 * The ratio is acceptable, so compare current split with previously
 		 * selected one. Between splits of one dimension we search for minimal
 		 * overlap (allowing negative values) and minimal ration (between same
 		 * overlaps. We switch dimension if find less overlap (non-negative)
 		 * or less range with same overlap.
 		 */
 		if (dimNum == 0)
-			range = context->boundingBox.high.x - context->boundingBox.low.x;
+			range = float8_mi(context->boundingBox.high.x,
+							  context->boundingBox.low.x);
 		else
-			range = context->boundingBox.high.y - context->boundingBox.low.y;
+			range = float8_mi(context->boundingBox.high.y,
+							  context->boundingBox.low.y);
 
-		overlap = (leftUpper - rightLower) / range;
+		overlap = float8_div(float8_mi(leftUpper, rightLower), range);
 
 		/* If there is no previous selection, select this */
 		if (context->first)
 			selectthis = true;
 		else if (context->dim == dimNum)
 		{
 			/*
 			 * Within the same dimension, choose the new split if it has a
 			 * smaller overlap, or same overlap but better ratio.
 			 */
-			if (overlap < context->overlap ||
-				(overlap == context->overlap && ratio > context->ratio))
+			if (float4_lt(overlap, context->overlap) ||
+				(float4_eq(overlap, context->overlap) &&
+				 float4_gt(ratio, context->ratio)))
 				selectthis = true;
 		}
 		else
 		{
 			/*
 			 * Across dimensions, choose the new split if it has a smaller
 			 * *non-negative* overlap, or same *non-negative* overlap but
 			 * bigger range. This condition differs from the one described in
 			 * the article. On the datasets where leaf MBRs don't overlap
 			 * themselves, non-overlapping splits (i.e. splits which have zero
@@ -416,55 +420,49 @@ g_box_consider_split(ConsiderSplitContext *context, int dimNum,
 			 * non-overlapping splits (i.e. having lowest negative overlap)
 			 * appears to be in the same dimension as in the previous split.
 			 * Therefore MBRs appear to be very prolonged along another
 			 * dimension, which leads to bad search performance. Using range
 			 * as the second split criteria makes MBRs more quadratic. Using
 			 * *non-negative* overlap instead of overlap as the first split
 			 * criteria gives to range criteria a chance to matter, because
 			 * non-overlapping splits are equivalent in this criteria.
 			 */
 			if (non_negative(overlap) < non_negative(context->overlap) ||
-				(range > context->range &&
+				(float4_gt(range, context->range) &&
 				 non_negative(overlap) <= non_negative(context->overlap)))
 				selectthis = true;
 		}
 
 		if (selectthis)
 		{
 			/* save information about selected split */
 			context->first = false;
 			context->ratio = ratio;
 			context->range = range;
 			context->overlap = overlap;
 			context->rightLower = rightLower;
 			context->leftUpper = leftUpper;
 			context->dim = dimNum;
 		}
 	}
 }
 
 /*
  * Compare common entries by their deltas.
- * (We assume the deltas can't be NaN.)
  */
 static int
 common_entry_cmp(const void *i1, const void *i2)
 {
-	double		delta1 = ((const CommonEntry *) i1)->delta,
+	float8		delta1 = ((const CommonEntry *) i1)->delta,
 				delta2 = ((const CommonEntry *) i2)->delta;
 
-	if (delta1 < delta2)
-		return -1;
-	else if (delta1 > delta2)
-		return 1;
-	else
-		return 0;
+	return float8_cmp_internal(delta1, delta2);
 }
 
 /*
  * --------------------------------------------------------------------------
  * Double sorting split algorithm. This is used for both boxes and points.
  *
  * The algorithm finds split of boxes by considering splits along each axis.
  * Each entry is first projected as an interval on the X-axis, and different
  * ways to split the intervals into two groups are considered, trying to
  * minimize the overlap of the groups. Then the same is repeated for the
@@ -524,21 +522,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		else
 			adjustBox(&context.boundingBox, box);
 	}
 
 	/*
 	 * Iterate over axes for optimal split searching.
 	 */
 	context.first = true;		/* nothing selected yet */
 	for (dim = 0; dim < 2; dim++)
 	{
-		double		leftUpper,
+		float8		leftUpper,
 					rightLower;
 		int			i1,
 					i2;
 
 		/* Project each entry as an interval on the selected axis. */
 		for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 		{
 			box = DatumGetBoxP(entryvec->vector[i].key);
 			if (dim == 0)
 			{
@@ -721,21 +719,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 			*rightBox = *(box);					\
 		v->spl_right[v->spl_nright++] = off;	\
 	} while(0)
 
 	/*
 	 * Distribute entries which can be distributed unambiguously, and collect
 	 * common entries.
 	 */
 	for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 	{
-		double		lower,
+		float8		lower,
 					upper;
 
 		/*
 		 * Get upper and lower bounds along selected axis.
 		 */
 		box = DatumGetBoxP(entryvec->vector[i].key);
 		if (context.dim == 0)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
@@ -776,31 +774,31 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
 	{
 		/*
 		 * Calculate minimum number of entries that must be placed in both
 		 * groups, to reach LIMIT_RATIO.
 		 */
-		int			m = ceil(LIMIT_RATIO * (double) nentries);
+		int			m = ceil(LIMIT_RATIO * (float8) nentries);
 
 		/*
 		 * Calculate delta between penalties of join "common entries" to
 		 * different groups.
 		 */
 		for (i = 0; i < commonEntriesCount; i++)
 		{
 			box = DatumGetBoxP(entryvec->vector[commonEntries[i].index].key);
-			commonEntries[i].delta = Abs(box_penalty(leftBox, box) -
-										 box_penalty(rightBox, box));
+			commonEntries[i].delta = Abs(float8_mi(box_penalty(leftBox, box),
+												   box_penalty(rightBox, box)));
 		}
 
 		/*
 		 * Sort "common entries" by calculated deltas in order to distribute
 		 * the most ambiguous entries first.
 		 */
 		qsort(commonEntries, commonEntriesCount, sizeof(CommonEntry), common_entry_cmp);
 
 		/*
 		 * Distribute "common entries" between groups.
@@ -1100,24 +1098,24 @@ gist_circle_compress(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	GISTENTRY  *retval;
 
 	if (entry->leafkey)
 	{
 		CIRCLE	   *in = DatumGetCircleP(entry->key);
 		BOX		   *r;
 
 		r = (BOX *) palloc(sizeof(BOX));
-		r->high.x = in->center.x + in->radius;
-		r->low.x = in->center.x - in->radius;
-		r->high.y = in->center.y + in->radius;
-		r->low.y = in->center.y - in->radius;
+		r->high.x = float8_pl(in->center.x, in->radius);
+		r->low.x = float8_mi(in->center.x, in->radius);
+		r->high.y = float8_pl(in->center.y, in->radius);
+		r->low.y = float8_mi(in->center.y, in->radius);
 
 		retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
 		gistentryinit(*retval, PointerGetDatum(r),
 					  entry->rel, entry->page,
 					  entry->offset, FALSE);
 	}
 	else
 		retval = entry;
 	PG_RETURN_POINTER(retval);
 }
@@ -1141,24 +1139,24 @@ gist_circle_consistent(PG_FUNCTION_ARGS)
 	*recheck = true;
 
 	if (DatumGetBoxP(entry->key) == NULL || query == NULL)
 		PG_RETURN_BOOL(FALSE);
 
 	/*
 	 * Since the operators require recheck anyway, we can just use
 	 * rtree_internal_consistent even at leaf nodes.  (This works in part
 	 * because the index entries are bounding boxes not circles.)
 	 */
-	bbox.high.x = query->center.x + query->radius;
-	bbox.low.x = query->center.x - query->radius;
-	bbox.high.y = query->center.y + query->radius;
-	bbox.low.y = query->center.y - query->radius;
+	bbox.high.x = float8_pl(query->center.x, query->radius);
+	bbox.low.x = float8_mi(query->center.x, query->radius);
+	bbox.high.y = float8_pl(query->center.y, query->radius);
+	bbox.low.y = float8_mi(query->center.y, query->radius);
 
 	result = rtree_internal_consistent(DatumGetBoxP(entry->key),
 									   &bbox, strategy);
 
 	PG_RETURN_BOOL(result);
 }
 
 /**************************************************
  * Point ops
  **************************************************/
@@ -1209,80 +1207,84 @@ gist_point_fetch(PG_FUNCTION_ARGS)
 				  entry->offset, FALSE);
 
 	PG_RETURN_POINTER(retval);
 }
 
 
 #define point_point_distance(p1,p2) \
 	DatumGetFloat8(DirectFunctionCall2(point_distance, \
 									   PointPGetDatum(p1), PointPGetDatum(p2)))
 
-static double
+static float8
 computeDistance(bool isLeaf, BOX *box, Point *point)
 {
-	double		result = 0.0;
+	float8		result = 0.0;
 
 	if (isLeaf)
 	{
 		/* simple point to point distance */
 		result = point_point_distance(point, &box->low);
 	}
-	else if (point->x <= box->high.x && point->x >= box->low.x &&
-			 point->y <= box->high.y && point->y >= box->low.y)
+	else if (float8_le(point->x, box->high.x) &&
+			 float8_ge(point->x, box->low.x) &&
+			 float8_le(point->y, box->high.y) &&
+			 float8_ge(point->y, box->low.y))
 	{
 		/* point inside the box */
 		result = 0.0;
 	}
-	else if (point->x <= box->high.x && point->x >= box->low.x)
+	else if (float8_le(point->x, box->high.x) &&
+			 float8_ge(point->x, box->low.x))
 	{
 		/* point is over or below box */
-		Assert(box->low.y <= box->high.y);
-		if (point->y > box->high.y)
-			result = point->y - box->high.y;
-		else if (point->y < box->low.y)
-			result = box->low.y - point->y;
+		Assert(float8_le(box->low.y, box->high.y));
+		if (float8_gt(point->y, box->high.y))
+			result = float8_mi(point->y, box->high.y);
+		else if (float8_lt(point->y, box->low.y))
+			result = float8_mi(box->low.y, point->y);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
-	else if (point->y <= box->high.y && point->y >= box->low.y)
+	else if (float8_le(point->y, box->high.y) &&
+			 float8_ge(point->y, box->low.y))
 	{
 		/* point is to left or right of box */
-		Assert(box->low.x <= box->high.x);
-		if (point->x > box->high.x)
-			result = point->x - box->high.x;
-		else if (point->x < box->low.x)
-			result = box->low.x - point->x;
+		Assert(float8_lt(box->low.x, box->high.x));
+		if (float8_gt(point->x, box->high.x))
+			result = float8_mi(point->x, box->high.x);
+		else if (float8_lt(point->x, box->low.x))
+			result = float8_mi(box->low.x, point->x);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
 	else
 	{
 		/* closest point will be a vertex */
 		Point		p;
-		double		subresult;
+		float8		subresult;
 
 		result = point_point_distance(point, &box->low);
 
 		subresult = point_point_distance(point, &box->high);
-		if (result > subresult)
+		if (float8_gt(result, subresult))
 			result = subresult;
 
 		p.x = box->low.x;
 		p.y = box->high.y;
 		subresult = point_point_distance(point, &p);
-		if (result > subresult)
+		if (float8_gt(result, subresult))
 			result = subresult;
 
 		p.x = box->high.x;
 		p.y = box->low.y;
 		subresult = point_point_distance(point, &p);
-		if (result > subresult)
+		if (float8_gt(result, subresult))
 			result = subresult;
 	}
 
 	return result;
 }
 
 static bool
 gist_point_consistent_internal(StrategyNumber strategy,
 							   bool isLeaf, BOX *key, Point *query)
 {
@@ -1363,24 +1365,24 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 				 * Instead we write a non-fuzzy overlap test.  The same code
 				 * will also serve for leaf-page tests, since leaf keys have
 				 * high == low.
 				 */
 				BOX		   *query,
 						   *key;
 
 				query = PG_GETARG_BOX_P(1);
 				key = DatumGetBoxP(entry->key);
 
-				result = (key->high.x >= query->low.x &&
-						  key->low.x <= query->high.x &&
-						  key->high.y >= query->low.y &&
-						  key->low.y <= query->high.y);
+				result = (float8_ge(key->high.x, query->low.x) &&
+						  float8_le(key->low.x, query->high.x) &&
+						  float8_ge(key->high.y, query->low.y) &&
+						  float8_le(key->low.y, query->high.y));
 				*recheck = false;
 			}
 			break;
 		case PolygonStrategyNumberGroup:
 			{
 				POLYGON    *query = PG_GETARG_POLYGON_P(1);
 
 				result = DatumGetBool(DirectFunctionCall5(
 														  gist_poly_consistent,
 														  PointerGetDatum(entry),
@@ -1389,22 +1391,22 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 														  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);
+					Assert(float8_eq(box->high.x, box->low.x) &&
+						   float8_eq(box->high.y, box->low.y));
 					result = DatumGetBool(DirectFunctionCall2(
 															  poly_contain_pt,
 															  PolygonPGetDatum(query),
 															  PointPGetDatum(&box->high)));
 					*recheck = false;
 				}
 			}
 			break;
 		case CircleStrategyNumberGroup:
 			{
@@ -1418,22 +1420,22 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 														  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);
+					Assert(float8_eq(box->high.x, box->low.x) &&
+						   float8_eq(box->high.y, box->low.y));
 					result = DatumGetBool(DirectFunctionCall2(
 															  circle_contain_pt,
 															  CirclePGetDatum(query),
 															  PointPGetDatum(&box->high)));
 					*recheck = false;
 				}
 			}
 			break;
 		default:
 			elog(ERROR, "unrecognized strategy number: %d", strategy);
@@ -1442,21 +1444,21 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 	}
 
 	PG_RETURN_BOOL(result);
 }
 
 Datum
 gist_point_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(GIST_LEAF(entry),
 									   DatumGetBoxP(entry->key),
 									   PG_GETARG_POINT_P(1));
 			break;
 		default:
@@ -1471,25 +1473,25 @@ gist_point_distance(PG_FUNCTION_ARGS)
 /*
  * The inexact GiST distance method for geometric types that store bounding
  * boxes.
  *
  * Compute lossy distance from point to index entries.  The result is inexact
  * because index entries are bounding boxes, not the exact shapes of the
  * indexed geometric types.  We use distance from point to MBR of index entry.
  * This is a lower bound estimate of distance from point to indexed geometric
  * type.
  */
-static double
+static float8
 gist_bbox_distance(GISTENTRY *entry, Datum query,
 				   StrategyNumber strategy, bool *recheck)
 {
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	/* Bounding box distance is always inexact. */
 	*recheck = true;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(false,
 									   DatumGetBoxP(entry->key),
@@ -1505,32 +1507,32 @@ gist_bbox_distance(GISTENTRY *entry, Datum query,
 
 Datum
 gist_circle_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
 
 Datum
 gist_poly_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 567554735f..dbf1de0ca2 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -29,76 +29,77 @@
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
 /* Routines for float8 */
 static inline float8 float8_slope(float8 x1, float8 x2, float8 y1, float8 y2);
+static inline float8 float8_hypot(float8 x, float8 y);
 
 /* Routines for two-dimensional points */
 static inline void point_construct(Point *result, float8 x, float8 y);
 static inline void point_add_internal(Point *result, Point *pt1, Point *pt2);
 static inline void point_sub_internal(Point *result, Point *pt1, Point *pt2);
 static inline void point_mul_internal(Point *result, Point *pt1, Point *pt2);
 static inline void point_div_internal(Point *result, Point *pt1, Point *pt2);
 static inline bool point_eq_internal(Point *pt1, Point *pt2);
 static float8 point_dt(Point *pt1, Point *pt2);
 static int	point_inside(Point *p, int npts, Point *plist);
 
 /* Routines for two-dimensional boxes */
 static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
 static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
-static double box_ar(BOX *box);
-static double box_ht(BOX *box);
-static double box_wd(BOX *box);
+static float8 box_ar(BOX *box);
+static float8 box_ht(BOX *box);
+static float8 box_wd(BOX *box);
 
 /* Routines for two-dimensional circles */
-static double circle_ar(CIRCLE *circle);
+static float8 circle_ar(CIRCLE *circle);
 
 /* Routines for two-dimensional lines */
 static inline void line_construct_pm(LINE *result, Point *pt, float8 m);
 static inline void line_construct_pts(LINE *result, Point *pt1, Point *pt2);
 static bool line_interpt_internal(Point *result, LINE *l1, LINE *l2);
 static inline float8 line_calculate_point(LINE *line, Point *pt);
 
 /* Routines for two-dimensional line segments */
 static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
 static bool lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line);
 static bool lseg_interpt_internal(Point *result, LSEG *l1, LSEG *l2);
 static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
 static float8 lseg_dt(LSEG *l1, LSEG *l2);
-static int	lseg_crossing(double x, double y, double px, double py);
+static int	lseg_crossing(float8 x, float8 y, float8 px, float8 py);
 static bool on_ps_internal(Point *pt, LSEG *lseg);
 
 /* Routines for two-dimensional polygons */
 static void make_bound_box(POLYGON *poly);
 
 /* Unsorted */
 static bool plist_same(int npts, Point *p1, Point *p2);
-static double single_decode(char *num, char **endptr_p,
+static float8 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
-static void pair_decode(char *str, double *x, double *y, char **endptr_p,
+static void pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
 static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
-static double dist_pl_internal(Point *pt, LINE *line);
-static double dist_ps_internal(Point *pt, LSEG *lseg);
-static double dist_ppoly_internal(Point *pt, POLYGON *poly);
+static float8 dist_pl_internal(Point *pt, LINE *line);
+static float8 dist_ps_internal(Point *pt, LSEG *lseg);
+static float8 dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 
 /*
  * Delimiters for input and output strings.
  * LDELIM, RDELIM, and DELIM are left, right, and separator delimiters, respectively.
  * LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints.
  */
 
 #define LDELIM			'('
 #define RDELIM			')'
@@ -127,38 +128,38 @@ static double dist_ppoly_internal(Point *pt, POLYGON *poly);
  *
  * For boxes, the points are opposite corners with the first point at the top right.
  * For closed paths and polygons, the points should be reordered to allow
  *	fast and correct equality comparisons.
  *
  * XXX perhaps points in complex shapes should be reordered internally
  *	to allow faster internal operations, but should keep track of input order
  *	and restore that order for text output - tgl 97/01/16
  */
 
-static double
+static float8
 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string)
 {
 	return float8in_internal(num, endptr_p, type_name, orig_string);
 }								/* single_decode() */
 
 static void
 single_encode(float8 x, StringInfo str)
 {
 	char	   *xstr = float8out_internal(x);
 
 	appendStringInfoString(str, xstr);
 	pfree(xstr);
 }								/* single_encode() */
 
 static void
-pair_decode(char *str, double *x, double *y, char **endptr_p,
+pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string)
 {
 	bool		has_delim;
 
 	while (isspace((unsigned char) *str))
 		str++;
 	if ((has_delim = (*str == LDELIM)))
 		str++;
 
 	*x = float8in_internal(str, &str, type_name, orig_string);
@@ -358,21 +359,42 @@ pair_count(char *s, char delim)
  * to calculate inverse slope.  To achieve that pass the values in
  * (y1, y2, x2, x1) order.
  */
 static inline float8
 float8_slope(float8 x1, float8 x2, float8 y1, float8 y2)
 {
 	if (FPeq(x1, x2))
 		return DBL_MAX;
 	if (FPeq(y1, y2))
 		return 0.0;
-	return (y1 - y2) / (x1 - x2);
+	return float8_div(float8_mi(y1, y2), float8_mi(x1, x2));
+}
+
+
+/*
+ * Wrapper around libc hypot()
+ */
+static inline float8
+float8_hypot(float8 x, float8 y)
+{
+	float8		result;
+
+	errno = 0;
+	result = hypot(x, y);
+	if (errno == ERANGE)
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+	check_float8_val(result, isinf(x) || isinf(y), x == 0.0 && y == 0.0);
+	Assert(result >= 0.0);
+
+	return result;
 }
 
 
 /***********************************************************************
  **
  **		Routines for two-dimensional boxes.
  **
  ***********************************************************************/
 
 /*----------------------------------------------------------
@@ -384,33 +406,33 @@ float8_slope(float8 x1, float8 x2, float8 y1, float8 y2)
  *		External format: (two corners of box)
  *				"(f8, f8), (f8, f8)"
  *				also supports the older style "(f8, f8, f8, f8)"
  */
 Datum
 box_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	BOX		   *box = (BOX *) palloc(sizeof(BOX));
 	bool		isopen;
-	double		x,
+	float8		x,
 				y;
 
 	path_decode(str, false, 2, &(box->high), &isopen, NULL, "box", str);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*		box_out -		convert a box to external form.
@@ -424,38 +446,38 @@ box_out(PG_FUNCTION_ARGS)
 }
 
 /*
  *		box_recv			- converts external binary format to box
  */
 Datum
 box_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	BOX		   *box;
-	double		x,
+	float8		x,
 				y;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
 	box->high.x = pq_getmsgfloat8(buf);
 	box->high.y = pq_getmsgfloat8(buf);
 	box->low.x = pq_getmsgfloat8(buf);
 	box->low.y = pq_getmsgfloat8(buf);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*
@@ -474,31 +496,31 @@ box_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, box->low.y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*		box_construct	-		fill in a new box.
  */
 static inline void
 box_construct(BOX *result, Point *pt1, Point *pt2)
 {
-	if (pt1->x > pt2->x)
+	if (float8_gt(pt1->x, pt2->x))
 	{
 		result->high.x = pt1->x;
 		result->low.x = pt2->x;
 	}
 	else
 	{
 		result->high.x = pt2->x;
 		result->low.x = pt1->x;
 	}
-	if (pt1->y > pt2->y)
+	if (float8_gt(pt1->y, pt2->y))
 	{
 		result->high.y = pt1->y;
 		result->low.y = pt2->y;
 	}
 	else
 	{
 		result->high.y = pt2->y;
 		result->low.y = pt1->y;
 	}
 }
@@ -810,54 +832,54 @@ box_center(PG_FUNCTION_ARGS)
 	Point	   *result = (Point *) palloc(sizeof(Point));
 
 	box_cn(result, box);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		box_ar	-		returns the area of the box.
  */
-static double
+static float8
 box_ar(BOX *box)
 {
-	return box_wd(box) * box_ht(box);
+	return float8_mul(box_wd(box), box_ht(box));
 }
 
 
 /*		box_cn	-		stores the centerpoint of the box into *center.
  */
 static void
 box_cn(Point *center, BOX *box)
 {
-	center->x = (box->high.x + box->low.x) / 2.0;
-	center->y = (box->high.y + box->low.y) / 2.0;
+	center->x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	center->y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 }
 
 
 /*		box_wd	-		returns the width (length) of the box
  *								  (horizontal magnitude).
  */
-static double
+static float8
 box_wd(BOX *box)
 {
-	return box->high.x - box->low.x;
+	return float8_mi(box->high.x, box->low.x);
 }
 
 
 /*		box_ht	-		returns the height of the box
  *								  (vertical magnitude).
  */
-static double
+static float8
 box_ht(BOX *box)
 {
-	return box->high.y - box->low.y;
+	return float8_mi(box->high.y, box->low.y);
 }
 
 
 /*----------------------------------------------------------
  *	Funky operations.
  *---------------------------------------------------------*/
 
 /*		box_intersect	-
  *				returns the overlapping portion of two boxes,
  *				  or NULL if they do not intersect.
@@ -867,24 +889,24 @@ box_intersect(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 	BOX		   *result;
 
 	if (!box_ov(box1, box2))
 		PG_RETURN_NULL();
 
 	result = (BOX *) palloc(sizeof(BOX));
 
-	result->high.x = Min(box1->high.x, box2->high.x);
-	result->low.x = Max(box1->low.x, box2->low.x);
-	result->high.y = Min(box1->high.y, box2->high.y);
-	result->low.y = Max(box1->low.y, box2->low.y);
+	result->high.x = float8_min(box1->high.x, box2->high.x);
+	result->low.x = float8_max(box1->low.x, box2->low.x);
+	result->high.y = float8_min(box1->high.y, box2->high.y);
+	result->low.y = float8_max(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(result);
 }
 
 
 /*		box_diagonal	-
  *				returns a line segment which happens to be the
  *				  positive-slope diagonal of "box".
  */
 Datum
@@ -1015,30 +1037,30 @@ line_send(PG_FUNCTION_ARGS)
 
 /*
  * Fill already-allocated LINE struct from the point and the slope
  */
 static inline void
 line_construct_pm(LINE *result, Point *pt, float8 m)
 {
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
-		result->A = -1;
-		result->B = 0;
+		result->A = -1.0;
+		result->B = 0.0;
 		result->C = pt->x;
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
-		result->C = pt->y - m * pt->x;
+		result->C = float8_mi(pt->y, float8_mul(m, pt->x));
 	}
 }
 
 
 /*
  * Fill already-allocated LINE struct from two points on the line
  */
 static inline void
 line_construct_pts(LINE *result, Point *pt1, Point *pt2)
 {
@@ -1066,21 +1088,22 @@ line_construct_pp(PG_FUNCTION_ARGS)
 
 /*
  * Calculate the line equation for a point
  *
  * This returns the result of the line equation Ax + By + C.  The result
  * needs to be 0 for the point to be on the line.
  */
 static inline float8
 line_calculate_point(LINE *line, Point *pt)
 {
-	return line->A * pt->x + line->B * pt->y + line->C;
+	return float8_pl(float8_pl(float8_mul(line->A, pt->x),
+							   float8_mul(line->B, pt->y)), line->C);
 }
 
 
 /*----------------------------------------------------------
  *	Relative position routines.
  *---------------------------------------------------------*/
 
 Datum
 line_intersect(PG_FUNCTION_ARGS)
 {
@@ -1103,21 +1126,22 @@ Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
 	else if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
 
-	PG_RETURN_BOOL(FPeq(((l1->A * l2->B) / (l1->B * l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
+								   float8_mul(l1->B, l2->A)), -1.0));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
@@ -1127,34 +1151,34 @@ line_horizontal(PG_FUNCTION_ARGS)
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->A));
 }
 
 Datum
 line_eq(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	double		k;
+	float8		ratio;
 
 	if (!FPzero(l2->A))
-		k = l1->A / l2->A;
+		ratio = float8_div(l1->A, l2->A);
 	else if (!FPzero(l2->B))
-		k = l1->B / l2->B;
+		ratio = float8_div(l1->B, l2->B);
 	else if (!FPzero(l2->C))
-		k = l1->C / l2->C;
+		ratio = float8_div(l1->C, l2->C);
 	else
-		k = 1.0;
+		ratio = 1.0;
 
-	PG_RETURN_BOOL(FPeq(l1->A, k * l2->A) &&
-				   FPeq(l1->B, k * l2->B) &&
-				   FPeq(l1->C, k * l2->C));
+	PG_RETURN_BOOL(FPeq(l1->A, float8_mul(ratio, l2->A)) &&
+				   FPeq(l1->B, float8_mul(ratio, l2->B)) &&
+				   FPeq(l1->C, float8_mul(ratio, l2->C)));
 }
 
 
 /*----------------------------------------------------------
  *	Line arithmetic routines.
  *---------------------------------------------------------*/
 
 /* line_distance()
  * Distance between two lines.
  */
@@ -1162,21 +1186,21 @@ Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
 	Point		tmp;
 
 	if (line_interpt_internal(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
+		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
 	point_construct(&tmp, 0.0, l1->C);
 	result = dist_pl_internal(&tmp, l2);
 	PG_RETURN_FLOAT8(result);
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
@@ -1199,41 +1223,41 @@ line_interpt(PG_FUNCTION_ARGS)
  * parallel), false if they do not.  This also sets the intersection point
  * to *result, if it is not NULL.
  *
  * NOTE: If the lines are identical then we will find they are parallel
  * and report "no intersection".  This is a little weird, but since
  * there's no *unique* intersection, maybe it's appropriate behavior.
  */
 static bool
 line_interpt_internal(Point *result, LINE *l1, LINE *l2)
 {
-	double		x,
+	float8		x,
 				y;
 
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
 		if (FPzero(l2->B))		/* l2 vertical? */
 			return false;
 
 		x = l1->C;
-		y = (l2->A * x + l2->C);
+		y = float8_pl(float8_mul(l2->A, x), l2->C);
 	}
 	else
 	{
-		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
 			return false;
 
 		if (FPzero(l2->B))
 			x = l2->C;
 		else
-			x = (l1->C - l2->C) / (l2->A - l1->A);
-		y = (l1->A * x + l1->C);
+			x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
+		y = float8_pl(float8_mul(l1->A, x), l1->C);
 	}
 	if (result != NULL)
 		point_construct(result, x, y);
 
 #ifdef GEODEBUG
 	printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
 		   DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
 	printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
 #endif
 
@@ -1260,36 +1284,35 @@ line_interpt_internal(Point *result, LINE *l1, LINE *l2)
  *				"(xcoord, ycoord),... "
  *				"[xcoord, ycoord,... ]"
  *		Also support older format:
  *				"(closed, npts, xcoord, ycoord,... )"
  *---------------------------------------------------------*/
 
 Datum
 path_area(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P(0);
-	double		area = 0.0;
+	float8		area = 0.0;
 	int			i,
 				j;
 
 	if (!path->closed)
 		PG_RETURN_NULL();
 
 	for (i = 0; i < path->npts; i++)
 	{
 		j = (i + 1) % path->npts;
-		area += path->p[i].x * path->p[j].y;
-		area -= path->p[i].y * path->p[j].x;
+		area = float8_pl(area, float8_mul(path->p[i].x, path->p[j].y));
+		area = float8_mi(area, float8_mul(path->p[i].y, path->p[j].x));
 	}
 
-	area *= 0.5;
-	PG_RETURN_FLOAT8(area < 0.0 ? -area : area);
+	PG_RETURN_FLOAT8(float8_div(fabs(area), 2.0));
 }
 
 
 Datum
 path_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	PATH	   *path;
 	bool		isopen;
 	char	   *s;
@@ -1506,31 +1529,31 @@ path_npoints(PG_FUNCTION_ARGS)
 
 	PG_RETURN_INT32(path->npts);
 }
 
 
 Datum
 path_close(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 
-	path->closed = TRUE;
+	path->closed = true;
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_open(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 
-	path->closed = FALSE;
+	path->closed = false;
 
 	PG_RETURN_PATH_P(path);
 }
 
 
 /* path_inter -
  *		Does p1 intersect p2 at any point?
  *		Use bounding boxes for a quick (O(n)) check, then do a
  *		O(n^2) iterative edge check.
  */
@@ -1546,33 +1569,33 @@ path_inter(PG_FUNCTION_ARGS)
 	LSEG		seg1,
 				seg2;
 
 	if (p1->npts <= 0 || p2->npts <= 0)
 		PG_RETURN_BOOL(false);
 
 	b1.high.x = b1.low.x = p1->p[0].x;
 	b1.high.y = b1.low.y = p1->p[0].y;
 	for (i = 1; i < p1->npts; i++)
 	{
-		b1.high.x = Max(p1->p[i].x, b1.high.x);
-		b1.high.y = Max(p1->p[i].y, b1.high.y);
-		b1.low.x = Min(p1->p[i].x, b1.low.x);
-		b1.low.y = Min(p1->p[i].y, b1.low.y);
+		b1.high.x = float8_max(p1->p[i].x, b1.high.x);
+		b1.high.y = float8_max(p1->p[i].y, b1.high.y);
+		b1.low.x = float8_min(p1->p[i].x, b1.low.x);
+		b1.low.y = float8_min(p1->p[i].y, b1.low.y);
 	}
 	b2.high.x = b2.low.x = p2->p[0].x;
 	b2.high.y = b2.low.y = p2->p[0].y;
 	for (i = 1; i < p2->npts; i++)
 	{
-		b2.high.x = Max(p2->p[i].x, b2.high.x);
-		b2.high.y = Max(p2->p[i].y, b2.high.y);
-		b2.low.x = Min(p2->p[i].x, b2.low.x);
-		b2.low.y = Min(p2->p[i].y, b2.low.y);
+		b2.high.x = float8_max(p2->p[i].x, b2.high.x);
+		b2.high.y = float8_max(p2->p[i].y, b2.high.y);
+		b2.low.x = float8_min(p2->p[i].x, b2.low.x);
+		b2.low.y = float8_min(p2->p[i].y, b2.low.y);
 	}
 	if (!box_ov(&b1, &b2))
 		PG_RETURN_BOOL(false);
 
 	/* pairwise check lseg intersections */
 	for (i = 0; i < p1->npts; i++)
 	{
 		int			iprev;
 
 		if (i > 0)
@@ -1648,21 +1671,21 @@ path_distance(PG_FUNCTION_ARGS)
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
 			tmp = lseg_dt(&seg1, &seg2);
-			if (!have_min || tmp < min)
+			if (!have_min || float8_lt(tmp, min))
 			{
 				min = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	if (!have_min)
 		PG_RETURN_NULL();
 
@@ -1687,21 +1710,21 @@ path_length(PG_FUNCTION_ARGS)
 
 		if (i > 0)
 			iprev = i - 1;
 		else
 		{
 			if (!path->closed)
 				continue;
 			iprev = path->npts - 1; /* include the closure segment */
 		}
 
-		result += point_dt(&path->p[iprev], &path->p[i]);
+		result = float8_pl(result, point_dt(&path->p[iprev], &path->p[i]));
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /***********************************************************************
  **
  **		Routines for 2D points.
  **
  ***********************************************************************/
@@ -1875,21 +1898,21 @@ point_distance(PG_FUNCTION_ARGS)
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
 static float8
 point_dt(Point *pt1, Point *pt2)
 {
 	float8		result;
 
-	result = hypot(pt1->x - pt2->x, pt1->y - pt2->y);
+	result = float8_hypot(float8_mi(pt1->x, pt2->x), float8_mi(pt1->y, pt2->y));
 
 #ifdef GEODEBUG
 	printf("point_dt- segment (%f,%f),(%f,%f) length is %f\n",
 		   pt1->x, pt1->y, pt2->x, pt2->y, result);
 #endif
 
 	return result;
 }
 
 Datum
@@ -2049,35 +2072,35 @@ lseg_parallel(PG_FUNCTION_ARGS)
  *	'((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg
  * So, modified it to check explicitly for slope of vertical line
  *	returned by float8_slope() and the results seem better.
  * - thomas 1998-01-31
  */
 Datum
 lseg_perp(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	double		m1,
+	float8		m1,
 				m2;
 
 	m1 = float8_slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y);
 	m2 = float8_slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y);
 
 #ifdef GEODEBUG
 	printf("lseg_perp- slopes are %g and %g\n", m1, m2);
 #endif
 	if (FPzero(m1))
 		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
 	else if (FPzero(m2))
 		PG_RETURN_BOOL(FPeq(m1, DBL_MAX));
 
-	PG_RETURN_BOOL(FPeq(m1 / m2, -1.0));
+	PG_RETURN_BOOL(FPeq(float8_div(m1, m2), -1.0));
 }
 
 Datum
 lseg_vertical(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 
 	PG_RETURN_BOOL(FPeq(lseg->p[0].x, lseg->p[1].x));
 }
 
@@ -2167,52 +2190,47 @@ lseg_distance(PG_FUNCTION_ARGS)
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_FLOAT8(lseg_dt(l1, l2));
 }
 
 /* lseg_dt()
  * Distance between two line segments.
  * Must check both sets of endpoints to ensure minimum distance is found.
  * - thomas 1998-02-01
  */
-static double
+static float8
 lseg_dt(LSEG *l1, LSEG *l2)
 {
-	double		result,
-				d;
+	float8		result;
 
 	if (lseg_interpt_internal(NULL, l1, l2))
 		return 0.0;
 
-	d = dist_ps_internal(&l1->p[0], l2);
-	result = d;
-	d = dist_ps_internal(&l1->p[1], l2);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[0], l1);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[1], l1);
-	result = Min(result, d);
+	result = dist_ps_internal(&l1->p[0], l2);
+	result = float8_min(result, dist_ps_internal(&l1->p[1], l2));
+	result = float8_min(result, dist_ps_internal(&l2->p[0], l1));
+	result = float8_min(result, dist_ps_internal(&l2->p[1], l1));
 
 	return result;
 }
 
 
 Datum
 lseg_center(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
-	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
+	result->x = float8_div(float8_pl(lseg->p[0].x, lseg->p[1].x), 2.0);
+	result->y = float8_div(float8_pl(lseg->p[0].y, lseg->p[1].y), 2.0);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static bool
 lseg_interpt_internal(Point *result, LSEG *l1, LSEG *l2)
 {
 	Point		interpt;
 	LINE		tmp1,
 				tmp2;
@@ -2296,45 +2314,44 @@ lseg_interpt(PG_FUNCTION_ARGS)
  */
 Datum
 dist_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
 	PG_RETURN_FLOAT8(dist_pl_internal(pt, line));
 }
 
-static double
+static float8
 dist_pl_internal(Point *pt, LINE *line)
 {
-	return fabs(line_calculate_point(line, pt) /
-				hypot(line->A, line->B));
+	return float8_div(fabs(line_calculate_point(line, pt)),
+					  float8_hypot(line->A, line->B));
 }
 
 /*
  * Distance from a point to a lseg
  */
 Datum
 dist_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_FLOAT8(dist_ps_internal(pt, lseg));
 }
 
-static double
+static float8
 dist_ps_internal(Point *pt, LSEG *lseg)
 {
-	double		m;				/* slope of perp. */
-	double		result,
-				tmpdist;
+	float8		m;				/* slope of perp. */
+	float8		result;
 	Point		interpt;
 	LINE		ln;
 
 	/*
 	 * Construct a line perpendicular to the input segment and through the
 	 * input point
 	 */
 	m = float8_slope(lseg->p[0].y, lseg->p[1].y, lseg->p[1].x, lseg->p[0].x);
 	line_construct_pm(&ln, pt, m);
 
@@ -2354,24 +2371,22 @@ dist_ps_internal(Point *pt, LSEG *lseg)
 		/* yes, so use distance to the intersection point */
 		result = point_dt(pt, &interpt);
 #ifdef GEODEBUG
 		printf("dist_ps- distance is %f to intersection point is (%f,%f)\n",
 			   result, tmp.x, tmp.y);
 #endif
 	}
 	else
 	{
 		/* no, so use distance to the nearer endpoint */
-		result = point_dt(pt, &lseg->p[0]);
-		tmpdist = point_dt(pt, &lseg->p[1]);
-		if (tmpdist < result)
-			result = tmpdist;
+		result = float8_min(point_dt(pt, &lseg->p[0]),
+							point_dt(pt, &lseg->p[1]));
 	}
 
 	return result;
 }
 
 /*
  * Distance from a point to a path
  */
 Datum
 dist_ppath(PG_FUNCTION_ARGS)
@@ -2409,21 +2424,21 @@ dist_ppath(PG_FUNCTION_ARGS)
 					iprev = i - 1;
 				else
 				{
 					if (!path->closed)
 						continue;
 					iprev = path->npts - 1; /* include the closure segment */
 				}
 
 				statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
 				tmp = dist_ps_internal(pt, &lseg);
-				if (!have_min || tmp < result)
+				if (!have_min || float8_lt(tmp, result))
 				{
 					result = tmp;
 					have_min = true;
 				}
 			}
 			break;
 	}
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -2447,33 +2462,28 @@ dist_pb(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
-	float8		result,
-				d2;
+	float8		result;
 
 	if (lseg_interpt_line_internal(NULL, lseg, line))
 		result = 0.0;
 	else
-	{
-		result = dist_pl_internal(&lseg->p[0], line);
-		d2 = dist_pl_internal(&lseg->p[1], line);
 		/* XXX shouldn't we take the min not max? */
-		if (d2 > result)
-			result = d2;
-	}
+		result = float8_max(dist_pl_internal(&lseg->p[0], line),
+							dist_pl_internal(&lseg->p[1], line));
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
@@ -2515,25 +2525,22 @@ dist_lb(PG_FUNCTION_ARGS)
  * Distance from a circle to a polygon
  */
 Datum
 dist_cpoly(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	POLYGON    *poly = PG_GETARG_POLYGON_P(1);
 	float8		result;
 
 	/* calculate distance to center, and subtract radius */
-	result = dist_ppoly_internal(&circle->center, poly);
-
-	result -= circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_min(float8_mi(dist_ppoly_internal(&circle->center, poly),
+								  circle->radius), 0.0);
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a point to a polygon
  */
 Datum
 dist_ppoly(PG_FUNCTION_ARGS)
 {
@@ -2551,21 +2558,21 @@ dist_polyp(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	float8		result;
 
 	result = dist_ppoly_internal(point, poly);
 
 	PG_RETURN_FLOAT8(result);
 }
 
-static double
+static float8
 dist_ppoly_internal(Point *pt, POLYGON *poly)
 {
 	float8		result;
 	float8		d;
 	int			i;
 	LSEG		seg;
 
 	if (point_inside(pt, poly->npts, poly->p) != 0)
 	{
 #ifdef GEODEBUG
@@ -2588,21 +2595,21 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
 	for (i = 0; (i < poly->npts - 1); i++)
 	{
 		seg.p[0].x = poly->p[i].x;
 		seg.p[0].y = poly->p[i].y;
 		seg.p[1].x = poly->p[i + 1].x;
 		seg.p[1].y = poly->p[i + 1].y;
 		d = dist_ps_internal(pt, &seg);
 #ifdef GEODEBUG
 		printf("dist_ppoly_internal- segment %d distance is %f\n", (i + 1), d);
 #endif
-		if (d < result)
+		if (float8_lt(d, result))
 			result = d;
 	}
 
 	return result;
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
  *				Intersection point of objects.
@@ -2656,41 +2663,41 @@ lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line)
 /* close_pl -
  *		The intersection point of a perpendicular of the line
  *		through the point.
  */
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
-	double		invm;
+	float8		invm;
 	LINE		tmp;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (FPzero(line->B))		/* vertical? */
 	{
 		result->x = line->C;
 		result->y = pt->y;
 		PG_RETURN_POINT_P(result);
 	}
 	if (FPzero(line->A))		/* horizontal? */
 	{
 		result->x = pt->x;
 		result->y = line->C;
 		PG_RETURN_POINT_P(result);
 	}
 	/* drop a perpendicular and find the intersection point */
 
 	/* invert and flip the sign on the slope to get a perpendicular */
-	invm = line->B / line->A;
+	invm = float8_div(line->B, line->A);
 	line_construct_pm(&tmp, pt, invm);
 	line_interpt_internal(result, &tmp, line);
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_ps()
  * Closest point on line segment to specified point.
  * Take the closest endpoint if the point is left, right,
  *	above, or below the segment, otherwise find the intersection
@@ -2699,21 +2706,21 @@ close_pl(PG_FUNCTION_ARGS)
  * Some tricky code here, relying on boolean expressions
  *	evaluating to only zero or one to use as an array index.
  *		bug fixes by gthaker@atl.lmco.com; May 1, 1998
  */
 Datum
 close_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
-	double		invm;
+	float8		invm;
 	int			xh,
 				yh;
 	LINE		tmp;
 
 	result = (Point *) palloc(sizeof(Point));
 
 #ifdef GEODEBUG
 	printf("close_sp:pt->x %f pt->y %f\nlseg(0).x %f lseg(0).y %f  lseg(1).x %f lseg(1).y %f\n",
 		   pt->x, pt->y, lseg->p[0].x, lseg->p[0].y,
 		   lseg->p[1].x, lseg->p[1].y);
@@ -2758,32 +2765,32 @@ close_ps(PG_FUNCTION_ARGS)
 	}
 
 	/*
 	 * vert. and horiz. cases are down, now check if the closest point is one
 	 * of the end points or someplace on the lseg.
 	 */
 
 	invm = float8_slope(lseg->p[0].y, lseg->p[1].y, lseg->p[1].x, lseg->p[0].x);
 	line_construct_pm(&tmp, &lseg->p[!yh], invm);	/* lower edge of the
 													 * "band" */
-	if (pt->y < (tmp.A * pt->x + tmp.C))
+	if (pt->y < float8_pl(float8_mul(tmp.A, pt->x), tmp.C))
 	{							/* we are below the lower edge */
 		*result = lseg->p[!yh]; /* below the lseg, take lower end pt */
 #ifdef GEODEBUG
 		printf("close_ps below: tmp A %f  B %f   C %f\n",
 			   tmp->A, tmp->B, tmp->C);
 #endif
 		PG_RETURN_POINT_P(result);
 	}
 	line_construct_pm(&tmp, &lseg->p[yh], invm);	/* upper edge of the
 													 * "band" */
-	if (pt->y > (tmp.A * pt->x + tmp.C))
+	if (pt->y > float8_pl(float8_mul(tmp.A, pt->x), tmp.C))
 	{							/* we are below the lower edge */
 		*result = lseg->p[yh];	/* above the lseg, take higher end pt */
 #ifdef GEODEBUG
 		printf("close_ps above: tmp A %f  B %f   C %f\n",
 			   tmp->A, tmp->B, tmp->C);
 #endif
 		PG_RETURN_POINT_P(result);
 	}
 
 	/*
@@ -2819,32 +2826,32 @@ close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 	double		dist,
 				dist0,
 				dist1;
 
 	dist0 = dist_ps_internal(&l1->p[0], l2);
 	dist1 = dist_ps_internal(&l1->p[1], l2);
-	dist = Min(dist0, dist1);
+	dist = float8_min(dist0, dist1);
 
-	if (dist_ps_internal(&l2->p[0], l1) < dist)
+	if (float8_lt(dist_ps_internal(&l2->p[0], l1), dist))
 	{
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(&l2->p[0]),
 													LsegPGetDatum(l1)));
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(result),
 													LsegPGetDatum(l2)));
 	}
-	else if (dist_ps_internal(&l2->p[1], l1) < dist)
+	else if (float8_lt(dist_ps_internal(&l2->p[1], l1), dist))
 	{
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(&l2->p[1]),
 													LsegPGetDatum(l1)));
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(result),
 													LsegPGetDatum(l2)));
 	}
 	else
 	{
@@ -2859,52 +2866,55 @@ close_lseg(PG_FUNCTION_ARGS)
  * Closest point on or in box to specified point.
  */
 Datum
 close_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	LSEG		lseg,
 				seg;
 	Point		point;
-	double		dist,
+	float8		dist,
 				d;
 
 	if (DatumGetBool(DirectFunctionCall2(on_pb,
 										 PointPGetDatum(pt),
 										 BoxPGetDatum(box))))
 		PG_RETURN_POINT_P(pt);
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&lseg, &box->low, &point);
 	dist = dist_ps_internal(pt, &lseg);
 
 	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	d = dist_ps_internal(pt, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&lseg, &seg, sizeof(lseg));
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&seg, &box->low, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	d = dist_ps_internal(pt, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&lseg, &seg, sizeof(lseg));
 	}
 
 	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	d = dist_ps_internal(pt, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&lseg, &seg, sizeof(lseg));
 	}
 
 	PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
 										PointPGetDatum(pt),
 										LsegPGetDatum(&lseg)));
 }
 
@@ -2927,21 +2937,21 @@ close_sl(PG_FUNCTION_ARGS)
 	float8		d1,
 				d2;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (lseg_interpt_line_internal(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = dist_pl_internal(&lseg->p[0], line);
 	d2 = dist_pl_internal(&lseg->p[1], line);
-	if (d1 < d2)
+	if (float8_lt(d1, d2))
 		*result = lseg->p[0];
 	else
 		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
 
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_sl\" not implemented")));
@@ -2961,77 +2971,80 @@ close_ls(PG_FUNCTION_ARGS)
 	float8		d1,
 				d2;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (lseg_interpt_line_internal(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = dist_pl_internal(&lseg->p[0], line);
 	d2 = dist_pl_internal(&lseg->p[1], line);
-	if (d1 < d2)
+	if (float8_lt(d1, d2))
 		*result = lseg->p[0];
 	else
 		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 }
 
 /* close_sb()
  * Closest point on or in box to line segment.
  */
 Datum
 close_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	Point		point;
 	LSEG		bseg,
 				seg;
-	double		dist,
+	float8		dist,
 				d;
 
 	/* segment intersects box? then just return closest point to center */
 	if (DatumGetBool(DirectFunctionCall2(inter_sb,
 										 LsegPGetDatum(lseg),
 										 BoxPGetDatum(box))))
 	{
 		box_cn(&point, box);
 		PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
 											PointPGetDatum(&point),
 											LsegPGetDatum(lseg)));
 	}
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
 	dist = lseg_dt(lseg, &bseg);
 
 	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	d = lseg_dt(lseg, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&bseg, &seg, sizeof(bseg));
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&seg, &box->low, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	d = lseg_dt(lseg, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&bseg, &seg, sizeof(bseg));
 	}
 
 	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	d = lseg_dt(lseg, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&bseg, &seg, sizeof(bseg));
 	}
 
 	/* OK, we now have the closest line segment on the box boundary */
 	PG_RETURN_DATUM(DirectFunctionCall2(close_lseg,
 										LsegPGetDatum(lseg),
 										LsegPGetDatum(&bseg)));
 }
@@ -3079,50 +3092,55 @@ on_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_BOOL(on_ps_internal(pt, lseg));
 }
 
 static bool
 on_ps_internal(Point *pt, LSEG *lseg)
 {
-	return FPeq(point_dt(pt, &lseg->p[0]) + point_dt(pt, &lseg->p[1]),
+	return FPeq(float8_pl(point_dt(pt, &lseg->p[0]),
+						  point_dt(pt, &lseg->p[1])),
 				point_dt(&lseg->p[0], &lseg->p[1]));
 }
 
 
 /*
  * Check whether the point is in the box or on its border
  */
 Datum
 on_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_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);
+	PG_RETURN_BOOL(float8_le(pt->x, box->high.x) &&
+				   float8_ge(pt->x, box->low.x) &&
+				   float8_le(pt->y, box->high.y) &&
+				   float8_ge(pt->y, box->low.y));
 }
 
 
 /*
  * Commutator of on_pb()
  */
 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);
+	PG_RETURN_BOOL(float8_le(pt->x, box->high.x) &&
+				   float8_ge(pt->x, box->low.x) &&
+				   float8_le(pt->y, box->high.y) &&
+				   float8_ge(pt->y, box->low.y));
 }
 
 
 /* on_ppath -
  *		Whether a point lies within (on) a polyline.
  *		If open, we have to (groan) check each segment.
  * (uses same algorithm as for point intersecting segment - tgl 1997-07-09)
  *		If closed, we use the old O(n) ray method for point-in-polygon.
  *				The ray is horizontal, from pt out to the right.
  *				Each segment that crosses the ray counts as an
@@ -3130,33 +3148,32 @@ box_contain_pt(PG_FUNCTION_ARGS)
  *				but not cross.
  *				(we can do p-in-p in lg(n), but it takes preprocessing)
  */
 Datum
 on_ppath(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	PATH	   *path = PG_GETARG_PATH_P(1);
 	int			i,
 				n;
-	double		a,
+	float8		a,
 				b;
 
 	/*-- OPEN --*/
 	if (!path->closed)
 	{
 		n = path->npts - 1;
 		a = point_dt(pt, &path->p[0]);
 		for (i = 0; i < n; i++)
 		{
 			b = point_dt(pt, &path->p[i + 1]);
-			if (FPeq(a + b,
-					 point_dt(&path->p[i], &path->p[i + 1])))
+			if (FPeq(float8_pl(a, b), point_dt(&path->p[i], &path->p[i + 1])))
 				PG_RETURN_BOOL(true);
 			a = b;
 		}
 		PG_RETURN_BOOL(false);
 	}
 
 	/*-- CLOSED --*/
 	PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
 }
 
@@ -3226,24 +3243,24 @@ inter_sl(PG_FUNCTION_ARGS)
  */
 Datum
 inter_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	BOX			lbox;
 	LSEG		bseg;
 	Point		point;
 
-	lbox.low.x = Min(lseg->p[0].x, lseg->p[1].x);
-	lbox.low.y = Min(lseg->p[0].y, lseg->p[1].y);
-	lbox.high.x = Max(lseg->p[0].x, lseg->p[1].x);
-	lbox.high.y = Max(lseg->p[0].y, lseg->p[1].y);
+	lbox.low.x = float8_min(lseg->p[0].x, lseg->p[1].x);
+	lbox.low.y = float8_min(lseg->p[0].y, lseg->p[1].y);
+	lbox.high.x = float8_max(lseg->p[0].x, lseg->p[1].x);
+	lbox.high.y = float8_max(lseg->p[0].y, lseg->p[1].y);
 
 	/* nothing close to overlap? then not going to intersect */
 	if (!box_ov(&lbox, box))
 		PG_RETURN_BOOL(false);
 
 	/* an endpoint of segment is inside box? then clearly intersects */
 	if (DatumGetBool(DirectFunctionCall2(on_pb,
 										 PointPGetDatum(&lseg->p[0]),
 										 BoxPGetDatum(box))) ||
 		DatumGetBool(DirectFunctionCall2(on_pb,
@@ -3332,27 +3349,27 @@ make_bound_box(POLYGON *poly)
 {
 	int			i;
 	BOX		   *boundbox = &poly->boundbox;
 
 	if (poly->npts > 0)
 	{
 		boundbox->low.x = boundbox->high.x = poly->p[0].x;
 		boundbox->low.y = boundbox->high.y = poly->p[0].y;
 		for (i = 1; i < poly->npts; i++)
 		{
-			if (poly->p[i].x < boundbox->low.x)
+			if (float8_lt(poly->p[i].x, boundbox->low.x))
 				boundbox->low.x = poly->p[i].x;
-			if (poly->p[i].x > boundbox->high.x)
+			if (float8_gt(poly->p[i].x, boundbox->high.x))
 				boundbox->high.x = poly->p[i].x;
-			if (poly->p[i].y < boundbox->low.y)
+			if (float8_lt(poly->p[i].y, boundbox->low.y))
 				boundbox->low.y = poly->p[i].y;
-			if (poly->p[i].y > boundbox->high.y)
+			if (float8_gt(poly->p[i].y, boundbox->high.y))
 				boundbox->high.y = poly->p[i].y;
 		}
 	}
 	else
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("cannot create bounding box for empty polygon")));
 }
 
 /*------------------------------------------------------------------
@@ -3478,21 +3495,21 @@ poly_send(PG_FUNCTION_ARGS)
  * the right most point of A left of the left most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_left(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.high.x < polyb->boundbox.low.x;
+	result = float8_lt(polya->boundbox.high.x, polyb->boundbox.low.x);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3501,21 +3518,21 @@ poly_left(PG_FUNCTION_ARGS)
  * the right most point of A at or left of the right most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_overleft(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.high.x <= polyb->boundbox.high.x;
+	result = float8_le(polya->boundbox.high.x, polyb->boundbox.high.x);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3524,21 +3541,21 @@ poly_overleft(PG_FUNCTION_ARGS)
  * the left most point of A right of the right most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_right(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.low.x > polyb->boundbox.high.x;
+	result = float8_gt(polya->boundbox.low.x, polyb->boundbox.high.x);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3547,21 +3564,21 @@ poly_right(PG_FUNCTION_ARGS)
  * the left most point of A at or right of the left most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_overright(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.low.x >= polyb->boundbox.low.x;
+	result = float8_ge(polya->boundbox.low.x, polyb->boundbox.low.x);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3570,21 +3587,21 @@ poly_overright(PG_FUNCTION_ARGS)
  * the upper most point of A below the lower most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_below(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.high.y < polyb->boundbox.low.y;
+	result = float8_lt(polya->boundbox.high.y, polyb->boundbox.low.y);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3593,21 +3610,21 @@ poly_below(PG_FUNCTION_ARGS)
  * the upper most point of A at or below the upper most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_overbelow(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.high.y <= polyb->boundbox.high.y;
+	result = float8_le(polya->boundbox.high.y, polyb->boundbox.high.y);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3616,21 +3633,21 @@ poly_overbelow(PG_FUNCTION_ARGS)
  * the lower most point of A above the upper most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_above(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.low.y > polyb->boundbox.high.y;
+	result = float8_gt(polya->boundbox.low.y, polyb->boundbox.high.y);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3639,21 +3656,21 @@ poly_above(PG_FUNCTION_ARGS)
  * the lower most point of A at or above the lower most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_overabove(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.low.y >= polyb->boundbox.low.y;
+	result = float8_ge(polya->boundbox.low.y, polyb->boundbox.low.y);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3850,22 +3867,22 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 	}
 
 	if (res && !intersection)
 	{
 		Point		p;
 
 		/*
 		 * if X-intersection wasn't found  then check central point of tested
 		 * segment. In opposite case we already check all subsegments
 		 */
-		p.x = (t.p[0].x + t.p[1].x) / 2.0;
-		p.y = (t.p[0].y + t.p[1].y) / 2.0;
+		p.x = float8_div(float8_pl(t.p[0].x, t.p[1].x), 2.0);
+		p.y = float8_div(float8_pl(t.p[0].y, t.p[1].y), 2.0);
 
 		res = point_inside(&p, poly->npts, poly->p);
 	}
 
 	return res;
 }
 
 /*-----------------------------------------------------------------
  * Determine if polygon A contains polygon B.
  *-----------------------------------------------------------------*/
@@ -3992,22 +4009,22 @@ point_add(PG_FUNCTION_ARGS)
 
 	point_add_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static inline void
 point_add_internal(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x + pt2->x,
-					pt1->y + pt2->y);
+					float8_pl(pt1->x, pt2->x),
+					float8_pl(pt1->y, pt2->y));
 }
 
 
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
@@ -4015,22 +4032,22 @@ point_sub(PG_FUNCTION_ARGS)
 
 	point_sub_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static inline void
 point_sub_internal(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x - pt2->x,
-					pt1->y - pt2->y);
+					float8_mi(pt1->x, pt2->x),
+					float8_mi(pt1->y, pt2->y));
 }
 
 
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
@@ -4038,22 +4055,24 @@ point_mul(PG_FUNCTION_ARGS)
 
 	point_mul_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static inline void
 point_mul_internal(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					(pt1->x * pt2->x) - (pt1->y * pt2->y),
-					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+					float8_mi(float8_mul(pt1->x, pt2->x),
+							  float8_mul(pt1->y, pt2->y)),
+					float8_pl(float8_mul(pt1->x, pt2->y),
+							  float8_mul(pt1->y, pt2->x)));
 }
 
 
 Datum
 point_div(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
@@ -4062,24 +4081,26 @@ point_div(PG_FUNCTION_ARGS)
 	point_div_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static inline void
 point_div_internal(Point *result, Point *pt1, Point *pt2)
 {
 	float8		div;
 
-	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
+	div = float8_pl(float8_mul(pt2->x, pt2->x), float8_mul(pt2->y, pt2->y));
 	point_construct(result,
-					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
-					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+					float8_div(float8_pl(float8_mul(pt1->x, pt2->x),
+										 float8_mul(pt1->y, pt2->y)), div),
+					float8_div(float8_mi(float8_mul(pt1->y, pt2->x),
+										 float8_mul(pt1->x, pt2->y)), div));
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D boxes.
  **
  ***********************************************************************/
 
 Datum
@@ -4188,24 +4209,24 @@ point_box(PG_FUNCTION_ARGS)
  */
 Datum
 boxes_bound_box(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0),
 			   *box2 = PG_GETARG_BOX_P(1),
 			   *container;
 
 	container = (BOX *) palloc(sizeof(BOX));
 
-	container->high.x = Max(box1->high.x, box2->high.x);
-	container->low.x = Min(box1->low.x, box2->low.x);
-	container->high.y = Max(box1->high.y, box2->high.y);
-	container->low.y = Min(box1->low.y, box2->low.y);
+	container->high.x = float8_max(box1->high.x, box2->high.x);
+	container->low.x = float8_min(box1->low.x, box2->low.x);
+	container->high.y = float8_max(box1->high.y, box2->high.y);
+	container->low.y = float8_min(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(container);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D paths.
  **
  ***********************************************************************/
@@ -4514,21 +4535,21 @@ circle_in(PG_FUNCTION_ARGS)
 		if (*cp == LDELIM)
 			s = cp;
 	}
 
 	pair_decode(s, &circle->center.x, &circle->center.y, &s, "circle", str);
 
 	if (*s == DELIM)
 		s++;
 
 	circle->radius = single_decode(s, &s, "circle", str);
-	if (circle->radius < 0)
+	if (float8_lt(circle->radius, 0.0))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
 
 	while (depth > 0)
 	{
 		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
@@ -4581,21 +4602,21 @@ circle_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	circle->center.x = pq_getmsgfloat8(buf);
 	circle->center.y = pq_getmsgfloat8(buf);
 	circle->radius = pq_getmsgfloat8(buf);
 
-	if (circle->radius < 0)
+	if (float8_lt(circle->radius, 0.0))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
 				 errmsg("invalid radius in external \"circle\" value")));
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 /*
  *		circle_send			- converts circle to binary format
  */
@@ -4632,144 +4653,146 @@ circle_same(PG_FUNCTION_ARGS)
 
 /*		circle_overlap	-		does circle1 overlap circle2?
  */
 Datum
 circle_overlap(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle1->radius + circle2->radius));
+						float8_pl(circle1->radius, circle2->radius)));
 }
 
 /*		circle_overleft -		is the right edge of circle1 at or left of
  *								the right edge of circle2?
  */
 Datum
 circle_overleft(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.x + circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_left		-		is circle1 strictly left of circle2?
  */
 Datum
 circle_left(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.x + circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_right	-		is circle1 strictly right of circle2?
  */
 Datum
 circle_right(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.x - circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_overright	-	is the left edge of circle1 at or right of
  *								the left edge of circle2?
  */
 Datum
 circle_overright(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.x - circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_contained		-		is circle1 contained by circle2?
  */
 Datum
 circle_contained(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle1->radius), circle2->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						float8_mi(circle2->radius, circle1->radius)));
 }
 
 /*		circle_contain	-		does circle1 contain circle2?
  */
 Datum
 circle_contain(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle2->radius), circle1->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						float8_mi(circle1->radius, circle2->radius)));
 }
 
 
 /*		circle_below		-		is circle1 strictly below circle2?
  */
 Datum
 circle_below(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.y + circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_above	-		is circle1 strictly above circle2?
  */
 Datum
 circle_above(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.y - circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overbelow -		is the upper edge of circle1 at or below
  *								the upper edge of circle2?
  */
 Datum
 circle_overbelow(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.y + circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overabove	-	is the lower edge of circle1 at or above
  *								the lower edge of circle2?
  */
 Datum
 circle_overabove(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.y - circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 
 /*		circle_relop	-		is area(circle1) relop area(circle2), within
  *								our accuracy constraint?
  */
 Datum
 circle_eq(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
@@ -4868,36 +4891,38 @@ circle_sub_pt(PG_FUNCTION_ARGS)
 Datum
 circle_mul_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_mul_internal(&result->center, &circle->center, point);
-	result->radius *= hypot(point->x, point->y);
+	result->radius = float8_mul(circle->radius,
+								float8_hypot(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_div_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_div_internal(&result->center, &circle->center, point);
-	result->radius /= hypot(point->x, point->y);
+	result->radius = float8_div(circle->radius,
+								float8_hypot(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /*		circle_area		-		returns the area of the circle.
  */
 Datum
 circle_area(PG_FUNCTION_ARGS)
 {
@@ -4907,21 +4932,21 @@ circle_area(PG_FUNCTION_ARGS)
 }
 
 
 /*		circle_diameter -		returns the diameter of the circle.
  */
 Datum
 circle_diameter(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
-	PG_RETURN_FLOAT8(2 * circle->radius);
+	PG_RETURN_FLOAT8(float8_mul(circle->radius, 2.0));
 }
 
 
 /*		circle_radius	-		returns the radius of the circle.
  */
 Datum
 circle_radius(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
@@ -4932,81 +4957,84 @@ circle_radius(PG_FUNCTION_ARGS)
 /*		circle_distance -		returns the distance between
  *								  two circles.
  */
 Datum
 circle_distance(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(&circle1->center, &circle2->center) -
-		(circle1->radius + circle2->radius);
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(&circle1->center, &circle2->center),
+					   float8_pl(circle1->radius, circle2->radius));
+	if (float8_lt(result, 0.0))
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 
 Datum
 circle_contain_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
-	PG_RETURN_BOOL(d <= circle->radius);
+	PG_RETURN_BOOL(float8_le(d, circle->radius));
 }
 
 
 Datum
 pt_contained_circle(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
-	PG_RETURN_BOOL(d <= circle->radius);
+	PG_RETURN_BOOL(float8_le(d, circle->radius));
 }
 
 
 /*		dist_pc -		returns the distance between
  *						  a point and a circle.
  */
 Datum
 dist_pc(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center), circle->radius);
+	if (float8_lt(result, 0.0))
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a circle to a point
  */
 Datum
 dist_cpoint(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center), circle->radius);
+	if (float8_lt(result, 0.0))
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*		circle_center	-		returns the center point of the circle.
  */
 Datum
 circle_center(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *result;
@@ -5014,24 +5042,24 @@ circle_center(PG_FUNCTION_ARGS)
 	result = (Point *) palloc(sizeof(Point));
 	result->x = circle->center.x;
 	result->y = circle->center.y;
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		circle_ar		-		returns the area of the circle.
  */
-static double
+static float8
 circle_ar(CIRCLE *circle)
 {
-	return M_PI * (circle->radius * circle->radius);
+	return float8_mul(float8_mul(circle->radius, circle->radius), M_PI);
 }
 
 
 /*----------------------------------------------------------
  *	Conversion operators.
  *---------------------------------------------------------*/
 
 Datum
 cr_circle(PG_FUNCTION_ARGS)
 {
@@ -5046,65 +5074,65 @@ cr_circle(PG_FUNCTION_ARGS)
 	result->radius = radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_box(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	BOX		   *box;
-	double		delta;
+	float8		delta;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
-	delta = circle->radius / sqrt(2.0);
+	delta = float8_div(circle->radius, sqrt(2.0));
 
-	box->high.x = circle->center.x + delta;
-	box->low.x = circle->center.x - delta;
-	box->high.y = circle->center.y + delta;
-	box->low.y = circle->center.y - delta;
+	box->high.x = float8_pl(circle->center.x, delta);
+	box->low.x = float8_mi(circle->center.x, delta);
+	box->high.y = float8_pl(circle->center.y, delta);
+	box->low.y = float8_mi(circle->center.y, delta);
 
 	PG_RETURN_BOX_P(box);
 }
 
 /* box_circle()
  * Convert a box to a circle.
  */
 Datum
 box_circle(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	circle->center.x = (box->high.x + box->low.x) / 2;
-	circle->center.y = (box->high.y + box->low.y) / 2;
+	circle->center.x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	circle->center.y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 
 	circle->radius = point_dt(&circle->center, &box->high);
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 
 Datum
 circle_poly(PG_FUNCTION_ARGS)
 {
 	int32		npts = PG_GETARG_INT32(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	POLYGON    *poly;
 	int			base_size,
 				size;
 	int			i;
-	double		angle;
-	double		anglestep;
+	float8		angle;
+	float8		anglestep;
 
 	if (FPzero(circle->radius))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("cannot convert circle with radius zero to polygon")));
 
 	if (npts < 2)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("must request at least 2 points")));
@@ -5115,27 +5143,30 @@ circle_poly(PG_FUNCTION_ARGS)
 	/* Check for integer overflow */
 	if (base_size / npts != sizeof(poly->p[0]) || size <= base_size)
 		ereport(ERROR,
 				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 				 errmsg("too many points requested")));
 
 	poly = (POLYGON *) palloc0(size);	/* zero any holes */
 	SET_VARSIZE(poly, size);
 	poly->npts = npts;
 
-	anglestep = (2.0 * M_PI) / npts;
+	anglestep = float8_div(2.0 * M_PI, npts);
 
 	for (i = 0; i < npts; i++)
 	{
-		angle = i * anglestep;
-		poly->p[i].x = circle->center.x - (circle->radius * cos(angle));
-		poly->p[i].y = circle->center.y + (circle->radius * sin(angle));
+		angle = float8_mul(anglestep, i);
+
+		poly->p[i].x = float8_mi(circle->center.x,
+								 float8_mul(circle->radius, cos(angle)));
+		poly->p[i].y = float8_pl(circle->center.y,
+								 float8_mul(circle->radius, sin(angle)));
 	}
 
 	make_bound_box(poly);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
 /*		poly_circle		- convert polygon to circle
  *
  * XXX This algorithm should use weighted means of line segments
@@ -5154,29 +5185,30 @@ poly_circle(PG_FUNCTION_ARGS)
 				 errmsg("cannot convert empty polygon to circle")));
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	circle->center.x = 0;
 	circle->center.y = 0;
 	circle->radius = 0;
 
 	for (i = 0; i < poly->npts; i++)
 	{
-		circle->center.x += poly->p[i].x;
-		circle->center.y += poly->p[i].y;
+		circle->center.x = float8_pl(circle->center.x, poly->p[i].x);
+		circle->center.y = float8_pl(circle->center.y, poly->p[i].y);
 	}
-	circle->center.x /= poly->npts;
-	circle->center.y /= poly->npts;
+	circle->center.x = float8_div(circle->center.x, poly->npts);
+	circle->center.y = float8_div(circle->center.y, poly->npts);
 
 	for (i = 0; i < poly->npts; i++)
-		circle->radius += point_dt(&poly->p[i], &circle->center);
-	circle->radius /= poly->npts;
+		circle->radius = float8_pl(circle->radius, point_dt(&poly->p[i],
+															&circle->center));
+	circle->radius = float8_div(circle->radius, poly->npts);
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 
 /***********************************************************************
  **
  **		Private routines for multiple types.
  **
  ***********************************************************************/
@@ -5190,45 +5222,45 @@ poly_circle(PG_FUNCTION_ARGS)
  *	http://hopf.math.northwestern.edu/index.html
  *	Description of algorithm:  http://www.linuxjournal.com/article/2197
  *							   http://www.linuxjournal.com/article/2029
  */
 
 #define POINT_ON_POLYGON INT_MAX
 
 static int
 point_inside(Point *p, int npts, Point *plist)
 {
-	double		x0,
+	float8		x0,
 				y0;
-	double		prev_x,
+	float8		prev_x,
 				prev_y;
 	int			i = 0;
-	double		x,
+	float8		x,
 				y;
 	int			cross,
 				total_cross = 0;
 
 	if (npts <= 0)
 		return 0;
 
 	/* compute first polygon point relative to single point */
-	x0 = plist[0].x - p->x;
-	y0 = plist[0].y - p->y;
+	x0 = float8_mi(plist[0].x, p->x);
+	y0 = float8_mi(plist[0].y, p->y);
 
 	prev_x = x0;
 	prev_y = y0;
 	/* loop over polygon points and aggregate total_cross */
 	for (i = 1; i < npts; i++)
 	{
 		/* compute next polygon point relative to single point */
-		x = plist[i].x - p->x;
-		y = plist[i].y - p->y;
+		x = float8_mi(plist[i].x, p->x);
+		y = float8_mi(plist[i].y, p->y);
 
 		/* compute previous to current point crossing */
 		if ((cross = lseg_crossing(x, y, prev_x, prev_y)) == POINT_ON_POLYGON)
 			return 2;
 		total_cross += cross;
 
 		prev_x = x;
 		prev_y = y;
 	}
 
@@ -5246,69 +5278,74 @@ point_inside(Point *p, int npts, Point *plist)
 /* lseg_crossing()
  * Returns +/-2 if line segment crosses the positive X-axis in a +/- direction.
  * Returns +/-1 if one point is on the positive X-axis.
  * Returns 0 if both points are on the positive X-axis, or there is no crossing.
  * Returns POINT_ON_POLYGON if the segment contains (0,0).
  * Wow, that is one confusing API, but it is used above, and when summed,
  * can tell is if a point is in a polygon.
  */
 
 static int
-lseg_crossing(double x, double y, double prev_x, double prev_y)
+lseg_crossing(float8 x, float8 y, float8 prev_x, float8 prev_y)
 {
-	double		z;
+	float8		z;
 	int			y_sign;
 
 	if (FPzero(y))
 	{							/* y == 0, on X axis */
 		if (FPzero(x))			/* (x,y) is (0,0)? */
 			return POINT_ON_POLYGON;
 		else if (FPgt(x, 0))
 		{						/* x > 0 */
 			if (FPzero(prev_y)) /* y and prev_y are zero */
 				/* prev_x > 0? */
-				return FPgt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
-			return FPlt(prev_y, 0) ? 1 : -1;
+				return FPgt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
+			return FPlt(prev_y, 0.0) ? 1 : -1;
 		}
 		else
 		{						/* x < 0, x not on positive X axis */
 			if (FPzero(prev_y))
 				/* prev_x < 0? */
-				return FPlt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
+				return FPlt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
 			return 0;
 		}
 	}
 	else
 	{							/* y != 0 */
 		/* compute y crossing direction from previous point */
-		y_sign = FPgt(y, 0) ? 1 : -1;
+		y_sign = FPgt(y, 0.0) ? 1 : -1;
 
 		if (FPzero(prev_y))
 			/* previous point was on X axis, so new point is either off or on */
-			return FPlt(prev_x, 0) ? 0 : y_sign;
-		else if (FPgt(y_sign * prev_y, 0))
+			return FPlt(prev_x, 0.0) ? 0 : y_sign;
+		else if ((y_sign < 0 && FPlt(prev_y, 0.0)) ||
+				 (y_sign > 0 && FPgt(prev_y, 0.0)))
 			/* both above or below X axis */
 			return 0;			/* same sign */
 		else
 		{						/* y and prev_y cross X-axis */
-			if (FPge(x, 0) && FPgt(prev_x, 0))
+			if (FPge(x, 0.0) && FPgt(prev_x, 0.0))
 				/* both non-negative so cross positive X-axis */
 				return 2 * y_sign;
-			if (FPlt(x, 0) && FPle(prev_x, 0))
+			if (FPlt(x, 0.0) && FPle(prev_x, 0.0))
 				/* both non-positive so do not cross positive X-axis */
 				return 0;
 
 			/* x and y cross axises, see URL above point_inside() */
-			z = (x - prev_x) * y - (y - prev_y) * x;
+			z = float8_mi(float8_mul(float8_mi(x, prev_x), y),
+						  float8_mul(float8_mi(y, prev_y), x));
 			if (FPzero(z))
 				return POINT_ON_POLYGON;
-			return FPgt((y_sign * z), 0) ? 0 : 2 * y_sign;
+			if ((y_sign < 0 && FPlt(z, 0.0)) ||
+				(y_sign > 0 && FPgt(z, 0.0)))
+				return 0;
+			return 2 * y_sign;
 		}
 	}
 }
 
 
 static bool
 plist_same(int npts, Point *p1, Point *p2)
 {
 	int			i,
 				ii,
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index c800bb1338..f62be1061e 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -76,38 +76,38 @@
 #include "access/spgist.h"
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
 #include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
- * is going only going to be used in a place to effect the performance
+ * is only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
 compareDoubles(const void *a, const void *b)
 {
-	double		x = *(double *) a;
-	double		y = *(double *) b;
+	float8		x = *(float8 *) a;
+	float8		y = *(float8 *) b;
 
 	if (x == y)
 		return 0;
 	return (x > y) ? 1 : -1;
 }
 
 typedef struct
 {
-	double		low;
-	double		high;
+	float8		low;
+	float8		high;
 } Range;
 
 typedef struct
 {
 	Range		left;
 	Range		right;
 } RangeBox;
 
 typedef struct
 {
@@ -121,30 +121,30 @@ typedef struct
  * The quadrant is 8 bit unsigned integer with 4 least bits in use.
  * This function accepts BOXes as input.  They are not casted to
  * RangeBoxes, yet.  All 4 bits are set by comparing a corner of the box.
  * This makes 16 quadrants in total.
  */
 static uint8
 getQuadrant(BOX *centroid, BOX *inBox)
 {
 	uint8		quadrant = 0;
 
-	if (inBox->low.x > centroid->low.x)
+	if (float8_gt(inBox->low.x, centroid->low.x))
 		quadrant |= 0x8;
 
-	if (inBox->high.x > centroid->high.x)
+	if (float8_gt(inBox->high.x, centroid->high.x))
 		quadrant |= 0x4;
 
-	if (inBox->low.y > centroid->low.y)
+	if (float8_gt(inBox->low.y, centroid->low.y))
 		quadrant |= 0x2;
 
-	if (inBox->high.y > centroid->high.y)
+	if (float8_gt(inBox->high.y, centroid->high.y))
 		quadrant |= 0x1;
 
 	return quadrant;
 }
 
 /*
  * Get RangeBox using BOX
  *
  * We are turning the BOX to our structures to emphasize their function
  * of representing points in 4D space.  It also is more convenient to
@@ -167,21 +167,21 @@ getRangeBox(BOX *box)
 /*
  * Initialize the traversal value
  *
  * In the beginning, we don't have any restrictions.  We have to
  * initialize the struct to cover the whole 4D space.
  */
 static RectBox *
 initRectBox(void)
 {
 	RectBox    *rect_box = (RectBox *) palloc(sizeof(RectBox));
-	double		infinity = get_float8_infinity();
+	float8		infinity = get_float8_infinity();
 
 	rect_box->range_box_x.left.low = -infinity;
 	rect_box->range_box_x.left.high = infinity;
 
 	rect_box->range_box_x.right.low = -infinity;
 	rect_box->range_box_x.right.high = infinity;
 
 	rect_box->range_box_y.left.low = -infinity;
 	rect_box->range_box_y.left.high = infinity;
 
@@ -410,40 +410,40 @@ spg_box_quad_choose(PG_FUNCTION_ARGS)
  * point as the median of the coordinates of the boxes.
  */
 Datum
 spg_box_quad_picksplit(PG_FUNCTION_ARGS)
 {
 	spgPickSplitIn *in = (spgPickSplitIn *) PG_GETARG_POINTER(0);
 	spgPickSplitOut *out = (spgPickSplitOut *) PG_GETARG_POINTER(1);
 	BOX		   *centroid;
 	int			median,
 				i;
-	double	   *lowXs = palloc(sizeof(double) * in->nTuples);
-	double	   *highXs = palloc(sizeof(double) * in->nTuples);
-	double	   *lowYs = palloc(sizeof(double) * in->nTuples);
-	double	   *highYs = palloc(sizeof(double) * in->nTuples);
+	float8	   *lowXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *lowYs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highYs = palloc(sizeof(float8) * in->nTuples);
 
 	/* Calculate median of all 4D coordinates */
 	for (i = 0; i < in->nTuples; i++)
 	{
 		BOX		   *box = DatumGetBoxP(in->datums[i]);
 
 		lowXs[i] = box->low.x;
 		highXs[i] = box->high.x;
 		lowYs[i] = box->low.y;
 		highYs[i] = box->high.y;
 	}
 
-	qsort(lowXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(lowYs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highYs, in->nTuples, sizeof(double), compareDoubles);
+	qsort(lowXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(lowYs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highYs, in->nTuples, sizeof(float8), compareDoubles);
 
 	median = in->nTuples / 2;
 
 	centroid = palloc(sizeof(BOX));
 
 	centroid->low.x = lowXs[median];
 	centroid->high.x = highXs[median];
 	centroid->low.y = lowYs[median];
 	centroid->high.y = highYs[median];
 
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 22c68f5b62..eee0ceff11 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -1,23 +1,20 @@
 /*-------------------------------------------------------------------------
  *
  * geo_decls.h - Declarations for various 2D constructs.
  *
  *
  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * src/include/utils/geo_decls.h
  *
- * NOTE
- *	  These routines do *not* use the float types from adt/.
- *
  *	  XXX These routines were not written by a numerical analyst.
  *
  *	  XXX I have made some attempt to flesh out the operators
  *		and data types. There are still some more to do. - tgl 97/04/19
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEO_DECLS_H
 #define GEO_DECLS_H
 
@@ -28,43 +25,43 @@
 
 /*--------------------------------------------------------------------
  * Useful floating point utilities and constants.
  *-------------------------------------------------------------------*/
 
 
 #define EPSILON					1.0E-06
 
 #ifdef EPSILON
 #define FPzero(A)				(fabs(A) <= EPSILON)
-#define FPeq(A,B)				(fabs((A) - (B)) <= EPSILON)
-#define FPne(A,B)				(fabs((A) - (B)) > EPSILON)
-#define FPlt(A,B)				((B) - (A) > EPSILON)
-#define FPle(A,B)				((A) - (B) <= EPSILON)
-#define FPgt(A,B)				((A) - (B) > EPSILON)
-#define FPge(A,B)				((B) - (A) <= EPSILON)
+#define FPeq(A, B)				(float8_le(fabs(float8_mi(A, B)), EPSILON))
+#define FPne(A, B)				(float8_gt(fabs(float8_mi(A, B)), EPSILON))
+#define FPlt(A, B)				(float8_gt(float8_mi(B, A), EPSILON))
+#define FPle(A, B)				(float8_le(float8_mi(A, B), EPSILON))
+#define FPgt(A, B)				(float8_gt(float8_mi(A, B), EPSILON))
+#define FPge(A, B)				(float8_le(float8_mi(B, A), EPSILON))
 #else
-#define FPzero(A)				((A) == 0)
-#define FPeq(A,B)				((A) == (B))
-#define FPne(A,B)				((A) != (B))
-#define FPlt(A,B)				((A) < (B))
-#define FPle(A,B)				((A) <= (B))
-#define FPgt(A,B)				((A) > (B))
-#define FPge(A,B)				((A) >= (B))
+#define FPzero(A)				((A) == 0.0)
+#define FPeq(A, B)				(float8_eq(A, B))
+#define FPne(A, B)				(float8_ne(A, B))
+#define FPlt(A, B)				(float8_lt(A, B))
+#define FPle(A, B)				(float8_le(A, B))
+#define FPgt(A, B)				(float8_gt(A, B))
+#define FPge(A, B)				(float8_ge(A, B))
 #endif
 
 
 /*---------------------------------------------------------------------
  * Point - (x,y)
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		x,
+	float8		x,
 				y;
 } Point;
 
 
 /*---------------------------------------------------------------------
  * LSEG - A straight line, specified by endpoints.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		p[2];
@@ -72,66 +69,66 @@ typedef struct
 
 
 /*---------------------------------------------------------------------
  * PATH - Specified by vertex points.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	int32		vl_len_;		/* varlena header (do not touch directly!) */
 	int32		npts;
 	int32		closed;			/* is this a closed polygon? */
-	int32		dummy;			/* padding to make it double align */
+	int32		dummy;			/* padding to make it float8 align */
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } PATH;
 
 
 /*---------------------------------------------------------------------
  * LINE - Specified by its general equation (Ax+By+C=0).
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		A,
+	float8		A,
 				B,
 				C;
 } LINE;
 
 
 /*---------------------------------------------------------------------
  * BOX	- Specified by two corner points, which are
  *		 sorted to save calculation time later.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		high,
 				low;			/* corner POINTs */
 } BOX;
 
 /*---------------------------------------------------------------------
- * POLYGON - Specified by an array of doubles defining the points,
+ * POLYGON - Specified by an array of float8s defining the points,
  *		keeping the number of points and the bounding box for
  *		speed purposes.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	int32		vl_len_;		/* varlena header (do not touch directly!) */
 	int32		npts;
 	BOX			boundbox;
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } POLYGON;
 
 /*---------------------------------------------------------------------
  * CIRCLE - Specified by a center point and radius.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		center;
-	double		radius;
+	float8		radius;
 } CIRCLE;
 
 /*
  * fmgr interface macros
  *
  * Path and Polygon are toastable varlena types, the others are just
  * fixed-size pass-by-reference types.
  */
 
 #define DatumGetPointP(X)	 ((Point *) DatumGetPointer(X))
@@ -166,11 +163,11 @@ typedef struct
 #define PolygonPGetDatum(X)			PointerGetDatum(X)
 #define PG_GETARG_POLYGON_P(n)		DatumGetPolygonP(PG_GETARG_DATUM(n))
 #define PG_GETARG_POLYGON_P_COPY(n) DatumGetPolygonPCopy(PG_GETARG_DATUM(n))
 #define PG_RETURN_POLYGON_P(x)		return PolygonPGetDatum(x)
 
 #define DatumGetCircleP(X)	  ((CIRCLE *) DatumGetPointer(X))
 #define CirclePGetDatum(X)	  PointerGetDatum(X)
 #define PG_GETARG_CIRCLE_P(n) DatumGetCircleP(PG_GETARG_DATUM(n))
 #define PG_RETURN_CIRCLE_P(x) return CirclePGetDatum(x)
 
-#endif   /* GEO_DECLS_H */
+#endif							/* GEO_DECLS_H */
-- 
2.13.5 (Apple Git-94)

0004-line-fixes-v03.patchapplication/octet-stream; name=0004-line-fixes-v03.patchDownload
From 82fd7f782555f7390210e8c07f811bb1ca419659 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sun, 28 May 2017 11:35:17 +0200
Subject: [PATCH 4/4] line-fixes-v03

Fix obvious problems around the line datatype

I have noticed some line operators retuning wrong results, and Tom Lane
spotted similar problems on more places.  Source history reveals that
during 1990s, the internal format of the line datatype is changed, but
most functions haven't got the hint.  The fixes include:

* Reject invalid specification A=B=0 on receive
* Avoid division by zero on perpendicular operator
* Fix intersection and distance operators when neither A nor B are 1
* Avoid point distance operator crashing on float precision loss
* Fix line segment distance by getting the minimum as the comment suggested

The changes are also aiming make line operators more symmetric.  Changing
results for same lines in different order are surely not expected.

Previous discussion:
https://www.postgresql.org/message-id/flat/CAE2gYzw_-z%3DV2kh8QqFjenu%3D8MJXzOP44wRW%3DAzzeamrmTT1%3DQ%40mail.gmail.com
---
 src/backend/utils/adt/geo_ops.c | 134 ++++++++++++++++++++++++----------------
 1 file changed, 81 insertions(+), 53 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index dbf1de0ca2..c8714ff78f 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -1003,20 +1003,25 @@ line_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LINE	   *line;
 
 	line = (LINE *) palloc(sizeof(LINE));
 
 	line->A = pq_getmsgfloat8(buf);
 	line->B = pq_getmsgfloat8(buf);
 	line->C = pq_getmsgfloat8(buf);
 
+	if (line->A == 0.0 && line->B == 0.0)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+				 errmsg("invalid line specification: A and B cannot both be zero")));
+
 	PG_RETURN_LINE_P(line);
 }
 
 /*
  *		line_send			- converts line to binary format
  */
 Datum
 line_send(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -1123,25 +1128,28 @@ line_parallel(PG_FUNCTION_ARGS)
 }
 
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
-	else if (FPzero(l1->B))
+	if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
+	if (FPzero(l2->A))
+		PG_RETURN_BOOL(FPzero(l1->B));
+	if (FPzero(l2->B))
+		PG_RETURN_BOOL(FPzero(l1->A));
 
-	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
-								   float8_mul(l1->B, l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(float8_mul(l1->A, l2->B), -float8_mul(l1->B, l2->A)));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
@@ -1153,20 +1161,21 @@ line_horizontal(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(FPzero(line->A));
 }
 
 Datum
 line_eq(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		ratio;
 
+	/* A and B cannot be both 0, but we never really know with the EPSILON. */
 	if (!FPzero(l2->A))
 		ratio = float8_div(l1->A, l2->A);
 	else if (!FPzero(l2->B))
 		ratio = float8_div(l1->B, l2->B);
 	else if (!FPzero(l2->C))
 		ratio = float8_div(l1->C, l2->C);
 	else
 		ratio = 1.0;
 
 	PG_RETURN_BOOL(FPeq(l1->A, float8_mul(ratio, l2->A)) &&
@@ -1180,30 +1189,36 @@ line_eq(PG_FUNCTION_ARGS)
  *---------------------------------------------------------*/
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	float8		result;
-	Point		tmp;
+	float8		ratio;
 
 	if (line_interpt_internal(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
-	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
-	point_construct(&tmp, 0.0, l1->C);
-	result = dist_pl_internal(&tmp, l2);
-	PG_RETURN_FLOAT8(result);
+
+	/* A and B cannot be both 0, but we never really know with the EPSILON. */
+	if (!FPzero(l2->A))
+		ratio = float8_div(l1->A, l2->A);
+	else if (!FPzero(l2->B))
+		ratio = float8_div(l1->B, l2->B);
+	else
+		ratio = 1.0;
+
+	PG_RETURN_FLOAT8(float8_div(fabs(float8_mi(l1->C,
+											   float8_mul(ratio, l2->C))),
+								float8_hypot(l1->A, l1->B)));
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
@@ -1226,38 +1241,62 @@ line_interpt(PG_FUNCTION_ARGS)
  * NOTE: If the lines are identical then we will find they are parallel
  * and report "no intersection".  This is a little weird, but since
  * there's no *unique* intersection, maybe it's appropriate behavior.
  */
 static bool
 line_interpt_internal(Point *result, LINE *l1, LINE *l2)
 {
 	float8		x,
 				y;
 
-	if (FPzero(l1->B))			/* l1 vertical? */
+	if (FPzero(l1->A))			/* l1 horizontal? */
+	{
+		if (FPzero(l2->A))		/* l2 horizontal? */
+			return false;
+
+		y = float8_div(-l1->C, l1->B);
+		x = float8_div(-float8_pl(float8_mul(l2->B, y), l2->C), l2->A);
+	}
+	else if (FPzero(l1->B))		/* l1 vertical? */
 	{
 		if (FPzero(l2->B))		/* l2 vertical? */
 			return false;
 
-		x = l1->C;
-		y = float8_pl(float8_mul(l2->A, x), l2->C);
+		x = float8_div(-l1->C, l1->A);
+		y = float8_div(-float8_pl(float8_mul(l2->A, x), l2->C), l2->B);
+	}
+	else if (FPzero(l2->A))		/* l2 horizontal? */
+	{
+		if (FPzero(l1->A))		/* l1 horizontal? */
+			return false;
+
+		y = float8_div(-l2->C, l2->B);
+		x = float8_div(-float8_pl(float8_mul(l1->B, y), l1->C), l1->A);
+	}
+	else if (FPzero(l2->B))		/* l2 vertical? */
+	{
+		if (FPzero(l1->B))		/* l1 vertical? */
+			return false;
+
+		x = float8_div(-l2->C, l2->A);
+		y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
 	}
 	else
 	{
-		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
+		if (FPeq(float8_mul(l1->A, l2->B), float8_mul(l2->A, l1->B)))
 			return false;
 
-		if (FPzero(l2->B))
-			x = l2->C;
-		else
-			x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
-		y = float8_pl(float8_mul(l1->A, x), l1->C);
+		x = float8_div(float8_mi(float8_mul(l1->B, l2->C),
+								 float8_mul(l2->B, l1->C)),
+					   float8_mi(float8_mul(l1->A, l2->B),
+								 float8_mul(l2->A, l1->B)));
+		y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
 	}
 	if (result != NULL)
 		point_construct(result, x, y);
 
 #ifdef GEODEBUG
 	printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
 		   DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
 	printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
 #endif
 
@@ -2061,46 +2100,35 @@ lseg_parallel(PG_FUNCTION_ARGS)
 
 	m1 = float8_slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y);
 	m2 = float8_slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y);
 
 	PG_RETURN_BOOL(FPeq(m1, m2));
 }
 
 /* lseg_perp()
  * Determine if two line segments are perpendicular.
  *
- * This code did not get the correct answer for
- *	'((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg
- * So, modified it to check explicitly for slope of vertical line
- *	returned by float8_slope() and the results seem better.
- * - thomas 1998-01-31
+ * We are comparing the slope of the first line segment with the inverse slope
+ * of the second line segment.
  */
 Datum
 lseg_perp(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	float8		m1,
 				m2;
 
 	m1 = float8_slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y);
-	m2 = float8_slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y);
+	m2 = float8_slope(l2->p[0].y, l2->p[1].y, l2->p[1].x, l2->p[0].x);
 
-#ifdef GEODEBUG
-	printf("lseg_perp- slopes are %g and %g\n", m1, m2);
-#endif
-	if (FPzero(m1))
-		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
-	else if (FPzero(m2))
-		PG_RETURN_BOOL(FPeq(m1, DBL_MAX));
-
-	PG_RETURN_BOOL(FPeq(float8_div(m1, m2), -1.0));
+	PG_RETURN_BOOL(FPeq(m1, m2));
 }
 
 Datum
 lseg_vertical(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 
 	PG_RETURN_BOOL(FPeq(lseg->p[0].x, lseg->p[1].x));
 }
 
@@ -2467,22 +2495,21 @@ dist_pb(PG_FUNCTION_ARGS)
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	float8		result;
 
 	if (lseg_interpt_line_internal(NULL, lseg, line))
 		result = 0.0;
 	else
-		/* XXX shouldn't we take the min not max? */
-		result = float8_max(dist_pl_internal(&lseg->p[0], line),
+		result = float8_min(dist_pl_internal(&lseg->p[0], line),
 							dist_pl_internal(&lseg->p[1], line));
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
@@ -2663,43 +2690,44 @@ lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line)
 /* close_pl -
  *		The intersection point of a perpendicular of the line
  *		through the point.
  */
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
-	float8		invm;
-	LINE		tmp;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (FPzero(line->B))		/* vertical? */
+		point_construct(result, float8_div(-line->C, line->A), pt->y);
+	else if (FPzero(line->A))	/* horizontal? */
+		point_construct(result, pt->x, float8_div(-line->C, line->B));
+	else
 	{
-		result->x = line->C;
-		result->y = pt->y;
-		PG_RETURN_POINT_P(result);
-	}
-	if (FPzero(line->A))		/* horizontal? */
-	{
-		result->x = pt->x;
-		result->y = line->C;
-		PG_RETURN_POINT_P(result);
-	}
-	/* drop a perpendicular and find the intersection point */
+		LINE		perp;
+
+		/*
+		 * Drop a perpendicular and find the intersection point
+		 *
+		 * We need to invert and flip the sign on the slope to get the
+		 * perpendicular.  We might lose some precision on the division. It
+		 * shouldn't be as much to turn the line.  If it happens anyway, we
+		 * will assume the point it on the line.
+		 */
+		line_construct_pm(&perp, pt, float8_div(line->B, line->A));
+		if (!line_interpt_internal(result, &perp, line))
+			*result = *pt;
+	}
 
-	/* invert and flip the sign on the slope to get a perpendicular */
-	invm = float8_div(line->B, line->A);
-	line_construct_pm(&tmp, pt, invm);
-	line_interpt_internal(result, &tmp, line);
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_ps()
  * Closest point on line segment to specified point.
  * Take the closest endpoint if the point is left, right,
  *	above, or below the segment, otherwise find the intersection
  *	point of the segment and its perpendicular through the point.
  *
-- 
2.13.5 (Apple Git-94)

0001-geo-funcs-v03.patchapplication/octet-stream; name=0001-geo-funcs-v03.patchDownload
From b23b68d4908cf5d2532db51cc5b18595026abf84 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 27 May 2017 11:27:18 -0400
Subject: [PATCH 1/4] geo-funcs-v03

Refactor geometric functions and operators code

Most of the geometric types were not using functions of each other's.
I believe the reason behind this is simpler types line point and line
being developed after more complicated ones.  This patch reduces duplicate
code and makes functions of different datatypes more compatible.  We can
do better than that, but it would require touching many more lines.
The changes can be summarised as:

* Re-use more functions to implement others
* Unify *_construct and *_interpt_internal functions to obtain
  pre-allocated memory
* Remove private functions from geo_decls.h
* Switch using C11 hypot() as the comment suggested
* Add comments to describe some functions
---
 src/backend/utils/adt/geo_ops.c | 1011 +++++++++++++++++----------------------
 src/include/utils/geo_decls.h   |   13 +-
 src/test/regress/regress.c      |   11 +-
 3 files changed, 455 insertions(+), 580 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 0348855b11..d3dc2ee602 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -31,60 +31,77 @@
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
+/* Routines for float8 */
+static inline float8 float8_slope(float8 x1, float8 x2, float8 y1, float8 y2);
+
+/* Routines for two-dimensional points */
+static inline void point_construct(Point *result, float8 x, float8 y);
+static inline void point_add_internal(Point *result, Point *pt1, Point *pt2);
+static inline void point_sub_internal(Point *result, Point *pt1, Point *pt2);
+static inline void point_mul_internal(Point *result, Point *pt1, Point *pt2);
+static inline void point_div_internal(Point *result, Point *pt1, Point *pt2);
+static inline bool point_eq_internal(Point *pt1, Point *pt2);
+static float8 point_dt(Point *pt1, Point *pt2);
 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);
+
+/* Routines for two-dimensional boxes */
+static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
+static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
+static double box_ar(BOX *box);
 static double box_ht(BOX *box);
 static double box_wd(BOX *box);
+
+/* Routines for two-dimensional circles */
 static double circle_ar(CIRCLE *circle);
-static CIRCLE *circle_copy(CIRCLE *circle);
-static LINE *line_construct_pm(Point *pt, double m);
-static void line_construct_pts(LINE *line, Point *pt1, Point *pt2);
-static bool lseg_intersect_internal(LSEG *l1, LSEG *l2);
-static double lseg_dt(LSEG *l1, LSEG *l2);
+
+/* Routines for two-dimensional lines */
+static inline void line_construct_pm(LINE *result, Point *pt, float8 m);
+static inline void line_construct_pts(LINE *result, Point *pt1, Point *pt2);
+static bool line_interpt_internal(Point *result, LINE *l1, LINE *l2);
+static inline float8 line_calculate_point(LINE *line, Point *pt);
+
+/* Routines for two-dimensional line segments */
+static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
+static bool lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line);
+static bool lseg_interpt_internal(Point *result, LSEG *l1, LSEG *l2);
+static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
+static float8 lseg_dt(LSEG *l1, LSEG *l2);
+static int	lseg_crossing(double x, double y, double px, double py);
 static bool on_ps_internal(Point *pt, LSEG *lseg);
+
+/* Routines for two-dimensional polygons */
 static void make_bound_box(POLYGON *poly);
+
+/* Unsorted */
 static bool plist_same(int npts, Point *p1, Point *p2);
-static Point *point_construct(double x, double y);
-static Point *point_copy(Point *pt);
 static double single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
 static void pair_decode(char *str, double *x, double *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
 static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
-static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
-static double box_ar(BOX *box);
-static void box_cn(Point *center, BOX *box);
-static Point *interpt_sl(LSEG *lseg, LINE *line);
-static bool has_interpt_sl(LSEG *lseg, LINE *line);
 static double dist_pl_internal(Point *pt, LINE *line);
 static double dist_ps_internal(Point *pt, LSEG *lseg);
-static Point *line_interpt_internal(LINE *l1, LINE *l2);
-static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
-static Point *lseg_interpt_internal(LSEG *l1, LSEG *l2);
 static double dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 
 /*
  * Delimiters for input and output strings.
  * LDELIM, RDELIM, and DELIM are left, right, and separator delimiters, respectively.
  * LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints.
  */
 
 #define LDELIM			'('
@@ -327,20 +344,44 @@ pair_count(char *s, char delim)
 	{
 		ndelim++;
 		s++;
 	}
 	return (ndelim % 2) ? ((ndelim + 1) / 2) : -1;
 }
 
 
 /***********************************************************************
  **
+ **		Routines for float8
+ **
+ ***********************************************************************/
+
+/*
+ * Return slope of two points
+ *
+ * This function accepts x and y coordinates separately to let it be used
+ * to calculate inverse slope.  To achieve that pass the values in
+ * (y1, y2, x2, x1) order.
+ */
+static inline float8
+float8_slope(float8 x1, float8 x2, float8 y1, float8 y2)
+{
+	if (FPeq(x1, x2))
+		return DBL_MAX;
+	if (FPeq(y1, y2))
+		return 0.0;
+	return (y1 - y2) / (x1 - x2);
+}
+
+
+/***********************************************************************
+ **
  **		Routines for two-dimensional boxes.
  **
  ***********************************************************************/
 
 /*----------------------------------------------------------
  * Formatting and conversion routines.
  *---------------------------------------------------------*/
 
 /*		box_in	-		convert a string to internal form.
  *
@@ -434,89 +475,61 @@ box_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, box->high.x);
 	pq_sendfloat8(&buf, box->high.y);
 	pq_sendfloat8(&buf, box->low.x);
 	pq_sendfloat8(&buf, box->low.y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*		box_construct	-		fill in a new box.
  */
-static BOX *
-box_construct(double x1, double x2, double y1, double y2)
+static inline void
+box_construct(BOX *result, Point *pt1, Point *pt2)
 {
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	return box_fill(result, x1, x2, y1, y2);
-}
-
-
-/*		box_fill		-		fill in a given box struct
- */
-static BOX *
-box_fill(BOX *result, double x1, double x2, double y1, double y2)
-{
-	if (x1 > x2)
+	if (pt1->x > pt2->x)
 	{
-		result->high.x = x1;
-		result->low.x = x2;
+		result->high.x = pt1->x;
+		result->low.x = pt2->x;
 	}
 	else
 	{
-		result->high.x = x2;
-		result->low.x = x1;
+		result->high.x = pt2->x;
+		result->low.x = pt1->x;
 	}
-	if (y1 > y2)
+	if (pt1->y > pt2->y)
 	{
-		result->high.y = y1;
-		result->low.y = y2;
+		result->high.y = pt1->y;
+		result->low.y = pt2->y;
 	}
 	else
 	{
-		result->high.y = y2;
-		result->low.y = y1;
+		result->high.y = pt2->y;
+		result->low.y = pt1->y;
 	}
-
-	return result;
-}
-
-
-/*		box_copy		-		copy a box
- */
-static BOX *
-box_copy(BOX *box)
-{
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	memcpy((char *) result, (char *) box, sizeof(BOX));
-
-	return result;
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for BOXes.
  *		<, >, <=, >=, and == are based on box area.
  *---------------------------------------------------------*/
 
 /*		box_same		-		are two boxes identical?
  */
 Datum
 box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPeq(box1->high.x, box2->high.x) &&
-				   FPeq(box1->low.x, box2->low.x) &&
-				   FPeq(box1->high.y, box2->high.y) &&
-				   FPeq(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(point_eq_internal(&box1->high, &box2->high) &&
+				   point_eq_internal(&box1->low, &box2->low));
 }
 
 /*		box_overlap		-		does box1 overlap box2?
  */
 Datum
 box_overlap(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
@@ -751,51 +764,51 @@ box_area(PG_FUNCTION_ARGS)
 
 
 /*		box_width		-		returns the width of the box
  *								  (horizontal magnitude).
  */
 Datum
 box_width(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.x - box->low.x);
+	PG_RETURN_FLOAT8(box_wd(box));
 }
 
 
 /*		box_height		-		returns the height of the box
  *								  (vertical magnitude).
  */
 Datum
 box_height(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.y - box->low.y);
+	PG_RETURN_FLOAT8(box_ht(box));
 }
 
 
 /*		box_distance	-		returns the distance between the
  *								  center points of two boxes.
  */
 Datum
 box_distance(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 	Point		a,
 				b;
 
 	box_cn(&a, box1);
 	box_cn(&b, box2);
 
-	PG_RETURN_FLOAT8(HYPOT(a.x - b.x, a.y - b.y));
+	PG_RETURN_FLOAT8(point_dt(&a, &b));
 }
 
 
 /*		box_center		-		returns the center point of the box.
  */
 Datum
 box_center(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *result = (Point *) palloc(sizeof(Point));
@@ -934,22 +947,22 @@ line_in(PG_FUNCTION_ARGS)
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
 							"line", str)));
 		if (FPzero(line->A) && FPzero(line->B))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: A and B cannot both be zero")));
 	}
 	else
 	{
-		path_decode(s, true, 2, &(lseg.p[0]), &isopen, NULL, "line", str);
-		if (FPeq(lseg.p[0].x, lseg.p[1].x) && FPeq(lseg.p[0].y, lseg.p[1].y))
+		path_decode(s, true, 2, &lseg.p[0], &isopen, NULL, "line", str);
+		if (point_eq_internal(&lseg.p[0], &lseg.p[1]))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: must be two distinct points")));
 		line_construct_pts(line, &lseg.p[0], &lseg.p[1]);
 	}
 
 	PG_RETURN_LINE_P(line);
 }
 
 
@@ -997,128 +1010,104 @@ line_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, line->C);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*----------------------------------------------------------
  *	Conversion routines from one line formula to internal.
  *		Internal form:	Ax+By+C=0
  *---------------------------------------------------------*/
 
-/* line_construct_pm()
- * point-slope
+/*
+ * Fill already-allocated LINE struct from the point and the slope
  */
-static LINE *
-line_construct_pm(Point *pt, double m)
+static inline void
+line_construct_pm(LINE *result, Point *pt, float8 m)
 {
-	LINE	   *result = (LINE *) palloc(sizeof(LINE));
-
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
 		result->A = -1;
 		result->B = 0;
 		result->C = pt->x;
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
 		result->C = pt->y - m * pt->x;
 	}
-
-	return result;
 }
 
+
 /*
  * Fill already-allocated LINE struct from two points on the line
  */
-static void
-line_construct_pts(LINE *line, Point *pt1, Point *pt2)
+static inline void
+line_construct_pts(LINE *result, Point *pt1, Point *pt2)
 {
-	if (FPeq(pt1->x, pt2->x))
-	{							/* vertical */
-		/* use "x = C" */
-		line->A = -1;
-		line->B = 0;
-		line->C = pt1->x;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is vertical\n");
-#endif
-	}
-	else if (FPeq(pt1->y, pt2->y))
-	{							/* horizontal */
-		/* use "y = C" */
-		line->A = 0;
-		line->B = -1;
-		line->C = pt1->y;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is horizontal\n");
-#endif
-	}
-	else
-	{
-		/* use "mx - y + yinter = 0" */
-		line->A = (pt2->y - pt1->y) / (pt2->x - pt1->x);
-		line->B = -1.0;
-		line->C = pt1->y - line->A * pt1->x;
-		/* on some platforms, the preceding expression tends to produce -0 */
-		if (line->C == 0.0)
-			line->C = 0.0;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is neither vertical nor horizontal (diffs x=%.*g, y=%.*g\n",
-			   DBL_DIG, (pt2->x - pt1->x), DBL_DIG, (pt2->y - pt1->y));
-#endif
-	}
+	float8		m;
+
+	m = float8_slope(pt1->x, pt2->x, pt1->y, pt2->y);
+	line_construct_pm(result, pt1, m);
 }
 
-/* line_construct_pp()
- * two points
+
+/*
+ * Construct a line from 2 points
  */
 Datum
 line_construct_pp(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 	LINE	   *result = (LINE *) palloc(sizeof(LINE));
 
 	line_construct_pts(result, pt1, pt2);
 	PG_RETURN_LINE_P(result);
 }
 
 
+/*
+ * Calculate the line equation for a point
+ *
+ * This returns the result of the line equation Ax + By + C.  The result
+ * needs to be 0 for the point to be on the line.
+ */
+static inline float8
+line_calculate_point(LINE *line, Point *pt)
+{
+	return line->A * pt->x + line->B * pt->y + line->C;
+}
+
+
 /*----------------------------------------------------------
  *	Relative position routines.
  *---------------------------------------------------------*/
 
 Datum
 line_intersect(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(!DatumGetBool(DirectFunctionCall2(line_parallel,
-													 LinePGetDatum(l1),
-													 LinePGetDatum(l2))));
+	PG_RETURN_BOOL(line_interpt_internal(NULL, l1, l2));
 }
 
 Datum
 line_parallel(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
-	if (FPzero(l1->B))
-		PG_RETURN_BOOL(FPzero(l2->B));
-
-	PG_RETURN_BOOL(FPeq(l2->A, l1->A * (l2->B / l1->B)));
+	PG_RETURN_BOOL(!line_interpt_internal(NULL, l1, l2));
 }
 
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
@@ -1172,96 +1161,94 @@ line_eq(PG_FUNCTION_ARGS)
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
-	Point	   *tmp;
+	Point		tmp;
 
-	if (!DatumGetBool(DirectFunctionCall2(line_parallel,
-										  LinePGetDatum(l1),
-										  LinePGetDatum(l2))))
+	if (line_interpt_internal(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
 		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
-	tmp = point_construct(0.0, l1->C);
-	result = dist_pl_internal(tmp, l2);
+	point_construct(&tmp, 0.0, l1->C);
+	result = dist_pl_internal(&tmp, l2);
 	PG_RETURN_FLOAT8(result);
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
-	result = line_interpt_internal(l1, l2);
+	result = (Point *) palloc(sizeof(Point));
 
-	if (result == NULL)
+	if (!line_interpt_internal(result, l1, l2))
 		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
 
 /*
  * Internal version of line_interpt
  *
- * returns a NULL pointer if no intersection point
+ * This returns true if two lines intersect (they do, if they are not
+ * parallel), false if they do not.  This also sets the intersection point
+ * to *result, if it is not NULL.
+ *
+ * NOTE: If the lines are identical then we will find they are parallel
+ * and report "no intersection".  This is a little weird, but since
+ * there's no *unique* intersection, maybe it's appropriate behavior.
  */
-static Point *
-line_interpt_internal(LINE *l1, LINE *l2)
+static bool
+line_interpt_internal(Point *result, LINE *l1, LINE *l2)
 {
-	Point	   *result;
 	double		x,
 				y;
 
-	/*
-	 * NOTE: if the lines are identical then we will find they are parallel
-	 * and report "no intersection".  This is a little weird, but since
-	 * there's no *unique* intersection, maybe it's appropriate behavior.
-	 */
-	if (DatumGetBool(DirectFunctionCall2(line_parallel,
-										 LinePGetDatum(l1),
-										 LinePGetDatum(l2))))
-		return NULL;
-
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
+		if (FPzero(l2->B))		/* l2 vertical? */
+			return false;
+
 		x = l1->C;
 		y = (l2->A * x + l2->C);
 	}
-	else if (FPzero(l2->B))		/* l2 vertical? */
-	{
-		x = l2->C;
-		y = (l1->A * x + l1->C);
-	}
 	else
 	{
-		x = (l1->C - l2->C) / (l2->A - l1->A);
+		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+			return false;
+
+		if (FPzero(l2->B))
+			x = l2->C;
+		else
+			x = (l1->C - l2->C) / (l2->A - l1->A);
 		y = (l1->A * x + l1->C);
 	}
-	result = point_construct(x, y);
+	if (result != NULL)
+		point_construct(result, x, y);
 
 #ifdef GEODEBUG
 	printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
 		   DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
 	printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
 #endif
 
-	return result;
+	return true;
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D paths (sequences of line segments, also
  **				called `polylines').
  **
  **				This is not a general package for geometric paths,
  **				which of course include polygons; the emphasis here
@@ -1609,21 +1596,21 @@ path_inter(PG_FUNCTION_ARGS)
 				jprev = j - 1;
 			else
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
-			if (lseg_intersect_internal(&seg1, &seg2))
+			if (lseg_interpt_internal(NULL, &seg1, &seg2))
 				PG_RETURN_BOOL(true);
 		}
 	}
 
 	/* if we dropped through, no two segs intersected */
 	PG_RETURN_BOOL(false);
 }
 
 /* path_distance()
  * This essentially does a cartesian product of the lsegs in the
@@ -1664,23 +1651,21 @@ path_distance(PG_FUNCTION_ARGS)
 			else
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
-			tmp = DatumGetFloat8(DirectFunctionCall2(lseg_distance,
-													 LsegPGetDatum(&seg1),
-													 LsegPGetDatum(&seg2)));
+			tmp = lseg_dt(&seg1, &seg2);
 			if (!have_min || tmp < min)
 			{
 				min = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	if (!have_min)
 		PG_RETURN_NULL();
@@ -1774,44 +1759,31 @@ point_send(PG_FUNCTION_ARGS)
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	StringInfoData buf;
 
 	pq_begintypsend(&buf);
 	pq_sendfloat8(&buf, pt->x);
 	pq_sendfloat8(&buf, pt->y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
-static Point *
-point_construct(double x, double y)
+/*
+ * Initialize a point
+ *
+ * This function is over-simple, but it is, at least, useful when the new
+ * point is calculated using the existing one.
+ */
+static inline void
+point_construct(Point *result, float8 x, float8 y)
 {
-	Point	   *result = (Point *) palloc(sizeof(Point));
-
 	result->x = x;
 	result->y = y;
-	return result;
-}
-
-
-static Point *
-point_copy(Point *pt)
-{
-	Point	   *result;
-
-	if (!PointerIsValid(pt))
-		return NULL;
-
-	result = (Point *) palloc(sizeof(Point));
-
-	result->x = pt->x;
-	result->y = pt->y;
-	return result;
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for Points.
  *		Since we do have a sense of coordinates being
  *		"equal" to a given accuracy (point_vert, point_horiz),
  *		the other ops must preserve that sense.  This means
  *		that results may, strictly speaking, be a lie (unless
  *		EPSILON = 0.0).
@@ -1870,71 +1842,74 @@ point_horiz(PG_FUNCTION_ARGS)
 
 	PG_RETURN_BOOL(FPeq(pt1->y, pt2->y));
 }
 
 Datum
 point_eq(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y));
+	PG_RETURN_BOOL(point_eq_internal(pt1, pt2));
 }
 
 Datum
 point_ne(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPne(pt1->x, pt2->x) || FPne(pt1->y, pt2->y));
+	PG_RETURN_BOOL(!point_eq_internal(pt1, pt2));
 }
 
+static inline bool
+point_eq_internal(Point *pt1, Point *pt2)
+{
+	return FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y);
+}
+
+
 /*----------------------------------------------------------
  *	"Arithmetic" operators on points.
  *---------------------------------------------------------*/
 
 Datum
 point_distance(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_FLOAT8(HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
+	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
-double
+static float8
 point_dt(Point *pt1, Point *pt2)
 {
+	float8		result;
+
+	result = hypot(pt1->x - pt2->x, pt1->y - pt2->y);
+
 #ifdef GEODEBUG
 	printf("point_dt- segment (%f,%f),(%f,%f) length is %f\n",
-		   pt1->x, pt1->y, pt2->x, pt2->y, HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
+		   pt1->x, pt1->y, pt2->x, pt2->y, result);
 #endif
-	return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
+
+	return result;
 }
 
 Datum
 point_slope(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_FLOAT8(point_sl(pt1, pt2));
-}
-
-
-double
-point_sl(Point *pt1, Point *pt2)
-{
-	return (FPeq(pt1->x, pt2->x)
-			? (double) DBL_MAX
-			: (pt1->y - pt2->y) / (pt1->x - pt2->x));
+	PG_RETURN_FLOAT8(float8_slope(pt1->x, pt2->x, pt1->y, pt2->y));
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D line segments.
  **
  ***********************************************************************/
 
 /*----------------------------------------------------------
@@ -1946,31 +1921,31 @@ point_sl(Point *pt1, Point *pt2)
  *		(old form)		"(x1, y1, x2, y2)"
  *---------------------------------------------------------*/
 
 Datum
 lseg_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	LSEG	   *lseg = (LSEG *) palloc(sizeof(LSEG));
 	bool		isopen;
 
-	path_decode(str, true, 2, &(lseg->p[0]), &isopen, NULL, "lseg", str);
+	path_decode(str, true, 2, &lseg->p[0], &isopen, NULL, "lseg", str);
 	PG_RETURN_LSEG_P(lseg);
 }
 
 
 Datum
 lseg_out(PG_FUNCTION_ARGS)
 {
 	LSEG	   *ls = PG_GETARG_LSEG_P(0);
 
-	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, (Point *) &(ls->p[0])));
+	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, &ls->p[0]));
 }
 
 /*
  *		lseg_recv			- converts external binary format to lseg
  */
 Datum
 lseg_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LSEG	   *lseg;
@@ -2015,21 +1990,21 @@ lseg_construct(PG_FUNCTION_ARGS)
 
 	result->p[0].x = pt1->x;
 	result->p[0].y = pt1->y;
 	result->p[1].x = pt2->x;
 	result->p[1].y = pt2->y;
 
 	PG_RETURN_LSEG_P(result);
 }
 
 /* like lseg_construct, but assume space already allocated */
-static void
+static inline void
 statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2)
 {
 	lseg->p[0].x = pt1->x;
 	lseg->p[0].y = pt1->y;
 	lseg->p[1].x = pt2->x;
 	lseg->p[1].y = pt2->y;
 }
 
 Datum
 lseg_length(PG_FUNCTION_ARGS)
@@ -2046,69 +2021,57 @@ lseg_length(PG_FUNCTION_ARGS)
 /*
  **  find intersection of the two lines, and see if it falls on
  **  both segments.
  */
 Datum
 lseg_intersect(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(lseg_intersect_internal(l1, l2));
+	PG_RETURN_BOOL(lseg_interpt_internal(NULL, l1, l2));
 }
 
-static bool
-lseg_intersect_internal(LSEG *l1, LSEG *l2)
-{
-	LINE		ln;
-	Point	   *interpt;
-	bool		retval;
-
-	line_construct_pts(&ln, &l2->p[0], &l2->p[1]);
-	interpt = interpt_sl(l1, &ln);
-
-	if (interpt != NULL && on_ps_internal(interpt, l2))
-		retval = true;			/* interpt on l1 and l2 */
-	else
-		retval = false;
-	return retval;
-}
 
 Datum
 lseg_parallel(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
+	float8		m1,
+				m2;
 
-	PG_RETURN_BOOL(FPeq(point_sl(&l1->p[0], &l1->p[1]),
-						point_sl(&l2->p[0], &l2->p[1])));
+	m1 = float8_slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y);
+	m2 = float8_slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y);
+
+	PG_RETURN_BOOL(FPeq(m1, m2));
 }
 
 /* lseg_perp()
  * Determine if two line segments are perpendicular.
  *
  * This code did not get the correct answer for
  *	'((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg
  * So, modified it to check explicitly for slope of vertical line
- *	returned by point_sl() and the results seem better.
+ *	returned by float8_slope() and the results seem better.
  * - thomas 1998-01-31
  */
 Datum
 lseg_perp(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	double		m1,
 				m2;
 
-	m1 = point_sl(&(l1->p[0]), &(l1->p[1]));
-	m2 = point_sl(&(l2->p[0]), &(l2->p[1]));
+	m1 = float8_slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y);
+	m2 = float8_slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y);
 
 #ifdef GEODEBUG
 	printf("lseg_perp- slopes are %g and %g\n", m1, m2);
 #endif
 	if (FPzero(m1))
 		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
 	else if (FPzero(m2))
 		PG_RETURN_BOOL(FPeq(m1, DBL_MAX));
 
 	PG_RETURN_BOOL(FPeq(m1 / m2, -1.0));
@@ -2130,36 +2093,32 @@ lseg_horizontal(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(FPeq(lseg->p[0].y, lseg->p[1].y));
 }
 
 
 Datum
 lseg_eq(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPeq(l1->p[0].x, l2->p[0].x) &&
-				   FPeq(l1->p[0].y, l2->p[0].y) &&
-				   FPeq(l1->p[1].x, l2->p[1].x) &&
-				   FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(point_eq_internal(&l1->p[0], &l2->p[0]) &&
+				   point_eq_internal(&l1->p[1], &l2->p[1]));
 }
 
 Datum
 lseg_ne(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(!FPeq(l1->p[0].x, l2->p[0].x) ||
-				   !FPeq(l1->p[0].y, l2->p[0].y) ||
-				   !FPeq(l1->p[1].x, l2->p[1].x) ||
-				   !FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(!point_eq_internal(&l1->p[0], &l2->p[0]) ||
+				   !point_eq_internal(&l1->p[1], &l2->p[1]));
 }
 
 Datum
 lseg_lt(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_BOOL(FPlt(point_dt(&l1->p[0], &l1->p[1]),
 						point_dt(&l2->p[0], &l2->p[1])));
@@ -2218,21 +2177,21 @@ lseg_distance(PG_FUNCTION_ARGS)
  * Distance between two line segments.
  * Must check both sets of endpoints to ensure minimum distance is found.
  * - thomas 1998-02-01
  */
 static double
 lseg_dt(LSEG *l1, LSEG *l2)
 {
 	double		result,
 				d;
 
-	if (lseg_intersect_internal(l1, l2))
+	if (lseg_interpt_internal(NULL, l1, l2))
 		return 0.0;
 
 	d = dist_ps_internal(&l1->p[0], l2);
 	result = d;
 	d = dist_ps_internal(&l1->p[1], l2);
 	result = Min(result, d);
 	d = dist_ps_internal(&l2->p[0], l1);
 	result = Min(result, d);
 	d = dist_ps_internal(&l2->p[1], l1);
 	result = Min(result, d);
@@ -2248,82 +2207,86 @@ lseg_center(PG_FUNCTION_ARGS)
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
 	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
 
 	PG_RETURN_POINT_P(result);
 }
 
-static Point *
-lseg_interpt_internal(LSEG *l1, LSEG *l2)
+static bool
+lseg_interpt_internal(Point *result, LSEG *l1, LSEG *l2)
 {
-	Point	   *result;
+	Point		interpt;
 	LINE		tmp1,
 				tmp2;
 
 	/*
 	 * Find the intersection of the appropriate lines, if any.
 	 */
 	line_construct_pts(&tmp1, &l1->p[0], &l1->p[1]);
 	line_construct_pts(&tmp2, &l2->p[0], &l2->p[1]);
-	result = line_interpt_internal(&tmp1, &tmp2);
-	if (!PointerIsValid(result))
-		return NULL;
+	if (!line_interpt_internal(&interpt, &tmp1, &tmp2))
+		return false;
 
 	/*
 	 * If the line intersection point isn't within l1 (or equivalently l2),
 	 * there is no valid segment intersection point at all.
 	 */
-	if (!on_ps_internal(result, l1) ||
-		!on_ps_internal(result, l2))
-	{
-		pfree(result);
-		return NULL;
-	}
+	if (!on_ps_internal(&interpt, l1) ||
+		!on_ps_internal(&interpt, l2))
+		return false;
+
+	if (result == NULL)
+		return true;
 
 	/*
 	 * If there is an intersection, then check explicitly for matching
 	 * endpoints since there may be rounding effects with annoying lsb
 	 * residue. - tgl 1997-07-09
 	 */
 	if ((FPeq(l1->p[0].x, l2->p[0].x) && FPeq(l1->p[0].y, l2->p[0].y)) ||
 		(FPeq(l1->p[0].x, l2->p[1].x) && FPeq(l1->p[0].y, l2->p[1].y)))
 	{
 		result->x = l1->p[0].x;
 		result->y = l1->p[0].y;
 	}
 	else if ((FPeq(l1->p[1].x, l2->p[0].x) && FPeq(l1->p[1].y, l2->p[0].y)) ||
 			 (FPeq(l1->p[1].x, l2->p[1].x) && FPeq(l1->p[1].y, l2->p[1].y)))
 	{
 		result->x = l1->p[1].x;
 		result->y = l1->p[1].y;
 	}
+	else
+	{
+		result->x = interpt.x;
+		result->y = interpt.y;
+	}
 
-	return result;
+	return true;
 }
 
 /* lseg_interpt -
  *		Find the intersection point of two segments (if any).
  */
 Datum
 lseg_interpt(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
-	result = lseg_interpt_internal(l1, l2);
-	if (!PointerIsValid(result))
-		PG_RETURN_NULL();
+	result = (Point *) palloc(sizeof(Point));
 
+	if (!lseg_interpt_internal(result, l1, l2))
+		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
 
 /***********************************************************************
  **
  **		Routines for position comparisons of differently-typed
  **				2D objects.
  **
  ***********************************************************************/
 
@@ -2340,75 +2303,70 @@ dist_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
 	PG_RETURN_FLOAT8(dist_pl_internal(pt, line));
 }
 
 static double
 dist_pl_internal(Point *pt, LINE *line)
 {
-	return fabs((line->A * pt->x + line->B * pt->y + line->C) /
-				HYPOT(line->A, line->B));
+	return fabs(line_calculate_point(line, pt) /
+				hypot(line->A, line->B));
 }
 
 /*
  * Distance from a point to a lseg
  */
 Datum
 dist_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_FLOAT8(dist_ps_internal(pt, lseg));
 }
 
 static double
 dist_ps_internal(Point *pt, LSEG *lseg)
 {
 	double		m;				/* slope of perp. */
-	LINE	   *ln;
 	double		result,
 				tmpdist;
-	Point	   *ip;
+	Point		interpt;
+	LINE		ln;
 
 	/*
 	 * Construct a line perpendicular to the input segment and through the
 	 * input point
 	 */
-	if (lseg->p[1].x == lseg->p[0].x)
-		m = 0;
-	else if (lseg->p[1].y == lseg->p[0].y)
-		m = (double) DBL_MAX;	/* slope is infinite */
-	else
-		m = (lseg->p[0].x - lseg->p[1].x) / (lseg->p[1].y - lseg->p[0].y);
-	ln = line_construct_pm(pt, m);
+	m = float8_slope(lseg->p[0].y, lseg->p[1].y, lseg->p[1].x, lseg->p[0].x);
+	line_construct_pm(&ln, pt, m);
 
 #ifdef GEODEBUG
 	printf("dist_ps- line is A=%g B=%g C=%g from (point) slope (%f,%f) %g\n",
 		   ln->A, ln->B, ln->C, pt->x, pt->y, m);
 #endif
 
 	/*
 	 * Calculate distance to the line segment or to the nearest endpoint of
 	 * the segment.
 	 */
 
 	/* intersection is on the line segment? */
-	if ((ip = interpt_sl(lseg, ln)) != NULL)
+	if (lseg_interpt_line_internal(&interpt, lseg, &ln))
 	{
 		/* yes, so use distance to the intersection point */
-		result = point_dt(pt, ip);
+		result = point_dt(pt, &interpt);
 #ifdef GEODEBUG
 		printf("dist_ps- distance is %f to intersection point is (%f,%f)\n",
-			   result, ip->x, ip->y);
+			   result, tmp.x, tmp.y);
 #endif
 	}
 	else
 	{
 		/* no, so use distance to the nearer endpoint */
 		result = point_dt(pt, &lseg->p[0]);
 		tmpdist = point_dt(pt, &lseg->p[1]);
 		if (tmpdist < result)
 			result = tmpdist;
 	}
@@ -2496,21 +2454,21 @@ dist_pb(PG_FUNCTION_ARGS)
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	float8		result,
 				d2;
 
-	if (has_interpt_sl(lseg, line))
+	if (lseg_interpt_line_internal(NULL, lseg, line))
 		result = 0.0;
 	else
 	{
 		result = dist_pl_internal(&lseg->p[0], line);
 		d2 = dist_pl_internal(&lseg->p[1], line);
 		/* XXX shouldn't we take the min not max? */
 		if (d2 > result)
 			result = d2;
 	}
 
@@ -2649,284 +2607,261 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
  *				Intersection point of objects.
  *				We choose to ignore the "point" of intersection between
  *				  lines and boxes, since there are typically two.
  *-------------------------------------------------------------------*/
 
-/* Get intersection point of lseg and line; returns NULL if no intersection */
-static Point *
-interpt_sl(LSEG *lseg, LINE *line)
+/*
+ * Check if the line segment intersects with the line
+ *
+ * It sets the intersection point to *result, if it is not NULL.
+ */
+static bool
+lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line)
 {
+	Point		interpt;
 	LINE		tmp;
-	Point	   *p;
 
 	line_construct_pts(&tmp, &lseg->p[0], &lseg->p[1]);
-	p = line_interpt_internal(&tmp, line);
 #ifdef GEODEBUG
-	printf("interpt_sl- segment is (%.*g %.*g) (%.*g %.*g)\n",
+	printf("lseg_interpt_line- segment is (%.*g %.*g) (%.*g %.*g)\n",
 		   DBL_DIG, lseg->p[0].x, DBL_DIG, lseg->p[0].y, DBL_DIG, lseg->p[1].x, DBL_DIG, lseg->p[1].y);
-	printf("interpt_sl- segment becomes line A=%.*g B=%.*g C=%.*g\n",
+	printf("lseg_interpt_line_- segment becomes line A=%.*g B=%.*g C=%.*g\n",
 		   DBL_DIG, tmp.A, DBL_DIG, tmp.B, DBL_DIG, tmp.C);
 #endif
-	if (PointerIsValid(p))
+	if (line_interpt_internal(&interpt, &tmp, line))
 	{
 #ifdef GEODEBUG
-		printf("interpt_sl- intersection point is (%.*g %.*g)\n", DBL_DIG, p->x, DBL_DIG, p->y);
+		printf("lseg_interpt_line- intersection point is (%.*g %.*g)\n", DBL_DIG, p->x, DBL_DIG, p->y);
 #endif
-		if (on_ps_internal(p, lseg))
+		if (on_ps_internal(&interpt, lseg))
 		{
 #ifdef GEODEBUG
-			printf("interpt_sl- intersection point is on segment\n");
+			printf("lseg_interpt_line- intersection point is on segment\n");
 #endif
+			if (result != NULL)
+				*result = interpt;
+			return true;
 		}
-		else
-			p = NULL;
 	}
 
-	return p;
-}
-
-/* variant: just indicate if intersection point exists */
-static bool
-has_interpt_sl(LSEG *lseg, LINE *line)
-{
-	Point	   *tmp;
-
-	tmp = interpt_sl(lseg, line);
-	if (tmp)
-		return true;
 	return false;
 }
 
+
 /*---------------------------------------------------------------------
  *		close_
  *				Point of closest proximity between objects.
  *-------------------------------------------------------------------*/
 
 /* close_pl -
  *		The intersection point of a perpendicular of the line
  *		through the point.
  */
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
-	LINE	   *tmp;
 	double		invm;
+	LINE		tmp;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (FPzero(line->B))		/* vertical? */
 	{
 		result->x = line->C;
 		result->y = pt->y;
 		PG_RETURN_POINT_P(result);
 	}
 	if (FPzero(line->A))		/* horizontal? */
 	{
 		result->x = pt->x;
 		result->y = line->C;
 		PG_RETURN_POINT_P(result);
 	}
 	/* drop a perpendicular and find the intersection point */
 
 	/* invert and flip the sign on the slope to get a perpendicular */
 	invm = line->B / line->A;
-	tmp = line_construct_pm(pt, invm);
-	result = line_interpt_internal(tmp, line);
-	Assert(result != NULL);
+	line_construct_pm(&tmp, pt, invm);
+	line_interpt_internal(result, &tmp, line);
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_ps()
  * Closest point on line segment to specified point.
  * Take the closest endpoint if the point is left, right,
  *	above, or below the segment, otherwise find the intersection
  *	point of the segment and its perpendicular through the point.
  *
  * Some tricky code here, relying on boolean expressions
  *	evaluating to only zero or one to use as an array index.
  *		bug fixes by gthaker@atl.lmco.com; May 1, 1998
  */
 Datum
 close_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
-	LINE	   *tmp;
+	Point	   *result;
 	double		invm;
 	int			xh,
 				yh;
+	LINE		tmp;
+
+	result = (Point *) palloc(sizeof(Point));
 
 #ifdef GEODEBUG
 	printf("close_sp:pt->x %f pt->y %f\nlseg(0).x %f lseg(0).y %f  lseg(1).x %f lseg(1).y %f\n",
 		   pt->x, pt->y, lseg->p[0].x, lseg->p[0].y,
 		   lseg->p[1].x, lseg->p[1].y);
 #endif
 
 	/* xh (or yh) is the index of upper x( or y) end point of lseg */
 	/* !xh (or !yh) is the index of lower x( or y) end point of lseg */
 	xh = lseg->p[0].x < lseg->p[1].x;
 	yh = lseg->p[0].y < lseg->p[1].y;
 
 	if (FPeq(lseg->p[0].x, lseg->p[1].x))	/* vertical? */
 	{
 #ifdef GEODEBUG
 		printf("close_ps- segment is vertical\n");
 #endif
 		/* first check if point is below or above the entire lseg. */
 		if (pt->y < lseg->p[!yh].y)
-			result = point_copy(&lseg->p[!yh]); /* below the lseg */
+			*result = lseg->p[!yh]; /* below the lseg */
 		else if (pt->y > lseg->p[yh].y)
-			result = point_copy(&lseg->p[yh]);	/* above the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
+			*result = lseg->p[yh];	/* above the lseg */
+		else
+			/* point lines along (to left or right) of the vertical lseg. */
+			point_construct(result, lseg->p[0].x, pt->y);
 
-		/* point lines along (to left or right) of the vertical lseg. */
-
-		result = (Point *) palloc(sizeof(Point));
-		result->x = lseg->p[0].x;
-		result->y = pt->y;
 		PG_RETURN_POINT_P(result);
 	}
 	else if (FPeq(lseg->p[0].y, lseg->p[1].y))	/* horizontal? */
 	{
 #ifdef GEODEBUG
 		printf("close_ps- segment is horizontal\n");
 #endif
 		/* first check if point is left or right of the entire lseg. */
 		if (pt->x < lseg->p[!xh].x)
-			result = point_copy(&lseg->p[!xh]); /* left of the lseg */
+			*result = lseg->p[!xh]; /* left of the lseg */
 		else if (pt->x > lseg->p[xh].x)
-			result = point_copy(&lseg->p[xh]);	/* right of the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
+			*result = lseg->p[xh];	/* right of the lseg */
+		else
+			/* point lines along (at top or below) the horiz. lseg. */
+			point_construct(result, pt->x, lseg->p[0].y);
 
-		/* point lines along (at top or below) the horiz. lseg. */
-		result = (Point *) palloc(sizeof(Point));
-		result->x = pt->x;
-		result->y = lseg->p[0].y;
 		PG_RETURN_POINT_P(result);
 	}
 
 	/*
 	 * vert. and horiz. cases are down, now check if the closest point is one
 	 * of the end points or someplace on the lseg.
 	 */
 
-	invm = -1.0 / point_sl(&(lseg->p[0]), &(lseg->p[1]));
-	tmp = line_construct_pm(&lseg->p[!yh], invm);	/* lower edge of the
+	invm = float8_slope(lseg->p[0].y, lseg->p[1].y, lseg->p[1].x, lseg->p[0].x);
+	line_construct_pm(&tmp, &lseg->p[!yh], invm);	/* lower edge of the
 													 * "band" */
-	if (pt->y < (tmp->A * pt->x + tmp->C))
+	if (pt->y < (tmp.A * pt->x + tmp.C))
 	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[!yh]); /* below the lseg, take lower end
-											 * pt */
+		*result = lseg->p[!yh]; /* below the lseg, take lower end pt */
 #ifdef GEODEBUG
 		printf("close_ps below: tmp A %f  B %f   C %f\n",
 			   tmp->A, tmp->B, tmp->C);
 #endif
 		PG_RETURN_POINT_P(result);
 	}
-	tmp = line_construct_pm(&lseg->p[yh], invm);	/* upper edge of the
+	line_construct_pm(&tmp, &lseg->p[yh], invm);	/* upper edge of the
 													 * "band" */
-	if (pt->y > (tmp->A * pt->x + tmp->C))
+	if (pt->y > (tmp.A * pt->x + tmp.C))
 	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[yh]);	/* above the lseg, take higher end
-											 * pt */
+		*result = lseg->p[yh];	/* above the lseg, take higher end pt */
 #ifdef GEODEBUG
 		printf("close_ps above: tmp A %f  B %f   C %f\n",
 			   tmp->A, tmp->B, tmp->C);
 #endif
 		PG_RETURN_POINT_P(result);
 	}
 
 	/*
 	 * at this point the "normal" from point will hit lseg. The closest point
 	 * will be somewhere on the lseg
 	 */
-	tmp = line_construct_pm(pt, invm);
+	line_construct_pm(&tmp, pt, invm);
 #ifdef GEODEBUG
 	printf("close_ps- tmp A %f  B %f   C %f\n",
 		   tmp->A, tmp->B, tmp->C);
 #endif
-	result = interpt_sl(lseg, tmp);
 
 	/*
 	 * ordinarily we should always find an intersection point, but that could
 	 * fail in the presence of NaN coordinates, and perhaps even from simple
 	 * roundoff issues.  Return a SQL NULL if so.
 	 */
-	if (result == NULL)
+	if (!lseg_interpt_line_internal(result, lseg, &tmp))
 		PG_RETURN_NULL();
 
 #ifdef GEODEBUG
 	printf("close_ps- result.x %f  result.y %f\n", result->x, result->y);
 #endif
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_lseg()
  * Closest point to l1 on l2.
  */
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
-	Point		point;
-	double		dist;
-	double		d;
+	Point	   *result;
+	double		dist,
+				dist0,
+				dist1;
 
-	d = dist_ps_internal(&l1->p[0], l2);
-	dist = d;
-	memcpy(&point, &l1->p[0], sizeof(Point));
-
-	if ((d = dist_ps_internal(&l1->p[1], l2)) < dist)
-	{
-		dist = d;
-		memcpy(&point, &l1->p[1], sizeof(Point));
-	}
+	dist0 = dist_ps_internal(&l1->p[0], l2);
+	dist1 = dist_ps_internal(&l1->p[1], l2);
+	dist = Min(dist0, dist1);
 
 	if (dist_ps_internal(&l2->p[0], l1) < dist)
 	{
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(&l2->p[0]),
 													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
+													PointPGetDatum(result),
 													LsegPGetDatum(l2)));
 	}
-
-	if (dist_ps_internal(&l2->p[1], l1) < dist)
+	else if (dist_ps_internal(&l2->p[1], l1) < dist)
 	{
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(&l2->p[1]),
 													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
+													PointPGetDatum(result),
 													LsegPGetDatum(l2)));
 	}
-
-	if (result == NULL)
-		result = point_copy(&point);
+	else
+	{
+		result = (Point *) palloc(sizeof(Point));
+		*result = l1->p[dist == dist0 ? 0 : 1];
+	}
 
 	PG_RETURN_POINT_P(result);
 }
 
 /* close_pb()
  * Closest point on or in box to specified point.
  */
 Datum
 close_pb(PG_FUNCTION_ARGS)
 {
@@ -2989,30 +2924,31 @@ close_pb(PG_FUNCTION_ARGS)
 Datum
 close_sl(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 	float8		d1,
 				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
+	result = (Point *) palloc(sizeof(Point));
+
+	if (lseg_interpt_line_internal(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = dist_pl_internal(&lseg->p[0], line);
 	d2 = dist_pl_internal(&lseg->p[1], line);
 	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
+		*result = lseg->p[0];
 	else
-		result = point_copy(&lseg->p[1]);
+		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
 
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_sl\" not implemented")));
 
 	PG_RETURN_NULL();
 }
@@ -3022,30 +2958,31 @@ close_sl(PG_FUNCTION_ARGS)
  */
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 	float8		d1,
 				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
+	result = (Point *) palloc(sizeof(Point));
+
+	if (lseg_interpt_line_internal(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = dist_pl_internal(&lseg->p[0], line);
 	d2 = dist_pl_internal(&lseg->p[1], line);
 	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
+		*result = lseg->p[0];
 	else
-		result = point_copy(&lseg->p[1]);
+		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 }
 
 /* close_sb()
  * Closest point on or in box to line segment.
  */
 Datum
 close_sb(PG_FUNCTION_ARGS)
 {
@@ -3126,21 +3063,21 @@ close_lb(PG_FUNCTION_ARGS)
 
 /* on_pl -
  *		Does the point satisfy the equation?
  */
 Datum
 on_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(FPzero(line->A * pt->x + line->B * pt->y + line->C));
+	PG_RETURN_BOOL(FPzero(line_calculate_point(line, pt)));
 }
 
 
 /* on_ps -
  *		Determine colinearity by detecting a triangle inequality.
  * This algorithm seems to behave nicely even with lsb residues - tgl 1997-07-09
  */
 Datum
 on_ps(PG_FUNCTION_ARGS)
 {
@@ -3150,40 +3087,49 @@ on_ps(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(on_ps_internal(pt, lseg));
 }
 
 static bool
 on_ps_internal(Point *pt, LSEG *lseg)
 {
 	return FPeq(point_dt(pt, &lseg->p[0]) + point_dt(pt, &lseg->p[1]),
 				point_dt(&lseg->p[0], &lseg->p[1]));
 }
 
+
+/*
+ * Check whether the point is in the box or on its border
+ */
 Datum
 on_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_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);
 }
 
+
+/*
+ * Commutator of on_pb()
+ */
 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.
  * (uses same algorithm as for point intersecting segment - tgl 1997-07-09)
  *		If closed, we use the old O(n) ray method for point-in-polygon.
  *				The ray is horizontal, from pt out to the right.
  *				Each segment that crosses the ray counts as an
  *				intersection; note that an endpoint or edge may touch
  *				but not cross.
  *				(we can do p-in-p in lg(n), but it takes preprocessing)
@@ -3211,34 +3157,46 @@ on_ppath(PG_FUNCTION_ARGS)
 				PG_RETURN_BOOL(true);
 			a = b;
 		}
 		PG_RETURN_BOOL(false);
 	}
 
 	/*-- CLOSED --*/
 	PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
 }
 
+
+/*
+ * Check whether the line segment is on the line or close enough
+ *
+ * It is, if both of its points are on the line or close enough.
+ */
 Datum
 on_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
 	PG_RETURN_BOOL(DatumGetBool(DirectFunctionCall2(on_pl,
 													PointPGetDatum(&lseg->p[0]),
 													LinePGetDatum(line))) &&
 				   DatumGetBool(DirectFunctionCall2(on_pl,
 													PointPGetDatum(&lseg->p[1]),
 													LinePGetDatum(line))));
 }
 
+
+/*
+ * Check whether the line segment is in the box or on its border
+ *
+ * It is, if both of its points are in the box or on its border.
+ */
 Datum
 on_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 
 	PG_RETURN_BOOL(DatumGetBool(DirectFunctionCall2(on_pb,
 													PointPGetDatum(&lseg->p[0]),
 													BoxPGetDatum(box))) &&
 				   DatumGetBool(DirectFunctionCall2(on_pb,
@@ -3250,21 +3208,21 @@ on_sb(PG_FUNCTION_ARGS)
  *		inter_
  *				Whether one object intersects another.
  *-------------------------------------------------------------------*/
 
 Datum
 inter_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(has_interpt_sl(lseg, line));
+	PG_RETURN_BOOL(lseg_interpt_line_internal(NULL, lseg, line));
 }
 
 /* inter_sb()
  * Do line segment and box intersect?
  *
  * Segment completely inside box counts as intersection.
  * If you want only segments crossing box boundaries,
  *	try converting box to path first.
  *
  * Optimize for non-intersection by checking for box intersection first.
@@ -3294,35 +3252,35 @@ inter_sb(PG_FUNCTION_ARGS)
 										 BoxPGetDatum(box))) ||
 		DatumGetBool(DirectFunctionCall2(on_pb,
 										 PointPGetDatum(&lseg->p[1]),
 										 BoxPGetDatum(box))))
 		PG_RETURN_BOOL(true);
 
 	/* pairwise check lseg intersections */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
+	if (lseg_interpt_internal(NULL, &bseg, lseg))
 		PG_RETURN_BOOL(true);
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
+	if (lseg_interpt_internal(NULL, &bseg, lseg))
 		PG_RETURN_BOOL(true);
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
+	if (lseg_interpt_internal(NULL, &bseg, lseg))
 		PG_RETURN_BOOL(true);
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
+	if (lseg_interpt_internal(NULL, &bseg, lseg))
 		PG_RETURN_BOOL(true);
 
 	/* if we dropped through, no two segs intersected */
 	PG_RETURN_BOOL(false);
 }
 
 /* inter_lb()
  * Do line and box intersect?
  */
 Datum
@@ -3333,36 +3291,36 @@ inter_lb(PG_FUNCTION_ARGS)
 	LSEG		bseg;
 	Point		p1,
 				p2;
 
 	/* pairwise check lseg intersections */
 	p1.x = box->low.x;
 	p1.y = box->low.y;
 	p2.x = box->low.x;
 	p2.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line_internal(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->high.x;
 	p1.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line_internal(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p2.x = box->high.x;
 	p2.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line_internal(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->low.x;
 	p1.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line_internal(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 
 	/* if we dropped through, no intersection */
 	PG_RETURN_BOOL(false);
 }
 
 /*------------------------------------------------------------------
  * The following routines define a data type and operator class for
  * POLYGONS .... Part of which (the polygon's bounding box) is built on
  * top of the BOX data type.
@@ -3370,42 +3328,37 @@ inter_lb(PG_FUNCTION_ARGS)
  * make_bound_box - create the bounding box for the input polygon
  *------------------------------------------------------------------*/
 
 /*---------------------------------------------------------------------
  * Make the smallest bounding box for the given polygon.
  *---------------------------------------------------------------------*/
 static void
 make_bound_box(POLYGON *poly)
 {
 	int			i;
-	double		x1,
-				y1,
-				x2,
-				y2;
+	BOX		   *boundbox = &poly->boundbox;
 
 	if (poly->npts > 0)
 	{
-		x2 = x1 = poly->p[0].x;
-		y2 = y1 = poly->p[0].y;
+		boundbox->low.x = boundbox->high.x = poly->p[0].x;
+		boundbox->low.y = boundbox->high.y = poly->p[0].y;
 		for (i = 1; i < poly->npts; i++)
 		{
-			if (poly->p[i].x < x1)
-				x1 = poly->p[i].x;
-			if (poly->p[i].x > x2)
-				x2 = poly->p[i].x;
-			if (poly->p[i].y < y1)
-				y1 = poly->p[i].y;
-			if (poly->p[i].y > y2)
-				y2 = poly->p[i].y;
+			if (poly->p[i].x < boundbox->low.x)
+				boundbox->low.x = poly->p[i].x;
+			if (poly->p[i].x > boundbox->high.x)
+				boundbox->high.x = poly->p[i].x;
+			if (poly->p[i].y < boundbox->low.y)
+				boundbox->low.y = poly->p[i].y;
+			if (poly->p[i].y > boundbox->high.y)
+				boundbox->high.y = poly->p[i].y;
 		}
-
-		box_fill(&(poly->boundbox), x1, x2, y1, y2);
 	}
 	else
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("cannot create bounding box for empty polygon")));
 }
 
 /*------------------------------------------------------------------
  * poly_in - read in the polygon from a string specification
  *
@@ -3742,21 +3695,21 @@ poly_same(PG_FUNCTION_ARGS)
  *-----------------------------------------------------------------*/
 Datum
 poly_overlap(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
 	/* Quick check by bounding box */
 	result = (polya->npts > 0 && polyb->npts > 0 &&
-			  box_ov(&polya->boundbox, &polyb->boundbox)) ? true : false;
+			  box_ov(&polya->boundbox, &polyb->boundbox));
 
 	/*
 	 * Brute-force algorithm - try to find intersected edges, if so then
 	 * polygons are overlapped else check is one polygon inside other or not
 	 * by testing single point of them.
 	 */
 	if (result)
 	{
 		int			ia,
 					ib;
@@ -3771,34 +3724,33 @@ poly_overlap(PG_FUNCTION_ARGS)
 		{
 			/* Second point of polya's edge is a current one */
 			sa.p[1] = polya->p[ia];
 
 			/* Init first of polyb's edge with last point */
 			sb.p[0] = polyb->p[polyb->npts - 1];
 
 			for (ib = 0; ib < polyb->npts && result == false; ib++)
 			{
 				sb.p[1] = polyb->p[ib];
-				result = lseg_intersect_internal(&sa, &sb);
+				result = lseg_interpt_internal(NULL, &sa, &sb);
 				sb.p[0] = sb.p[1];
 			}
 
 			/*
 			 * move current endpoint to the first point of next edge
 			 */
 			sa.p[0] = sa.p[1];
 		}
 
 		if (result == false)
 		{
-			result = (point_inside(polya->p, polyb->npts, polyb->p)
-					  ||
+			result = (point_inside(polya->p, polyb->npts, polyb->p) ||
 					  point_inside(polyb->p, polya->npts, polya->p));
 		}
 	}
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
@@ -3818,27 +3770,26 @@ poly_overlap(PG_FUNCTION_ARGS)
 
 static bool
 touched_lseg_inside_poly(Point *a, Point *b, LSEG *s, POLYGON *poly, int start)
 {
 	/* point a is on s, b is not */
 	LSEG		t;
 
 	t.p[0] = *a;
 	t.p[1] = *b;
 
-#define POINTEQ(pt1, pt2)	(FPeq((pt1)->x, (pt2)->x) && FPeq((pt1)->y, (pt2)->y))
-	if (POINTEQ(a, s->p))
+	if (point_eq_internal(a, s->p))
 	{
 		if (on_ps_internal(s->p + 1, &t))
 			return lseg_inside_poly(b, s->p + 1, poly, start);
 	}
-	else if (POINTEQ(a, s->p + 1))
+	else if (point_eq_internal(a, s->p + 1))
 	{
 		if (on_ps_internal(s->p, &t))
 			return lseg_inside_poly(b, s->p, poly, start);
 	}
 	else if (on_ps_internal(s->p, &t))
 	{
 		return lseg_inside_poly(b, s->p, poly, start);
 	}
 	else if (on_ps_internal(s->p + 1, &t))
 	{
@@ -3861,50 +3812,49 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 	int			i;
 	bool		res = true,
 				intersection = false;
 
 	t.p[0] = *a;
 	t.p[1] = *b;
 	s.p[0] = poly->p[(start == 0) ? (poly->npts - 1) : (start - 1)];
 
 	for (i = start; i < poly->npts && res; i++)
 	{
-		Point	   *interpt;
+		Point		interpt;
 
 		CHECK_FOR_INTERRUPTS();
 
 		s.p[1] = poly->p[i];
 
 		if (on_ps_internal(t.p, &s))
 		{
 			if (on_ps_internal(t.p + 1, &s))
 				return true;	/* t is contained by s */
 
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p, t.p + 1, &s, poly, i + 1);
 		}
 		else if (on_ps_internal(t.p + 1, &s))
 		{
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p + 1, t.p, &s, poly, i + 1);
 		}
-		else if ((interpt = lseg_interpt_internal(&t, &s)) != NULL)
+		else if (lseg_interpt_internal(&interpt, &t, &s))
 		{
 			/*
 			 * segments are X-crossing, go to check each subsegment
 			 */
 
 			intersection = true;
-			res = lseg_inside_poly(t.p, interpt, poly, i + 1);
+			res = lseg_inside_poly(t.p, &interpt, poly, i + 1);
 			if (res)
-				res = lseg_inside_poly(t.p + 1, interpt, poly, i + 1);
-			pfree(interpt);
+				res = lseg_inside_poly(t.p + 1, &interpt, poly, i + 1);
 		}
 
 		s.p[0] = s.p[1];
 	}
 
 	if (res && !intersection)
 	{
 		Point		p;
 
 		/*
@@ -4019,170 +3969,208 @@ poly_distance(PG_FUNCTION_ARGS)
  **
  **		Routines for 2D points.
  **
  ***********************************************************************/
 
 Datum
 construct_point(PG_FUNCTION_ARGS)
 {
 	float8		x = PG_GETARG_FLOAT8(0);
 	float8		y = PG_GETARG_FLOAT8(1);
+	Point	   *result;
 
-	PG_RETURN_POINT_P(point_construct(x, y));
+	result = (Point *) palloc(sizeof(Point));
+
+	point_construct(result, x, y);
+
+	PG_RETURN_POINT_P(result);
 }
 
 Datum
 point_add(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x + p2->x);
-	result->y = (p1->y + p2->y);
+	point_add_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+static inline void
+point_add_internal(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x + pt2->x,
+					pt1->y + pt2->y);
+}
+
+
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x - p2->x);
-	result->y = (p1->y - p2->y);
+	point_sub_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+static inline void
+point_sub_internal(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x - pt2->x,
+					pt1->y - pt2->y);
+}
+
+
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x * p2->x) - (p1->y * p2->y);
-	result->y = (p1->x * p2->y) + (p1->y * p2->x);
+	point_mul_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+static inline void
+point_mul_internal(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					(pt1->x * pt2->x) - (pt1->y * pt2->y),
+					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+}
+
+
 Datum
 point_div(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
-	double		div;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	div = (p2->x * p2->x) + (p2->y * p2->y);
-
-	if (div == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result->x = ((p1->x * p2->x) + (p1->y * p2->y)) / div;
-	result->y = ((p2->x * p1->y) - (p2->y * p1->x)) / div;
+	point_div_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+static inline void
+point_div_internal(Point *result, Point *pt1, Point *pt2)
+{
+	float8		div;
+
+	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
+	point_construct(result,
+					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
+					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+}
+
 
 /***********************************************************************
  **
  **		Routines for 2D boxes.
  **
  ***********************************************************************/
 
 Datum
 points_box(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct(p1->x, p2->x, p1->y, p2->y));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	box_construct(result, p1, p2);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_add(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct((box->high.x + p->x),
-								  (box->low.x + p->x),
-								  (box->high.y + p->y),
-								  (box->low.y + p->y)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_add_internal(&result->high, &box->high, p);
+	point_add_internal(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_sub(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct((box->high.x - p->x),
-								  (box->low.x - p->x),
-								  (box->high.y - p->y),
-								  (box->low.y - p->y)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_sub_internal(&result->high, &box->high, p);
+	point_sub_internal(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_mul(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
 
-	high = DatumGetPointP(DirectFunctionCall2(point_mul,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_mul,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	result = (BOX *) palloc(sizeof(BOX));
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	point_mul_internal(&high, &box->high, p);
+	point_mul_internal(&low, &box->low, p);
+
+	box_construct(result, &high, &low);
 
 	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_div(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
 
-	high = DatumGetPointP(DirectFunctionCall2(point_div,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_div,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	result = (BOX *) palloc(sizeof(BOX));
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	point_div_internal(&high, &box->high, p);
+	point_div_internal(&low, &box->low, p);
+
+	box_construct(result, &high, &low);
 
 	PG_RETURN_BOX_P(result);
 }
 
 /*
  * Convert point to empty box
  */
 Datum
 point_box(PG_FUNCTION_ARGS)
 {
@@ -4278,83 +4266,63 @@ path_add(PG_FUNCTION_ARGS)
  * Translation operators.
  */
 Datum
 path_add_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x += point->x;
-		path->p[i].y += point->y;
-	}
+		point_add_internal(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_sub_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x -= point->x;
-		path->p[i].y -= point->y;
-	}
+		point_sub_internal(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 /* path_mul_pt()
  * Rotation and scaling operators.
  */
 Datum
 path_mul_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_mul,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_mul_internal(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_div_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_div,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_div_internal(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 
 Datum
 path_center(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	PATH	   *path = PG_GETARG_PATH_P(0);
@@ -4436,21 +4404,22 @@ poly_center(PG_FUNCTION_ARGS)
 
 Datum
 poly_box(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	BOX		   *box;
 
 	if (poly->npts < 1)
 		PG_RETURN_NULL();
 
-	box = box_copy(&poly->boundbox);
+	box = (BOX *) palloc(sizeof(BOX));
+	*box = poly->boundbox;
 
 	PG_RETURN_BOX_P(box);
 }
 
 
 /* box_poly()
  * Convert a box to a polygon.
  */
 Datum
 box_poly(PG_FUNCTION_ARGS)
@@ -4468,22 +4437,21 @@ box_poly(PG_FUNCTION_ARGS)
 
 	poly->p[0].x = box->low.x;
 	poly->p[0].y = box->low.y;
 	poly->p[1].x = box->low.x;
 	poly->p[1].y = box->high.y;
 	poly->p[2].x = box->high.x;
 	poly->p[2].y = box->high.y;
 	poly->p[3].x = box->high.x;
 	poly->p[3].y = box->low.y;
 
-	box_fill(&poly->boundbox, box->high.x, box->low.x,
-			 box->high.y, box->low.y);
+	box_construct(&poly->boundbox, &box->high, &box->low);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
 
 Datum
 poly_path(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	PATH	   *path;
@@ -4492,21 +4460,21 @@ poly_path(PG_FUNCTION_ARGS)
 
 	/*
 	 * Never overflows: the old size fit in MaxAllocSize, and the new size is
 	 * smaller by a small constant.
 	 */
 	size = offsetof(PATH, p) + sizeof(path->p[0]) * poly->npts;
 	path = (PATH *) palloc(size);
 
 	SET_VARSIZE(path, size);
 	path->npts = poly->npts;
-	path->closed = TRUE;
+	path->closed = true;
 	/* prevent instability in unused pad bytes */
 	path->dummy = 0;
 
 	for (i = 0; i < poly->npts; i++)
 	{
 		path->p[i].x = poly->p[i].x;
 		path->p[i].y = poly->p[i].y;
 	}
 
 	PG_RETURN_PATH_P(path);
@@ -4558,22 +4526,21 @@ circle_in(PG_FUNCTION_ARGS)
 
 	circle->radius = single_decode(s, &s, "circle", str);
 	if (circle->radius < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
 
 	while (depth > 0)
 	{
-		if ((*s == RDELIM)
-			|| ((*s == RDELIM_C) && (depth == 1)))
+		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
 			s++;
 			while (isspace((unsigned char) *s))
 				s++;
 		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
@@ -4657,22 +4624,21 @@ circle_send(PG_FUNCTION_ARGS)
 
 /*		circles identical?
  */
 Datum
 circle_same(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPeq(circle1->radius, circle2->radius) &&
-				   FPeq(circle1->center.x, circle2->center.x) &&
-				   FPeq(circle1->center.y, circle2->center.y));
+				   point_eq_internal(&circle1->center, &circle2->center));
 }
 
 /*		circle_overlap	-		does circle1 overlap circle2?
  */
 Datum
 circle_overlap(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
@@ -4859,107 +4825,83 @@ circle_ge(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPge(circle_ar(circle1), circle_ar(circle2)));
 }
 
 
 /*----------------------------------------------------------
  *	"Arithmetic" operators on circles.
  *---------------------------------------------------------*/
 
-static CIRCLE *
-circle_copy(CIRCLE *circle)
-{
-	CIRCLE	   *result;
-
-	if (!PointerIsValid(circle))
-		return NULL;
-
-	result = (CIRCLE *) palloc(sizeof(CIRCLE));
-	memcpy((char *) result, (char *) circle, sizeof(CIRCLE));
-	return result;
-}
-
-
 /* circle_add_pt()
  * Translation operator.
  */
 Datum
 circle_add_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x += point->x;
-	result->center.y += point->y;
+	point_add_internal(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_sub_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x -= point->x;
-	result->center.y -= point->y;
+	point_sub_internal(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /* circle_mul_pt()
  * Rotation and scaling operators.
  */
 Datum
 circle_mul_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_mul,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
-	result->radius *= HYPOT(point->x, point->y);
+	point_mul_internal(&result->center, &circle->center, point);
+	result->radius *= hypot(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_div_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_div,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
-	result->radius /= HYPOT(point->x, point->y);
+	point_div_internal(&result->center, &circle->center, point);
+	result->radius /= hypot(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /*		circle_area		-		returns the area of the circle.
  */
 Datum
 circle_area(PG_FUNCTION_ARGS)
 {
@@ -4994,22 +4936,22 @@ circle_radius(PG_FUNCTION_ARGS)
 /*		circle_distance -		returns the distance between
  *								  two circles.
  */
 Datum
 circle_distance(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(&circle1->center, &circle2->center)
-		- (circle1->radius + circle2->radius);
+	result = point_dt(&circle1->center, &circle2->center) -
+		(circle1->radius + circle2->radius);
 	if (result < 0)
 		result = 0;
 	PG_RETURN_FLOAT8(result);
 }
 
 
 Datum
 circle_contain_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
@@ -5372,118 +5314,55 @@ lseg_crossing(double x, double y, double prev_x, double prev_y)
 static bool
 plist_same(int npts, Point *p1, Point *p2)
 {
 	int			i,
 				ii,
 				j;
 
 	/* find match for first point */
 	for (i = 0; i < npts; i++)
 	{
-		if ((FPeq(p2[i].x, p1[0].x))
-			&& (FPeq(p2[i].y, p1[0].y)))
+		if (point_eq_internal(&p2[i], &p1[0]))
 		{
 
 			/* match found? then look forward through remaining points */
 			for (ii = 1, j = i + 1; ii < npts; ii++, j++)
 			{
 				if (j >= npts)
 					j = 0;
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_internal(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed forward match with %d\n", j, ii);
 #endif
 					break;
 				}
 			}
 #ifdef GEODEBUG
 			printf("plist_same- ii = %d/%d after forward match\n", ii, npts);
 #endif
 			if (ii == npts)
-				return TRUE;
+				return true;
 
 			/* match not found forwards? then look backwards */
 			for (ii = 1, j = i - 1; ii < npts; ii++, j--)
 			{
 				if (j < 0)
 					j = (npts - 1);
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_internal(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed reverse match with %d\n", j, ii);
 #endif
 					break;
 				}
 			}
 #ifdef GEODEBUG
 			printf("plist_same- ii = %d/%d after reverse match\n", ii, npts);
 #endif
 			if (ii == npts)
-				return TRUE;
+				return true;
 		}
 	}
 
-	return FALSE;
-}
-
-
-/*-------------------------------------------------------------------------
- * Determine the hypotenuse.
- *
- * If required, x and y are swapped to make x the larger number. The
- * traditional formula of x^2+y^2 is rearranged to factor x outside the
- * sqrt. This allows computation of the hypotenuse for significantly
- * larger values, and with a higher precision than when using the naive
- * formula.  In particular, this cannot overflow unless the final result
- * would be out-of-range.
- *
- * sqrt( x^2 + y^2 ) = sqrt( x^2( 1 + y^2/x^2) )
- *					 = x * sqrt( 1 + y^2/x^2 )
- *					 = x * sqrt( 1 + y/x * y/x )
- *
- * It is expected that this routine will eventually be replaced with the
- * C99 hypot() function.
- *
- * This implementation conforms to IEEE Std 1003.1 and GLIBC, in that the
- * case of hypot(inf,nan) results in INF, and not NAN.
- *-----------------------------------------------------------------------
- */
-double
-pg_hypot(double x, double y)
-{
-	double		yx;
-
-	/* Handle INF and NaN properly */
-	if (isinf(x) || isinf(y))
-		return get_float8_infinity();
-
-	if (isnan(x) || isnan(y))
-		return get_float8_nan();
-
-	/* Else, drop any minus signs */
-	x = fabs(x);
-	y = fabs(y);
-
-	/* Swap x and y if needed to make x the larger one */
-	if (x < y)
-	{
-		double		temp = x;
-
-		x = y;
-		y = temp;
-	}
-
-	/*
-	 * If y is zero, the hypotenuse is x.  This test saves a few cycles in
-	 * such cases, but more importantly it also protects against
-	 * divide-by-zero errors, since now x >= y.
-	 */
-	if (y == 0.0)
-		return x;
-
-	/* Determine the hypotenuse */
-	yx = y / x;
-	return x * sqrt(1.0 + (yx * yx));
+	return false;
 }
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 44c6381b85..c94e17af5f 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -43,21 +43,20 @@
 #else
 #define FPzero(A)				((A) == 0)
 #define FPeq(A,B)				((A) == (B))
 #define FPne(A,B)				((A) != (B))
 #define FPlt(A,B)				((A) < (B))
 #define FPle(A,B)				((A) <= (B))
 #define FPgt(A,B)				((A) > (B))
 #define FPge(A,B)				((A) >= (B))
 #endif
 
-#define HYPOT(A, B)				pg_hypot(A, B)
 
 /*---------------------------------------------------------------------
  * Point - (x,y)
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	double		x,
 				y;
 } Point;
 
@@ -166,21 +165,11 @@ typedef struct
 #define PolygonPGetDatum(X)			PointerGetDatum(X)
 #define PG_GETARG_POLYGON_P(n)		DatumGetPolygonP(PG_GETARG_DATUM(n))
 #define PG_GETARG_POLYGON_P_COPY(n) DatumGetPolygonPCopy(PG_GETARG_DATUM(n))
 #define PG_RETURN_POLYGON_P(x)		return PolygonPGetDatum(x)
 
 #define DatumGetCircleP(X)	  ((CIRCLE *) DatumGetPointer(X))
 #define CirclePGetDatum(X)	  PointerGetDatum(X)
 #define PG_GETARG_CIRCLE_P(n) DatumGetCircleP(PG_GETARG_DATUM(n))
 #define PG_RETURN_CIRCLE_P(x) return CirclePGetDatum(x)
 
-
-/*
- * 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 */
+#endif   /* GEO_DECLS_H */
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index 0a123f2b39..4140f40b71 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -62,21 +62,23 @@ regress_dist_ptpath(PG_FUNCTION_ARGS)
 	float8		result = 0.0;	/* keep compiler quiet */
 	float8		tmp;
 	int			i;
 	LSEG		lseg;
 
 	switch (path->npts)
 	{
 		case 0:
 			PG_RETURN_NULL();
 		case 1:
-			result = point_dt(pt, &path->p[0]);
+			result = DatumGetFloat8(DirectFunctionCall2(point_distance,
+														PointPGetDatum(pt),
+												PointPGetDatum(&path->p[0])));
 			break;
 		default:
 
 			/*
 			 * the distance from a point to a path is the smallest distance
 			 * from the point to any of its constituent segments.
 			 */
 			Assert(path->npts > 1);
 			for (i = 0; i < path->npts - 1; ++i)
 			{
@@ -280,22 +282,27 @@ widget_out(PG_FUNCTION_ARGS)
 	PG_RETURN_CSTRING(str);
 }
 
 PG_FUNCTION_INFO_V1(pt_in_widget);
 
 Datum
 pt_in_widget(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	WIDGET	   *widget = (WIDGET *) PG_GETARG_POINTER(1);
+	float8		distance;
 
-	PG_RETURN_BOOL(point_dt(point, &widget->center) < widget->radius);
+	distance = DatumGetFloat8(DirectFunctionCall2(point_distance,
+												  PointPGetDatum(point),
+											PointPGetDatum(&widget->center)));
+
+	PG_RETURN_BOOL(distance < widget->radius);
 }
 
 PG_FUNCTION_INFO_V1(boxarea);
 
 Datum
 boxarea(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	double		width,
 				height;
-- 
2.13.5 (Apple Git-94)

0002-float-header-v07.patchapplication/octet-stream; name=0002-float-header-v07.patchDownload
From 691dbd38cef296e4258b0cd1937d530a170e3bb1 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 28 May 2016 18:16:05 +0200
Subject: [PATCH 2/4] float-header-v07

Provide header file for built-in float datatypes

Even though, some datatypes under adt/ have separate header files,
most of the simple ones do not.  Their public functions were on
the builtins.h.  We would need to make more functions of floats public
to let the geometric types built on top of them.  This is a good
opportunity to make a separate header file for floats.

1acf7572554515b99ef6e783750aaea8777524ec made _cmp functions public
to solve NaN problem locally for GiST indexes.  This patch reworks it
in favour of a more extensive API.  Kevin Grittner suggested to design
the API using inline functions.  They are easier to use compared
to macros, and avoid double-evaluation hazards.
---
 contrib/btree_gin/btree_gin.c                 |   1 +
 contrib/btree_gist/btree_ts.c                 |   1 +
 contrib/cube/cube.c                           |   2 +-
 contrib/cube/cubeparse.y                      |   2 +-
 contrib/postgres_fdw/postgres_fdw.c           |   1 +
 src/backend/access/gist/gistget.c             |   2 +-
 src/backend/access/gist/gistproc.c            |  55 +--
 src/backend/access/gist/gistutil.c            |   2 +-
 src/backend/utils/adt/float.c                 | 589 ++++++--------------------
 src/backend/utils/adt/formatting.c            |   1 +
 src/backend/utils/adt/geo_ops.c               |   6 +-
 src/backend/utils/adt/geo_spgist.c            |   2 +-
 src/backend/utils/adt/numeric.c               |   1 +
 src/backend/utils/adt/rangetypes_gist.c       |   3 +-
 src/backend/utils/adt/rangetypes_selfuncs.c   |   3 +-
 src/backend/utils/adt/rangetypes_typanalyze.c |   3 +-
 src/backend/utils/adt/timestamp.c             |   1 +
 src/backend/utils/misc/guc.c                  |   1 +
 src/include/utils/builtins.h                  |  14 -
 src/include/utils/float.h                     | 376 ++++++++++++++++
 src/include/utils/geo_decls.h                 |   1 +
 21 files changed, 554 insertions(+), 513 deletions(-)
 create mode 100644 src/include/utils/float.h

diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index 2473f79ca1..301caefd47 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -3,20 +3,21 @@
  */
 #include "postgres.h"
 
 #include <limits.h>
 
 #include "access/stratnum.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/cash.h"
 #include "utils/date.h"
+#include "utils/float.h"
 #include "utils/inet.h"
 #include "utils/numeric.h"
 #include "utils/timestamp.h"
 #include "utils/varbit.h"
 
 PG_MODULE_MAGIC;
 
 typedef struct QueryInfo
 {
 	StrategyNumber strategy;
diff --git a/contrib/btree_gist/btree_ts.c b/contrib/btree_gist/btree_ts.c
index 1582cff102..6e77ebab0d 100644
--- a/contrib/btree_gist/btree_ts.c
+++ b/contrib/btree_gist/btree_ts.c
@@ -2,20 +2,21 @@
  * contrib/btree_gist/btree_ts.c
  */
 #include "postgres.h"
 
 #include <limits.h>
 
 #include "btree_gist.h"
 #include "btree_utils_num.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 typedef struct
 {
 	Timestamp	lower;
 	Timestamp	upper;
 } tsKEY;
 
 /*
 ** timestamp ops
 */
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c
index b7702716fe..f5a39cb53b 100644
--- a/contrib/cube/cube.c
+++ b/contrib/cube/cube.c
@@ -7,21 +7,21 @@
 ******************************************************************************/
 
 #include "postgres.h"
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 
 #include "cubedata.h"
 
 PG_MODULE_MAGIC;
 
 /*
  * Taken from the intarray contrib header
  */
 #define ARRPTR(x)  ( (double *) ARR_DATA_PTR(x) )
 #define ARRNELEMS(x)  ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x))
diff --git a/contrib/cube/cubeparse.y b/contrib/cube/cubeparse.y
index 1b65fa967c..deb2efdc0d 100644
--- a/contrib/cube/cubeparse.y
+++ b/contrib/cube/cubeparse.y
@@ -1,20 +1,20 @@
 %{
 /* contrib/cube/cubeparse.y */
 
 /* NdBox = [(lowerleft),(upperright)] */
 /* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */
 
 #include "postgres.h"
 
 #include "cubedata.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 
 /* All grammar constructs return strings */
 #define YYSTYPE char *
 
 /*
  * Bison doesn't allocate anything that needs to live across parser calls,
  * so we can easily have it use palloc instead of malloc.  This prevents
  * memory leaks if we error out during parsing.  Note this only works with
  * bison >= 2.0.  However, in bison 1.875 the default is to use alloca()
  * if possible, so there's not really much problem anyhow, at least if
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index fb65e2eb20..33bf0fe142 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -28,20 +28,21 @@
 #include "optimizer/cost.h"
 #include "optimizer/clauses.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
 #include "optimizer/planmain.h"
 #include "optimizer/restrictinfo.h"
 #include "optimizer/var.h"
 #include "optimizer/tlist.h"
 #include "parser/parsetree.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 #include "utils/sampling.h"
 #include "utils/selfuncs.h"
 
 PG_MODULE_MAGIC;
 
 /* Default CPU cost to start up a foreign query. */
diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c
index 06dac0bb53..56dca026ee 100644
--- a/src/backend/access/gist/gistget.c
+++ b/src/backend/access/gist/gistget.c
@@ -13,21 +13,21 @@
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/gist_private.h"
 #include "access/relscan.h"
 #include "catalog/pg_type.h"
 #include "miscadmin.h"
 #include "pgstat.h"
 #include "lib/pairingheap.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 
 /*
  * gistkillitems() -- set LP_DEAD state for items an indexscan caller has
  * told us were killed.
  *
  * We re-read page here, so it's important to check page LSN. If the page
  * has been modified since the last read (as determined by LSN), we cannot
  * flag any entries because it is possible that the old entry was vacuumed
diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index d1919fc74b..13524b4da0 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -27,62 +27,53 @@
 
 
 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
 						 StrategyNumber strategy);
 static bool rtree_internal_consistent(BOX *key, BOX *query,
 						  StrategyNumber strategy);
 
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
 
-/* Convenience macros for NaN-aware comparisons */
-#define FLOAT8_EQ(a,b)	(float8_cmp_internal(a, b) == 0)
-#define FLOAT8_LT(a,b)	(float8_cmp_internal(a, b) < 0)
-#define FLOAT8_LE(a,b)	(float8_cmp_internal(a, b) <= 0)
-#define FLOAT8_GT(a,b)	(float8_cmp_internal(a, b) > 0)
-#define FLOAT8_GE(a,b)	(float8_cmp_internal(a, b) >= 0)
-#define FLOAT8_MAX(a,b)  (FLOAT8_GT(a, b) ? (a) : (b))
-#define FLOAT8_MIN(a,b)  (FLOAT8_LT(a, b) ? (a) : (b))
-
 
 /**************************************************
  * Box ops
  **************************************************/
 
 /*
  * Calculates union of two boxes, a and b. The result is stored in *n.
  */
 static void
 rt_box_union(BOX *n, const BOX *a, const BOX *b)
 {
-	n->high.x = FLOAT8_MAX(a->high.x, b->high.x);
-	n->high.y = FLOAT8_MAX(a->high.y, b->high.y);
-	n->low.x = FLOAT8_MIN(a->low.x, b->low.x);
-	n->low.y = FLOAT8_MIN(a->low.y, b->low.y);
+	n->high.x = float8_max(a->high.x, b->high.x);
+	n->high.y = float8_max(a->high.y, b->high.y);
+	n->low.x = float8_min(a->low.x, b->low.x);
+	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
 static double
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
-	if (FLOAT8_LE(box->high.x, box->low.x) ||
-		FLOAT8_LE(box->high.y, box->low.y))
+	if (float8_le(box->high.x, box->low.x) ||
+		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
 	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
@@ -137,27 +128,27 @@ gist_box_consistent(PG_FUNCTION_ARGS)
 												 query,
 												 strategy));
 }
 
 /*
  * Increase BOX b to include addon.
  */
 static void
 adjustBox(BOX *b, const BOX *addon)
 {
-	if (FLOAT8_LT(b->high.x, addon->high.x))
+	if (float8_lt(b->high.x, addon->high.x))
 		b->high.x = addon->high.x;
-	if (FLOAT8_GT(b->low.x, addon->low.x))
+	if (float8_gt(b->low.x, addon->low.x))
 		b->low.x = addon->low.x;
-	if (FLOAT8_LT(b->high.y, addon->high.y))
+	if (float8_lt(b->high.y, addon->high.y))
 		b->high.y = addon->high.y;
-	if (FLOAT8_GT(b->low.y, addon->low.y))
+	if (float8_gt(b->low.y, addon->low.y))
 		b->low.y = addon->low.y;
 }
 
 /*
  * The GiST Union method for boxes
  *
  * returns the minimal bounding box that encloses all the entries in entryvec
  */
 Datum
 gist_box_union(PG_FUNCTION_ARGS)
@@ -609,36 +600,36 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		i1 = 0;
 		i2 = 0;
 		rightLower = intervalsLower[i1].lower;
 		leftUpper = intervalsUpper[i2].lower;
 		while (true)
 		{
 			/*
 			 * Find next lower bound of right group.
 			 */
 			while (i1 < nentries &&
-				   FLOAT8_EQ(rightLower, intervalsLower[i1].lower))
+				   float8_eq(rightLower, intervalsLower[i1].lower))
 			{
-				if (FLOAT8_LT(leftUpper, intervalsLower[i1].upper))
+				if (float8_lt(leftUpper, intervalsLower[i1].upper))
 					leftUpper = intervalsLower[i1].upper;
 				i1++;
 			}
 			if (i1 >= nentries)
 				break;
 			rightLower = intervalsLower[i1].lower;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * left group.
 			 */
 			while (i2 < nentries &&
-				   FLOAT8_LE(intervalsUpper[i2].upper, leftUpper))
+				   float8_le(intervalsUpper[i2].upper, leftUpper))
 				i2++;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim, rightLower, i1, leftUpper, i2);
 		}
 
 		/*
 		 * Iterate over upper bound of left group finding greatest possible
@@ -646,35 +637,35 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		 */
 		i1 = nentries - 1;
 		i2 = nentries - 1;
 		rightLower = intervalsLower[i1].upper;
 		leftUpper = intervalsUpper[i2].upper;
 		while (true)
 		{
 			/*
 			 * Find next upper bound of left group.
 			 */
-			while (i2 >= 0 && FLOAT8_EQ(leftUpper, intervalsUpper[i2].upper))
+			while (i2 >= 0 && float8_eq(leftUpper, intervalsUpper[i2].upper))
 			{
-				if (FLOAT8_GT(rightLower, intervalsUpper[i2].lower))
+				if (float8_gt(rightLower, intervalsUpper[i2].lower))
 					rightLower = intervalsUpper[i2].lower;
 				i2--;
 			}
 			if (i2 < 0)
 				break;
 			leftUpper = intervalsUpper[i2].upper;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * right group.
 			 */
-			while (i1 >= 0 && FLOAT8_GE(intervalsLower[i1].lower, rightLower))
+			while (i1 >= 0 && float8_ge(intervalsLower[i1].lower, rightLower))
 				i1--;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim,
 								 rightLower, i1 + 1, leftUpper, i2 + 1);
 		}
 	}
 
@@ -748,42 +739,42 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
 		}
 		else
 		{
 			lower = box->low.y;
 			upper = box->high.y;
 		}
 
-		if (FLOAT8_LE(upper, context.leftUpper))
+		if (float8_le(upper, context.leftUpper))
 		{
 			/* Fits to the left group */
-			if (FLOAT8_GE(lower, context.rightLower))
+			if (float8_ge(lower, context.rightLower))
 			{
 				/* Fits also to the right group, so "common entry" */
 				commonEntries[commonEntriesCount++].index = i;
 			}
 			else
 			{
 				/* Doesn't fit to the right group, so join to the left group */
 				PLACE_LEFT(box, i);
 			}
 		}
 		else
 		{
 			/*
 			 * Each entry should fit on either left or right group. Since this
 			 * entry didn't fit on the left group, it better fit in the right
 			 * group.
 			 */
-			Assert(FLOAT8_GE(lower, context.rightLower));
+			Assert(float8_ge(lower, context.rightLower));
 
 			/* Doesn't fit to the left group, so join to the right group */
 			PLACE_RIGHT(box, i);
 		}
 	}
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
@@ -853,24 +844,24 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
  * equivalent to box_same().
  */
 Datum
 gist_box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *b1 = PG_GETARG_BOX_P(0);
 	BOX		   *b2 = PG_GETARG_BOX_P(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
 	if (b1 && b2)
-		*result = (FLOAT8_EQ(b1->low.x, b2->low.x) &&
-				   FLOAT8_EQ(b1->low.y, b2->low.y) &&
-				   FLOAT8_EQ(b1->high.x, b2->high.x) &&
-				   FLOAT8_EQ(b1->high.y, b2->high.y));
+		*result = (float8_eq(b1->low.x, b2->low.x) &&
+				   float8_eq(b1->low.y, b2->low.y) &&
+				   float8_eq(b1->high.x, b2->high.x) &&
+				   float8_eq(b1->high.y, b2->high.y));
 	else
 		*result = (b1 == NULL && b2 == NULL);
 	PG_RETURN_POINTER(result);
 }
 
 /*
  * Leaf-level consistency for boxes: just apply the query operator
  */
 static bool
 gist_box_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy)
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 26d89f79ae..6a08756988 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -15,21 +15,21 @@
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist_private.h"
 #include "access/htup_details.h"
 #include "access/reloptions.h"
 #include "catalog/pg_opclass.h"
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/syscache.h"
 
 
 /*
  * Write itup vector to page, has no control of free space.
  */
 void
 gistfillbuffer(Page page, IndexTuple *itup, int len, OffsetNumber off)
 {
 	OffsetNumber l = InvalidOffsetNumber;
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index 18b3b949ac..dfd82bb80e 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -15,62 +15,29 @@
 #include "postgres.h"
 
 #include <ctype.h>
 #include <float.h>
 #include <math.h>
 #include <limits.h>
 
 #include "catalog/pg_type.h"
 #include "libpq/pqformat.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/sortsupport.h"
 
 
-#ifndef M_PI
-/* from my RH5.2 gcc math.h file - thomas 2000-04-03 */
-#define M_PI 3.14159265358979323846
-#endif
-
-/* Radians per degree, a.k.a. PI / 180 */
-#define RADIANS_PER_DEGREE 0.0174532925199432957692
-
-/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0.  NAN definition from
- * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfNotNumberNANItems.asp
- */
-#if defined(WIN32) && !defined(NAN)
-static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
-
-#define NAN (*(const double *) nan)
-#endif
-
 /* not sure what the following should be, but better to make it over-sufficient */
 #define MAXFLOATWIDTH	64
 #define MAXDOUBLEWIDTH	128
 
-/*
- * check to see if a float4/8 val has underflowed or overflowed
- */
-#define CHECKFLOATVAL(val, inf_is_valid, zero_is_valid)			\
-do {															\
-	if (isinf(val) && !(inf_is_valid))							\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		  errmsg("value out of range: overflow")));				\
-																\
-	if ((val) == 0.0 && !(zero_is_valid))						\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		 errmsg("value out of range: underflow")));				\
-} while(0)
-
-
 /* Configurable GUC parameter */
 int			extra_float_digits = 0; /* Added to DBL_DIG or FLT_DIG */
 
 /* Cached constants for degree-based trig functions */
 static bool degree_consts_set = false;
 static float8 sin_30 = 0;
 static float8 one_minus_cos_60 = 0;
 static float8 asin_0_5 = 0;
 static float8 acos_0_5 = 0;
 static float8 atan_1_0 = 0;
@@ -102,100 +69,20 @@ static void init_degree_constants(void);
  * their compilers spit up at the mismatch between extern declaration
  * and static definition.  We work around that here by the expedient
  * of a #define to make the actual name of the static function different.
  */
 #define cbrt my_cbrt
 static double cbrt(double x);
 #endif							/* HAVE_CBRT */
 
 
 /*
- * Routines to provide reasonably platform-independent handling of
- * infinity and NaN.  We assume that isinf() and isnan() are available
- * and work per spec.  (On some platforms, we have to supply our own;
- * see src/port.)  However, generating an Infinity or NaN in the first
- * place is less well standardized; pre-C99 systems tend not to have C99's
- * INFINITY and NAN macros.  We centralize our workarounds for this here.
- */
-
-double
-get_float8_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (double) INFINITY;
-#else
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (double) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-/*
-* The funny placements of the two #pragmas is necessary because of a
-* long lived bug in the Microsoft compilers.
-* See http://support.microsoft.com/kb/120968/en-us for details
-*/
-#if (_MSC_VER >= 1800)
-#pragma warning(disable:4756)
-#endif
-float
-get_float4_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (float) INFINITY;
-#else
-#if (_MSC_VER >= 1800)
-#pragma warning(default:4756)
-#endif
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (float) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-double
-get_float8_nan(void)
-{
-	/* (double) NAN doesn't work on some NetBSD/MIPS releases */
-#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
-	/* C99 standard way */
-	return (double) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (double) (0.0 / 0.0);
-#endif
-}
-
-float
-get_float4_nan(void)
-{
-#ifdef NAN
-	/* C99 standard way */
-	return (float) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (float) (0.0 / 0.0);
-#endif
-}
-
-
-/*
  * Returns -1 if 'val' represents negative infinity, 1 if 'val'
  * represents (positive) infinity, and 0 otherwise. On some platforms,
  * this is equivalent to the isinf() macro, but not everywhere: C99
  * does not specify that isinf() needs to distinguish between positive
  * and negative infinity.
  */
 int
 is_infinite(double val)
 {
 	int			inf = isinf(val);
@@ -339,21 +226,21 @@ float4in(PG_FUNCTION_ARGS)
 	if (*endptr != '\0')
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"real", orig_num)));
 
 	/*
 	 * if we get here, we have a legal double, still need to check to see if
 	 * it's a legal float4
 	 */
-	CHECKFLOATVAL((float4) val, isinf(val), val == 0);
+	check_float4_val((float4) val, isinf(val), val == 0);
 
 	PG_RETURN_FLOAT4((float4) val);
 }
 
 /*
  *		float4out		- converts a float4 number to a string
  *						  using a standard output format
  */
 Datum
 float4out(PG_FUNCTION_ARGS)
@@ -689,35 +576,35 @@ float4up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT4(arg);
 }
 
 Datum
 float4larger(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) > 0)
+	if (float4_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 Datum
 float4smaller(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) < 0)
+	if (float4_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 /*
  *		======================
  *		FLOAT8 BASE OPERATIONS
  *		======================
@@ -756,35 +643,35 @@ float8up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT8(arg);
 }
 
 Datum
 float8larger(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) > 0)
+	if (float8_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 Datum
 float8smaller(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) < 0)
+	if (float8_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		====================
  *		ARITHMETIC OPERATORS
@@ -795,234 +682,165 @@ float8smaller(PG_FUNCTION_ARGS)
  *		float4pl		- returns arg1 + arg2
  *		float4mi		- returns arg1 - arg2
  *		float4mul		- returns arg1 * arg2
  *		float4div		- returns arg1 / arg2
  */
 Datum
 float4pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 + arg2;
-
-	/*
-	 * There isn't any way to check for underflow of addition/subtraction
-	 * because numbers near the underflow value have already been rounded to
-	 * the point where we can't detect that the two values were originally
-	 * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
-	 * 1.4013e-45.
-	 */
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_pl(arg1, arg2));
 }
 
 Datum
 float4mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mi(arg1, arg2));
 }
 
 Datum
 float4mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mul(arg1, arg2));
 }
 
 Datum
 float4div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_div(arg1, arg2));
 }
 
 /*
  *		float8pl		- returns arg1 + arg2
  *		float8mi		- returns arg1 - arg2
  *		float8mul		- returns arg1 * arg2
  *		float8div		- returns arg1 / arg2
  */
 Datum
 float8pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 + arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, arg2));
 }
 
 Datum
 float8mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 - arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, arg2));
 }
 
 Datum
 float8mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 * arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, arg2));
 }
 
 Datum
 float8div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, arg2));
 }
 
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float4{eq,ne,lt,le,gt,ge}		- float4/float4 comparison operations
  */
 int
 float4_cmp_internal(float4 a, float4 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float4_gt(a, b))
+		return 1;
+	if (float4_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
 float4eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float4_eq(arg1, arg2));
 }
 
 Datum
 float4ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float4_ne(arg1, arg2));
 }
 
 Datum
 float4lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float4_lt(arg1, arg2));
 }
 
 Datum
 float4le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float4_le(arg1, arg2));
 }
 
 Datum
 float4gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float4_gt(arg1, arg2));
 }
 
 Datum
 float4ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float4_ge(arg1, arg2));
 }
 
 Datum
 btfloat4cmp(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
 	PG_RETURN_INT32(float4_cmp_internal(arg1, arg2));
 }
@@ -1044,99 +862,79 @@ btfloat4sortsupport(PG_FUNCTION_ARGS)
 	ssup->comparator = btfloat4fastcmp;
 	PG_RETURN_VOID();
 }
 
 /*
  *		float8{eq,ne,lt,le,gt,ge}		- float8/float8 comparison operations
  */
 int
 float8_cmp_internal(float8 a, float8 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float8_gt(a, b))
+		return 1;
+	if (float8_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
 float8eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, arg2));
 }
 
 Datum
 float8ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, arg2));
 }
 
 Datum
 float8lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, arg2));
 }
 
 Datum
 float8le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, arg2));
 }
 
 Datum
 float8gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, arg2));
 }
 
 Datum
 float8ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, arg2));
 }
 
 Datum
 btfloat8cmp(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
 	PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
 }
@@ -1199,21 +997,21 @@ ftod(PG_FUNCTION_ARGS)
 
 
 /*
  *		dtof			- converts a float8 number to a float4 number
  */
 Datum
 dtof(PG_FUNCTION_ARGS)
 {
 	float8		num = PG_GETARG_FLOAT8(0);
 
-	CHECKFLOATVAL((float4) num, isinf(num), num == 0);
+	check_float4_val((float4) num, isinf(num), num == 0);
 
 	PG_RETURN_FLOAT4((float4) num);
 }
 
 
 /*
  *		dtoi4			- converts a float8 number to an int4 number
  */
 Datum
 dtoi4(PG_FUNCTION_ARGS)
@@ -1424,36 +1222,36 @@ dsqrt(PG_FUNCTION_ARGS)
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
 				 errmsg("cannot take square root of a negative number")));
 
 	result = sqrt(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcbrt			- returns cube root of arg1
  */
 Datum
 dcbrt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	result = cbrt(arg1);
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dpow			- returns pow(arg1,arg2)
  */
 Datum
 dpow(PG_FUNCTION_ARGS)
 {
@@ -1492,40 +1290,40 @@ dpow(PG_FUNCTION_ARGS)
 			/* The sign of Inf is not significant in this case. */
 			result = get_float8_infinity();
 		else if (fabs(arg1) != 1)
 			result = 0;
 		else
 			result = 1;
 	}
 	else if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
+	check_float8_val(result, isinf(arg1) || isinf(arg2), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dexp			- returns the exponential function of arg1
  */
 Datum
 dexp(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	errno = 0;
 	result = exp(arg1);
 	if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1), false);
+	check_float8_val(result, isinf(arg1), false);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dlog1			- returns the natural logarithm of arg1
  */
 Datum
 dlog1(PG_FUNCTION_ARGS)
 {
@@ -1540,21 +1338,21 @@ dlog1(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of zero")));
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of a negative number")));
 
 	result = log(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dlog10			- returns the base 10 logarithm of arg1
  */
 Datum
 dlog10(PG_FUNCTION_ARGS)
 {
@@ -1570,21 +1368,21 @@ dlog10(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of zero")));
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of a negative number")));
 
 	result = log10(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dacos			- returns the arccos of arg1 (radians)
  */
 Datum
 dacos(PG_FUNCTION_ARGS)
 {
@@ -1600,21 +1398,21 @@ dacos(PG_FUNCTION_ARGS)
 	 * range [-1, 1] to values in the range [0, Pi], so we should reject any
 	 * inputs outside that range and the result will always be finite.
 	 */
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = acos(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dasin			- returns the arcsin of arg1 (radians)
  */
 Datum
 dasin(PG_FUNCTION_ARGS)
 {
@@ -1630,21 +1428,21 @@ dasin(PG_FUNCTION_ARGS)
 	 * range [-1, 1] to values in the range [-Pi/2, Pi/2], so we should reject
 	 * any inputs outside that range and the result will always be finite.
 	 */
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = asin(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		datan			- returns the arctan of arg1 (radians)
  */
 Datum
 datan(PG_FUNCTION_ARGS)
 {
@@ -1655,21 +1453,21 @@ datan(PG_FUNCTION_ARGS)
 	if (isnan(arg1))
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/*
 	 * The principal branch of the inverse tangent function maps all inputs to
 	 * values in the range [-Pi/2, Pi/2], so the result should always be
 	 * finite, even if the input is infinite.
 	 */
 	result = atan(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		atan2			- returns the arctan of arg1/arg2 (radians)
  */
 Datum
 datan2(PG_FUNCTION_ARGS)
 {
@@ -1680,21 +1478,21 @@ datan2(PG_FUNCTION_ARGS)
 	/* Per the POSIX spec, return NaN if either input is NaN */
 	if (isnan(arg1) || isnan(arg2))
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/*
 	 * atan2 maps all inputs to values in the range [-Pi, Pi], so the result
 	 * should always be finite, even if the inputs are infinite.
 	 */
 	result = atan2(arg1, arg2);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcos			- returns the cosine of arg1 (radians)
  */
 Datum
 dcos(PG_FUNCTION_ARGS)
 {
@@ -1720,21 +1518,21 @@ dcos(PG_FUNCTION_ARGS)
 	 * platform reports via errno, so also explicitly test for infinite
 	 * inputs.
 	 */
 	errno = 0;
 	result = cos(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcot			- returns the cotangent of arg1 (radians)
  */
 Datum
 dcot(PG_FUNCTION_ARGS)
 {
@@ -1747,21 +1545,21 @@ dcot(PG_FUNCTION_ARGS)
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = tan(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = 1.0 / result;
-	CHECKFLOATVAL(result, true /* cot(0) == Inf */ , true);
+	check_float8_val(result, true /* cot(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dsin			- returns the sine of arg1 (radians)
  */
 Datum
 dsin(PG_FUNCTION_ARGS)
 {
@@ -1773,21 +1571,21 @@ dsin(PG_FUNCTION_ARGS)
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = sin(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dtan			- returns the tangent of arg1 (radians)
  */
 Datum
 dtan(PG_FUNCTION_ARGS)
 {
@@ -1799,21 +1597,21 @@ dtan(PG_FUNCTION_ARGS)
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = tan(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, true /* tan(pi/2) == Inf */ , true);
+	check_float8_val(result, true /* tan(pi/2) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /* ========== DEGREE-BASED TRIGONOMETRIC FUNCTIONS ========== */
 
 
 /*
  * Initialize the cached constants declared at the head of this file
  * (sin_30 etc).  The fact that we need those at all, let alone need this
@@ -1951,21 +1749,21 @@ dacosd(PG_FUNCTION_ARGS)
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	if (arg1 >= 0.0)
 		result = acosd_q1(arg1);
 	else
 		result = 90.0 + asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dasind			- returns the arcsin of arg1 (degrees)
  */
 Datum
 dasind(PG_FUNCTION_ARGS)
 {
@@ -1986,21 +1784,21 @@ dasind(PG_FUNCTION_ARGS)
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	if (arg1 >= 0.0)
 		result = asind_q1(arg1);
 	else
 		result = -asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		datand			- returns the arctan of arg1 (degrees)
  */
 Datum
 datand(PG_FUNCTION_ARGS)
 {
@@ -2016,21 +1814,21 @@ datand(PG_FUNCTION_ARGS)
 
 	/*
 	 * The principal branch of the inverse tangent function maps all inputs to
 	 * values in the range [-90, 90], so the result should always be finite,
 	 * even if the input is infinite.  Additionally, we take care to ensure
 	 * than when arg1 is 1, the result is exactly 45.
 	 */
 	atan_arg1 = atan(arg1);
 	result = (atan_arg1 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		atan2d			- returns the arctan of arg1/arg2 (degrees)
  */
 Datum
 datan2d(PG_FUNCTION_ARGS)
 {
@@ -2050,21 +1848,21 @@ datan2d(PG_FUNCTION_ARGS)
 	 * result should always be finite, even if the inputs are infinite.
 	 *
 	 * Note: this coding assumes that atan(1.0) is a suitable scaling constant
 	 * to get an exact result from atan2().  This might well fail on us at
 	 * some point, requiring us to decide exactly what inputs we think we're
 	 * going to guarantee an exact result for.
 	 */
 	atan2_arg1_arg2 = atan2(arg1, arg2);
 	result = (atan2_arg1_arg2 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		sind_0_to_30	- returns the sine of an angle that lies between 0 and
  *						  30 degrees.  This will return exactly 0 when x is 0,
  *						  and exactly 0.5 when x is 30 degrees.
  */
 static double
@@ -2171,21 +1969,21 @@ dcosd(PG_FUNCTION_ARGS)
 
 	if (arg1 > 90.0)
 	{
 		/* cosd(180-x) = -cosd(x) */
 		arg1 = 180.0 - arg1;
 		sign = -sign;
 	}
 
 	result = sign * cosd_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcotd			- returns the cotangent of arg1 (degrees)
  */
 Datum
 dcotd(PG_FUNCTION_ARGS)
 {
@@ -2236,21 +2034,21 @@ dcotd(PG_FUNCTION_ARGS)
 	result = sign * (cot_arg1 / cot_45);
 
 	/*
 	 * On some machines we get cotd(270) = minus zero, but this isn't always
 	 * true.  For portability, and because the user constituency for this
 	 * function probably doesn't want minus zero, force it to plain zero.
 	 */
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* cotd(0) == Inf */ , true);
+	check_float8_val(result, true /* cotd(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dsind			- returns the sine of arg1 (degrees)
  */
 Datum
 dsind(PG_FUNCTION_ARGS)
 {
@@ -2290,21 +2088,21 @@ dsind(PG_FUNCTION_ARGS)
 	}
 
 	if (arg1 > 90.0)
 	{
 		/* sind(180-x) = sind(x) */
 		arg1 = 180.0 - arg1;
 	}
 
 	result = sign * sind_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dtand			- returns the tangent of arg1 (degrees)
  */
 Datum
 dtand(PG_FUNCTION_ARGS)
 {
@@ -2355,64 +2153,56 @@ dtand(PG_FUNCTION_ARGS)
 	result = sign * (tan_arg1 / tan_45);
 
 	/*
 	 * On some machines we get tand(180) = minus zero, but this isn't always
 	 * true.  For portability, and because the user constituency for this
 	 * function probably doesn't want minus zero, force it to plain zero.
 	 */
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* tand(90) == Inf */ , true);
+	check_float8_val(result, true /* tand(90) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		degrees		- returns degrees converted from radians
  */
 Datum
 degrees(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
 
-	result = arg1 / RADIANS_PER_DEGREE;
-
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, RADIANS_PER_DEGREE));
 }
 
 
 /*
  *		dpi				- returns the constant PI
  */
 Datum
 dpi(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_FLOAT8(M_PI);
 }
 
 
 /*
  *		radians		- returns radians converted from degrees
  */
 Datum
 radians(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
 
-	result = arg1 * RADIANS_PER_DEGREE;
-
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, RADIANS_PER_DEGREE));
 }
 
 
 /*
  *		drandom		- returns a random number
  */
 Datum
 drandom(PG_FUNCTION_ARGS)
 {
 	float8		result;
@@ -2490,144 +2280,105 @@ check_float8_array(ArrayType *transarray, const char *caller, int n)
  * This function is used only in two stage aggregation and
  * shouldn't be called outside aggregate context.
  */
 Datum
 float8_combine(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_combine", 3);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-
 	transvalues2 = check_float8_array(transarray2, "float8_combine", 3);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
 
 Datum
 float8_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8		newval = PG_GETARG_FLOAT8(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float8_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
 	else
 	{
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
 								 sizeof(float8), FLOAT8PASSBYVAL, 'd');
 
 		PG_RETURN_ARRAYTYPE_P(result);
 	}
 }
 
 Datum
 float4_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 
 	/* do computations as float8 */
 	float8		newval = PG_GETARG_FLOAT4(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float4_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
 	else
 	{
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
 								 sizeof(float8), FLOAT8PASSBYVAL, 'd');
 
 		PG_RETURN_ARRAYTYPE_P(result);
 	}
 }
 
 Datum
@@ -2663,21 +2414,21 @@ float8_var_pop(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_var_pop", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Population variance is undefined when N is 0, so return NULL */
 	if (N == 0.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / (N * N));
 }
 
 Datum
 float8_var_samp(PG_FUNCTION_ARGS)
@@ -2692,21 +2443,21 @@ float8_var_samp(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_var_samp", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Sample variance is undefined when N is 0 or 1, so return NULL */
 	if (N <= 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
 }
 
 Datum
 float8_stddev_pop(PG_FUNCTION_ARGS)
@@ -2721,21 +2472,21 @@ float8_stddev_pop(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_stddev_pop", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Population stddev is undefined when N is 0, so return NULL */
 	if (N == 0.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(sqrt(numerator / (N * N)));
 }
 
 Datum
 float8_stddev_samp(PG_FUNCTION_ARGS)
@@ -2750,21 +2501,21 @@ float8_stddev_samp(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_stddev_samp", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Sample stddev is undefined when N is 0 or 1, so return NULL */
 	if (N <= 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(sqrt(numerator / (N * (N - 1.0))));
 }
 
 /*
  *		=========================
@@ -2799,30 +2550,30 @@ float8_regr_accum(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_accum", 6);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	N += 1.0;
 	sumX += newvalX;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
+	check_float8_val(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
 	sumX2 += newvalX * newvalX;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
+	check_float8_val(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
 	sumY += newvalY;
-	CHECKFLOATVAL(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
+	check_float8_val(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
 	sumY2 += newvalY * newvalY;
-	CHECKFLOATVAL(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
+	check_float8_val(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
 	sumXY += newvalX * newvalY;
-	CHECKFLOATVAL(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
-				  isinf(newvalY), true);
+	check_float8_val(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
+					 isinf(newvalY), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
 		transvalues[0] = N;
 		transvalues[1] = sumX;
@@ -2861,63 +2612,33 @@ float8_regr_accum(PG_FUNCTION_ARGS)
  * This function is used only in two stage aggregation and
  * shouldn't be called outside aggregate context.
  */
 Datum
 float8_regr_combine(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2,
-				sumY,
-				sumY2,
-				sumXY;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_regr_combine", 6);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-	sumY = transvalues1[3];
-	sumY2 = transvalues1[4];
-	sumXY = transvalues1[5];
-
 	transvalues2 = check_float8_array(transarray2, "float8_regr_combine", 6);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-	sumY += transvalues2[3];
-	CHECKFLOATVAL(sumY, isinf(transvalues1[3]) || isinf(transvalues2[3]),
-				  true);
-	sumY2 += transvalues2[4];
-	CHECKFLOATVAL(sumY2, isinf(transvalues1[4]) || isinf(transvalues2[4]),
-				  true);
-	sumXY += transvalues2[5];
-	CHECKFLOATVAL(sumXY, isinf(transvalues1[5]) || isinf(transvalues2[5]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
-	transvalues1[3] = sumY;
-	transvalues1[4] = sumY2;
-	transvalues1[5] = sumXY;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
+	transvalues1[3] = float8_pl(transvalues1[3], transvalues2[3]);
+	transvalues1[4] = float8_pl(transvalues1[4], transvalues2[4]);
+	transvalues1[5] = float8_pl(transvalues1[5], transvalues2[5]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
 
 
 Datum
 float8_regr_sxx(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
@@ -2929,21 +2650,21 @@ float8_regr_sxx(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_sxx", 6);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_syy(PG_FUNCTION_ARGS)
@@ -2958,21 +2679,21 @@ float8_regr_syy(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_syy", 6);
 	N = transvalues[0];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumY2) || isinf(sumY), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_sxy(PG_FUNCTION_ARGS)
@@ -2989,22 +2710,22 @@ float8_regr_sxy(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	/* A negative result is valid here */
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_avgx(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3057,22 +2778,22 @@ float8_covar_pop(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * N));
 }
 
 Datum
 float8_covar_samp(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
 	float8		N,
@@ -3085,22 +2806,22 @@ float8_covar_samp(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is <= 1 we should return NULL */
 	if (N < 2.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
 }
 
 Datum
 float8_corr(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
 	float8		N,
@@ -3119,26 +2840,26 @@ float8_corr(PG_FUNCTION_ARGS)
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0 || numeratorY <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXY / sqrt(numeratorX * numeratorY));
 }
 
 Datum
 float8_regr_r2(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3159,26 +2880,26 @@ float8_regr_r2(PG_FUNCTION_ARGS)
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 	/* per spec, horizontal line produces 1.0 */
 	if (numeratorY <= 0)
 		PG_RETURN_FLOAT8(1.0);
 
 	PG_RETURN_FLOAT8((numeratorXY * numeratorXY) /
 					 (numeratorX * numeratorY));
 }
 
@@ -3200,24 +2921,24 @@ float8_regr_slope(PG_FUNCTION_ARGS)
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXY / numeratorX);
 }
 
 Datum
 float8_regr_intercept(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3235,24 +2956,24 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXXY = sumY * sumX2 - sumX * sumXY;
-	CHECKFLOATVAL(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
-				  isinf(sumX) || isinf(sumXY), true);
+	check_float8_val(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
+					 isinf(sumX) || isinf(sumXY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXXY / numeratorX);
 }
 
 
 /*
  *		====================================
  *		MIXED-PRECISION ARITHMETIC OPERATORS
@@ -3263,251 +2984,211 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
  *		float48pl		- returns arg1 + arg2
  *		float48mi		- returns arg1 - arg2
  *		float48mul		- returns arg1 * arg2
  *		float48div		- returns arg1 / arg2
  */
 Datum
 float48pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 + arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl((float8) arg1, arg2));
 }
 
 Datum
 float48mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi((float8) arg1, arg2));
 }
 
 Datum
 float48mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul((float8) arg1, arg2));
 }
 
 Datum
 float48div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div((float8) arg1, arg2));
 }
 
 /*
  *		float84pl		- returns arg1 + arg2
  *		float84mi		- returns arg1 - arg2
  *		float84mul		- returns arg1 * arg2
  *		float84div		- returns arg1 / arg2
  */
 Datum
 float84pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 + arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, (float8) arg2));
 }
 
 Datum
 float84mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 - arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, (float8) arg2));
 }
 
 Datum
 float84mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 * arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, (float8) arg2));
 }
 
 Datum
 float84div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, (float8) arg2));
 }
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float48{eq,ne,lt,le,gt,ge}		- float4/float8 comparison operations
  */
 Datum
 float48eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq((float8) arg1, arg2));
 }
 
 Datum
 float48ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne((float8) arg1, arg2));
 }
 
 Datum
 float48lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt((float8) arg1, arg2));
 }
 
 Datum
 float48le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le((float8) arg1, arg2));
 }
 
 Datum
 float48gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt((float8) arg1, arg2));
 }
 
 Datum
 float48ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge((float8) arg1, arg2));
 }
 
 /*
  *		float84{eq,ne,lt,le,gt,ge}		- float8/float4 comparison operations
  */
 Datum
 float84eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, (float8) arg2));
 }
 
 Datum
 float84ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, (float8) arg2));
 }
 
 Datum
 float84lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, (float8) arg2));
 }
 
 Datum
 float84le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, (float8) arg2));
 }
 
 Datum
 float84gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, (float8) arg2));
 }
 
 Datum
 float84ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, (float8) arg2));
 }
 
 /*
  * Implements the float8 version of the width_bucket() function
  * defined by SQL2003. See also width_bucket_numeric().
  *
  * 'bound1' and 'bound2' are the lower and upper bounds of the
  * histogram's range, respectively. 'count' is the number of buckets
  * in the histogram. width_bucket() returns an integer indicating the
  * bucket number that 'operand' belongs to in an equiwidth histogram
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c
index 7877af2d6b..4cb5aba044 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -84,20 +84,21 @@
 
 #ifdef USE_ICU
 #include <unicode/ustring.h>
 #endif
 
 #include "catalog/pg_collation.h"
 #include "mb/pg_wchar.h"
 #include "utils/builtins.h"
 #include "utils/date.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 #include "utils/formatting.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/pg_locale.h"
 
 /* ----------
  * Routines type
  * ----------
  */
 #define DCH_TYPE		1		/* DATE-TIME version	*/
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index d3dc2ee602..567554735f 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -14,27 +14,23 @@
  */
 #include "postgres.h"
 
 #include <math.h>
 #include <limits.h>
 #include <float.h>
 #include <ctype.h>
 
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
-#include "utils/builtins.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index f6334bae14..c800bb1338 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -69,21 +69,21 @@
  *			src/backend/utils/adt/geo_spgist.c
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
 
 #include "access/spgist.h"
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
  * is going only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index ddc44d5179..f482acacb4 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -28,20 +28,21 @@
 
 #include "access/hash.h"
 #include "catalog/pg_type.h"
 #include "funcapi.h"
 #include "lib/hyperloglog.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/sortsupport.h"
 
 /* ----------
  * Uncomment the following to enable compilation of dump_numeric()
  * and dump_var() and to get a dump of any result produced by make_result().
  * ----------
 #define NUMERIC_DEBUG
diff --git a/src/backend/utils/adt/rangetypes_gist.c b/src/backend/utils/adt/rangetypes_gist.c
index 29fa1ae325..d8c1525acc 100644
--- a/src/backend/utils/adt/rangetypes_gist.c
+++ b/src/backend/utils/adt/rangetypes_gist.c
@@ -9,21 +9,22 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_gist.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/gist.h"
 #include "access/stratnum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/datum.h"
 #include "utils/rangetypes.h"
 
 
 /*
  * Range class properties used to segregate different classes of ranges in
  * GiST.  Each unique combination of properties is a class.  CLS_EMPTY cannot
  * be combined with anything else.
  */
 #define CLS_NORMAL			0	/* Ordinary finite range (no bits set) */
diff --git a/src/backend/utils/adt/rangetypes_selfuncs.c b/src/backend/utils/adt/rangetypes_selfuncs.c
index cba8974dbe..97308aea9a 100644
--- a/src/backend/utils/adt/rangetypes_selfuncs.c
+++ b/src/backend/utils/adt/rangetypes_selfuncs.c
@@ -14,21 +14,22 @@
  *	  src/backend/utils/adt/rangetypes_selfuncs.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/htup_details.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 #include "utils/selfuncs.h"
 #include "utils/typcache.h"
 
 static double calc_rangesel(TypeCacheEntry *typcache, VariableStatData *vardata,
 			  RangeType *constval, Oid operator);
 static double default_range_selectivity(Oid operator);
 static double calc_hist_selectivity(TypeCacheEntry *typcache,
 					  VariableStatData *vardata, RangeType *constval,
diff --git a/src/backend/utils/adt/rangetypes_typanalyze.c b/src/backend/utils/adt/rangetypes_typanalyze.c
index 3efd982d1b..8a7ad4f3f7 100644
--- a/src/backend/utils/adt/rangetypes_typanalyze.c
+++ b/src/backend/utils/adt/rangetypes_typanalyze.c
@@ -19,21 +19,22 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_typanalyze.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "catalog/pg_operator.h"
 #include "commands/vacuum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 
 static int	float8_qsort_cmp(const void *a1, const void *a2);
 static int	range_bound_qsort_cmp(const void *a1, const void *a2, void *arg);
 static void compute_range_stats(VacAttrStats *stats,
 					AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows);
 
 /*
  * range_typanalyze -- typanalyze function for range columns
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index b11d452fc8..3df4010b97 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -27,20 +27,21 @@
 #include "common/int128.h"
 #include "funcapi.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
 #include "parser/scansup.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 /*
  * gcc's -ffast-math switch breaks routines that expect exact results from
  * expressions like timeval / SECS_PER_HOUR, where timeval is double.
  */
 #ifdef __FAST_MATH__
 #error -ffast-math is known to break this code
 #endif
 
 #define SAMESIGN(a,b)	(((a) < 0) == ((b) < 0))
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 47a5f25707..4f1b87ee13 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -72,20 +72,21 @@
 #include "storage/standby.h"
 #include "storage/fd.h"
 #include "storage/pg_shmem.h"
 #include "storage/proc.h"
 #include "storage/predicate.h"
 #include "tcop/tcopprot.h"
 #include "tsearch/ts_cache.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/guc_tables.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/pg_locale.h"
 #include "utils/plancache.h"
 #include "utils/portal.h"
 #include "utils/ps_status.h"
 #include "utils/rls.h"
 #include "utils/snapmgr.h"
 #include "utils/tzparser.h"
 #include "utils/varlena.h"
 #include "utils/xml.h"
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 762532f636..668e037737 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -43,34 +43,20 @@ extern int	namestrcmp(Name name, const char *str);
 
 /* numutils.c */
 extern int32 pg_atoi(const char *s, int size, int c);
 extern void pg_itoa(int16 i, char *a);
 extern void pg_ltoa(int32 l, char *a);
 extern void pg_lltoa(int64 ll, char *a);
 extern char *pg_ltostr_zeropad(char *str, int32 value, int32 minwidth);
 extern char *pg_ltostr(char *str, int32 value);
 extern uint64 pg_strtouint64(const char *str, char **endptr, int base);
 
-/* float.c */
-extern PGDLLIMPORT int extra_float_digits;
-
-extern double get_float8_infinity(void);
-extern float get_float4_infinity(void);
-extern double get_float8_nan(void);
-extern float get_float4_nan(void);
-extern int	is_infinite(double val);
-extern double float8in_internal(char *num, char **endptr_p,
-				  const char *type_name, const char *orig_string);
-extern char *float8out_internal(double num);
-extern int	float4_cmp_internal(float4 a, float4 b);
-extern int	float8_cmp_internal(float8 a, float8 b);
-
 /* oid.c */
 extern oidvector *buildoidvector(const Oid *oids, int n);
 extern Oid	oidparse(Node *node);
 extern int	oid_cmp(const void *p1, const void *p2);
 
 /* regexp.c */
 extern char *regexp_fixed_prefix(text *text_re, bool case_insensitive,
 					Oid collation, bool *exact);
 
 /* ruleutils.c */
diff --git a/src/include/utils/float.h b/src/include/utils/float.h
new file mode 100644
index 0000000000..b96c6e071c
--- /dev/null
+++ b/src/include/utils/float.h
@@ -0,0 +1,376 @@
+/*-------------------------------------------------------------------------
+ *
+ * float.h
+ *	  Definitions for the built-in floating-point types
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/include/utils/float.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef FLOAT_H
+#define FLOAT_H
+
+#include <math.h>
+
+#ifndef M_PI
+/* From my RH5.2 gcc math.h file - thomas 2000-04-03 */
+#define M_PI 3.14159265358979323846
+#endif
+
+/* Radians per degree, a.k.a. PI / 180 */
+#define RADIANS_PER_DEGREE 0.0174532925199432957692
+
+/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0.  NAN definition from
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfNotNumberNANItems.asp
+ */
+#if defined(WIN32) && !defined(NAN)
+static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
+
+#define NAN (*(const float8 *) nan)
+#endif
+
+extern PGDLLIMPORT int extra_float_digits;
+
+/*
+ * Utility functions in float.c
+ */
+extern int	is_infinite(float8 val);
+extern float8 float8in_internal(char *num, char **endptr_p,
+				  const char *type_name, const char *orig_string);
+extern char *float8out_internal(float8 num);
+extern int	float4_cmp_internal(float4 a, float4 b);
+extern int	float8_cmp_internal(float8 a, float8 b);
+
+/*
+ * Routines to provide reasonably platform-independent handling of
+ * infinity and NaN
+ *
+ * We assume that isinf() and isnan() are available and work per spec.
+ * (On some platforms, we have to supply our own; see src/port.)  However,
+ * generating an Infinity or NaN in the first place is less well standardized;
+ * pre-C99 systems tend not to have C99's INFINITY and NAN macros.  We
+ * centralize our workarounds for this here.
+ */
+
+/*
+ * The funny placements of the two #pragmas is necessary because of a
+ * long lived bug in the Microsoft compilers.
+ * See http://support.microsoft.com/kb/120968/en-us for details
+ */
+#if (_MSC_VER >= 1800)
+#pragma warning(disable:4756)
+#endif
+static inline float
+get_float4_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float) INFINITY;
+#else
+#if (_MSC_VER >= 1800)
+#pragma warning(default:4756)
+#endif
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float8
+get_float8_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float8) INFINITY;
+#else
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float8) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float4
+get_float4_nan(void)
+{
+#ifdef NAN
+	/* C99 standard way */
+	return (float) NAN;
+#else
+	/* Assume we can get a NAN via zero divide */
+	return (float) (0.0 / 0.0);
+#endif
+}
+
+static inline float8
+get_float8_nan(void)
+{
+	/* (float8) NAN doesn't work on some NetBSD/MIPS releases */
+#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
+	/* C99 standard way */
+	return (float8) NAN;
+#else
+	/* Assume we can get a NAN via zero divide */
+	return (float8) (0.0 / 0.0);
+#endif
+}
+
+/*
+ * Checks to see if a float4/8 val has underflowed or overflowed
+ */
+
+static inline void
+check_float4_val(float4 val, bool inf_is_valid, bool zero_is_valid)
+{
+	if (isinf(val) && !(inf_is_valid))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if ((val) == 0.0 && !(zero_is_valid))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+static inline void
+check_float8_val(float8 val, bool inf_is_valid, bool zero_is_valid)
+{
+	if (isinf(val) && !(inf_is_valid))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if ((val) == 0.0 && !(zero_is_valid))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+/*
+ * Routines for operations with the checks above
+ *
+ * There isn't any way to check for underflow of addition/subtraction
+ * because numbers near the underflow value have already been rounded to
+ * the point where we can't detect that the two values were originally
+ * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
+ * 1.4013e-45.
+ */
+
+static inline float4
+float4_pl(float4 val1, float4 val2)
+{
+	float4		result;
+
+	result = val1 + val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_pl(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = val1 + val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mi(float4 val1, float4 val2)
+{
+	float4		result;
+
+	result = val1 - val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_mi(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = val1 - val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mul(float4 val1, float4 val2)
+{
+	float4		result;
+
+	result = val1 * val2;
+	check_float4_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0f || val2 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_mul(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = val1 * val2;
+	check_float8_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0 || val2 == 0.0);
+
+	return result;
+}
+
+static inline float4
+float4_div(float4 val1, float4 val2)
+{
+	float4		result;
+
+	if (val2 == 0.0f)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), val1 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_div(float8 val1, float8 val2)
+{
+	float8		result;
+
+	if (val2 == 0.0)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
+
+	return result;
+}
+
+/*
+ * Routines for NaN-aware comparisons
+ *
+ * We consider all NANs to be equal and larger than any non-NAN. This is
+ * somewhat arbitrary; the important thing is to have a consistent sort
+ * order.
+ */
+
+static inline bool
+float4_eq(float4 val1, float4 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float8_eq(float8 val1, float8 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float4_ne(float4 val1, float4 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float8_ne(float8 val1, float8 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float4_lt(float4 val1, float4 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float8_lt(float8 val1, float8 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float4_le(float4 val1, float4 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float8_le(float8 val1, float8 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float4_gt(float4 val1, float4 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float8_gt(float8 val1, float8 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float4_ge(float4 val1, float4 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline bool
+float8_ge(float8 val1, float8 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline float4
+float4_min(float4 val1, float4 val2)
+{
+	return float4_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_min(float8 val1, float8 val2)
+{
+	return float8_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float4
+float4_max(float4 val1, float4 val2)
+{
+	return float4_gt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_max(float8 val1, float8 val2)
+{
+	return float8_gt(val1, val2) ? val1 : val2;
+}
+
+#endif							/* FLOAT_H */
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index c94e17af5f..22c68f5b62 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -17,20 +17,21 @@
  *		and data types. There are still some more to do. - tgl 97/04/19
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEO_DECLS_H
 #define GEO_DECLS_H
 
 #include <math.h>
 
 #include "fmgr.h"
+#include "utils/float.h"
 
 /*--------------------------------------------------------------------
  * Useful floating point utilities and constants.
  *-------------------------------------------------------------------*/
 
 
 #define EPSILON					1.0E-06
 
 #ifdef EPSILON
 #define FPzero(A)				(fabs(A) <= EPSILON)
-- 
2.13.5 (Apple Git-94)

#17Emre Hasegeli
emre@hasegeli.com
In reply to: Kyotaro HORIGUCHI (#13)
Re: [PATCH] Improve geometric types

The patch replace pg_hypot with hypot in libc. The man page says
as follows.

man 3 hypot

If the result overflows, a range error occurs, and the functions return
HUGE_VAL, HUGE_VALF, or HUGE_VALL, respectively.

..

ERRORS
See math_error(7) for information on how to determine whether an error
has occurred when calling these functions.

The following errors can occur:

Range error: result overflow
errno is set to ERANGE. An overflow floating-point exception
(FE_OVERFLOW) is raised.

Range error: result underflow
An underflow floating-point exception (FE_UNDERFLOW) is raised.

These functions do not set errno for this case.

So, the code seems to need some amendments following to this
spec.

I included them on the latest version.

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

#18Kyotaro HORIGUCHI
horiguchi.kyotaro@lab.ntt.co.jp
In reply to: Emre Hasegeli (#8)
Re: [PATCH] Improve geometric types

Hello. Thank you for the new version.

0001: applies cleanly. regress passed.
this mainly refactoring geo_ops.c and replacing pg_hypot with hypot(3).
0002: applies cleanly. regress passed.
this just replaces float-ops macros into inline functions.
0003: applies cleanly. regress passed.
replaces double with float8 and bare arithmetic with defined functions.
0004: applies cleanly. regress passsed.
fix broken line-related functions.
I have some comments on this (later).

At Wed, 27 Sep 2017 17:44:52 +0200, Emre Hasegeli <emre@hasegeli.com> wrote in <CAE2gYzz2=335XEMHK-neNo=HgGskkPHQxUXkh8yDNsZAnCB5Bg@mail.gmail.com>

The new versions of the patches are attached addressing your comments.

C++ surely make just static functions inlined but I'm not sure C
compiler does that.

Thank you for your explanation. I marked the mentioned functions "inline".

Thanks.

So we should be safe to have a buffer with 26 byte length and 500
bytes will apparently too large and even 128 will be too loose in
most cases. So how about something like the following?

#define MINDOUBLEWIDTH 32

I left this part out for now. We can improve it separately.

Agreed. I found that psprintf does that with initial length of
128.

By the way, I found that MAXDOUBLEWIDTH has two inconsistent
definitions in formatting.c(500) and float.c(128). The definition
in new float.h is according to float.c and it seems better to be
untouched and it would be another issue.

At Wed, 27 Sep 2017 17:45:04 +0200, Emre Hasegeli <emre@hasegeli.com> wrote in <CAE2gYzz1KuT57vrO-XZk3KSqdpehAupJPLYu7AshuUwRF7MiMg@mail.gmail.com>

The patch replace pg_hypot with hypot in libc. The man page says
as follows.

...

I included them on the latest version.

# The commit message of 0001 says that "using C11 hypot()" but it
# is sine C99. I suppose we shold follow C99 at the time so I
# suggest rewrite it in the next version if any.

It seems bettern than expected. I confirmed that
pg_hypot(DBL_MAX, DBL_MAX) returned a value that is equivalent to
HUGE_VAL * HUGE_VAL on glibc, but I'm not sure the behavior on
other platforms is the same.

======
For other potential reviewers:

I found the origin of the function here.

/messages/by-id/4A90BD76.7070804@netspace.net.au
/messages/by-id/AANLkTim4cHELcGPf5w7Zd43_dQi_2RJ_b5_F_idSSbZI@mail.gmail.com

And the reason for pg_hypot is seen here.

/messages/by-id/407d949e0908222139t35ad3ad2q3e6b15646a27dd64@mail.gmail.com

I think the replacement is now acceptable according to the discussion.
======

And this should be the last comment of mine on the patch set.

In 0004, line_distance and line_interpt_internal seem
correct. Seemingly horizontal/vertical checks are redundant but
it is because unclearly defined EPSLON bahavior. lseg_perp seems
correct.

close_pl got a bug fix not only refactoring. I think it is
recommended to separate bugs and improvements, but I'm fine with
the current patch.

You added sanity check "A==0 && B==0" (in Ax + By + C) in
line_recv. I'm not sure the necessity of the check since it has
been checked in line_in but anyway the comparisons seem to be
typo(or thinko) of FPzero.

dist_pl is changed to take the smaller distance of both ends of
the segment. It seems absorbing error, so it might be better
taking the mean of the two distances. If you have a firm reason
for the change, it is better to be written there, or it might be
better left alone.

regards,

--
Kyotaro Horiguchi
NTT Open Source Software Center

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

#19Emre Hasegeli
emre@hasegeli.com
In reply to: Kyotaro HORIGUCHI (#18)
4 attachment(s)
Re: [PATCH] Improve geometric types

And this should be the last comment of mine on the patch set.

Thank you. The new versions of the patches are attached addressing
your comments.

By the way, I found that MAXDOUBLEWIDTH has two inconsistent
definitions in formatting.c(500) and float.c(128). The definition
in new float.h is according to float.c and it seems better to be
untouched and it would be another issue.

The last version of the patch don't move these declarations to the header file.

# The commit message of 0001 says that "using C11 hypot()" but it
# is sine C99. I suppose we shold follow C99 at the time so I
# suggest rewrite it in the next version if any.

Changed.

close_pl got a bug fix not only refactoring. I think it is
recommended to separate bugs and improvements, but I'm fine with
the current patch.

I split the refactoring to the first patch.

You added sanity check "A==0 && B==0" (in Ax + By + C) in
line_recv. I'm not sure the necessity of the check since it has
been checked in line_in but anyway the comparisons seem to be
typo(or thinko) of FPzero.

Tom Lane suggested [1]/messages/by-id/11053.1466362319@sss.pgh.pa.us this one. I now made it use FPzero().

dist_pl is changed to take the smaller distance of both ends of
the segment. It seems absorbing error, so it might be better
taking the mean of the two distances. If you have a firm reason
for the change, it is better to be written there, or it might be
better left alone.

I don't really, so I left that part out.

[1]: /messages/by-id/11053.1466362319@sss.pgh.pa.us

Attachments:

0001-geo-funcs-v04.patchapplication/octet-stream; name=0001-geo-funcs-v04.patchDownload
From 745e4f59d00cd6fd7ab304c72843dc81cae498b1 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 27 May 2017 11:27:18 -0400
Subject: [PATCH 1/4] geo-funcs-v04

Refactor geometric functions and operators code

Most of the geometric types were not using functions of each other's.
I believe the reason behind this is simpler types line point and line
being developed after more complicated ones.  This patch reduces duplicate
code and makes functions of different datatypes more compatible.  We can
do better than that, but it would require touching many more lines.
The changes can be summarised as:

* Re-use more functions to implement others
* Unify *_construct and *_interpt_internal functions to obtain
  pre-allocated memory
* Remove private functions from geo_decls.h
* Switch using C99 hypot() as the comment suggested
* Add comments to describe some functions
---
 src/backend/utils/adt/geo_ops.c | 1036 +++++++++++++++++----------------------
 src/include/utils/geo_decls.h   |   13 +-
 src/test/regress/regress.c      |   11 +-
 3 files changed, 466 insertions(+), 594 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 0348855b11..fe4155d0b2 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -31,60 +31,77 @@
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
+/* Routines for float8 */
+static inline float8 float8_slope(float8 x1, float8 x2, float8 y1, float8 y2);
+
+/* Routines for two-dimensional points */
+static inline void point_construct(Point *result, float8 x, float8 y);
+static inline void point_add_internal(Point *result, Point *pt1, Point *pt2);
+static inline void point_sub_internal(Point *result, Point *pt1, Point *pt2);
+static inline void point_mul_internal(Point *result, Point *pt1, Point *pt2);
+static inline void point_div_internal(Point *result, Point *pt1, Point *pt2);
+static inline bool point_eq_internal(Point *pt1, Point *pt2);
+static float8 point_dt(Point *pt1, Point *pt2);
 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);
+
+/* Routines for two-dimensional boxes */
+static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
+static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
+static double box_ar(BOX *box);
 static double box_ht(BOX *box);
 static double box_wd(BOX *box);
+
+/* Routines for two-dimensional circles */
 static double circle_ar(CIRCLE *circle);
-static CIRCLE *circle_copy(CIRCLE *circle);
-static LINE *line_construct_pm(Point *pt, double m);
-static void line_construct_pts(LINE *line, Point *pt1, Point *pt2);
-static bool lseg_intersect_internal(LSEG *l1, LSEG *l2);
-static double lseg_dt(LSEG *l1, LSEG *l2);
+
+/* Routines for two-dimensional lines */
+static inline void line_construct_pm(LINE *result, Point *pt, float8 m);
+static inline void line_construct_pts(LINE *result, Point *pt1, Point *pt2);
+static bool line_interpt_internal(Point *result, LINE *l1, LINE *l2);
+static inline float8 line_calculate_point(LINE *line, Point *pt);
+
+/* Routines for two-dimensional line segments */
+static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
+static bool lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line);
+static bool lseg_interpt_internal(Point *result, LSEG *l1, LSEG *l2);
+static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
+static float8 lseg_dt(LSEG *l1, LSEG *l2);
+static int	lseg_crossing(double x, double y, double px, double py);
 static bool on_ps_internal(Point *pt, LSEG *lseg);
+
+/* Routines for two-dimensional polygons */
 static void make_bound_box(POLYGON *poly);
+
+/* Unsorted */
 static bool plist_same(int npts, Point *p1, Point *p2);
-static Point *point_construct(double x, double y);
-static Point *point_copy(Point *pt);
 static double single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
 static void pair_decode(char *str, double *x, double *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
 static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
-static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
-static double box_ar(BOX *box);
-static void box_cn(Point *center, BOX *box);
-static Point *interpt_sl(LSEG *lseg, LINE *line);
-static bool has_interpt_sl(LSEG *lseg, LINE *line);
 static double dist_pl_internal(Point *pt, LINE *line);
 static double dist_ps_internal(Point *pt, LSEG *lseg);
-static Point *line_interpt_internal(LINE *l1, LINE *l2);
-static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
-static Point *lseg_interpt_internal(LSEG *l1, LSEG *l2);
 static double dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 
 /*
  * Delimiters for input and output strings.
  * LDELIM, RDELIM, and DELIM are left, right, and separator delimiters, respectively.
  * LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints.
  */
 
 #define LDELIM			'('
@@ -327,20 +344,44 @@ pair_count(char *s, char delim)
 	{
 		ndelim++;
 		s++;
 	}
 	return (ndelim % 2) ? ((ndelim + 1) / 2) : -1;
 }
 
 
 /***********************************************************************
  **
+ **		Routines for float8
+ **
+ ***********************************************************************/
+
+/*
+ * Return slope of two points
+ *
+ * This function accepts x and y coordinates separately to let it be used
+ * to calculate inverse slope.  To achieve that pass the values in
+ * (y1, y2, x2, x1) order.
+ */
+static inline float8
+float8_slope(float8 x1, float8 x2, float8 y1, float8 y2)
+{
+	if (FPeq(x1, x2))
+		return DBL_MAX;
+	if (FPeq(y1, y2))
+		return 0.0;
+	return (y1 - y2) / (x1 - x2);
+}
+
+
+/***********************************************************************
+ **
  **		Routines for two-dimensional boxes.
  **
  ***********************************************************************/
 
 /*----------------------------------------------------------
  * Formatting and conversion routines.
  *---------------------------------------------------------*/
 
 /*		box_in	-		convert a string to internal form.
  *
@@ -434,89 +475,61 @@ box_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, box->high.x);
 	pq_sendfloat8(&buf, box->high.y);
 	pq_sendfloat8(&buf, box->low.x);
 	pq_sendfloat8(&buf, box->low.y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*		box_construct	-		fill in a new box.
  */
-static BOX *
-box_construct(double x1, double x2, double y1, double y2)
+static inline void
+box_construct(BOX *result, Point *pt1, Point *pt2)
 {
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	return box_fill(result, x1, x2, y1, y2);
-}
-
-
-/*		box_fill		-		fill in a given box struct
- */
-static BOX *
-box_fill(BOX *result, double x1, double x2, double y1, double y2)
-{
-	if (x1 > x2)
+	if (pt1->x > pt2->x)
 	{
-		result->high.x = x1;
-		result->low.x = x2;
+		result->high.x = pt1->x;
+		result->low.x = pt2->x;
 	}
 	else
 	{
-		result->high.x = x2;
-		result->low.x = x1;
+		result->high.x = pt2->x;
+		result->low.x = pt1->x;
 	}
-	if (y1 > y2)
+	if (pt1->y > pt2->y)
 	{
-		result->high.y = y1;
-		result->low.y = y2;
+		result->high.y = pt1->y;
+		result->low.y = pt2->y;
 	}
 	else
 	{
-		result->high.y = y2;
-		result->low.y = y1;
+		result->high.y = pt2->y;
+		result->low.y = pt1->y;
 	}
-
-	return result;
-}
-
-
-/*		box_copy		-		copy a box
- */
-static BOX *
-box_copy(BOX *box)
-{
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	memcpy((char *) result, (char *) box, sizeof(BOX));
-
-	return result;
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for BOXes.
  *		<, >, <=, >=, and == are based on box area.
  *---------------------------------------------------------*/
 
 /*		box_same		-		are two boxes identical?
  */
 Datum
 box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPeq(box1->high.x, box2->high.x) &&
-				   FPeq(box1->low.x, box2->low.x) &&
-				   FPeq(box1->high.y, box2->high.y) &&
-				   FPeq(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(point_eq_internal(&box1->high, &box2->high) &&
+				   point_eq_internal(&box1->low, &box2->low));
 }
 
 /*		box_overlap		-		does box1 overlap box2?
  */
 Datum
 box_overlap(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
@@ -751,51 +764,51 @@ box_area(PG_FUNCTION_ARGS)
 
 
 /*		box_width		-		returns the width of the box
  *								  (horizontal magnitude).
  */
 Datum
 box_width(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.x - box->low.x);
+	PG_RETURN_FLOAT8(box_wd(box));
 }
 
 
 /*		box_height		-		returns the height of the box
  *								  (vertical magnitude).
  */
 Datum
 box_height(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.y - box->low.y);
+	PG_RETURN_FLOAT8(box_ht(box));
 }
 
 
 /*		box_distance	-		returns the distance between the
  *								  center points of two boxes.
  */
 Datum
 box_distance(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 	Point		a,
 				b;
 
 	box_cn(&a, box1);
 	box_cn(&b, box2);
 
-	PG_RETURN_FLOAT8(HYPOT(a.x - b.x, a.y - b.y));
+	PG_RETURN_FLOAT8(point_dt(&a, &b));
 }
 
 
 /*		box_center		-		returns the center point of the box.
  */
 Datum
 box_center(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *result = (Point *) palloc(sizeof(Point));
@@ -934,22 +947,22 @@ line_in(PG_FUNCTION_ARGS)
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
 							"line", str)));
 		if (FPzero(line->A) && FPzero(line->B))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: A and B cannot both be zero")));
 	}
 	else
 	{
-		path_decode(s, true, 2, &(lseg.p[0]), &isopen, NULL, "line", str);
-		if (FPeq(lseg.p[0].x, lseg.p[1].x) && FPeq(lseg.p[0].y, lseg.p[1].y))
+		path_decode(s, true, 2, &lseg.p[0], &isopen, NULL, "line", str);
+		if (point_eq_internal(&lseg.p[0], &lseg.p[1]))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: must be two distinct points")));
 		line_construct_pts(line, &lseg.p[0], &lseg.p[1]);
 	}
 
 	PG_RETURN_LINE_P(line);
 }
 
 
@@ -997,128 +1010,104 @@ line_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, line->C);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*----------------------------------------------------------
  *	Conversion routines from one line formula to internal.
  *		Internal form:	Ax+By+C=0
  *---------------------------------------------------------*/
 
-/* line_construct_pm()
- * point-slope
+/*
+ * Fill already-allocated LINE struct from the point and the slope
  */
-static LINE *
-line_construct_pm(Point *pt, double m)
+static inline void
+line_construct_pm(LINE *result, Point *pt, float8 m)
 {
-	LINE	   *result = (LINE *) palloc(sizeof(LINE));
-
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
 		result->A = -1;
 		result->B = 0;
 		result->C = pt->x;
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
 		result->C = pt->y - m * pt->x;
 	}
-
-	return result;
 }
 
+
 /*
  * Fill already-allocated LINE struct from two points on the line
  */
-static void
-line_construct_pts(LINE *line, Point *pt1, Point *pt2)
+static inline void
+line_construct_pts(LINE *result, Point *pt1, Point *pt2)
 {
-	if (FPeq(pt1->x, pt2->x))
-	{							/* vertical */
-		/* use "x = C" */
-		line->A = -1;
-		line->B = 0;
-		line->C = pt1->x;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is vertical\n");
-#endif
-	}
-	else if (FPeq(pt1->y, pt2->y))
-	{							/* horizontal */
-		/* use "y = C" */
-		line->A = 0;
-		line->B = -1;
-		line->C = pt1->y;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is horizontal\n");
-#endif
-	}
-	else
-	{
-		/* use "mx - y + yinter = 0" */
-		line->A = (pt2->y - pt1->y) / (pt2->x - pt1->x);
-		line->B = -1.0;
-		line->C = pt1->y - line->A * pt1->x;
-		/* on some platforms, the preceding expression tends to produce -0 */
-		if (line->C == 0.0)
-			line->C = 0.0;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is neither vertical nor horizontal (diffs x=%.*g, y=%.*g\n",
-			   DBL_DIG, (pt2->x - pt1->x), DBL_DIG, (pt2->y - pt1->y));
-#endif
-	}
+	float8		m;
+
+	m = float8_slope(pt1->x, pt2->x, pt1->y, pt2->y);
+	line_construct_pm(result, pt1, m);
 }
 
-/* line_construct_pp()
- * two points
+
+/*
+ * Construct a line from 2 points
  */
 Datum
 line_construct_pp(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 	LINE	   *result = (LINE *) palloc(sizeof(LINE));
 
 	line_construct_pts(result, pt1, pt2);
 	PG_RETURN_LINE_P(result);
 }
 
 
+/*
+ * Calculate the line equation for a point
+ *
+ * This returns the result of the line equation Ax + By + C.  The result
+ * needs to be 0 for the point to be on the line.
+ */
+static inline float8
+line_calculate_point(LINE *line, Point *pt)
+{
+	return line->A * pt->x + line->B * pt->y + line->C;
+}
+
+
 /*----------------------------------------------------------
  *	Relative position routines.
  *---------------------------------------------------------*/
 
 Datum
 line_intersect(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(!DatumGetBool(DirectFunctionCall2(line_parallel,
-													 LinePGetDatum(l1),
-													 LinePGetDatum(l2))));
+	PG_RETURN_BOOL(line_interpt_internal(NULL, l1, l2));
 }
 
 Datum
 line_parallel(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
-	if (FPzero(l1->B))
-		PG_RETURN_BOOL(FPzero(l2->B));
-
-	PG_RETURN_BOOL(FPeq(l2->A, l1->A * (l2->B / l1->B)));
+	PG_RETURN_BOOL(!line_interpt_internal(NULL, l1, l2));
 }
 
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
@@ -1172,96 +1161,94 @@ line_eq(PG_FUNCTION_ARGS)
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
-	Point	   *tmp;
+	Point		tmp;
 
-	if (!DatumGetBool(DirectFunctionCall2(line_parallel,
-										  LinePGetDatum(l1),
-										  LinePGetDatum(l2))))
+	if (line_interpt_internal(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
 		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
-	tmp = point_construct(0.0, l1->C);
-	result = dist_pl_internal(tmp, l2);
+	point_construct(&tmp, 0.0, l1->C);
+	result = dist_pl_internal(&tmp, l2);
 	PG_RETURN_FLOAT8(result);
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
-	result = line_interpt_internal(l1, l2);
+	result = (Point *) palloc(sizeof(Point));
 
-	if (result == NULL)
+	if (!line_interpt_internal(result, l1, l2))
 		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
 
 /*
  * Internal version of line_interpt
  *
- * returns a NULL pointer if no intersection point
+ * This returns true if two lines intersect (they do, if they are not
+ * parallel), false if they do not.  This also sets the intersection point
+ * to *result, if it is not NULL.
+ *
+ * NOTE: If the lines are identical then we will find they are parallel
+ * and report "no intersection".  This is a little weird, but since
+ * there's no *unique* intersection, maybe it's appropriate behavior.
  */
-static Point *
-line_interpt_internal(LINE *l1, LINE *l2)
+static bool
+line_interpt_internal(Point *result, LINE *l1, LINE *l2)
 {
-	Point	   *result;
 	double		x,
 				y;
 
-	/*
-	 * NOTE: if the lines are identical then we will find they are parallel
-	 * and report "no intersection".  This is a little weird, but since
-	 * there's no *unique* intersection, maybe it's appropriate behavior.
-	 */
-	if (DatumGetBool(DirectFunctionCall2(line_parallel,
-										 LinePGetDatum(l1),
-										 LinePGetDatum(l2))))
-		return NULL;
-
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
+		if (FPzero(l2->B))		/* l2 vertical? */
+			return false;
+
 		x = l1->C;
 		y = (l2->A * x + l2->C);
 	}
-	else if (FPzero(l2->B))		/* l2 vertical? */
-	{
-		x = l2->C;
-		y = (l1->A * x + l1->C);
-	}
 	else
 	{
-		x = (l1->C - l2->C) / (l2->A - l1->A);
+		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+			return false;
+
+		if (FPzero(l2->B))
+			x = l2->C;
+		else
+			x = (l1->C - l2->C) / (l2->A - l1->A);
 		y = (l1->A * x + l1->C);
 	}
-	result = point_construct(x, y);
+	if (result != NULL)
+		point_construct(result, x, y);
 
 #ifdef GEODEBUG
 	printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
 		   DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
 	printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
 #endif
 
-	return result;
+	return true;
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D paths (sequences of line segments, also
  **				called `polylines').
  **
  **				This is not a general package for geometric paths,
  **				which of course include polygons; the emphasis here
@@ -1609,21 +1596,21 @@ path_inter(PG_FUNCTION_ARGS)
 				jprev = j - 1;
 			else
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
-			if (lseg_intersect_internal(&seg1, &seg2))
+			if (lseg_interpt_internal(NULL, &seg1, &seg2))
 				PG_RETURN_BOOL(true);
 		}
 	}
 
 	/* if we dropped through, no two segs intersected */
 	PG_RETURN_BOOL(false);
 }
 
 /* path_distance()
  * This essentially does a cartesian product of the lsegs in the
@@ -1664,23 +1651,21 @@ path_distance(PG_FUNCTION_ARGS)
 			else
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
-			tmp = DatumGetFloat8(DirectFunctionCall2(lseg_distance,
-													 LsegPGetDatum(&seg1),
-													 LsegPGetDatum(&seg2)));
+			tmp = lseg_dt(&seg1, &seg2);
 			if (!have_min || tmp < min)
 			{
 				min = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	if (!have_min)
 		PG_RETURN_NULL();
@@ -1774,44 +1759,31 @@ point_send(PG_FUNCTION_ARGS)
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	StringInfoData buf;
 
 	pq_begintypsend(&buf);
 	pq_sendfloat8(&buf, pt->x);
 	pq_sendfloat8(&buf, pt->y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
-static Point *
-point_construct(double x, double y)
+/*
+ * Initialize a point
+ *
+ * This function is over-simple, but it is, at least, useful when the new
+ * point is calculated using the existing one.
+ */
+static inline void
+point_construct(Point *result, float8 x, float8 y)
 {
-	Point	   *result = (Point *) palloc(sizeof(Point));
-
 	result->x = x;
 	result->y = y;
-	return result;
-}
-
-
-static Point *
-point_copy(Point *pt)
-{
-	Point	   *result;
-
-	if (!PointerIsValid(pt))
-		return NULL;
-
-	result = (Point *) palloc(sizeof(Point));
-
-	result->x = pt->x;
-	result->y = pt->y;
-	return result;
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for Points.
  *		Since we do have a sense of coordinates being
  *		"equal" to a given accuracy (point_vert, point_horiz),
  *		the other ops must preserve that sense.  This means
  *		that results may, strictly speaking, be a lie (unless
  *		EPSILON = 0.0).
@@ -1870,71 +1842,74 @@ point_horiz(PG_FUNCTION_ARGS)
 
 	PG_RETURN_BOOL(FPeq(pt1->y, pt2->y));
 }
 
 Datum
 point_eq(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y));
+	PG_RETURN_BOOL(point_eq_internal(pt1, pt2));
 }
 
 Datum
 point_ne(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPne(pt1->x, pt2->x) || FPne(pt1->y, pt2->y));
+	PG_RETURN_BOOL(!point_eq_internal(pt1, pt2));
 }
 
+static inline bool
+point_eq_internal(Point *pt1, Point *pt2)
+{
+	return FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y);
+}
+
+
 /*----------------------------------------------------------
  *	"Arithmetic" operators on points.
  *---------------------------------------------------------*/
 
 Datum
 point_distance(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_FLOAT8(HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
+	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
-double
+static float8
 point_dt(Point *pt1, Point *pt2)
 {
+	float8		result;
+
+	result = hypot(pt1->x - pt2->x, pt1->y - pt2->y);
+
 #ifdef GEODEBUG
 	printf("point_dt- segment (%f,%f),(%f,%f) length is %f\n",
-		   pt1->x, pt1->y, pt2->x, pt2->y, HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
+		   pt1->x, pt1->y, pt2->x, pt2->y, result);
 #endif
-	return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
+
+	return result;
 }
 
 Datum
 point_slope(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_FLOAT8(point_sl(pt1, pt2));
-}
-
-
-double
-point_sl(Point *pt1, Point *pt2)
-{
-	return (FPeq(pt1->x, pt2->x)
-			? (double) DBL_MAX
-			: (pt1->y - pt2->y) / (pt1->x - pt2->x));
+	PG_RETURN_FLOAT8(float8_slope(pt1->x, pt2->x, pt1->y, pt2->y));
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D line segments.
  **
  ***********************************************************************/
 
 /*----------------------------------------------------------
@@ -1946,31 +1921,31 @@ point_sl(Point *pt1, Point *pt2)
  *		(old form)		"(x1, y1, x2, y2)"
  *---------------------------------------------------------*/
 
 Datum
 lseg_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	LSEG	   *lseg = (LSEG *) palloc(sizeof(LSEG));
 	bool		isopen;
 
-	path_decode(str, true, 2, &(lseg->p[0]), &isopen, NULL, "lseg", str);
+	path_decode(str, true, 2, &lseg->p[0], &isopen, NULL, "lseg", str);
 	PG_RETURN_LSEG_P(lseg);
 }
 
 
 Datum
 lseg_out(PG_FUNCTION_ARGS)
 {
 	LSEG	   *ls = PG_GETARG_LSEG_P(0);
 
-	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, (Point *) &(ls->p[0])));
+	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, &ls->p[0]));
 }
 
 /*
  *		lseg_recv			- converts external binary format to lseg
  */
 Datum
 lseg_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LSEG	   *lseg;
@@ -2015,21 +1990,21 @@ lseg_construct(PG_FUNCTION_ARGS)
 
 	result->p[0].x = pt1->x;
 	result->p[0].y = pt1->y;
 	result->p[1].x = pt2->x;
 	result->p[1].y = pt2->y;
 
 	PG_RETURN_LSEG_P(result);
 }
 
 /* like lseg_construct, but assume space already allocated */
-static void
+static inline void
 statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2)
 {
 	lseg->p[0].x = pt1->x;
 	lseg->p[0].y = pt1->y;
 	lseg->p[1].x = pt2->x;
 	lseg->p[1].y = pt2->y;
 }
 
 Datum
 lseg_length(PG_FUNCTION_ARGS)
@@ -2046,69 +2021,57 @@ lseg_length(PG_FUNCTION_ARGS)
 /*
  **  find intersection of the two lines, and see if it falls on
  **  both segments.
  */
 Datum
 lseg_intersect(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(lseg_intersect_internal(l1, l2));
+	PG_RETURN_BOOL(lseg_interpt_internal(NULL, l1, l2));
 }
 
-static bool
-lseg_intersect_internal(LSEG *l1, LSEG *l2)
-{
-	LINE		ln;
-	Point	   *interpt;
-	bool		retval;
-
-	line_construct_pts(&ln, &l2->p[0], &l2->p[1]);
-	interpt = interpt_sl(l1, &ln);
-
-	if (interpt != NULL && on_ps_internal(interpt, l2))
-		retval = true;			/* interpt on l1 and l2 */
-	else
-		retval = false;
-	return retval;
-}
 
 Datum
 lseg_parallel(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
+	float8		m1,
+				m2;
 
-	PG_RETURN_BOOL(FPeq(point_sl(&l1->p[0], &l1->p[1]),
-						point_sl(&l2->p[0], &l2->p[1])));
+	m1 = float8_slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y);
+	m2 = float8_slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y);
+
+	PG_RETURN_BOOL(FPeq(m1, m2));
 }
 
 /* lseg_perp()
  * Determine if two line segments are perpendicular.
  *
  * This code did not get the correct answer for
  *	'((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg
  * So, modified it to check explicitly for slope of vertical line
- *	returned by point_sl() and the results seem better.
+ *	returned by float8_slope() and the results seem better.
  * - thomas 1998-01-31
  */
 Datum
 lseg_perp(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	double		m1,
 				m2;
 
-	m1 = point_sl(&(l1->p[0]), &(l1->p[1]));
-	m2 = point_sl(&(l2->p[0]), &(l2->p[1]));
+	m1 = float8_slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y);
+	m2 = float8_slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y);
 
 #ifdef GEODEBUG
 	printf("lseg_perp- slopes are %g and %g\n", m1, m2);
 #endif
 	if (FPzero(m1))
 		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
 	else if (FPzero(m2))
 		PG_RETURN_BOOL(FPeq(m1, DBL_MAX));
 
 	PG_RETURN_BOOL(FPeq(m1 / m2, -1.0));
@@ -2130,36 +2093,32 @@ lseg_horizontal(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(FPeq(lseg->p[0].y, lseg->p[1].y));
 }
 
 
 Datum
 lseg_eq(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPeq(l1->p[0].x, l2->p[0].x) &&
-				   FPeq(l1->p[0].y, l2->p[0].y) &&
-				   FPeq(l1->p[1].x, l2->p[1].x) &&
-				   FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(point_eq_internal(&l1->p[0], &l2->p[0]) &&
+				   point_eq_internal(&l1->p[1], &l2->p[1]));
 }
 
 Datum
 lseg_ne(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(!FPeq(l1->p[0].x, l2->p[0].x) ||
-				   !FPeq(l1->p[0].y, l2->p[0].y) ||
-				   !FPeq(l1->p[1].x, l2->p[1].x) ||
-				   !FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(!point_eq_internal(&l1->p[0], &l2->p[0]) ||
+				   !point_eq_internal(&l1->p[1], &l2->p[1]));
 }
 
 Datum
 lseg_lt(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_BOOL(FPlt(point_dt(&l1->p[0], &l1->p[1]),
 						point_dt(&l2->p[0], &l2->p[1])));
@@ -2218,21 +2177,21 @@ lseg_distance(PG_FUNCTION_ARGS)
  * Distance between two line segments.
  * Must check both sets of endpoints to ensure minimum distance is found.
  * - thomas 1998-02-01
  */
 static double
 lseg_dt(LSEG *l1, LSEG *l2)
 {
 	double		result,
 				d;
 
-	if (lseg_intersect_internal(l1, l2))
+	if (lseg_interpt_internal(NULL, l1, l2))
 		return 0.0;
 
 	d = dist_ps_internal(&l1->p[0], l2);
 	result = d;
 	d = dist_ps_internal(&l1->p[1], l2);
 	result = Min(result, d);
 	d = dist_ps_internal(&l2->p[0], l1);
 	result = Min(result, d);
 	d = dist_ps_internal(&l2->p[1], l1);
 	result = Min(result, d);
@@ -2248,82 +2207,86 @@ lseg_center(PG_FUNCTION_ARGS)
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
 	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
 
 	PG_RETURN_POINT_P(result);
 }
 
-static Point *
-lseg_interpt_internal(LSEG *l1, LSEG *l2)
+static bool
+lseg_interpt_internal(Point *result, LSEG *l1, LSEG *l2)
 {
-	Point	   *result;
+	Point		interpt;
 	LINE		tmp1,
 				tmp2;
 
 	/*
 	 * Find the intersection of the appropriate lines, if any.
 	 */
 	line_construct_pts(&tmp1, &l1->p[0], &l1->p[1]);
 	line_construct_pts(&tmp2, &l2->p[0], &l2->p[1]);
-	result = line_interpt_internal(&tmp1, &tmp2);
-	if (!PointerIsValid(result))
-		return NULL;
+	if (!line_interpt_internal(&interpt, &tmp1, &tmp2))
+		return false;
 
 	/*
 	 * If the line intersection point isn't within l1 (or equivalently l2),
 	 * there is no valid segment intersection point at all.
 	 */
-	if (!on_ps_internal(result, l1) ||
-		!on_ps_internal(result, l2))
-	{
-		pfree(result);
-		return NULL;
-	}
+	if (!on_ps_internal(&interpt, l1) ||
+		!on_ps_internal(&interpt, l2))
+		return false;
+
+	if (result == NULL)
+		return true;
 
 	/*
 	 * If there is an intersection, then check explicitly for matching
 	 * endpoints since there may be rounding effects with annoying lsb
 	 * residue. - tgl 1997-07-09
 	 */
 	if ((FPeq(l1->p[0].x, l2->p[0].x) && FPeq(l1->p[0].y, l2->p[0].y)) ||
 		(FPeq(l1->p[0].x, l2->p[1].x) && FPeq(l1->p[0].y, l2->p[1].y)))
 	{
 		result->x = l1->p[0].x;
 		result->y = l1->p[0].y;
 	}
 	else if ((FPeq(l1->p[1].x, l2->p[0].x) && FPeq(l1->p[1].y, l2->p[0].y)) ||
 			 (FPeq(l1->p[1].x, l2->p[1].x) && FPeq(l1->p[1].y, l2->p[1].y)))
 	{
 		result->x = l1->p[1].x;
 		result->y = l1->p[1].y;
 	}
+	else
+	{
+		result->x = interpt.x;
+		result->y = interpt.y;
+	}
 
-	return result;
+	return true;
 }
 
 /* lseg_interpt -
  *		Find the intersection point of two segments (if any).
  */
 Datum
 lseg_interpt(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
-	result = lseg_interpt_internal(l1, l2);
-	if (!PointerIsValid(result))
-		PG_RETURN_NULL();
+	result = (Point *) palloc(sizeof(Point));
 
+	if (!lseg_interpt_internal(result, l1, l2))
+		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
 
 /***********************************************************************
  **
  **		Routines for position comparisons of differently-typed
  **				2D objects.
  **
  ***********************************************************************/
 
@@ -2340,75 +2303,70 @@ dist_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
 	PG_RETURN_FLOAT8(dist_pl_internal(pt, line));
 }
 
 static double
 dist_pl_internal(Point *pt, LINE *line)
 {
-	return fabs((line->A * pt->x + line->B * pt->y + line->C) /
-				HYPOT(line->A, line->B));
+	return fabs(line_calculate_point(line, pt) /
+				hypot(line->A, line->B));
 }
 
 /*
  * Distance from a point to a lseg
  */
 Datum
 dist_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_FLOAT8(dist_ps_internal(pt, lseg));
 }
 
 static double
 dist_ps_internal(Point *pt, LSEG *lseg)
 {
 	double		m;				/* slope of perp. */
-	LINE	   *ln;
 	double		result,
 				tmpdist;
-	Point	   *ip;
+	Point		interpt;
+	LINE		ln;
 
 	/*
 	 * Construct a line perpendicular to the input segment and through the
 	 * input point
 	 */
-	if (lseg->p[1].x == lseg->p[0].x)
-		m = 0;
-	else if (lseg->p[1].y == lseg->p[0].y)
-		m = (double) DBL_MAX;	/* slope is infinite */
-	else
-		m = (lseg->p[0].x - lseg->p[1].x) / (lseg->p[1].y - lseg->p[0].y);
-	ln = line_construct_pm(pt, m);
+	m = float8_slope(lseg->p[0].y, lseg->p[1].y, lseg->p[1].x, lseg->p[0].x);
+	line_construct_pm(&ln, pt, m);
 
 #ifdef GEODEBUG
 	printf("dist_ps- line is A=%g B=%g C=%g from (point) slope (%f,%f) %g\n",
 		   ln->A, ln->B, ln->C, pt->x, pt->y, m);
 #endif
 
 	/*
 	 * Calculate distance to the line segment or to the nearest endpoint of
 	 * the segment.
 	 */
 
 	/* intersection is on the line segment? */
-	if ((ip = interpt_sl(lseg, ln)) != NULL)
+	if (lseg_interpt_line_internal(&interpt, lseg, &ln))
 	{
 		/* yes, so use distance to the intersection point */
-		result = point_dt(pt, ip);
+		result = point_dt(pt, &interpt);
 #ifdef GEODEBUG
 		printf("dist_ps- distance is %f to intersection point is (%f,%f)\n",
-			   result, ip->x, ip->y);
+			   result, tmp.x, tmp.y);
 #endif
 	}
 	else
 	{
 		/* no, so use distance to the nearer endpoint */
 		result = point_dt(pt, &lseg->p[0]);
 		tmpdist = point_dt(pt, &lseg->p[1]);
 		if (tmpdist < result)
 			result = tmpdist;
 	}
@@ -2496,21 +2454,21 @@ dist_pb(PG_FUNCTION_ARGS)
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	float8		result,
 				d2;
 
-	if (has_interpt_sl(lseg, line))
+	if (lseg_interpt_line_internal(NULL, lseg, line))
 		result = 0.0;
 	else
 	{
 		result = dist_pl_internal(&lseg->p[0], line);
 		d2 = dist_pl_internal(&lseg->p[1], line);
 		/* XXX shouldn't we take the min not max? */
 		if (d2 > result)
 			result = d2;
 	}
 
@@ -2649,284 +2607,258 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
  *				Intersection point of objects.
  *				We choose to ignore the "point" of intersection between
  *				  lines and boxes, since there are typically two.
  *-------------------------------------------------------------------*/
 
-/* Get intersection point of lseg and line; returns NULL if no intersection */
-static Point *
-interpt_sl(LSEG *lseg, LINE *line)
+/*
+ * Check if the line segment intersects with the line
+ *
+ * It sets the intersection point to *result, if it is not NULL.
+ */
+static bool
+lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line)
 {
+	Point		interpt;
 	LINE		tmp;
-	Point	   *p;
 
 	line_construct_pts(&tmp, &lseg->p[0], &lseg->p[1]);
-	p = line_interpt_internal(&tmp, line);
 #ifdef GEODEBUG
-	printf("interpt_sl- segment is (%.*g %.*g) (%.*g %.*g)\n",
+	printf("lseg_interpt_line- segment is (%.*g %.*g) (%.*g %.*g)\n",
 		   DBL_DIG, lseg->p[0].x, DBL_DIG, lseg->p[0].y, DBL_DIG, lseg->p[1].x, DBL_DIG, lseg->p[1].y);
-	printf("interpt_sl- segment becomes line A=%.*g B=%.*g C=%.*g\n",
+	printf("lseg_interpt_line_- segment becomes line A=%.*g B=%.*g C=%.*g\n",
 		   DBL_DIG, tmp.A, DBL_DIG, tmp.B, DBL_DIG, tmp.C);
 #endif
-	if (PointerIsValid(p))
+	if (line_interpt_internal(&interpt, &tmp, line))
 	{
 #ifdef GEODEBUG
-		printf("interpt_sl- intersection point is (%.*g %.*g)\n", DBL_DIG, p->x, DBL_DIG, p->y);
+		printf("lseg_interpt_line- intersection point is (%.*g %.*g)\n", DBL_DIG, p->x, DBL_DIG, p->y);
 #endif
-		if (on_ps_internal(p, lseg))
+		if (on_ps_internal(&interpt, lseg))
 		{
 #ifdef GEODEBUG
-			printf("interpt_sl- intersection point is on segment\n");
+			printf("lseg_interpt_line- intersection point is on segment\n");
 #endif
+			if (result != NULL)
+				*result = interpt;
+			return true;
 		}
-		else
-			p = NULL;
 	}
 
-	return p;
-}
-
-/* variant: just indicate if intersection point exists */
-static bool
-has_interpt_sl(LSEG *lseg, LINE *line)
-{
-	Point	   *tmp;
-
-	tmp = interpt_sl(lseg, line);
-	if (tmp)
-		return true;
 	return false;
 }
 
+
 /*---------------------------------------------------------------------
  *		close_
  *				Point of closest proximity between objects.
  *-------------------------------------------------------------------*/
 
 /* close_pl -
  *		The intersection point of a perpendicular of the line
  *		through the point.
  */
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
-	LINE	   *tmp;
-	double		invm;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (FPzero(line->B))		/* vertical? */
+		point_construct(result, line->C, pt->y);
+	else if (FPzero(line->A))	/* horizontal? */
+		point_construct(result, pt->x, line->C);
+	else
 	{
-		result->x = line->C;
-		result->y = pt->y;
-		PG_RETURN_POINT_P(result);
-	}
-	if (FPzero(line->A))		/* horizontal? */
-	{
-		result->x = pt->x;
-		result->y = line->C;
-		PG_RETURN_POINT_P(result);
-	}
-	/* drop a perpendicular and find the intersection point */
+		LINE		tmp;
+
+		/*
+		 * Drop a perpendicular and find the intersection point
+		 *
+		 * We need to invert the slope to get the perpendicular.
+		 */
+		line_construct_pm(&tmp, pt, line->B / line->A);
+		line_interpt_internal(result, &tmp, line);
+	}
 
-	/* invert and flip the sign on the slope to get a perpendicular */
-	invm = line->B / line->A;
-	tmp = line_construct_pm(pt, invm);
-	result = line_interpt_internal(tmp, line);
-	Assert(result != NULL);
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_ps()
  * Closest point on line segment to specified point.
  * Take the closest endpoint if the point is left, right,
  *	above, or below the segment, otherwise find the intersection
  *	point of the segment and its perpendicular through the point.
  *
  * Some tricky code here, relying on boolean expressions
  *	evaluating to only zero or one to use as an array index.
  *		bug fixes by gthaker@atl.lmco.com; May 1, 1998
  */
 Datum
 close_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
-	LINE	   *tmp;
+	Point	   *result;
 	double		invm;
 	int			xh,
 				yh;
+	LINE		tmp;
+
+	result = (Point *) palloc(sizeof(Point));
 
 #ifdef GEODEBUG
 	printf("close_sp:pt->x %f pt->y %f\nlseg(0).x %f lseg(0).y %f  lseg(1).x %f lseg(1).y %f\n",
 		   pt->x, pt->y, lseg->p[0].x, lseg->p[0].y,
 		   lseg->p[1].x, lseg->p[1].y);
 #endif
 
 	/* xh (or yh) is the index of upper x( or y) end point of lseg */
 	/* !xh (or !yh) is the index of lower x( or y) end point of lseg */
 	xh = lseg->p[0].x < lseg->p[1].x;
 	yh = lseg->p[0].y < lseg->p[1].y;
 
 	if (FPeq(lseg->p[0].x, lseg->p[1].x))	/* vertical? */
 	{
 #ifdef GEODEBUG
 		printf("close_ps- segment is vertical\n");
 #endif
 		/* first check if point is below or above the entire lseg. */
 		if (pt->y < lseg->p[!yh].y)
-			result = point_copy(&lseg->p[!yh]); /* below the lseg */
+			*result = lseg->p[!yh]; /* below the lseg */
 		else if (pt->y > lseg->p[yh].y)
-			result = point_copy(&lseg->p[yh]);	/* above the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
+			*result = lseg->p[yh];	/* above the lseg */
+		else
+			/* point lines along (to left or right) of the vertical lseg. */
+			point_construct(result, lseg->p[0].x, pt->y);
 
-		/* point lines along (to left or right) of the vertical lseg. */
-
-		result = (Point *) palloc(sizeof(Point));
-		result->x = lseg->p[0].x;
-		result->y = pt->y;
 		PG_RETURN_POINT_P(result);
 	}
 	else if (FPeq(lseg->p[0].y, lseg->p[1].y))	/* horizontal? */
 	{
 #ifdef GEODEBUG
 		printf("close_ps- segment is horizontal\n");
 #endif
 		/* first check if point is left or right of the entire lseg. */
 		if (pt->x < lseg->p[!xh].x)
-			result = point_copy(&lseg->p[!xh]); /* left of the lseg */
+			*result = lseg->p[!xh]; /* left of the lseg */
 		else if (pt->x > lseg->p[xh].x)
-			result = point_copy(&lseg->p[xh]);	/* right of the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
+			*result = lseg->p[xh];	/* right of the lseg */
+		else
+			/* point lines along (at top or below) the horiz. lseg. */
+			point_construct(result, pt->x, lseg->p[0].y);
 
-		/* point lines along (at top or below) the horiz. lseg. */
-		result = (Point *) palloc(sizeof(Point));
-		result->x = pt->x;
-		result->y = lseg->p[0].y;
 		PG_RETURN_POINT_P(result);
 	}
 
 	/*
 	 * vert. and horiz. cases are down, now check if the closest point is one
 	 * of the end points or someplace on the lseg.
 	 */
 
-	invm = -1.0 / point_sl(&(lseg->p[0]), &(lseg->p[1]));
-	tmp = line_construct_pm(&lseg->p[!yh], invm);	/* lower edge of the
+	invm = float8_slope(lseg->p[0].y, lseg->p[1].y, lseg->p[1].x, lseg->p[0].x);
+	line_construct_pm(&tmp, &lseg->p[!yh], invm);	/* lower edge of the
 													 * "band" */
-	if (pt->y < (tmp->A * pt->x + tmp->C))
+	if (pt->y < (tmp.A * pt->x + tmp.C))
 	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[!yh]); /* below the lseg, take lower end
-											 * pt */
+		*result = lseg->p[!yh]; /* below the lseg, take lower end pt */
 #ifdef GEODEBUG
 		printf("close_ps below: tmp A %f  B %f   C %f\n",
 			   tmp->A, tmp->B, tmp->C);
 #endif
 		PG_RETURN_POINT_P(result);
 	}
-	tmp = line_construct_pm(&lseg->p[yh], invm);	/* upper edge of the
+	line_construct_pm(&tmp, &lseg->p[yh], invm);	/* upper edge of the
 													 * "band" */
-	if (pt->y > (tmp->A * pt->x + tmp->C))
+	if (pt->y > (tmp.A * pt->x + tmp.C))
 	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[yh]);	/* above the lseg, take higher end
-											 * pt */
+		*result = lseg->p[yh];	/* above the lseg, take higher end pt */
 #ifdef GEODEBUG
 		printf("close_ps above: tmp A %f  B %f   C %f\n",
 			   tmp->A, tmp->B, tmp->C);
 #endif
 		PG_RETURN_POINT_P(result);
 	}
 
 	/*
 	 * at this point the "normal" from point will hit lseg. The closest point
 	 * will be somewhere on the lseg
 	 */
-	tmp = line_construct_pm(pt, invm);
+	line_construct_pm(&tmp, pt, invm);
 #ifdef GEODEBUG
 	printf("close_ps- tmp A %f  B %f   C %f\n",
 		   tmp->A, tmp->B, tmp->C);
 #endif
-	result = interpt_sl(lseg, tmp);
 
 	/*
 	 * ordinarily we should always find an intersection point, but that could
 	 * fail in the presence of NaN coordinates, and perhaps even from simple
 	 * roundoff issues.  Return a SQL NULL if so.
 	 */
-	if (result == NULL)
+	if (!lseg_interpt_line_internal(result, lseg, &tmp))
 		PG_RETURN_NULL();
 
 #ifdef GEODEBUG
 	printf("close_ps- result.x %f  result.y %f\n", result->x, result->y);
 #endif
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_lseg()
  * Closest point to l1 on l2.
  */
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
-	Point		point;
-	double		dist;
-	double		d;
+	Point	   *result;
+	double		dist,
+				dist0,
+				dist1;
 
-	d = dist_ps_internal(&l1->p[0], l2);
-	dist = d;
-	memcpy(&point, &l1->p[0], sizeof(Point));
-
-	if ((d = dist_ps_internal(&l1->p[1], l2)) < dist)
-	{
-		dist = d;
-		memcpy(&point, &l1->p[1], sizeof(Point));
-	}
+	dist0 = dist_ps_internal(&l1->p[0], l2);
+	dist1 = dist_ps_internal(&l1->p[1], l2);
+	dist = Min(dist0, dist1);
 
 	if (dist_ps_internal(&l2->p[0], l1) < dist)
 	{
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(&l2->p[0]),
 													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
+													PointPGetDatum(result),
 													LsegPGetDatum(l2)));
 	}
-
-	if (dist_ps_internal(&l2->p[1], l1) < dist)
+	else if (dist_ps_internal(&l2->p[1], l1) < dist)
 	{
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(&l2->p[1]),
 													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
+													PointPGetDatum(result),
 													LsegPGetDatum(l2)));
 	}
-
-	if (result == NULL)
-		result = point_copy(&point);
+	else
+	{
+		result = (Point *) palloc(sizeof(Point));
+		*result = l1->p[dist == dist0 ? 0 : 1];
+	}
 
 	PG_RETURN_POINT_P(result);
 }
 
 /* close_pb()
  * Closest point on or in box to specified point.
  */
 Datum
 close_pb(PG_FUNCTION_ARGS)
 {
@@ -2989,30 +2921,31 @@ close_pb(PG_FUNCTION_ARGS)
 Datum
 close_sl(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 	float8		d1,
 				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
+	result = (Point *) palloc(sizeof(Point));
+
+	if (lseg_interpt_line_internal(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = dist_pl_internal(&lseg->p[0], line);
 	d2 = dist_pl_internal(&lseg->p[1], line);
 	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
+		*result = lseg->p[0];
 	else
-		result = point_copy(&lseg->p[1]);
+		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
 
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_sl\" not implemented")));
 
 	PG_RETURN_NULL();
 }
@@ -3022,30 +2955,31 @@ close_sl(PG_FUNCTION_ARGS)
  */
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 	float8		d1,
 				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
+	result = (Point *) palloc(sizeof(Point));
+
+	if (lseg_interpt_line_internal(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = dist_pl_internal(&lseg->p[0], line);
 	d2 = dist_pl_internal(&lseg->p[1], line);
 	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
+		*result = lseg->p[0];
 	else
-		result = point_copy(&lseg->p[1]);
+		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 }
 
 /* close_sb()
  * Closest point on or in box to line segment.
  */
 Datum
 close_sb(PG_FUNCTION_ARGS)
 {
@@ -3126,21 +3060,21 @@ close_lb(PG_FUNCTION_ARGS)
 
 /* on_pl -
  *		Does the point satisfy the equation?
  */
 Datum
 on_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(FPzero(line->A * pt->x + line->B * pt->y + line->C));
+	PG_RETURN_BOOL(FPzero(line_calculate_point(line, pt)));
 }
 
 
 /* on_ps -
  *		Determine colinearity by detecting a triangle inequality.
  * This algorithm seems to behave nicely even with lsb residues - tgl 1997-07-09
  */
 Datum
 on_ps(PG_FUNCTION_ARGS)
 {
@@ -3150,40 +3084,49 @@ on_ps(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(on_ps_internal(pt, lseg));
 }
 
 static bool
 on_ps_internal(Point *pt, LSEG *lseg)
 {
 	return FPeq(point_dt(pt, &lseg->p[0]) + point_dt(pt, &lseg->p[1]),
 				point_dt(&lseg->p[0], &lseg->p[1]));
 }
 
+
+/*
+ * Check whether the point is in the box or on its border
+ */
 Datum
 on_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_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);
 }
 
+
+/*
+ * Commutator of on_pb()
+ */
 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.
  * (uses same algorithm as for point intersecting segment - tgl 1997-07-09)
  *		If closed, we use the old O(n) ray method for point-in-polygon.
  *				The ray is horizontal, from pt out to the right.
  *				Each segment that crosses the ray counts as an
  *				intersection; note that an endpoint or edge may touch
  *				but not cross.
  *				(we can do p-in-p in lg(n), but it takes preprocessing)
@@ -3211,34 +3154,46 @@ on_ppath(PG_FUNCTION_ARGS)
 				PG_RETURN_BOOL(true);
 			a = b;
 		}
 		PG_RETURN_BOOL(false);
 	}
 
 	/*-- CLOSED --*/
 	PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
 }
 
+
+/*
+ * Check whether the line segment is on the line or close enough
+ *
+ * It is, if both of its points are on the line or close enough.
+ */
 Datum
 on_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
 	PG_RETURN_BOOL(DatumGetBool(DirectFunctionCall2(on_pl,
 													PointPGetDatum(&lseg->p[0]),
 													LinePGetDatum(line))) &&
 				   DatumGetBool(DirectFunctionCall2(on_pl,
 													PointPGetDatum(&lseg->p[1]),
 													LinePGetDatum(line))));
 }
 
+
+/*
+ * Check whether the line segment is in the box or on its border
+ *
+ * It is, if both of its points are in the box or on its border.
+ */
 Datum
 on_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 
 	PG_RETURN_BOOL(DatumGetBool(DirectFunctionCall2(on_pb,
 													PointPGetDatum(&lseg->p[0]),
 													BoxPGetDatum(box))) &&
 				   DatumGetBool(DirectFunctionCall2(on_pb,
@@ -3250,21 +3205,21 @@ on_sb(PG_FUNCTION_ARGS)
  *		inter_
  *				Whether one object intersects another.
  *-------------------------------------------------------------------*/
 
 Datum
 inter_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(has_interpt_sl(lseg, line));
+	PG_RETURN_BOOL(lseg_interpt_line_internal(NULL, lseg, line));
 }
 
 /* inter_sb()
  * Do line segment and box intersect?
  *
  * Segment completely inside box counts as intersection.
  * If you want only segments crossing box boundaries,
  *	try converting box to path first.
  *
  * Optimize for non-intersection by checking for box intersection first.
@@ -3294,35 +3249,35 @@ inter_sb(PG_FUNCTION_ARGS)
 										 BoxPGetDatum(box))) ||
 		DatumGetBool(DirectFunctionCall2(on_pb,
 										 PointPGetDatum(&lseg->p[1]),
 										 BoxPGetDatum(box))))
 		PG_RETURN_BOOL(true);
 
 	/* pairwise check lseg intersections */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
+	if (lseg_interpt_internal(NULL, &bseg, lseg))
 		PG_RETURN_BOOL(true);
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
+	if (lseg_interpt_internal(NULL, &bseg, lseg))
 		PG_RETURN_BOOL(true);
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
+	if (lseg_interpt_internal(NULL, &bseg, lseg))
 		PG_RETURN_BOOL(true);
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
+	if (lseg_interpt_internal(NULL, &bseg, lseg))
 		PG_RETURN_BOOL(true);
 
 	/* if we dropped through, no two segs intersected */
 	PG_RETURN_BOOL(false);
 }
 
 /* inter_lb()
  * Do line and box intersect?
  */
 Datum
@@ -3333,36 +3288,36 @@ inter_lb(PG_FUNCTION_ARGS)
 	LSEG		bseg;
 	Point		p1,
 				p2;
 
 	/* pairwise check lseg intersections */
 	p1.x = box->low.x;
 	p1.y = box->low.y;
 	p2.x = box->low.x;
 	p2.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line_internal(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->high.x;
 	p1.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line_internal(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p2.x = box->high.x;
 	p2.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line_internal(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->low.x;
 	p1.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line_internal(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 
 	/* if we dropped through, no intersection */
 	PG_RETURN_BOOL(false);
 }
 
 /*------------------------------------------------------------------
  * The following routines define a data type and operator class for
  * POLYGONS .... Part of which (the polygon's bounding box) is built on
  * top of the BOX data type.
@@ -3370,42 +3325,37 @@ inter_lb(PG_FUNCTION_ARGS)
  * make_bound_box - create the bounding box for the input polygon
  *------------------------------------------------------------------*/
 
 /*---------------------------------------------------------------------
  * Make the smallest bounding box for the given polygon.
  *---------------------------------------------------------------------*/
 static void
 make_bound_box(POLYGON *poly)
 {
 	int			i;
-	double		x1,
-				y1,
-				x2,
-				y2;
+	BOX		   *boundbox = &poly->boundbox;
 
 	if (poly->npts > 0)
 	{
-		x2 = x1 = poly->p[0].x;
-		y2 = y1 = poly->p[0].y;
+		boundbox->low.x = boundbox->high.x = poly->p[0].x;
+		boundbox->low.y = boundbox->high.y = poly->p[0].y;
 		for (i = 1; i < poly->npts; i++)
 		{
-			if (poly->p[i].x < x1)
-				x1 = poly->p[i].x;
-			if (poly->p[i].x > x2)
-				x2 = poly->p[i].x;
-			if (poly->p[i].y < y1)
-				y1 = poly->p[i].y;
-			if (poly->p[i].y > y2)
-				y2 = poly->p[i].y;
+			if (poly->p[i].x < boundbox->low.x)
+				boundbox->low.x = poly->p[i].x;
+			if (poly->p[i].x > boundbox->high.x)
+				boundbox->high.x = poly->p[i].x;
+			if (poly->p[i].y < boundbox->low.y)
+				boundbox->low.y = poly->p[i].y;
+			if (poly->p[i].y > boundbox->high.y)
+				boundbox->high.y = poly->p[i].y;
 		}
-
-		box_fill(&(poly->boundbox), x1, x2, y1, y2);
 	}
 	else
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("cannot create bounding box for empty polygon")));
 }
 
 /*------------------------------------------------------------------
  * poly_in - read in the polygon from a string specification
  *
@@ -3742,21 +3692,21 @@ poly_same(PG_FUNCTION_ARGS)
  *-----------------------------------------------------------------*/
 Datum
 poly_overlap(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
 	/* Quick check by bounding box */
 	result = (polya->npts > 0 && polyb->npts > 0 &&
-			  box_ov(&polya->boundbox, &polyb->boundbox)) ? true : false;
+			  box_ov(&polya->boundbox, &polyb->boundbox));
 
 	/*
 	 * Brute-force algorithm - try to find intersected edges, if so then
 	 * polygons are overlapped else check is one polygon inside other or not
 	 * by testing single point of them.
 	 */
 	if (result)
 	{
 		int			ia,
 					ib;
@@ -3771,34 +3721,33 @@ poly_overlap(PG_FUNCTION_ARGS)
 		{
 			/* Second point of polya's edge is a current one */
 			sa.p[1] = polya->p[ia];
 
 			/* Init first of polyb's edge with last point */
 			sb.p[0] = polyb->p[polyb->npts - 1];
 
 			for (ib = 0; ib < polyb->npts && result == false; ib++)
 			{
 				sb.p[1] = polyb->p[ib];
-				result = lseg_intersect_internal(&sa, &sb);
+				result = lseg_interpt_internal(NULL, &sa, &sb);
 				sb.p[0] = sb.p[1];
 			}
 
 			/*
 			 * move current endpoint to the first point of next edge
 			 */
 			sa.p[0] = sa.p[1];
 		}
 
 		if (result == false)
 		{
-			result = (point_inside(polya->p, polyb->npts, polyb->p)
-					  ||
+			result = (point_inside(polya->p, polyb->npts, polyb->p) ||
 					  point_inside(polyb->p, polya->npts, polya->p));
 		}
 	}
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
@@ -3818,27 +3767,26 @@ poly_overlap(PG_FUNCTION_ARGS)
 
 static bool
 touched_lseg_inside_poly(Point *a, Point *b, LSEG *s, POLYGON *poly, int start)
 {
 	/* point a is on s, b is not */
 	LSEG		t;
 
 	t.p[0] = *a;
 	t.p[1] = *b;
 
-#define POINTEQ(pt1, pt2)	(FPeq((pt1)->x, (pt2)->x) && FPeq((pt1)->y, (pt2)->y))
-	if (POINTEQ(a, s->p))
+	if (point_eq_internal(a, s->p))
 	{
 		if (on_ps_internal(s->p + 1, &t))
 			return lseg_inside_poly(b, s->p + 1, poly, start);
 	}
-	else if (POINTEQ(a, s->p + 1))
+	else if (point_eq_internal(a, s->p + 1))
 	{
 		if (on_ps_internal(s->p, &t))
 			return lseg_inside_poly(b, s->p, poly, start);
 	}
 	else if (on_ps_internal(s->p, &t))
 	{
 		return lseg_inside_poly(b, s->p, poly, start);
 	}
 	else if (on_ps_internal(s->p + 1, &t))
 	{
@@ -3861,50 +3809,49 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 	int			i;
 	bool		res = true,
 				intersection = false;
 
 	t.p[0] = *a;
 	t.p[1] = *b;
 	s.p[0] = poly->p[(start == 0) ? (poly->npts - 1) : (start - 1)];
 
 	for (i = start; i < poly->npts && res; i++)
 	{
-		Point	   *interpt;
+		Point		interpt;
 
 		CHECK_FOR_INTERRUPTS();
 
 		s.p[1] = poly->p[i];
 
 		if (on_ps_internal(t.p, &s))
 		{
 			if (on_ps_internal(t.p + 1, &s))
 				return true;	/* t is contained by s */
 
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p, t.p + 1, &s, poly, i + 1);
 		}
 		else if (on_ps_internal(t.p + 1, &s))
 		{
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p + 1, t.p, &s, poly, i + 1);
 		}
-		else if ((interpt = lseg_interpt_internal(&t, &s)) != NULL)
+		else if (lseg_interpt_internal(&interpt, &t, &s))
 		{
 			/*
 			 * segments are X-crossing, go to check each subsegment
 			 */
 
 			intersection = true;
-			res = lseg_inside_poly(t.p, interpt, poly, i + 1);
+			res = lseg_inside_poly(t.p, &interpt, poly, i + 1);
 			if (res)
-				res = lseg_inside_poly(t.p + 1, interpt, poly, i + 1);
-			pfree(interpt);
+				res = lseg_inside_poly(t.p + 1, &interpt, poly, i + 1);
 		}
 
 		s.p[0] = s.p[1];
 	}
 
 	if (res && !intersection)
 	{
 		Point		p;
 
 		/*
@@ -4019,170 +3966,208 @@ poly_distance(PG_FUNCTION_ARGS)
  **
  **		Routines for 2D points.
  **
  ***********************************************************************/
 
 Datum
 construct_point(PG_FUNCTION_ARGS)
 {
 	float8		x = PG_GETARG_FLOAT8(0);
 	float8		y = PG_GETARG_FLOAT8(1);
+	Point	   *result;
 
-	PG_RETURN_POINT_P(point_construct(x, y));
+	result = (Point *) palloc(sizeof(Point));
+
+	point_construct(result, x, y);
+
+	PG_RETURN_POINT_P(result);
 }
 
 Datum
 point_add(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x + p2->x);
-	result->y = (p1->y + p2->y);
+	point_add_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+static inline void
+point_add_internal(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x + pt2->x,
+					pt1->y + pt2->y);
+}
+
+
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x - p2->x);
-	result->y = (p1->y - p2->y);
+	point_sub_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+static inline void
+point_sub_internal(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x - pt2->x,
+					pt1->y - pt2->y);
+}
+
+
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x * p2->x) - (p1->y * p2->y);
-	result->y = (p1->x * p2->y) + (p1->y * p2->x);
+	point_mul_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+static inline void
+point_mul_internal(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					(pt1->x * pt2->x) - (pt1->y * pt2->y),
+					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+}
+
+
 Datum
 point_div(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
-	double		div;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	div = (p2->x * p2->x) + (p2->y * p2->y);
-
-	if (div == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result->x = ((p1->x * p2->x) + (p1->y * p2->y)) / div;
-	result->y = ((p2->x * p1->y) - (p2->y * p1->x)) / div;
+	point_div_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+static inline void
+point_div_internal(Point *result, Point *pt1, Point *pt2)
+{
+	float8		div;
+
+	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
+	point_construct(result,
+					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
+					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+}
+
 
 /***********************************************************************
  **
  **		Routines for 2D boxes.
  **
  ***********************************************************************/
 
 Datum
 points_box(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct(p1->x, p2->x, p1->y, p2->y));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	box_construct(result, p1, p2);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_add(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct((box->high.x + p->x),
-								  (box->low.x + p->x),
-								  (box->high.y + p->y),
-								  (box->low.y + p->y)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_add_internal(&result->high, &box->high, p);
+	point_add_internal(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_sub(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct((box->high.x - p->x),
-								  (box->low.x - p->x),
-								  (box->high.y - p->y),
-								  (box->low.y - p->y)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_sub_internal(&result->high, &box->high, p);
+	point_sub_internal(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_mul(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
 
-	high = DatumGetPointP(DirectFunctionCall2(point_mul,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_mul,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	result = (BOX *) palloc(sizeof(BOX));
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	point_mul_internal(&high, &box->high, p);
+	point_mul_internal(&low, &box->low, p);
+
+	box_construct(result, &high, &low);
 
 	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_div(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
 
-	high = DatumGetPointP(DirectFunctionCall2(point_div,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_div,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	result = (BOX *) palloc(sizeof(BOX));
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	point_div_internal(&high, &box->high, p);
+	point_div_internal(&low, &box->low, p);
+
+	box_construct(result, &high, &low);
 
 	PG_RETURN_BOX_P(result);
 }
 
 /*
  * Convert point to empty box
  */
 Datum
 point_box(PG_FUNCTION_ARGS)
 {
@@ -4278,83 +4263,63 @@ path_add(PG_FUNCTION_ARGS)
  * Translation operators.
  */
 Datum
 path_add_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x += point->x;
-		path->p[i].y += point->y;
-	}
+		point_add_internal(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_sub_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x -= point->x;
-		path->p[i].y -= point->y;
-	}
+		point_sub_internal(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 /* path_mul_pt()
  * Rotation and scaling operators.
  */
 Datum
 path_mul_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_mul,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_mul_internal(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_div_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_div,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_div_internal(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 
 Datum
 path_center(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	PATH	   *path = PG_GETARG_PATH_P(0);
@@ -4436,21 +4401,22 @@ poly_center(PG_FUNCTION_ARGS)
 
 Datum
 poly_box(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	BOX		   *box;
 
 	if (poly->npts < 1)
 		PG_RETURN_NULL();
 
-	box = box_copy(&poly->boundbox);
+	box = (BOX *) palloc(sizeof(BOX));
+	*box = poly->boundbox;
 
 	PG_RETURN_BOX_P(box);
 }
 
 
 /* box_poly()
  * Convert a box to a polygon.
  */
 Datum
 box_poly(PG_FUNCTION_ARGS)
@@ -4468,22 +4434,21 @@ box_poly(PG_FUNCTION_ARGS)
 
 	poly->p[0].x = box->low.x;
 	poly->p[0].y = box->low.y;
 	poly->p[1].x = box->low.x;
 	poly->p[1].y = box->high.y;
 	poly->p[2].x = box->high.x;
 	poly->p[2].y = box->high.y;
 	poly->p[3].x = box->high.x;
 	poly->p[3].y = box->low.y;
 
-	box_fill(&poly->boundbox, box->high.x, box->low.x,
-			 box->high.y, box->low.y);
+	box_construct(&poly->boundbox, &box->high, &box->low);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
 
 Datum
 poly_path(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	PATH	   *path;
@@ -4492,21 +4457,21 @@ poly_path(PG_FUNCTION_ARGS)
 
 	/*
 	 * Never overflows: the old size fit in MaxAllocSize, and the new size is
 	 * smaller by a small constant.
 	 */
 	size = offsetof(PATH, p) + sizeof(path->p[0]) * poly->npts;
 	path = (PATH *) palloc(size);
 
 	SET_VARSIZE(path, size);
 	path->npts = poly->npts;
-	path->closed = TRUE;
+	path->closed = true;
 	/* prevent instability in unused pad bytes */
 	path->dummy = 0;
 
 	for (i = 0; i < poly->npts; i++)
 	{
 		path->p[i].x = poly->p[i].x;
 		path->p[i].y = poly->p[i].y;
 	}
 
 	PG_RETURN_PATH_P(path);
@@ -4558,22 +4523,21 @@ circle_in(PG_FUNCTION_ARGS)
 
 	circle->radius = single_decode(s, &s, "circle", str);
 	if (circle->radius < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
 
 	while (depth > 0)
 	{
-		if ((*s == RDELIM)
-			|| ((*s == RDELIM_C) && (depth == 1)))
+		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
 			s++;
 			while (isspace((unsigned char) *s))
 				s++;
 		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
@@ -4657,22 +4621,21 @@ circle_send(PG_FUNCTION_ARGS)
 
 /*		circles identical?
  */
 Datum
 circle_same(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPeq(circle1->radius, circle2->radius) &&
-				   FPeq(circle1->center.x, circle2->center.x) &&
-				   FPeq(circle1->center.y, circle2->center.y));
+				   point_eq_internal(&circle1->center, &circle2->center));
 }
 
 /*		circle_overlap	-		does circle1 overlap circle2?
  */
 Datum
 circle_overlap(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
@@ -4859,107 +4822,83 @@ circle_ge(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPge(circle_ar(circle1), circle_ar(circle2)));
 }
 
 
 /*----------------------------------------------------------
  *	"Arithmetic" operators on circles.
  *---------------------------------------------------------*/
 
-static CIRCLE *
-circle_copy(CIRCLE *circle)
-{
-	CIRCLE	   *result;
-
-	if (!PointerIsValid(circle))
-		return NULL;
-
-	result = (CIRCLE *) palloc(sizeof(CIRCLE));
-	memcpy((char *) result, (char *) circle, sizeof(CIRCLE));
-	return result;
-}
-
-
 /* circle_add_pt()
  * Translation operator.
  */
 Datum
 circle_add_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x += point->x;
-	result->center.y += point->y;
+	point_add_internal(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_sub_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x -= point->x;
-	result->center.y -= point->y;
+	point_sub_internal(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /* circle_mul_pt()
  * Rotation and scaling operators.
  */
 Datum
 circle_mul_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_mul,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
-	result->radius *= HYPOT(point->x, point->y);
+	point_mul_internal(&result->center, &circle->center, point);
+	result->radius *= hypot(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_div_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_div,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
-	result->radius /= HYPOT(point->x, point->y);
+	point_div_internal(&result->center, &circle->center, point);
+	result->radius /= hypot(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /*		circle_area		-		returns the area of the circle.
  */
 Datum
 circle_area(PG_FUNCTION_ARGS)
 {
@@ -4994,22 +4933,22 @@ circle_radius(PG_FUNCTION_ARGS)
 /*		circle_distance -		returns the distance between
  *								  two circles.
  */
 Datum
 circle_distance(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(&circle1->center, &circle2->center)
-		- (circle1->radius + circle2->radius);
+	result = point_dt(&circle1->center, &circle2->center) -
+		(circle1->radius + circle2->radius);
 	if (result < 0)
 		result = 0;
 	PG_RETURN_FLOAT8(result);
 }
 
 
 Datum
 circle_contain_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
@@ -5372,118 +5311,55 @@ lseg_crossing(double x, double y, double prev_x, double prev_y)
 static bool
 plist_same(int npts, Point *p1, Point *p2)
 {
 	int			i,
 				ii,
 				j;
 
 	/* find match for first point */
 	for (i = 0; i < npts; i++)
 	{
-		if ((FPeq(p2[i].x, p1[0].x))
-			&& (FPeq(p2[i].y, p1[0].y)))
+		if (point_eq_internal(&p2[i], &p1[0]))
 		{
 
 			/* match found? then look forward through remaining points */
 			for (ii = 1, j = i + 1; ii < npts; ii++, j++)
 			{
 				if (j >= npts)
 					j = 0;
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_internal(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed forward match with %d\n", j, ii);
 #endif
 					break;
 				}
 			}
 #ifdef GEODEBUG
 			printf("plist_same- ii = %d/%d after forward match\n", ii, npts);
 #endif
 			if (ii == npts)
-				return TRUE;
+				return true;
 
 			/* match not found forwards? then look backwards */
 			for (ii = 1, j = i - 1; ii < npts; ii++, j--)
 			{
 				if (j < 0)
 					j = (npts - 1);
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_internal(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed reverse match with %d\n", j, ii);
 #endif
 					break;
 				}
 			}
 #ifdef GEODEBUG
 			printf("plist_same- ii = %d/%d after reverse match\n", ii, npts);
 #endif
 			if (ii == npts)
-				return TRUE;
+				return true;
 		}
 	}
 
-	return FALSE;
-}
-
-
-/*-------------------------------------------------------------------------
- * Determine the hypotenuse.
- *
- * If required, x and y are swapped to make x the larger number. The
- * traditional formula of x^2+y^2 is rearranged to factor x outside the
- * sqrt. This allows computation of the hypotenuse for significantly
- * larger values, and with a higher precision than when using the naive
- * formula.  In particular, this cannot overflow unless the final result
- * would be out-of-range.
- *
- * sqrt( x^2 + y^2 ) = sqrt( x^2( 1 + y^2/x^2) )
- *					 = x * sqrt( 1 + y^2/x^2 )
- *					 = x * sqrt( 1 + y/x * y/x )
- *
- * It is expected that this routine will eventually be replaced with the
- * C99 hypot() function.
- *
- * This implementation conforms to IEEE Std 1003.1 and GLIBC, in that the
- * case of hypot(inf,nan) results in INF, and not NAN.
- *-----------------------------------------------------------------------
- */
-double
-pg_hypot(double x, double y)
-{
-	double		yx;
-
-	/* Handle INF and NaN properly */
-	if (isinf(x) || isinf(y))
-		return get_float8_infinity();
-
-	if (isnan(x) || isnan(y))
-		return get_float8_nan();
-
-	/* Else, drop any minus signs */
-	x = fabs(x);
-	y = fabs(y);
-
-	/* Swap x and y if needed to make x the larger one */
-	if (x < y)
-	{
-		double		temp = x;
-
-		x = y;
-		y = temp;
-	}
-
-	/*
-	 * If y is zero, the hypotenuse is x.  This test saves a few cycles in
-	 * such cases, but more importantly it also protects against
-	 * divide-by-zero errors, since now x >= y.
-	 */
-	if (y == 0.0)
-		return x;
-
-	/* Determine the hypotenuse */
-	yx = y / x;
-	return x * sqrt(1.0 + (yx * yx));
+	return false;
 }
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 44c6381b85..c94e17af5f 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -43,21 +43,20 @@
 #else
 #define FPzero(A)				((A) == 0)
 #define FPeq(A,B)				((A) == (B))
 #define FPne(A,B)				((A) != (B))
 #define FPlt(A,B)				((A) < (B))
 #define FPle(A,B)				((A) <= (B))
 #define FPgt(A,B)				((A) > (B))
 #define FPge(A,B)				((A) >= (B))
 #endif
 
-#define HYPOT(A, B)				pg_hypot(A, B)
 
 /*---------------------------------------------------------------------
  * Point - (x,y)
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	double		x,
 				y;
 } Point;
 
@@ -166,21 +165,11 @@ typedef struct
 #define PolygonPGetDatum(X)			PointerGetDatum(X)
 #define PG_GETARG_POLYGON_P(n)		DatumGetPolygonP(PG_GETARG_DATUM(n))
 #define PG_GETARG_POLYGON_P_COPY(n) DatumGetPolygonPCopy(PG_GETARG_DATUM(n))
 #define PG_RETURN_POLYGON_P(x)		return PolygonPGetDatum(x)
 
 #define DatumGetCircleP(X)	  ((CIRCLE *) DatumGetPointer(X))
 #define CirclePGetDatum(X)	  PointerGetDatum(X)
 #define PG_GETARG_CIRCLE_P(n) DatumGetCircleP(PG_GETARG_DATUM(n))
 #define PG_RETURN_CIRCLE_P(x) return CirclePGetDatum(x)
 
-
-/*
- * 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 */
+#endif   /* GEO_DECLS_H */
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index 0a123f2b39..4140f40b71 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -62,21 +62,23 @@ regress_dist_ptpath(PG_FUNCTION_ARGS)
 	float8		result = 0.0;	/* keep compiler quiet */
 	float8		tmp;
 	int			i;
 	LSEG		lseg;
 
 	switch (path->npts)
 	{
 		case 0:
 			PG_RETURN_NULL();
 		case 1:
-			result = point_dt(pt, &path->p[0]);
+			result = DatumGetFloat8(DirectFunctionCall2(point_distance,
+														PointPGetDatum(pt),
+												PointPGetDatum(&path->p[0])));
 			break;
 		default:
 
 			/*
 			 * the distance from a point to a path is the smallest distance
 			 * from the point to any of its constituent segments.
 			 */
 			Assert(path->npts > 1);
 			for (i = 0; i < path->npts - 1; ++i)
 			{
@@ -280,22 +282,27 @@ widget_out(PG_FUNCTION_ARGS)
 	PG_RETURN_CSTRING(str);
 }
 
 PG_FUNCTION_INFO_V1(pt_in_widget);
 
 Datum
 pt_in_widget(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	WIDGET	   *widget = (WIDGET *) PG_GETARG_POINTER(1);
+	float8		distance;
 
-	PG_RETURN_BOOL(point_dt(point, &widget->center) < widget->radius);
+	distance = DatumGetFloat8(DirectFunctionCall2(point_distance,
+												  PointPGetDatum(point),
+											PointPGetDatum(&widget->center)));
+
+	PG_RETURN_BOOL(distance < widget->radius);
 }
 
 PG_FUNCTION_INFO_V1(boxarea);
 
 Datum
 boxarea(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	double		width,
 				height;
-- 
2.13.5 (Apple Git-94)

0002-float-header-v08.patchapplication/octet-stream; name=0002-float-header-v08.patchDownload
From 82969d289e5f9f3fe4bf898be075f4e0c2b4b3fb Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 28 May 2016 18:16:05 +0200
Subject: [PATCH 2/4] float-header-v08

Provide header file for built-in float datatypes

Even though, some datatypes under adt/ have separate header files,
most of the simple ones do not.  Their public functions were on
the builtins.h.  We would need to make more functions of floats public
to let the geometric types built on top of them.  This is a good
opportunity to make a separate header file for floats.

1acf7572554515b99ef6e783750aaea8777524ec made _cmp functions public
to solve NaN problem locally for GiST indexes.  This patch reworks it
in favour of a more extensive API.  Kevin Grittner suggested to design
the API using inline functions.  They are easier to use compared
to macros, and avoid double-evaluation hazards.
---
 contrib/btree_gin/btree_gin.c                 |   1 +
 contrib/btree_gist/btree_ts.c                 |   1 +
 contrib/cube/cube.c                           |   2 +-
 contrib/cube/cubeparse.y                      |   2 +-
 contrib/postgres_fdw/postgres_fdw.c           |   1 +
 src/backend/access/gist/gistget.c             |   2 +-
 src/backend/access/gist/gistproc.c            |  55 +--
 src/backend/access/gist/gistutil.c            |   2 +-
 src/backend/utils/adt/float.c                 | 589 ++++++--------------------
 src/backend/utils/adt/formatting.c            |   1 +
 src/backend/utils/adt/geo_ops.c               |   6 +-
 src/backend/utils/adt/geo_spgist.c            |   2 +-
 src/backend/utils/adt/numeric.c               |   1 +
 src/backend/utils/adt/rangetypes_gist.c       |   3 +-
 src/backend/utils/adt/rangetypes_selfuncs.c   |   3 +-
 src/backend/utils/adt/rangetypes_typanalyze.c |   3 +-
 src/backend/utils/adt/timestamp.c             |   1 +
 src/backend/utils/misc/guc.c                  |   1 +
 src/include/utils/builtins.h                  |  14 -
 src/include/utils/float.h                     | 376 ++++++++++++++++
 src/include/utils/geo_decls.h                 |   1 +
 21 files changed, 554 insertions(+), 513 deletions(-)
 create mode 100644 src/include/utils/float.h

diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index 2473f79ca1..301caefd47 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -3,20 +3,21 @@
  */
 #include "postgres.h"
 
 #include <limits.h>
 
 #include "access/stratnum.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/cash.h"
 #include "utils/date.h"
+#include "utils/float.h"
 #include "utils/inet.h"
 #include "utils/numeric.h"
 #include "utils/timestamp.h"
 #include "utils/varbit.h"
 
 PG_MODULE_MAGIC;
 
 typedef struct QueryInfo
 {
 	StrategyNumber strategy;
diff --git a/contrib/btree_gist/btree_ts.c b/contrib/btree_gist/btree_ts.c
index 1582cff102..6e77ebab0d 100644
--- a/contrib/btree_gist/btree_ts.c
+++ b/contrib/btree_gist/btree_ts.c
@@ -2,20 +2,21 @@
  * contrib/btree_gist/btree_ts.c
  */
 #include "postgres.h"
 
 #include <limits.h>
 
 #include "btree_gist.h"
 #include "btree_utils_num.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 typedef struct
 {
 	Timestamp	lower;
 	Timestamp	upper;
 } tsKEY;
 
 /*
 ** timestamp ops
 */
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c
index b7702716fe..f5a39cb53b 100644
--- a/contrib/cube/cube.c
+++ b/contrib/cube/cube.c
@@ -7,21 +7,21 @@
 ******************************************************************************/
 
 #include "postgres.h"
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 
 #include "cubedata.h"
 
 PG_MODULE_MAGIC;
 
 /*
  * Taken from the intarray contrib header
  */
 #define ARRPTR(x)  ( (double *) ARR_DATA_PTR(x) )
 #define ARRNELEMS(x)  ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x))
diff --git a/contrib/cube/cubeparse.y b/contrib/cube/cubeparse.y
index 1b65fa967c..deb2efdc0d 100644
--- a/contrib/cube/cubeparse.y
+++ b/contrib/cube/cubeparse.y
@@ -1,20 +1,20 @@
 %{
 /* contrib/cube/cubeparse.y */
 
 /* NdBox = [(lowerleft),(upperright)] */
 /* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */
 
 #include "postgres.h"
 
 #include "cubedata.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 
 /* All grammar constructs return strings */
 #define YYSTYPE char *
 
 /*
  * Bison doesn't allocate anything that needs to live across parser calls,
  * so we can easily have it use palloc instead of malloc.  This prevents
  * memory leaks if we error out during parsing.  Note this only works with
  * bison >= 2.0.  However, in bison 1.875 the default is to use alloca()
  * if possible, so there's not really much problem anyhow, at least if
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index fb65e2eb20..33bf0fe142 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -28,20 +28,21 @@
 #include "optimizer/cost.h"
 #include "optimizer/clauses.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
 #include "optimizer/planmain.h"
 #include "optimizer/restrictinfo.h"
 #include "optimizer/var.h"
 #include "optimizer/tlist.h"
 #include "parser/parsetree.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 #include "utils/sampling.h"
 #include "utils/selfuncs.h"
 
 PG_MODULE_MAGIC;
 
 /* Default CPU cost to start up a foreign query. */
diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c
index 06dac0bb53..56dca026ee 100644
--- a/src/backend/access/gist/gistget.c
+++ b/src/backend/access/gist/gistget.c
@@ -13,21 +13,21 @@
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/gist_private.h"
 #include "access/relscan.h"
 #include "catalog/pg_type.h"
 #include "miscadmin.h"
 #include "pgstat.h"
 #include "lib/pairingheap.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 
 /*
  * gistkillitems() -- set LP_DEAD state for items an indexscan caller has
  * told us were killed.
  *
  * We re-read page here, so it's important to check page LSN. If the page
  * has been modified since the last read (as determined by LSN), we cannot
  * flag any entries because it is possible that the old entry was vacuumed
diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index d1919fc74b..13524b4da0 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -27,62 +27,53 @@
 
 
 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
 						 StrategyNumber strategy);
 static bool rtree_internal_consistent(BOX *key, BOX *query,
 						  StrategyNumber strategy);
 
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
 
-/* Convenience macros for NaN-aware comparisons */
-#define FLOAT8_EQ(a,b)	(float8_cmp_internal(a, b) == 0)
-#define FLOAT8_LT(a,b)	(float8_cmp_internal(a, b) < 0)
-#define FLOAT8_LE(a,b)	(float8_cmp_internal(a, b) <= 0)
-#define FLOAT8_GT(a,b)	(float8_cmp_internal(a, b) > 0)
-#define FLOAT8_GE(a,b)	(float8_cmp_internal(a, b) >= 0)
-#define FLOAT8_MAX(a,b)  (FLOAT8_GT(a, b) ? (a) : (b))
-#define FLOAT8_MIN(a,b)  (FLOAT8_LT(a, b) ? (a) : (b))
-
 
 /**************************************************
  * Box ops
  **************************************************/
 
 /*
  * Calculates union of two boxes, a and b. The result is stored in *n.
  */
 static void
 rt_box_union(BOX *n, const BOX *a, const BOX *b)
 {
-	n->high.x = FLOAT8_MAX(a->high.x, b->high.x);
-	n->high.y = FLOAT8_MAX(a->high.y, b->high.y);
-	n->low.x = FLOAT8_MIN(a->low.x, b->low.x);
-	n->low.y = FLOAT8_MIN(a->low.y, b->low.y);
+	n->high.x = float8_max(a->high.x, b->high.x);
+	n->high.y = float8_max(a->high.y, b->high.y);
+	n->low.x = float8_min(a->low.x, b->low.x);
+	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
 static double
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
-	if (FLOAT8_LE(box->high.x, box->low.x) ||
-		FLOAT8_LE(box->high.y, box->low.y))
+	if (float8_le(box->high.x, box->low.x) ||
+		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
 	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
@@ -137,27 +128,27 @@ gist_box_consistent(PG_FUNCTION_ARGS)
 												 query,
 												 strategy));
 }
 
 /*
  * Increase BOX b to include addon.
  */
 static void
 adjustBox(BOX *b, const BOX *addon)
 {
-	if (FLOAT8_LT(b->high.x, addon->high.x))
+	if (float8_lt(b->high.x, addon->high.x))
 		b->high.x = addon->high.x;
-	if (FLOAT8_GT(b->low.x, addon->low.x))
+	if (float8_gt(b->low.x, addon->low.x))
 		b->low.x = addon->low.x;
-	if (FLOAT8_LT(b->high.y, addon->high.y))
+	if (float8_lt(b->high.y, addon->high.y))
 		b->high.y = addon->high.y;
-	if (FLOAT8_GT(b->low.y, addon->low.y))
+	if (float8_gt(b->low.y, addon->low.y))
 		b->low.y = addon->low.y;
 }
 
 /*
  * The GiST Union method for boxes
  *
  * returns the minimal bounding box that encloses all the entries in entryvec
  */
 Datum
 gist_box_union(PG_FUNCTION_ARGS)
@@ -609,36 +600,36 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		i1 = 0;
 		i2 = 0;
 		rightLower = intervalsLower[i1].lower;
 		leftUpper = intervalsUpper[i2].lower;
 		while (true)
 		{
 			/*
 			 * Find next lower bound of right group.
 			 */
 			while (i1 < nentries &&
-				   FLOAT8_EQ(rightLower, intervalsLower[i1].lower))
+				   float8_eq(rightLower, intervalsLower[i1].lower))
 			{
-				if (FLOAT8_LT(leftUpper, intervalsLower[i1].upper))
+				if (float8_lt(leftUpper, intervalsLower[i1].upper))
 					leftUpper = intervalsLower[i1].upper;
 				i1++;
 			}
 			if (i1 >= nentries)
 				break;
 			rightLower = intervalsLower[i1].lower;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * left group.
 			 */
 			while (i2 < nentries &&
-				   FLOAT8_LE(intervalsUpper[i2].upper, leftUpper))
+				   float8_le(intervalsUpper[i2].upper, leftUpper))
 				i2++;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim, rightLower, i1, leftUpper, i2);
 		}
 
 		/*
 		 * Iterate over upper bound of left group finding greatest possible
@@ -646,35 +637,35 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		 */
 		i1 = nentries - 1;
 		i2 = nentries - 1;
 		rightLower = intervalsLower[i1].upper;
 		leftUpper = intervalsUpper[i2].upper;
 		while (true)
 		{
 			/*
 			 * Find next upper bound of left group.
 			 */
-			while (i2 >= 0 && FLOAT8_EQ(leftUpper, intervalsUpper[i2].upper))
+			while (i2 >= 0 && float8_eq(leftUpper, intervalsUpper[i2].upper))
 			{
-				if (FLOAT8_GT(rightLower, intervalsUpper[i2].lower))
+				if (float8_gt(rightLower, intervalsUpper[i2].lower))
 					rightLower = intervalsUpper[i2].lower;
 				i2--;
 			}
 			if (i2 < 0)
 				break;
 			leftUpper = intervalsUpper[i2].upper;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * right group.
 			 */
-			while (i1 >= 0 && FLOAT8_GE(intervalsLower[i1].lower, rightLower))
+			while (i1 >= 0 && float8_ge(intervalsLower[i1].lower, rightLower))
 				i1--;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim,
 								 rightLower, i1 + 1, leftUpper, i2 + 1);
 		}
 	}
 
@@ -748,42 +739,42 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
 		}
 		else
 		{
 			lower = box->low.y;
 			upper = box->high.y;
 		}
 
-		if (FLOAT8_LE(upper, context.leftUpper))
+		if (float8_le(upper, context.leftUpper))
 		{
 			/* Fits to the left group */
-			if (FLOAT8_GE(lower, context.rightLower))
+			if (float8_ge(lower, context.rightLower))
 			{
 				/* Fits also to the right group, so "common entry" */
 				commonEntries[commonEntriesCount++].index = i;
 			}
 			else
 			{
 				/* Doesn't fit to the right group, so join to the left group */
 				PLACE_LEFT(box, i);
 			}
 		}
 		else
 		{
 			/*
 			 * Each entry should fit on either left or right group. Since this
 			 * entry didn't fit on the left group, it better fit in the right
 			 * group.
 			 */
-			Assert(FLOAT8_GE(lower, context.rightLower));
+			Assert(float8_ge(lower, context.rightLower));
 
 			/* Doesn't fit to the left group, so join to the right group */
 			PLACE_RIGHT(box, i);
 		}
 	}
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
@@ -853,24 +844,24 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
  * equivalent to box_same().
  */
 Datum
 gist_box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *b1 = PG_GETARG_BOX_P(0);
 	BOX		   *b2 = PG_GETARG_BOX_P(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
 	if (b1 && b2)
-		*result = (FLOAT8_EQ(b1->low.x, b2->low.x) &&
-				   FLOAT8_EQ(b1->low.y, b2->low.y) &&
-				   FLOAT8_EQ(b1->high.x, b2->high.x) &&
-				   FLOAT8_EQ(b1->high.y, b2->high.y));
+		*result = (float8_eq(b1->low.x, b2->low.x) &&
+				   float8_eq(b1->low.y, b2->low.y) &&
+				   float8_eq(b1->high.x, b2->high.x) &&
+				   float8_eq(b1->high.y, b2->high.y));
 	else
 		*result = (b1 == NULL && b2 == NULL);
 	PG_RETURN_POINTER(result);
 }
 
 /*
  * Leaf-level consistency for boxes: just apply the query operator
  */
 static bool
 gist_box_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy)
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 26d89f79ae..6a08756988 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -15,21 +15,21 @@
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist_private.h"
 #include "access/htup_details.h"
 #include "access/reloptions.h"
 #include "catalog/pg_opclass.h"
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/syscache.h"
 
 
 /*
  * Write itup vector to page, has no control of free space.
  */
 void
 gistfillbuffer(Page page, IndexTuple *itup, int len, OffsetNumber off)
 {
 	OffsetNumber l = InvalidOffsetNumber;
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index 18b3b949ac..dfd82bb80e 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -15,62 +15,29 @@
 #include "postgres.h"
 
 #include <ctype.h>
 #include <float.h>
 #include <math.h>
 #include <limits.h>
 
 #include "catalog/pg_type.h"
 #include "libpq/pqformat.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/sortsupport.h"
 
 
-#ifndef M_PI
-/* from my RH5.2 gcc math.h file - thomas 2000-04-03 */
-#define M_PI 3.14159265358979323846
-#endif
-
-/* Radians per degree, a.k.a. PI / 180 */
-#define RADIANS_PER_DEGREE 0.0174532925199432957692
-
-/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0.  NAN definition from
- * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfNotNumberNANItems.asp
- */
-#if defined(WIN32) && !defined(NAN)
-static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
-
-#define NAN (*(const double *) nan)
-#endif
-
 /* not sure what the following should be, but better to make it over-sufficient */
 #define MAXFLOATWIDTH	64
 #define MAXDOUBLEWIDTH	128
 
-/*
- * check to see if a float4/8 val has underflowed or overflowed
- */
-#define CHECKFLOATVAL(val, inf_is_valid, zero_is_valid)			\
-do {															\
-	if (isinf(val) && !(inf_is_valid))							\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		  errmsg("value out of range: overflow")));				\
-																\
-	if ((val) == 0.0 && !(zero_is_valid))						\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		 errmsg("value out of range: underflow")));				\
-} while(0)
-
-
 /* Configurable GUC parameter */
 int			extra_float_digits = 0; /* Added to DBL_DIG or FLT_DIG */
 
 /* Cached constants for degree-based trig functions */
 static bool degree_consts_set = false;
 static float8 sin_30 = 0;
 static float8 one_minus_cos_60 = 0;
 static float8 asin_0_5 = 0;
 static float8 acos_0_5 = 0;
 static float8 atan_1_0 = 0;
@@ -102,100 +69,20 @@ static void init_degree_constants(void);
  * their compilers spit up at the mismatch between extern declaration
  * and static definition.  We work around that here by the expedient
  * of a #define to make the actual name of the static function different.
  */
 #define cbrt my_cbrt
 static double cbrt(double x);
 #endif							/* HAVE_CBRT */
 
 
 /*
- * Routines to provide reasonably platform-independent handling of
- * infinity and NaN.  We assume that isinf() and isnan() are available
- * and work per spec.  (On some platforms, we have to supply our own;
- * see src/port.)  However, generating an Infinity or NaN in the first
- * place is less well standardized; pre-C99 systems tend not to have C99's
- * INFINITY and NAN macros.  We centralize our workarounds for this here.
- */
-
-double
-get_float8_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (double) INFINITY;
-#else
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (double) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-/*
-* The funny placements of the two #pragmas is necessary because of a
-* long lived bug in the Microsoft compilers.
-* See http://support.microsoft.com/kb/120968/en-us for details
-*/
-#if (_MSC_VER >= 1800)
-#pragma warning(disable:4756)
-#endif
-float
-get_float4_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (float) INFINITY;
-#else
-#if (_MSC_VER >= 1800)
-#pragma warning(default:4756)
-#endif
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (float) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-double
-get_float8_nan(void)
-{
-	/* (double) NAN doesn't work on some NetBSD/MIPS releases */
-#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
-	/* C99 standard way */
-	return (double) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (double) (0.0 / 0.0);
-#endif
-}
-
-float
-get_float4_nan(void)
-{
-#ifdef NAN
-	/* C99 standard way */
-	return (float) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (float) (0.0 / 0.0);
-#endif
-}
-
-
-/*
  * Returns -1 if 'val' represents negative infinity, 1 if 'val'
  * represents (positive) infinity, and 0 otherwise. On some platforms,
  * this is equivalent to the isinf() macro, but not everywhere: C99
  * does not specify that isinf() needs to distinguish between positive
  * and negative infinity.
  */
 int
 is_infinite(double val)
 {
 	int			inf = isinf(val);
@@ -339,21 +226,21 @@ float4in(PG_FUNCTION_ARGS)
 	if (*endptr != '\0')
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"real", orig_num)));
 
 	/*
 	 * if we get here, we have a legal double, still need to check to see if
 	 * it's a legal float4
 	 */
-	CHECKFLOATVAL((float4) val, isinf(val), val == 0);
+	check_float4_val((float4) val, isinf(val), val == 0);
 
 	PG_RETURN_FLOAT4((float4) val);
 }
 
 /*
  *		float4out		- converts a float4 number to a string
  *						  using a standard output format
  */
 Datum
 float4out(PG_FUNCTION_ARGS)
@@ -689,35 +576,35 @@ float4up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT4(arg);
 }
 
 Datum
 float4larger(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) > 0)
+	if (float4_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 Datum
 float4smaller(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) < 0)
+	if (float4_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 /*
  *		======================
  *		FLOAT8 BASE OPERATIONS
  *		======================
@@ -756,35 +643,35 @@ float8up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT8(arg);
 }
 
 Datum
 float8larger(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) > 0)
+	if (float8_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 Datum
 float8smaller(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) < 0)
+	if (float8_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		====================
  *		ARITHMETIC OPERATORS
@@ -795,234 +682,165 @@ float8smaller(PG_FUNCTION_ARGS)
  *		float4pl		- returns arg1 + arg2
  *		float4mi		- returns arg1 - arg2
  *		float4mul		- returns arg1 * arg2
  *		float4div		- returns arg1 / arg2
  */
 Datum
 float4pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 + arg2;
-
-	/*
-	 * There isn't any way to check for underflow of addition/subtraction
-	 * because numbers near the underflow value have already been rounded to
-	 * the point where we can't detect that the two values were originally
-	 * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
-	 * 1.4013e-45.
-	 */
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_pl(arg1, arg2));
 }
 
 Datum
 float4mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mi(arg1, arg2));
 }
 
 Datum
 float4mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mul(arg1, arg2));
 }
 
 Datum
 float4div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_div(arg1, arg2));
 }
 
 /*
  *		float8pl		- returns arg1 + arg2
  *		float8mi		- returns arg1 - arg2
  *		float8mul		- returns arg1 * arg2
  *		float8div		- returns arg1 / arg2
  */
 Datum
 float8pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 + arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, arg2));
 }
 
 Datum
 float8mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 - arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, arg2));
 }
 
 Datum
 float8mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 * arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, arg2));
 }
 
 Datum
 float8div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, arg2));
 }
 
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float4{eq,ne,lt,le,gt,ge}		- float4/float4 comparison operations
  */
 int
 float4_cmp_internal(float4 a, float4 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float4_gt(a, b))
+		return 1;
+	if (float4_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
 float4eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float4_eq(arg1, arg2));
 }
 
 Datum
 float4ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float4_ne(arg1, arg2));
 }
 
 Datum
 float4lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float4_lt(arg1, arg2));
 }
 
 Datum
 float4le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float4_le(arg1, arg2));
 }
 
 Datum
 float4gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float4_gt(arg1, arg2));
 }
 
 Datum
 float4ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float4_ge(arg1, arg2));
 }
 
 Datum
 btfloat4cmp(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
 	PG_RETURN_INT32(float4_cmp_internal(arg1, arg2));
 }
@@ -1044,99 +862,79 @@ btfloat4sortsupport(PG_FUNCTION_ARGS)
 	ssup->comparator = btfloat4fastcmp;
 	PG_RETURN_VOID();
 }
 
 /*
  *		float8{eq,ne,lt,le,gt,ge}		- float8/float8 comparison operations
  */
 int
 float8_cmp_internal(float8 a, float8 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float8_gt(a, b))
+		return 1;
+	if (float8_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
 float8eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, arg2));
 }
 
 Datum
 float8ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, arg2));
 }
 
 Datum
 float8lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, arg2));
 }
 
 Datum
 float8le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, arg2));
 }
 
 Datum
 float8gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, arg2));
 }
 
 Datum
 float8ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, arg2));
 }
 
 Datum
 btfloat8cmp(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
 	PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
 }
@@ -1199,21 +997,21 @@ ftod(PG_FUNCTION_ARGS)
 
 
 /*
  *		dtof			- converts a float8 number to a float4 number
  */
 Datum
 dtof(PG_FUNCTION_ARGS)
 {
 	float8		num = PG_GETARG_FLOAT8(0);
 
-	CHECKFLOATVAL((float4) num, isinf(num), num == 0);
+	check_float4_val((float4) num, isinf(num), num == 0);
 
 	PG_RETURN_FLOAT4((float4) num);
 }
 
 
 /*
  *		dtoi4			- converts a float8 number to an int4 number
  */
 Datum
 dtoi4(PG_FUNCTION_ARGS)
@@ -1424,36 +1222,36 @@ dsqrt(PG_FUNCTION_ARGS)
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
 				 errmsg("cannot take square root of a negative number")));
 
 	result = sqrt(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcbrt			- returns cube root of arg1
  */
 Datum
 dcbrt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	result = cbrt(arg1);
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dpow			- returns pow(arg1,arg2)
  */
 Datum
 dpow(PG_FUNCTION_ARGS)
 {
@@ -1492,40 +1290,40 @@ dpow(PG_FUNCTION_ARGS)
 			/* The sign of Inf is not significant in this case. */
 			result = get_float8_infinity();
 		else if (fabs(arg1) != 1)
 			result = 0;
 		else
 			result = 1;
 	}
 	else if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
+	check_float8_val(result, isinf(arg1) || isinf(arg2), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dexp			- returns the exponential function of arg1
  */
 Datum
 dexp(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	errno = 0;
 	result = exp(arg1);
 	if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1), false);
+	check_float8_val(result, isinf(arg1), false);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dlog1			- returns the natural logarithm of arg1
  */
 Datum
 dlog1(PG_FUNCTION_ARGS)
 {
@@ -1540,21 +1338,21 @@ dlog1(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of zero")));
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of a negative number")));
 
 	result = log(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dlog10			- returns the base 10 logarithm of arg1
  */
 Datum
 dlog10(PG_FUNCTION_ARGS)
 {
@@ -1570,21 +1368,21 @@ dlog10(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of zero")));
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of a negative number")));
 
 	result = log10(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dacos			- returns the arccos of arg1 (radians)
  */
 Datum
 dacos(PG_FUNCTION_ARGS)
 {
@@ -1600,21 +1398,21 @@ dacos(PG_FUNCTION_ARGS)
 	 * range [-1, 1] to values in the range [0, Pi], so we should reject any
 	 * inputs outside that range and the result will always be finite.
 	 */
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = acos(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dasin			- returns the arcsin of arg1 (radians)
  */
 Datum
 dasin(PG_FUNCTION_ARGS)
 {
@@ -1630,21 +1428,21 @@ dasin(PG_FUNCTION_ARGS)
 	 * range [-1, 1] to values in the range [-Pi/2, Pi/2], so we should reject
 	 * any inputs outside that range and the result will always be finite.
 	 */
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = asin(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		datan			- returns the arctan of arg1 (radians)
  */
 Datum
 datan(PG_FUNCTION_ARGS)
 {
@@ -1655,21 +1453,21 @@ datan(PG_FUNCTION_ARGS)
 	if (isnan(arg1))
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/*
 	 * The principal branch of the inverse tangent function maps all inputs to
 	 * values in the range [-Pi/2, Pi/2], so the result should always be
 	 * finite, even if the input is infinite.
 	 */
 	result = atan(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		atan2			- returns the arctan of arg1/arg2 (radians)
  */
 Datum
 datan2(PG_FUNCTION_ARGS)
 {
@@ -1680,21 +1478,21 @@ datan2(PG_FUNCTION_ARGS)
 	/* Per the POSIX spec, return NaN if either input is NaN */
 	if (isnan(arg1) || isnan(arg2))
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/*
 	 * atan2 maps all inputs to values in the range [-Pi, Pi], so the result
 	 * should always be finite, even if the inputs are infinite.
 	 */
 	result = atan2(arg1, arg2);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcos			- returns the cosine of arg1 (radians)
  */
 Datum
 dcos(PG_FUNCTION_ARGS)
 {
@@ -1720,21 +1518,21 @@ dcos(PG_FUNCTION_ARGS)
 	 * platform reports via errno, so also explicitly test for infinite
 	 * inputs.
 	 */
 	errno = 0;
 	result = cos(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcot			- returns the cotangent of arg1 (radians)
  */
 Datum
 dcot(PG_FUNCTION_ARGS)
 {
@@ -1747,21 +1545,21 @@ dcot(PG_FUNCTION_ARGS)
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = tan(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = 1.0 / result;
-	CHECKFLOATVAL(result, true /* cot(0) == Inf */ , true);
+	check_float8_val(result, true /* cot(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dsin			- returns the sine of arg1 (radians)
  */
 Datum
 dsin(PG_FUNCTION_ARGS)
 {
@@ -1773,21 +1571,21 @@ dsin(PG_FUNCTION_ARGS)
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = sin(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dtan			- returns the tangent of arg1 (radians)
  */
 Datum
 dtan(PG_FUNCTION_ARGS)
 {
@@ -1799,21 +1597,21 @@ dtan(PG_FUNCTION_ARGS)
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = tan(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, true /* tan(pi/2) == Inf */ , true);
+	check_float8_val(result, true /* tan(pi/2) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /* ========== DEGREE-BASED TRIGONOMETRIC FUNCTIONS ========== */
 
 
 /*
  * Initialize the cached constants declared at the head of this file
  * (sin_30 etc).  The fact that we need those at all, let alone need this
@@ -1951,21 +1749,21 @@ dacosd(PG_FUNCTION_ARGS)
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	if (arg1 >= 0.0)
 		result = acosd_q1(arg1);
 	else
 		result = 90.0 + asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dasind			- returns the arcsin of arg1 (degrees)
  */
 Datum
 dasind(PG_FUNCTION_ARGS)
 {
@@ -1986,21 +1784,21 @@ dasind(PG_FUNCTION_ARGS)
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	if (arg1 >= 0.0)
 		result = asind_q1(arg1);
 	else
 		result = -asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		datand			- returns the arctan of arg1 (degrees)
  */
 Datum
 datand(PG_FUNCTION_ARGS)
 {
@@ -2016,21 +1814,21 @@ datand(PG_FUNCTION_ARGS)
 
 	/*
 	 * The principal branch of the inverse tangent function maps all inputs to
 	 * values in the range [-90, 90], so the result should always be finite,
 	 * even if the input is infinite.  Additionally, we take care to ensure
 	 * than when arg1 is 1, the result is exactly 45.
 	 */
 	atan_arg1 = atan(arg1);
 	result = (atan_arg1 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		atan2d			- returns the arctan of arg1/arg2 (degrees)
  */
 Datum
 datan2d(PG_FUNCTION_ARGS)
 {
@@ -2050,21 +1848,21 @@ datan2d(PG_FUNCTION_ARGS)
 	 * result should always be finite, even if the inputs are infinite.
 	 *
 	 * Note: this coding assumes that atan(1.0) is a suitable scaling constant
 	 * to get an exact result from atan2().  This might well fail on us at
 	 * some point, requiring us to decide exactly what inputs we think we're
 	 * going to guarantee an exact result for.
 	 */
 	atan2_arg1_arg2 = atan2(arg1, arg2);
 	result = (atan2_arg1_arg2 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		sind_0_to_30	- returns the sine of an angle that lies between 0 and
  *						  30 degrees.  This will return exactly 0 when x is 0,
  *						  and exactly 0.5 when x is 30 degrees.
  */
 static double
@@ -2171,21 +1969,21 @@ dcosd(PG_FUNCTION_ARGS)
 
 	if (arg1 > 90.0)
 	{
 		/* cosd(180-x) = -cosd(x) */
 		arg1 = 180.0 - arg1;
 		sign = -sign;
 	}
 
 	result = sign * cosd_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcotd			- returns the cotangent of arg1 (degrees)
  */
 Datum
 dcotd(PG_FUNCTION_ARGS)
 {
@@ -2236,21 +2034,21 @@ dcotd(PG_FUNCTION_ARGS)
 	result = sign * (cot_arg1 / cot_45);
 
 	/*
 	 * On some machines we get cotd(270) = minus zero, but this isn't always
 	 * true.  For portability, and because the user constituency for this
 	 * function probably doesn't want minus zero, force it to plain zero.
 	 */
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* cotd(0) == Inf */ , true);
+	check_float8_val(result, true /* cotd(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dsind			- returns the sine of arg1 (degrees)
  */
 Datum
 dsind(PG_FUNCTION_ARGS)
 {
@@ -2290,21 +2088,21 @@ dsind(PG_FUNCTION_ARGS)
 	}
 
 	if (arg1 > 90.0)
 	{
 		/* sind(180-x) = sind(x) */
 		arg1 = 180.0 - arg1;
 	}
 
 	result = sign * sind_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dtand			- returns the tangent of arg1 (degrees)
  */
 Datum
 dtand(PG_FUNCTION_ARGS)
 {
@@ -2355,64 +2153,56 @@ dtand(PG_FUNCTION_ARGS)
 	result = sign * (tan_arg1 / tan_45);
 
 	/*
 	 * On some machines we get tand(180) = minus zero, but this isn't always
 	 * true.  For portability, and because the user constituency for this
 	 * function probably doesn't want minus zero, force it to plain zero.
 	 */
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* tand(90) == Inf */ , true);
+	check_float8_val(result, true /* tand(90) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		degrees		- returns degrees converted from radians
  */
 Datum
 degrees(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
 
-	result = arg1 / RADIANS_PER_DEGREE;
-
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, RADIANS_PER_DEGREE));
 }
 
 
 /*
  *		dpi				- returns the constant PI
  */
 Datum
 dpi(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_FLOAT8(M_PI);
 }
 
 
 /*
  *		radians		- returns radians converted from degrees
  */
 Datum
 radians(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
 
-	result = arg1 * RADIANS_PER_DEGREE;
-
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, RADIANS_PER_DEGREE));
 }
 
 
 /*
  *		drandom		- returns a random number
  */
 Datum
 drandom(PG_FUNCTION_ARGS)
 {
 	float8		result;
@@ -2490,144 +2280,105 @@ check_float8_array(ArrayType *transarray, const char *caller, int n)
  * This function is used only in two stage aggregation and
  * shouldn't be called outside aggregate context.
  */
 Datum
 float8_combine(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_combine", 3);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-
 	transvalues2 = check_float8_array(transarray2, "float8_combine", 3);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
 
 Datum
 float8_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8		newval = PG_GETARG_FLOAT8(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float8_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
 	else
 	{
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
 								 sizeof(float8), FLOAT8PASSBYVAL, 'd');
 
 		PG_RETURN_ARRAYTYPE_P(result);
 	}
 }
 
 Datum
 float4_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 
 	/* do computations as float8 */
 	float8		newval = PG_GETARG_FLOAT4(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float4_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
 	else
 	{
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
 								 sizeof(float8), FLOAT8PASSBYVAL, 'd');
 
 		PG_RETURN_ARRAYTYPE_P(result);
 	}
 }
 
 Datum
@@ -2663,21 +2414,21 @@ float8_var_pop(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_var_pop", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Population variance is undefined when N is 0, so return NULL */
 	if (N == 0.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / (N * N));
 }
 
 Datum
 float8_var_samp(PG_FUNCTION_ARGS)
@@ -2692,21 +2443,21 @@ float8_var_samp(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_var_samp", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Sample variance is undefined when N is 0 or 1, so return NULL */
 	if (N <= 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
 }
 
 Datum
 float8_stddev_pop(PG_FUNCTION_ARGS)
@@ -2721,21 +2472,21 @@ float8_stddev_pop(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_stddev_pop", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Population stddev is undefined when N is 0, so return NULL */
 	if (N == 0.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(sqrt(numerator / (N * N)));
 }
 
 Datum
 float8_stddev_samp(PG_FUNCTION_ARGS)
@@ -2750,21 +2501,21 @@ float8_stddev_samp(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_stddev_samp", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Sample stddev is undefined when N is 0 or 1, so return NULL */
 	if (N <= 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(sqrt(numerator / (N * (N - 1.0))));
 }
 
 /*
  *		=========================
@@ -2799,30 +2550,30 @@ float8_regr_accum(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_accum", 6);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	N += 1.0;
 	sumX += newvalX;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
+	check_float8_val(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
 	sumX2 += newvalX * newvalX;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
+	check_float8_val(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
 	sumY += newvalY;
-	CHECKFLOATVAL(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
+	check_float8_val(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
 	sumY2 += newvalY * newvalY;
-	CHECKFLOATVAL(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
+	check_float8_val(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
 	sumXY += newvalX * newvalY;
-	CHECKFLOATVAL(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
-				  isinf(newvalY), true);
+	check_float8_val(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
+					 isinf(newvalY), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
 		transvalues[0] = N;
 		transvalues[1] = sumX;
@@ -2861,63 +2612,33 @@ float8_regr_accum(PG_FUNCTION_ARGS)
  * This function is used only in two stage aggregation and
  * shouldn't be called outside aggregate context.
  */
 Datum
 float8_regr_combine(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2,
-				sumY,
-				sumY2,
-				sumXY;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_regr_combine", 6);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-	sumY = transvalues1[3];
-	sumY2 = transvalues1[4];
-	sumXY = transvalues1[5];
-
 	transvalues2 = check_float8_array(transarray2, "float8_regr_combine", 6);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-	sumY += transvalues2[3];
-	CHECKFLOATVAL(sumY, isinf(transvalues1[3]) || isinf(transvalues2[3]),
-				  true);
-	sumY2 += transvalues2[4];
-	CHECKFLOATVAL(sumY2, isinf(transvalues1[4]) || isinf(transvalues2[4]),
-				  true);
-	sumXY += transvalues2[5];
-	CHECKFLOATVAL(sumXY, isinf(transvalues1[5]) || isinf(transvalues2[5]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
-	transvalues1[3] = sumY;
-	transvalues1[4] = sumY2;
-	transvalues1[5] = sumXY;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
+	transvalues1[3] = float8_pl(transvalues1[3], transvalues2[3]);
+	transvalues1[4] = float8_pl(transvalues1[4], transvalues2[4]);
+	transvalues1[5] = float8_pl(transvalues1[5], transvalues2[5]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
 
 
 Datum
 float8_regr_sxx(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
@@ -2929,21 +2650,21 @@ float8_regr_sxx(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_sxx", 6);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_syy(PG_FUNCTION_ARGS)
@@ -2958,21 +2679,21 @@ float8_regr_syy(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_syy", 6);
 	N = transvalues[0];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumY2) || isinf(sumY), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_sxy(PG_FUNCTION_ARGS)
@@ -2989,22 +2710,22 @@ float8_regr_sxy(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	/* A negative result is valid here */
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_avgx(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3057,22 +2778,22 @@ float8_covar_pop(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * N));
 }
 
 Datum
 float8_covar_samp(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
 	float8		N,
@@ -3085,22 +2806,22 @@ float8_covar_samp(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is <= 1 we should return NULL */
 	if (N < 2.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
 }
 
 Datum
 float8_corr(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
 	float8		N,
@@ -3119,26 +2840,26 @@ float8_corr(PG_FUNCTION_ARGS)
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0 || numeratorY <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXY / sqrt(numeratorX * numeratorY));
 }
 
 Datum
 float8_regr_r2(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3159,26 +2880,26 @@ float8_regr_r2(PG_FUNCTION_ARGS)
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 	/* per spec, horizontal line produces 1.0 */
 	if (numeratorY <= 0)
 		PG_RETURN_FLOAT8(1.0);
 
 	PG_RETURN_FLOAT8((numeratorXY * numeratorXY) /
 					 (numeratorX * numeratorY));
 }
 
@@ -3200,24 +2921,24 @@ float8_regr_slope(PG_FUNCTION_ARGS)
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXY / numeratorX);
 }
 
 Datum
 float8_regr_intercept(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3235,24 +2956,24 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXXY = sumY * sumX2 - sumX * sumXY;
-	CHECKFLOATVAL(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
-				  isinf(sumX) || isinf(sumXY), true);
+	check_float8_val(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
+					 isinf(sumX) || isinf(sumXY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXXY / numeratorX);
 }
 
 
 /*
  *		====================================
  *		MIXED-PRECISION ARITHMETIC OPERATORS
@@ -3263,251 +2984,211 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
  *		float48pl		- returns arg1 + arg2
  *		float48mi		- returns arg1 - arg2
  *		float48mul		- returns arg1 * arg2
  *		float48div		- returns arg1 / arg2
  */
 Datum
 float48pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 + arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl((float8) arg1, arg2));
 }
 
 Datum
 float48mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi((float8) arg1, arg2));
 }
 
 Datum
 float48mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul((float8) arg1, arg2));
 }
 
 Datum
 float48div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div((float8) arg1, arg2));
 }
 
 /*
  *		float84pl		- returns arg1 + arg2
  *		float84mi		- returns arg1 - arg2
  *		float84mul		- returns arg1 * arg2
  *		float84div		- returns arg1 / arg2
  */
 Datum
 float84pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 + arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, (float8) arg2));
 }
 
 Datum
 float84mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 - arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, (float8) arg2));
 }
 
 Datum
 float84mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 * arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, (float8) arg2));
 }
 
 Datum
 float84div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, (float8) arg2));
 }
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float48{eq,ne,lt,le,gt,ge}		- float4/float8 comparison operations
  */
 Datum
 float48eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq((float8) arg1, arg2));
 }
 
 Datum
 float48ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne((float8) arg1, arg2));
 }
 
 Datum
 float48lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt((float8) arg1, arg2));
 }
 
 Datum
 float48le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le((float8) arg1, arg2));
 }
 
 Datum
 float48gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt((float8) arg1, arg2));
 }
 
 Datum
 float48ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge((float8) arg1, arg2));
 }
 
 /*
  *		float84{eq,ne,lt,le,gt,ge}		- float8/float4 comparison operations
  */
 Datum
 float84eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, (float8) arg2));
 }
 
 Datum
 float84ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, (float8) arg2));
 }
 
 Datum
 float84lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, (float8) arg2));
 }
 
 Datum
 float84le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, (float8) arg2));
 }
 
 Datum
 float84gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, (float8) arg2));
 }
 
 Datum
 float84ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, (float8) arg2));
 }
 
 /*
  * Implements the float8 version of the width_bucket() function
  * defined by SQL2003. See also width_bucket_numeric().
  *
  * 'bound1' and 'bound2' are the lower and upper bounds of the
  * histogram's range, respectively. 'count' is the number of buckets
  * in the histogram. width_bucket() returns an integer indicating the
  * bucket number that 'operand' belongs to in an equiwidth histogram
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c
index 7877af2d6b..4cb5aba044 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -84,20 +84,21 @@
 
 #ifdef USE_ICU
 #include <unicode/ustring.h>
 #endif
 
 #include "catalog/pg_collation.h"
 #include "mb/pg_wchar.h"
 #include "utils/builtins.h"
 #include "utils/date.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 #include "utils/formatting.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/pg_locale.h"
 
 /* ----------
  * Routines type
  * ----------
  */
 #define DCH_TYPE		1		/* DATE-TIME version	*/
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index fe4155d0b2..2cae70e3df 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -14,27 +14,23 @@
  */
 #include "postgres.h"
 
 #include <math.h>
 #include <limits.h>
 #include <float.h>
 #include <ctype.h>
 
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
-#include "utils/builtins.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index f6334bae14..c800bb1338 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -69,21 +69,21 @@
  *			src/backend/utils/adt/geo_spgist.c
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
 
 #include "access/spgist.h"
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
  * is going only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 48d95e9050..c24b5c3d5b 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -28,20 +28,21 @@
 
 #include "access/hash.h"
 #include "catalog/pg_type.h"
 #include "funcapi.h"
 #include "lib/hyperloglog.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/sortsupport.h"
 
 /* ----------
  * Uncomment the following to enable compilation of dump_numeric()
  * and dump_var() and to get a dump of any result produced by make_result().
  * ----------
 #define NUMERIC_DEBUG
diff --git a/src/backend/utils/adt/rangetypes_gist.c b/src/backend/utils/adt/rangetypes_gist.c
index 29fa1ae325..d8c1525acc 100644
--- a/src/backend/utils/adt/rangetypes_gist.c
+++ b/src/backend/utils/adt/rangetypes_gist.c
@@ -9,21 +9,22 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_gist.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/gist.h"
 #include "access/stratnum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/datum.h"
 #include "utils/rangetypes.h"
 
 
 /*
  * Range class properties used to segregate different classes of ranges in
  * GiST.  Each unique combination of properties is a class.  CLS_EMPTY cannot
  * be combined with anything else.
  */
 #define CLS_NORMAL			0	/* Ordinary finite range (no bits set) */
diff --git a/src/backend/utils/adt/rangetypes_selfuncs.c b/src/backend/utils/adt/rangetypes_selfuncs.c
index cba8974dbe..97308aea9a 100644
--- a/src/backend/utils/adt/rangetypes_selfuncs.c
+++ b/src/backend/utils/adt/rangetypes_selfuncs.c
@@ -14,21 +14,22 @@
  *	  src/backend/utils/adt/rangetypes_selfuncs.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/htup_details.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 #include "utils/selfuncs.h"
 #include "utils/typcache.h"
 
 static double calc_rangesel(TypeCacheEntry *typcache, VariableStatData *vardata,
 			  RangeType *constval, Oid operator);
 static double default_range_selectivity(Oid operator);
 static double calc_hist_selectivity(TypeCacheEntry *typcache,
 					  VariableStatData *vardata, RangeType *constval,
diff --git a/src/backend/utils/adt/rangetypes_typanalyze.c b/src/backend/utils/adt/rangetypes_typanalyze.c
index 3efd982d1b..8a7ad4f3f7 100644
--- a/src/backend/utils/adt/rangetypes_typanalyze.c
+++ b/src/backend/utils/adt/rangetypes_typanalyze.c
@@ -19,21 +19,22 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_typanalyze.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "catalog/pg_operator.h"
 #include "commands/vacuum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 
 static int	float8_qsort_cmp(const void *a1, const void *a2);
 static int	range_bound_qsort_cmp(const void *a1, const void *a2, void *arg);
 static void compute_range_stats(VacAttrStats *stats,
 					AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows);
 
 /*
  * range_typanalyze -- typanalyze function for range columns
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index b11d452fc8..3df4010b97 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -27,20 +27,21 @@
 #include "common/int128.h"
 #include "funcapi.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
 #include "parser/scansup.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 /*
  * gcc's -ffast-math switch breaks routines that expect exact results from
  * expressions like timeval / SECS_PER_HOUR, where timeval is double.
  */
 #ifdef __FAST_MATH__
 #error -ffast-math is known to break this code
 #endif
 
 #define SAMESIGN(a,b)	(((a) < 0) == ((b) < 0))
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 8292df00bb..905ee2aee2 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -72,20 +72,21 @@
 #include "storage/standby.h"
 #include "storage/fd.h"
 #include "storage/pg_shmem.h"
 #include "storage/proc.h"
 #include "storage/predicate.h"
 #include "tcop/tcopprot.h"
 #include "tsearch/ts_cache.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/guc_tables.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/pg_locale.h"
 #include "utils/plancache.h"
 #include "utils/portal.h"
 #include "utils/ps_status.h"
 #include "utils/rls.h"
 #include "utils/snapmgr.h"
 #include "utils/tzparser.h"
 #include "utils/varlena.h"
 #include "utils/xml.h"
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 762532f636..668e037737 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -43,34 +43,20 @@ extern int	namestrcmp(Name name, const char *str);
 
 /* numutils.c */
 extern int32 pg_atoi(const char *s, int size, int c);
 extern void pg_itoa(int16 i, char *a);
 extern void pg_ltoa(int32 l, char *a);
 extern void pg_lltoa(int64 ll, char *a);
 extern char *pg_ltostr_zeropad(char *str, int32 value, int32 minwidth);
 extern char *pg_ltostr(char *str, int32 value);
 extern uint64 pg_strtouint64(const char *str, char **endptr, int base);
 
-/* float.c */
-extern PGDLLIMPORT int extra_float_digits;
-
-extern double get_float8_infinity(void);
-extern float get_float4_infinity(void);
-extern double get_float8_nan(void);
-extern float get_float4_nan(void);
-extern int	is_infinite(double val);
-extern double float8in_internal(char *num, char **endptr_p,
-				  const char *type_name, const char *orig_string);
-extern char *float8out_internal(double num);
-extern int	float4_cmp_internal(float4 a, float4 b);
-extern int	float8_cmp_internal(float8 a, float8 b);
-
 /* oid.c */
 extern oidvector *buildoidvector(const Oid *oids, int n);
 extern Oid	oidparse(Node *node);
 extern int	oid_cmp(const void *p1, const void *p2);
 
 /* regexp.c */
 extern char *regexp_fixed_prefix(text *text_re, bool case_insensitive,
 					Oid collation, bool *exact);
 
 /* ruleutils.c */
diff --git a/src/include/utils/float.h b/src/include/utils/float.h
new file mode 100644
index 0000000000..b96c6e071c
--- /dev/null
+++ b/src/include/utils/float.h
@@ -0,0 +1,376 @@
+/*-------------------------------------------------------------------------
+ *
+ * float.h
+ *	  Definitions for the built-in floating-point types
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/include/utils/float.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef FLOAT_H
+#define FLOAT_H
+
+#include <math.h>
+
+#ifndef M_PI
+/* From my RH5.2 gcc math.h file - thomas 2000-04-03 */
+#define M_PI 3.14159265358979323846
+#endif
+
+/* Radians per degree, a.k.a. PI / 180 */
+#define RADIANS_PER_DEGREE 0.0174532925199432957692
+
+/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0.  NAN definition from
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfNotNumberNANItems.asp
+ */
+#if defined(WIN32) && !defined(NAN)
+static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
+
+#define NAN (*(const float8 *) nan)
+#endif
+
+extern PGDLLIMPORT int extra_float_digits;
+
+/*
+ * Utility functions in float.c
+ */
+extern int	is_infinite(float8 val);
+extern float8 float8in_internal(char *num, char **endptr_p,
+				  const char *type_name, const char *orig_string);
+extern char *float8out_internal(float8 num);
+extern int	float4_cmp_internal(float4 a, float4 b);
+extern int	float8_cmp_internal(float8 a, float8 b);
+
+/*
+ * Routines to provide reasonably platform-independent handling of
+ * infinity and NaN
+ *
+ * We assume that isinf() and isnan() are available and work per spec.
+ * (On some platforms, we have to supply our own; see src/port.)  However,
+ * generating an Infinity or NaN in the first place is less well standardized;
+ * pre-C99 systems tend not to have C99's INFINITY and NAN macros.  We
+ * centralize our workarounds for this here.
+ */
+
+/*
+ * The funny placements of the two #pragmas is necessary because of a
+ * long lived bug in the Microsoft compilers.
+ * See http://support.microsoft.com/kb/120968/en-us for details
+ */
+#if (_MSC_VER >= 1800)
+#pragma warning(disable:4756)
+#endif
+static inline float
+get_float4_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float) INFINITY;
+#else
+#if (_MSC_VER >= 1800)
+#pragma warning(default:4756)
+#endif
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float8
+get_float8_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float8) INFINITY;
+#else
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float8) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float4
+get_float4_nan(void)
+{
+#ifdef NAN
+	/* C99 standard way */
+	return (float) NAN;
+#else
+	/* Assume we can get a NAN via zero divide */
+	return (float) (0.0 / 0.0);
+#endif
+}
+
+static inline float8
+get_float8_nan(void)
+{
+	/* (float8) NAN doesn't work on some NetBSD/MIPS releases */
+#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
+	/* C99 standard way */
+	return (float8) NAN;
+#else
+	/* Assume we can get a NAN via zero divide */
+	return (float8) (0.0 / 0.0);
+#endif
+}
+
+/*
+ * Checks to see if a float4/8 val has underflowed or overflowed
+ */
+
+static inline void
+check_float4_val(float4 val, bool inf_is_valid, bool zero_is_valid)
+{
+	if (isinf(val) && !(inf_is_valid))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if ((val) == 0.0 && !(zero_is_valid))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+static inline void
+check_float8_val(float8 val, bool inf_is_valid, bool zero_is_valid)
+{
+	if (isinf(val) && !(inf_is_valid))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if ((val) == 0.0 && !(zero_is_valid))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+/*
+ * Routines for operations with the checks above
+ *
+ * There isn't any way to check for underflow of addition/subtraction
+ * because numbers near the underflow value have already been rounded to
+ * the point where we can't detect that the two values were originally
+ * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
+ * 1.4013e-45.
+ */
+
+static inline float4
+float4_pl(float4 val1, float4 val2)
+{
+	float4		result;
+
+	result = val1 + val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_pl(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = val1 + val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mi(float4 val1, float4 val2)
+{
+	float4		result;
+
+	result = val1 - val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_mi(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = val1 - val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mul(float4 val1, float4 val2)
+{
+	float4		result;
+
+	result = val1 * val2;
+	check_float4_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0f || val2 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_mul(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = val1 * val2;
+	check_float8_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0 || val2 == 0.0);
+
+	return result;
+}
+
+static inline float4
+float4_div(float4 val1, float4 val2)
+{
+	float4		result;
+
+	if (val2 == 0.0f)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), val1 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_div(float8 val1, float8 val2)
+{
+	float8		result;
+
+	if (val2 == 0.0)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
+
+	return result;
+}
+
+/*
+ * Routines for NaN-aware comparisons
+ *
+ * We consider all NANs to be equal and larger than any non-NAN. This is
+ * somewhat arbitrary; the important thing is to have a consistent sort
+ * order.
+ */
+
+static inline bool
+float4_eq(float4 val1, float4 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float8_eq(float8 val1, float8 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float4_ne(float4 val1, float4 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float8_ne(float8 val1, float8 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float4_lt(float4 val1, float4 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float8_lt(float8 val1, float8 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float4_le(float4 val1, float4 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float8_le(float8 val1, float8 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float4_gt(float4 val1, float4 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float8_gt(float8 val1, float8 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float4_ge(float4 val1, float4 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline bool
+float8_ge(float8 val1, float8 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline float4
+float4_min(float4 val1, float4 val2)
+{
+	return float4_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_min(float8 val1, float8 val2)
+{
+	return float8_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float4
+float4_max(float4 val1, float4 val2)
+{
+	return float4_gt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_max(float8 val1, float8 val2)
+{
+	return float8_gt(val1, val2) ? val1 : val2;
+}
+
+#endif							/* FLOAT_H */
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index c94e17af5f..22c68f5b62 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -17,20 +17,21 @@
  *		and data types. There are still some more to do. - tgl 97/04/19
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEO_DECLS_H
 #define GEO_DECLS_H
 
 #include <math.h>
 
 #include "fmgr.h"
+#include "utils/float.h"
 
 /*--------------------------------------------------------------------
  * Useful floating point utilities and constants.
  *-------------------------------------------------------------------*/
 
 
 #define EPSILON					1.0E-06
 
 #ifdef EPSILON
 #define FPzero(A)				(fabs(A) <= EPSILON)
-- 
2.13.5 (Apple Git-94)

0003-geo-float-v05.patchapplication/octet-stream; name=0003-geo-float-v05.patchDownload
From ca7b0db14e8f50bf81c601c66c1b785a977a88c7 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 27 May 2017 16:17:42 -0400
Subject: [PATCH 3/4] geo-float-v05

Use the built-in float datatype to implement geometric types

This will provide:

* Check for underflow and overflow
* Check for division by zero
* Handle NaNs consistently

The patch also replaces all occurrences of "double" as "float8".  They
are the same, but were randomly spread on the same file.
---
 src/backend/access/gist/gistproc.c | 156 +++++------
 src/backend/utils/adt/geo_ops.c    | 531 ++++++++++++++++++++-----------------
 src/backend/utils/adt/geo_spgist.c |  36 +--
 src/include/utils/geo_decls.h      |  41 ++-
 4 files changed, 400 insertions(+), 364 deletions(-)

diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index 13524b4da0..6fa97602c5 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -16,20 +16,21 @@
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/geo_decls.h"
 
 
 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
 						 StrategyNumber strategy);
 static bool rtree_internal_consistent(BOX *key, BOX *query,
 						  StrategyNumber strategy);
 
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
@@ -48,55 +49,56 @@ rt_box_union(BOX *n, const BOX *a, const BOX *b)
 	n->high.x = float8_max(a->high.x, b->high.x);
 	n->high.y = float8_max(a->high.y, b->high.y);
 	n->low.x = float8_min(a->low.x, b->low.x);
 	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
 	if (float8_le(box->high.x, box->low.x) ||
 		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
-	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
+	return float8_mul(float8_mi(box->high.x, box->low.x),
+					  float8_mi(box->high.y, box->low.y));
 }
 
 /*
  * Return amount by which the union of the two boxes is larger than
  * the original BOX's area.  The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 box_penalty(const BOX *original, const BOX *new)
 {
 	BOX			unionbox;
 
 	rt_box_union(&unionbox, original, new);
-	return size_box(&unionbox) - size_box(original);
+	return float8_mi(size_box(&unionbox), size_box(original));
 }
 
 /*
  * The GiST Consistent method for boxes
  *
  * Should return false if for all data items x below entry,
  * the predicate x op query must be FALSE, where op is the oper
  * corresponding to strategy in the pg_amop table.
  */
 Datum
@@ -256,74 +258,74 @@ fallbackSplit(GistEntryVector *entryvec, GIST_SPLITVEC *v)
 
 /*
  * Represents information about an entry that can be placed to either group
  * without affecting overlap over selected axis ("common entry").
  */
 typedef struct
 {
 	/* Index of entry in the initial array */
 	int			index;
 	/* Delta between penalties of entry insertion into different groups */
-	double		delta;
+	float8		delta;
 } CommonEntry;
 
 /*
  * Context for g_box_consider_split. Contains information about currently
  * selected split and some general information.
  */
 typedef struct
 {
 	int			entriesCount;	/* total number of entries being split */
 	BOX			boundingBox;	/* minimum bounding box across all entries */
 
 	/* Information about currently selected split follows */
 
 	bool		first;			/* true if no split was selected yet */
 
-	double		leftUpper;		/* upper bound of left interval */
-	double		rightLower;		/* lower bound of right interval */
+	float8		leftUpper;		/* upper bound of left interval */
+	float8		rightLower;		/* lower bound of right interval */
 
 	float4		ratio;
 	float4		overlap;
 	int			dim;			/* axis of this split */
-	double		range;			/* width of general MBR projection to the
+	float8		range;			/* width of general MBR projection to the
 								 * selected axis */
 } ConsiderSplitContext;
 
 /*
  * Interval represents projection of box to axis.
  */
 typedef struct
 {
-	double		lower,
+	float8		lower,
 				upper;
 } SplitInterval;
 
 /*
  * Interval comparison function by lower bound of the interval;
  */
 static int
 interval_cmp_lower(const void *i1, const void *i2)
 {
-	double		lower1 = ((const SplitInterval *) i1)->lower,
+	float8		lower1 = ((const SplitInterval *) i1)->lower,
 				lower2 = ((const SplitInterval *) i2)->lower;
 
 	return float8_cmp_internal(lower1, lower2);
 }
 
 /*
  * Interval comparison function by upper bound of the interval;
  */
 static int
 interval_cmp_upper(const void *i1, const void *i2)
 {
-	double		upper1 = ((const SplitInterval *) i1)->upper,
+	float8		upper1 = ((const SplitInterval *) i1)->upper,
 				upper2 = ((const SplitInterval *) i2)->upper;
 
 	return float8_cmp_internal(upper1, upper2);
 }
 
 /*
  * Replace negative (or NaN) value with zero.
  */
 static inline float
 non_negative(float val)
@@ -332,28 +334,28 @@ non_negative(float val)
 		return val;
 	else
 		return 0.0f;
 }
 
 /*
  * Consider replacement of currently selected split with the better one.
  */
 static inline void
 g_box_consider_split(ConsiderSplitContext *context, int dimNum,
-					 double rightLower, int minLeftCount,
-					 double leftUpper, int maxLeftCount)
+					 float8 rightLower, int minLeftCount,
+					 float8 leftUpper, int maxLeftCount)
 {
 	int			leftCount,
 				rightCount;
 	float4		ratio,
 				overlap;
-	double		range;
+	float8		range;
 
 	/*
 	 * Calculate entries distribution ratio assuming most uniform distribution
 	 * of common entries.
 	 */
 	if (minLeftCount >= (context->entriesCount + 1) / 2)
 	{
 		leftCount = minLeftCount;
 	}
 	else
@@ -362,52 +364,54 @@ g_box_consider_split(ConsiderSplitContext *context, int dimNum,
 			leftCount = maxLeftCount;
 		else
 			leftCount = context->entriesCount / 2;
 	}
 	rightCount = context->entriesCount - leftCount;
 
 	/*
 	 * Ratio of split - quotient between size of lesser group and total
 	 * entries count.
 	 */
-	ratio = ((float4) Min(leftCount, rightCount)) /
-		((float4) context->entriesCount);
+	ratio = float4_div(Min(leftCount, rightCount), context->entriesCount);
 
-	if (ratio > LIMIT_RATIO)
+	if (float4_gt(ratio, LIMIT_RATIO))
 	{
 		bool		selectthis = false;
 
 		/*
 		 * The ratio is acceptable, so compare current split with previously
 		 * selected one. Between splits of one dimension we search for minimal
 		 * overlap (allowing negative values) and minimal ration (between same
 		 * overlaps. We switch dimension if find less overlap (non-negative)
 		 * or less range with same overlap.
 		 */
 		if (dimNum == 0)
-			range = context->boundingBox.high.x - context->boundingBox.low.x;
+			range = float8_mi(context->boundingBox.high.x,
+							  context->boundingBox.low.x);
 		else
-			range = context->boundingBox.high.y - context->boundingBox.low.y;
+			range = float8_mi(context->boundingBox.high.y,
+							  context->boundingBox.low.y);
 
-		overlap = (leftUpper - rightLower) / range;
+		overlap = float8_div(float8_mi(leftUpper, rightLower), range);
 
 		/* If there is no previous selection, select this */
 		if (context->first)
 			selectthis = true;
 		else if (context->dim == dimNum)
 		{
 			/*
 			 * Within the same dimension, choose the new split if it has a
 			 * smaller overlap, or same overlap but better ratio.
 			 */
-			if (overlap < context->overlap ||
-				(overlap == context->overlap && ratio > context->ratio))
+			if (float4_lt(overlap, context->overlap) ||
+				(float4_eq(overlap, context->overlap) &&
+				 float4_gt(ratio, context->ratio)))
 				selectthis = true;
 		}
 		else
 		{
 			/*
 			 * Across dimensions, choose the new split if it has a smaller
 			 * *non-negative* overlap, or same *non-negative* overlap but
 			 * bigger range. This condition differs from the one described in
 			 * the article. On the datasets where leaf MBRs don't overlap
 			 * themselves, non-overlapping splits (i.e. splits which have zero
@@ -416,55 +420,49 @@ g_box_consider_split(ConsiderSplitContext *context, int dimNum,
 			 * non-overlapping splits (i.e. having lowest negative overlap)
 			 * appears to be in the same dimension as in the previous split.
 			 * Therefore MBRs appear to be very prolonged along another
 			 * dimension, which leads to bad search performance. Using range
 			 * as the second split criteria makes MBRs more quadratic. Using
 			 * *non-negative* overlap instead of overlap as the first split
 			 * criteria gives to range criteria a chance to matter, because
 			 * non-overlapping splits are equivalent in this criteria.
 			 */
 			if (non_negative(overlap) < non_negative(context->overlap) ||
-				(range > context->range &&
+				(float4_gt(range, context->range) &&
 				 non_negative(overlap) <= non_negative(context->overlap)))
 				selectthis = true;
 		}
 
 		if (selectthis)
 		{
 			/* save information about selected split */
 			context->first = false;
 			context->ratio = ratio;
 			context->range = range;
 			context->overlap = overlap;
 			context->rightLower = rightLower;
 			context->leftUpper = leftUpper;
 			context->dim = dimNum;
 		}
 	}
 }
 
 /*
  * Compare common entries by their deltas.
- * (We assume the deltas can't be NaN.)
  */
 static int
 common_entry_cmp(const void *i1, const void *i2)
 {
-	double		delta1 = ((const CommonEntry *) i1)->delta,
+	float8		delta1 = ((const CommonEntry *) i1)->delta,
 				delta2 = ((const CommonEntry *) i2)->delta;
 
-	if (delta1 < delta2)
-		return -1;
-	else if (delta1 > delta2)
-		return 1;
-	else
-		return 0;
+	return float8_cmp_internal(delta1, delta2);
 }
 
 /*
  * --------------------------------------------------------------------------
  * Double sorting split algorithm. This is used for both boxes and points.
  *
  * The algorithm finds split of boxes by considering splits along each axis.
  * Each entry is first projected as an interval on the X-axis, and different
  * ways to split the intervals into two groups are considered, trying to
  * minimize the overlap of the groups. Then the same is repeated for the
@@ -524,21 +522,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		else
 			adjustBox(&context.boundingBox, box);
 	}
 
 	/*
 	 * Iterate over axes for optimal split searching.
 	 */
 	context.first = true;		/* nothing selected yet */
 	for (dim = 0; dim < 2; dim++)
 	{
-		double		leftUpper,
+		float8		leftUpper,
 					rightLower;
 		int			i1,
 					i2;
 
 		/* Project each entry as an interval on the selected axis. */
 		for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 		{
 			box = DatumGetBoxP(entryvec->vector[i].key);
 			if (dim == 0)
 			{
@@ -721,21 +719,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 			*rightBox = *(box);					\
 		v->spl_right[v->spl_nright++] = off;	\
 	} while(0)
 
 	/*
 	 * Distribute entries which can be distributed unambiguously, and collect
 	 * common entries.
 	 */
 	for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 	{
-		double		lower,
+		float8		lower,
 					upper;
 
 		/*
 		 * Get upper and lower bounds along selected axis.
 		 */
 		box = DatumGetBoxP(entryvec->vector[i].key);
 		if (context.dim == 0)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
@@ -776,31 +774,31 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
 	{
 		/*
 		 * Calculate minimum number of entries that must be placed in both
 		 * groups, to reach LIMIT_RATIO.
 		 */
-		int			m = ceil(LIMIT_RATIO * (double) nentries);
+		int			m = ceil(LIMIT_RATIO * (float8) nentries);
 
 		/*
 		 * Calculate delta between penalties of join "common entries" to
 		 * different groups.
 		 */
 		for (i = 0; i < commonEntriesCount; i++)
 		{
 			box = DatumGetBoxP(entryvec->vector[commonEntries[i].index].key);
-			commonEntries[i].delta = Abs(box_penalty(leftBox, box) -
-										 box_penalty(rightBox, box));
+			commonEntries[i].delta = Abs(float8_mi(box_penalty(leftBox, box),
+												   box_penalty(rightBox, box)));
 		}
 
 		/*
 		 * Sort "common entries" by calculated deltas in order to distribute
 		 * the most ambiguous entries first.
 		 */
 		qsort(commonEntries, commonEntriesCount, sizeof(CommonEntry), common_entry_cmp);
 
 		/*
 		 * Distribute "common entries" between groups.
@@ -1100,24 +1098,24 @@ gist_circle_compress(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	GISTENTRY  *retval;
 
 	if (entry->leafkey)
 	{
 		CIRCLE	   *in = DatumGetCircleP(entry->key);
 		BOX		   *r;
 
 		r = (BOX *) palloc(sizeof(BOX));
-		r->high.x = in->center.x + in->radius;
-		r->low.x = in->center.x - in->radius;
-		r->high.y = in->center.y + in->radius;
-		r->low.y = in->center.y - in->radius;
+		r->high.x = float8_pl(in->center.x, in->radius);
+		r->low.x = float8_mi(in->center.x, in->radius);
+		r->high.y = float8_pl(in->center.y, in->radius);
+		r->low.y = float8_mi(in->center.y, in->radius);
 
 		retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
 		gistentryinit(*retval, PointerGetDatum(r),
 					  entry->rel, entry->page,
 					  entry->offset, FALSE);
 	}
 	else
 		retval = entry;
 	PG_RETURN_POINTER(retval);
 }
@@ -1141,24 +1139,24 @@ gist_circle_consistent(PG_FUNCTION_ARGS)
 	*recheck = true;
 
 	if (DatumGetBoxP(entry->key) == NULL || query == NULL)
 		PG_RETURN_BOOL(FALSE);
 
 	/*
 	 * Since the operators require recheck anyway, we can just use
 	 * rtree_internal_consistent even at leaf nodes.  (This works in part
 	 * because the index entries are bounding boxes not circles.)
 	 */
-	bbox.high.x = query->center.x + query->radius;
-	bbox.low.x = query->center.x - query->radius;
-	bbox.high.y = query->center.y + query->radius;
-	bbox.low.y = query->center.y - query->radius;
+	bbox.high.x = float8_pl(query->center.x, query->radius);
+	bbox.low.x = float8_mi(query->center.x, query->radius);
+	bbox.high.y = float8_pl(query->center.y, query->radius);
+	bbox.low.y = float8_mi(query->center.y, query->radius);
 
 	result = rtree_internal_consistent(DatumGetBoxP(entry->key),
 									   &bbox, strategy);
 
 	PG_RETURN_BOOL(result);
 }
 
 /**************************************************
  * Point ops
  **************************************************/
@@ -1209,80 +1207,84 @@ gist_point_fetch(PG_FUNCTION_ARGS)
 				  entry->offset, FALSE);
 
 	PG_RETURN_POINTER(retval);
 }
 
 
 #define point_point_distance(p1,p2) \
 	DatumGetFloat8(DirectFunctionCall2(point_distance, \
 									   PointPGetDatum(p1), PointPGetDatum(p2)))
 
-static double
+static float8
 computeDistance(bool isLeaf, BOX *box, Point *point)
 {
-	double		result = 0.0;
+	float8		result = 0.0;
 
 	if (isLeaf)
 	{
 		/* simple point to point distance */
 		result = point_point_distance(point, &box->low);
 	}
-	else if (point->x <= box->high.x && point->x >= box->low.x &&
-			 point->y <= box->high.y && point->y >= box->low.y)
+	else if (float8_le(point->x, box->high.x) &&
+			 float8_ge(point->x, box->low.x) &&
+			 float8_le(point->y, box->high.y) &&
+			 float8_ge(point->y, box->low.y))
 	{
 		/* point inside the box */
 		result = 0.0;
 	}
-	else if (point->x <= box->high.x && point->x >= box->low.x)
+	else if (float8_le(point->x, box->high.x) &&
+			 float8_ge(point->x, box->low.x))
 	{
 		/* point is over or below box */
-		Assert(box->low.y <= box->high.y);
-		if (point->y > box->high.y)
-			result = point->y - box->high.y;
-		else if (point->y < box->low.y)
-			result = box->low.y - point->y;
+		Assert(float8_le(box->low.y, box->high.y));
+		if (float8_gt(point->y, box->high.y))
+			result = float8_mi(point->y, box->high.y);
+		else if (float8_lt(point->y, box->low.y))
+			result = float8_mi(box->low.y, point->y);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
-	else if (point->y <= box->high.y && point->y >= box->low.y)
+	else if (float8_le(point->y, box->high.y) &&
+			 float8_ge(point->y, box->low.y))
 	{
 		/* point is to left or right of box */
-		Assert(box->low.x <= box->high.x);
-		if (point->x > box->high.x)
-			result = point->x - box->high.x;
-		else if (point->x < box->low.x)
-			result = box->low.x - point->x;
+		Assert(float8_lt(box->low.x, box->high.x));
+		if (float8_gt(point->x, box->high.x))
+			result = float8_mi(point->x, box->high.x);
+		else if (float8_lt(point->x, box->low.x))
+			result = float8_mi(box->low.x, point->x);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
 	else
 	{
 		/* closest point will be a vertex */
 		Point		p;
-		double		subresult;
+		float8		subresult;
 
 		result = point_point_distance(point, &box->low);
 
 		subresult = point_point_distance(point, &box->high);
-		if (result > subresult)
+		if (float8_gt(result, subresult))
 			result = subresult;
 
 		p.x = box->low.x;
 		p.y = box->high.y;
 		subresult = point_point_distance(point, &p);
-		if (result > subresult)
+		if (float8_gt(result, subresult))
 			result = subresult;
 
 		p.x = box->high.x;
 		p.y = box->low.y;
 		subresult = point_point_distance(point, &p);
-		if (result > subresult)
+		if (float8_gt(result, subresult))
 			result = subresult;
 	}
 
 	return result;
 }
 
 static bool
 gist_point_consistent_internal(StrategyNumber strategy,
 							   bool isLeaf, BOX *key, Point *query)
 {
@@ -1363,24 +1365,24 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 				 * Instead we write a non-fuzzy overlap test.  The same code
 				 * will also serve for leaf-page tests, since leaf keys have
 				 * high == low.
 				 */
 				BOX		   *query,
 						   *key;
 
 				query = PG_GETARG_BOX_P(1);
 				key = DatumGetBoxP(entry->key);
 
-				result = (key->high.x >= query->low.x &&
-						  key->low.x <= query->high.x &&
-						  key->high.y >= query->low.y &&
-						  key->low.y <= query->high.y);
+				result = (float8_ge(key->high.x, query->low.x) &&
+						  float8_le(key->low.x, query->high.x) &&
+						  float8_ge(key->high.y, query->low.y) &&
+						  float8_le(key->low.y, query->high.y));
 				*recheck = false;
 			}
 			break;
 		case PolygonStrategyNumberGroup:
 			{
 				POLYGON    *query = PG_GETARG_POLYGON_P(1);
 
 				result = DatumGetBool(DirectFunctionCall5(
 														  gist_poly_consistent,
 														  PointerGetDatum(entry),
@@ -1389,22 +1391,22 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 														  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);
+					Assert(float8_eq(box->high.x, box->low.x) &&
+						   float8_eq(box->high.y, box->low.y));
 					result = DatumGetBool(DirectFunctionCall2(
 															  poly_contain_pt,
 															  PolygonPGetDatum(query),
 															  PointPGetDatum(&box->high)));
 					*recheck = false;
 				}
 			}
 			break;
 		case CircleStrategyNumberGroup:
 			{
@@ -1418,22 +1420,22 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 														  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);
+					Assert(float8_eq(box->high.x, box->low.x) &&
+						   float8_eq(box->high.y, box->low.y));
 					result = DatumGetBool(DirectFunctionCall2(
 															  circle_contain_pt,
 															  CirclePGetDatum(query),
 															  PointPGetDatum(&box->high)));
 					*recheck = false;
 				}
 			}
 			break;
 		default:
 			elog(ERROR, "unrecognized strategy number: %d", strategy);
@@ -1442,21 +1444,21 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 	}
 
 	PG_RETURN_BOOL(result);
 }
 
 Datum
 gist_point_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(GIST_LEAF(entry),
 									   DatumGetBoxP(entry->key),
 									   PG_GETARG_POINT_P(1));
 			break;
 		default:
@@ -1471,25 +1473,25 @@ gist_point_distance(PG_FUNCTION_ARGS)
 /*
  * The inexact GiST distance method for geometric types that store bounding
  * boxes.
  *
  * Compute lossy distance from point to index entries.  The result is inexact
  * because index entries are bounding boxes, not the exact shapes of the
  * indexed geometric types.  We use distance from point to MBR of index entry.
  * This is a lower bound estimate of distance from point to indexed geometric
  * type.
  */
-static double
+static float8
 gist_bbox_distance(GISTENTRY *entry, Datum query,
 				   StrategyNumber strategy, bool *recheck)
 {
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	/* Bounding box distance is always inexact. */
 	*recheck = true;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(false,
 									   DatumGetBoxP(entry->key),
@@ -1505,32 +1507,32 @@ gist_bbox_distance(GISTENTRY *entry, Datum query,
 
 Datum
 gist_circle_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
 
 Datum
 gist_poly_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 2cae70e3df..a4f6c1992e 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -29,76 +29,77 @@
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
 /* Routines for float8 */
 static inline float8 float8_slope(float8 x1, float8 x2, float8 y1, float8 y2);
+static inline float8 float8_hypot(float8 x, float8 y);
 
 /* Routines for two-dimensional points */
 static inline void point_construct(Point *result, float8 x, float8 y);
 static inline void point_add_internal(Point *result, Point *pt1, Point *pt2);
 static inline void point_sub_internal(Point *result, Point *pt1, Point *pt2);
 static inline void point_mul_internal(Point *result, Point *pt1, Point *pt2);
 static inline void point_div_internal(Point *result, Point *pt1, Point *pt2);
 static inline bool point_eq_internal(Point *pt1, Point *pt2);
 static float8 point_dt(Point *pt1, Point *pt2);
 static int	point_inside(Point *p, int npts, Point *plist);
 
 /* Routines for two-dimensional boxes */
 static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
 static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
-static double box_ar(BOX *box);
-static double box_ht(BOX *box);
-static double box_wd(BOX *box);
+static float8 box_ar(BOX *box);
+static float8 box_ht(BOX *box);
+static float8 box_wd(BOX *box);
 
 /* Routines for two-dimensional circles */
-static double circle_ar(CIRCLE *circle);
+static float8 circle_ar(CIRCLE *circle);
 
 /* Routines for two-dimensional lines */
 static inline void line_construct_pm(LINE *result, Point *pt, float8 m);
 static inline void line_construct_pts(LINE *result, Point *pt1, Point *pt2);
 static bool line_interpt_internal(Point *result, LINE *l1, LINE *l2);
 static inline float8 line_calculate_point(LINE *line, Point *pt);
 
 /* Routines for two-dimensional line segments */
 static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
 static bool lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line);
 static bool lseg_interpt_internal(Point *result, LSEG *l1, LSEG *l2);
 static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
 static float8 lseg_dt(LSEG *l1, LSEG *l2);
-static int	lseg_crossing(double x, double y, double px, double py);
+static int	lseg_crossing(float8 x, float8 y, float8 px, float8 py);
 static bool on_ps_internal(Point *pt, LSEG *lseg);
 
 /* Routines for two-dimensional polygons */
 static void make_bound_box(POLYGON *poly);
 
 /* Unsorted */
 static bool plist_same(int npts, Point *p1, Point *p2);
-static double single_decode(char *num, char **endptr_p,
+static float8 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
-static void pair_decode(char *str, double *x, double *y, char **endptr_p,
+static void pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
 static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
-static double dist_pl_internal(Point *pt, LINE *line);
-static double dist_ps_internal(Point *pt, LSEG *lseg);
-static double dist_ppoly_internal(Point *pt, POLYGON *poly);
+static float8 dist_pl_internal(Point *pt, LINE *line);
+static float8 dist_ps_internal(Point *pt, LSEG *lseg);
+static float8 dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 
 /*
  * Delimiters for input and output strings.
  * LDELIM, RDELIM, and DELIM are left, right, and separator delimiters, respectively.
  * LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints.
  */
 
 #define LDELIM			'('
 #define RDELIM			')'
@@ -127,38 +128,38 @@ static double dist_ppoly_internal(Point *pt, POLYGON *poly);
  *
  * For boxes, the points are opposite corners with the first point at the top right.
  * For closed paths and polygons, the points should be reordered to allow
  *	fast and correct equality comparisons.
  *
  * XXX perhaps points in complex shapes should be reordered internally
  *	to allow faster internal operations, but should keep track of input order
  *	and restore that order for text output - tgl 97/01/16
  */
 
-static double
+static float8
 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string)
 {
 	return float8in_internal(num, endptr_p, type_name, orig_string);
 }								/* single_decode() */
 
 static void
 single_encode(float8 x, StringInfo str)
 {
 	char	   *xstr = float8out_internal(x);
 
 	appendStringInfoString(str, xstr);
 	pfree(xstr);
 }								/* single_encode() */
 
 static void
-pair_decode(char *str, double *x, double *y, char **endptr_p,
+pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string)
 {
 	bool		has_delim;
 
 	while (isspace((unsigned char) *str))
 		str++;
 	if ((has_delim = (*str == LDELIM)))
 		str++;
 
 	*x = float8in_internal(str, &str, type_name, orig_string);
@@ -358,21 +359,42 @@ pair_count(char *s, char delim)
  * to calculate inverse slope.  To achieve that pass the values in
  * (y1, y2, x2, x1) order.
  */
 static inline float8
 float8_slope(float8 x1, float8 x2, float8 y1, float8 y2)
 {
 	if (FPeq(x1, x2))
 		return DBL_MAX;
 	if (FPeq(y1, y2))
 		return 0.0;
-	return (y1 - y2) / (x1 - x2);
+	return float8_div(float8_mi(y1, y2), float8_mi(x1, x2));
+}
+
+
+/*
+ * Wrapper around libc hypot()
+ */
+static inline float8
+float8_hypot(float8 x, float8 y)
+{
+	float8		result;
+
+	errno = 0;
+	result = hypot(x, y);
+	if (errno == ERANGE)
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+	check_float8_val(result, isinf(x) || isinf(y), x == 0.0 && y == 0.0);
+	Assert(result >= 0.0);
+
+	return result;
 }
 
 
 /***********************************************************************
  **
  **		Routines for two-dimensional boxes.
  **
  ***********************************************************************/
 
 /*----------------------------------------------------------
@@ -384,33 +406,33 @@ float8_slope(float8 x1, float8 x2, float8 y1, float8 y2)
  *		External format: (two corners of box)
  *				"(f8, f8), (f8, f8)"
  *				also supports the older style "(f8, f8, f8, f8)"
  */
 Datum
 box_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	BOX		   *box = (BOX *) palloc(sizeof(BOX));
 	bool		isopen;
-	double		x,
+	float8		x,
 				y;
 
 	path_decode(str, false, 2, &(box->high), &isopen, NULL, "box", str);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*		box_out -		convert a box to external form.
@@ -424,38 +446,38 @@ box_out(PG_FUNCTION_ARGS)
 }
 
 /*
  *		box_recv			- converts external binary format to box
  */
 Datum
 box_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	BOX		   *box;
-	double		x,
+	float8		x,
 				y;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
 	box->high.x = pq_getmsgfloat8(buf);
 	box->high.y = pq_getmsgfloat8(buf);
 	box->low.x = pq_getmsgfloat8(buf);
 	box->low.y = pq_getmsgfloat8(buf);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*
@@ -474,31 +496,31 @@ box_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, box->low.y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*		box_construct	-		fill in a new box.
  */
 static inline void
 box_construct(BOX *result, Point *pt1, Point *pt2)
 {
-	if (pt1->x > pt2->x)
+	if (float8_gt(pt1->x, pt2->x))
 	{
 		result->high.x = pt1->x;
 		result->low.x = pt2->x;
 	}
 	else
 	{
 		result->high.x = pt2->x;
 		result->low.x = pt1->x;
 	}
-	if (pt1->y > pt2->y)
+	if (float8_gt(pt1->y, pt2->y))
 	{
 		result->high.y = pt1->y;
 		result->low.y = pt2->y;
 	}
 	else
 	{
 		result->high.y = pt2->y;
 		result->low.y = pt1->y;
 	}
 }
@@ -810,54 +832,54 @@ box_center(PG_FUNCTION_ARGS)
 	Point	   *result = (Point *) palloc(sizeof(Point));
 
 	box_cn(result, box);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		box_ar	-		returns the area of the box.
  */
-static double
+static float8
 box_ar(BOX *box)
 {
-	return box_wd(box) * box_ht(box);
+	return float8_mul(box_wd(box), box_ht(box));
 }
 
 
 /*		box_cn	-		stores the centerpoint of the box into *center.
  */
 static void
 box_cn(Point *center, BOX *box)
 {
-	center->x = (box->high.x + box->low.x) / 2.0;
-	center->y = (box->high.y + box->low.y) / 2.0;
+	center->x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	center->y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 }
 
 
 /*		box_wd	-		returns the width (length) of the box
  *								  (horizontal magnitude).
  */
-static double
+static float8
 box_wd(BOX *box)
 {
-	return box->high.x - box->low.x;
+	return float8_mi(box->high.x, box->low.x);
 }
 
 
 /*		box_ht	-		returns the height of the box
  *								  (vertical magnitude).
  */
-static double
+static float8
 box_ht(BOX *box)
 {
-	return box->high.y - box->low.y;
+	return float8_mi(box->high.y, box->low.y);
 }
 
 
 /*----------------------------------------------------------
  *	Funky operations.
  *---------------------------------------------------------*/
 
 /*		box_intersect	-
  *				returns the overlapping portion of two boxes,
  *				  or NULL if they do not intersect.
@@ -867,24 +889,24 @@ box_intersect(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 	BOX		   *result;
 
 	if (!box_ov(box1, box2))
 		PG_RETURN_NULL();
 
 	result = (BOX *) palloc(sizeof(BOX));
 
-	result->high.x = Min(box1->high.x, box2->high.x);
-	result->low.x = Max(box1->low.x, box2->low.x);
-	result->high.y = Min(box1->high.y, box2->high.y);
-	result->low.y = Max(box1->low.y, box2->low.y);
+	result->high.x = float8_min(box1->high.x, box2->high.x);
+	result->low.x = float8_max(box1->low.x, box2->low.x);
+	result->high.y = float8_min(box1->high.y, box2->high.y);
+	result->low.y = float8_max(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(result);
 }
 
 
 /*		box_diagonal	-
  *				returns a line segment which happens to be the
  *				  positive-slope diagonal of "box".
  */
 Datum
@@ -1015,30 +1037,30 @@ line_send(PG_FUNCTION_ARGS)
 
 /*
  * Fill already-allocated LINE struct from the point and the slope
  */
 static inline void
 line_construct_pm(LINE *result, Point *pt, float8 m)
 {
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
-		result->A = -1;
-		result->B = 0;
+		result->A = -1.0;
+		result->B = 0.0;
 		result->C = pt->x;
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
-		result->C = pt->y - m * pt->x;
+		result->C = float8_mi(pt->y, float8_mul(m, pt->x));
 	}
 }
 
 
 /*
  * Fill already-allocated LINE struct from two points on the line
  */
 static inline void
 line_construct_pts(LINE *result, Point *pt1, Point *pt2)
 {
@@ -1066,21 +1088,22 @@ line_construct_pp(PG_FUNCTION_ARGS)
 
 /*
  * Calculate the line equation for a point
  *
  * This returns the result of the line equation Ax + By + C.  The result
  * needs to be 0 for the point to be on the line.
  */
 static inline float8
 line_calculate_point(LINE *line, Point *pt)
 {
-	return line->A * pt->x + line->B * pt->y + line->C;
+	return float8_pl(float8_pl(float8_mul(line->A, pt->x),
+							   float8_mul(line->B, pt->y)), line->C);
 }
 
 
 /*----------------------------------------------------------
  *	Relative position routines.
  *---------------------------------------------------------*/
 
 Datum
 line_intersect(PG_FUNCTION_ARGS)
 {
@@ -1103,21 +1126,22 @@ Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
 	else if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
 
-	PG_RETURN_BOOL(FPeq(((l1->A * l2->B) / (l1->B * l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
+								   float8_mul(l1->B, l2->A)), -1.0));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
@@ -1127,34 +1151,34 @@ line_horizontal(PG_FUNCTION_ARGS)
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->A));
 }
 
 Datum
 line_eq(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	double		k;
+	float8		ratio;
 
 	if (!FPzero(l2->A))
-		k = l1->A / l2->A;
+		ratio = float8_div(l1->A, l2->A);
 	else if (!FPzero(l2->B))
-		k = l1->B / l2->B;
+		ratio = float8_div(l1->B, l2->B);
 	else if (!FPzero(l2->C))
-		k = l1->C / l2->C;
+		ratio = float8_div(l1->C, l2->C);
 	else
-		k = 1.0;
+		ratio = 1.0;
 
-	PG_RETURN_BOOL(FPeq(l1->A, k * l2->A) &&
-				   FPeq(l1->B, k * l2->B) &&
-				   FPeq(l1->C, k * l2->C));
+	PG_RETURN_BOOL(FPeq(l1->A, float8_mul(ratio, l2->A)) &&
+				   FPeq(l1->B, float8_mul(ratio, l2->B)) &&
+				   FPeq(l1->C, float8_mul(ratio, l2->C)));
 }
 
 
 /*----------------------------------------------------------
  *	Line arithmetic routines.
  *---------------------------------------------------------*/
 
 /* line_distance()
  * Distance between two lines.
  */
@@ -1162,21 +1186,21 @@ Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
 	Point		tmp;
 
 	if (line_interpt_internal(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
+		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
 	point_construct(&tmp, 0.0, l1->C);
 	result = dist_pl_internal(&tmp, l2);
 	PG_RETURN_FLOAT8(result);
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
@@ -1199,41 +1223,41 @@ line_interpt(PG_FUNCTION_ARGS)
  * parallel), false if they do not.  This also sets the intersection point
  * to *result, if it is not NULL.
  *
  * NOTE: If the lines are identical then we will find they are parallel
  * and report "no intersection".  This is a little weird, but since
  * there's no *unique* intersection, maybe it's appropriate behavior.
  */
 static bool
 line_interpt_internal(Point *result, LINE *l1, LINE *l2)
 {
-	double		x,
+	float8		x,
 				y;
 
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
 		if (FPzero(l2->B))		/* l2 vertical? */
 			return false;
 
 		x = l1->C;
-		y = (l2->A * x + l2->C);
+		y = float8_pl(float8_mul(l2->A, x), l2->C);
 	}
 	else
 	{
-		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
 			return false;
 
 		if (FPzero(l2->B))
 			x = l2->C;
 		else
-			x = (l1->C - l2->C) / (l2->A - l1->A);
-		y = (l1->A * x + l1->C);
+			x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
+		y = float8_pl(float8_mul(l1->A, x), l1->C);
 	}
 	if (result != NULL)
 		point_construct(result, x, y);
 
 #ifdef GEODEBUG
 	printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
 		   DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
 	printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
 #endif
 
@@ -1260,36 +1284,35 @@ line_interpt_internal(Point *result, LINE *l1, LINE *l2)
  *				"(xcoord, ycoord),... "
  *				"[xcoord, ycoord,... ]"
  *		Also support older format:
  *				"(closed, npts, xcoord, ycoord,... )"
  *---------------------------------------------------------*/
 
 Datum
 path_area(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P(0);
-	double		area = 0.0;
+	float8		area = 0.0;
 	int			i,
 				j;
 
 	if (!path->closed)
 		PG_RETURN_NULL();
 
 	for (i = 0; i < path->npts; i++)
 	{
 		j = (i + 1) % path->npts;
-		area += path->p[i].x * path->p[j].y;
-		area -= path->p[i].y * path->p[j].x;
+		area = float8_pl(area, float8_mul(path->p[i].x, path->p[j].y));
+		area = float8_mi(area, float8_mul(path->p[i].y, path->p[j].x));
 	}
 
-	area *= 0.5;
-	PG_RETURN_FLOAT8(area < 0.0 ? -area : area);
+	PG_RETURN_FLOAT8(float8_div(fabs(area), 2.0));
 }
 
 
 Datum
 path_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	PATH	   *path;
 	bool		isopen;
 	char	   *s;
@@ -1506,31 +1529,31 @@ path_npoints(PG_FUNCTION_ARGS)
 
 	PG_RETURN_INT32(path->npts);
 }
 
 
 Datum
 path_close(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 
-	path->closed = TRUE;
+	path->closed = true;
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_open(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 
-	path->closed = FALSE;
+	path->closed = false;
 
 	PG_RETURN_PATH_P(path);
 }
 
 
 /* path_inter -
  *		Does p1 intersect p2 at any point?
  *		Use bounding boxes for a quick (O(n)) check, then do a
  *		O(n^2) iterative edge check.
  */
@@ -1546,33 +1569,33 @@ path_inter(PG_FUNCTION_ARGS)
 	LSEG		seg1,
 				seg2;
 
 	if (p1->npts <= 0 || p2->npts <= 0)
 		PG_RETURN_BOOL(false);
 
 	b1.high.x = b1.low.x = p1->p[0].x;
 	b1.high.y = b1.low.y = p1->p[0].y;
 	for (i = 1; i < p1->npts; i++)
 	{
-		b1.high.x = Max(p1->p[i].x, b1.high.x);
-		b1.high.y = Max(p1->p[i].y, b1.high.y);
-		b1.low.x = Min(p1->p[i].x, b1.low.x);
-		b1.low.y = Min(p1->p[i].y, b1.low.y);
+		b1.high.x = float8_max(p1->p[i].x, b1.high.x);
+		b1.high.y = float8_max(p1->p[i].y, b1.high.y);
+		b1.low.x = float8_min(p1->p[i].x, b1.low.x);
+		b1.low.y = float8_min(p1->p[i].y, b1.low.y);
 	}
 	b2.high.x = b2.low.x = p2->p[0].x;
 	b2.high.y = b2.low.y = p2->p[0].y;
 	for (i = 1; i < p2->npts; i++)
 	{
-		b2.high.x = Max(p2->p[i].x, b2.high.x);
-		b2.high.y = Max(p2->p[i].y, b2.high.y);
-		b2.low.x = Min(p2->p[i].x, b2.low.x);
-		b2.low.y = Min(p2->p[i].y, b2.low.y);
+		b2.high.x = float8_max(p2->p[i].x, b2.high.x);
+		b2.high.y = float8_max(p2->p[i].y, b2.high.y);
+		b2.low.x = float8_min(p2->p[i].x, b2.low.x);
+		b2.low.y = float8_min(p2->p[i].y, b2.low.y);
 	}
 	if (!box_ov(&b1, &b2))
 		PG_RETURN_BOOL(false);
 
 	/* pairwise check lseg intersections */
 	for (i = 0; i < p1->npts; i++)
 	{
 		int			iprev;
 
 		if (i > 0)
@@ -1648,21 +1671,21 @@ path_distance(PG_FUNCTION_ARGS)
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
 			tmp = lseg_dt(&seg1, &seg2);
-			if (!have_min || tmp < min)
+			if (!have_min || float8_lt(tmp, min))
 			{
 				min = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	if (!have_min)
 		PG_RETURN_NULL();
 
@@ -1687,21 +1710,21 @@ path_length(PG_FUNCTION_ARGS)
 
 		if (i > 0)
 			iprev = i - 1;
 		else
 		{
 			if (!path->closed)
 				continue;
 			iprev = path->npts - 1; /* include the closure segment */
 		}
 
-		result += point_dt(&path->p[iprev], &path->p[i]);
+		result = float8_pl(result, point_dt(&path->p[iprev], &path->p[i]));
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /***********************************************************************
  **
  **		Routines for 2D points.
  **
  ***********************************************************************/
@@ -1875,21 +1898,21 @@ point_distance(PG_FUNCTION_ARGS)
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
 static float8
 point_dt(Point *pt1, Point *pt2)
 {
 	float8		result;
 
-	result = hypot(pt1->x - pt2->x, pt1->y - pt2->y);
+	result = float8_hypot(float8_mi(pt1->x, pt2->x), float8_mi(pt1->y, pt2->y));
 
 #ifdef GEODEBUG
 	printf("point_dt- segment (%f,%f),(%f,%f) length is %f\n",
 		   pt1->x, pt1->y, pt2->x, pt2->y, result);
 #endif
 
 	return result;
 }
 
 Datum
@@ -2049,35 +2072,35 @@ lseg_parallel(PG_FUNCTION_ARGS)
  *	'((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg
  * So, modified it to check explicitly for slope of vertical line
  *	returned by float8_slope() and the results seem better.
  * - thomas 1998-01-31
  */
 Datum
 lseg_perp(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	double		m1,
+	float8		m1,
 				m2;
 
 	m1 = float8_slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y);
 	m2 = float8_slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y);
 
 #ifdef GEODEBUG
 	printf("lseg_perp- slopes are %g and %g\n", m1, m2);
 #endif
 	if (FPzero(m1))
 		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
 	else if (FPzero(m2))
 		PG_RETURN_BOOL(FPeq(m1, DBL_MAX));
 
-	PG_RETURN_BOOL(FPeq(m1 / m2, -1.0));
+	PG_RETURN_BOOL(FPeq(float8_div(m1, m2), -1.0));
 }
 
 Datum
 lseg_vertical(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 
 	PG_RETURN_BOOL(FPeq(lseg->p[0].x, lseg->p[1].x));
 }
 
@@ -2167,52 +2190,47 @@ lseg_distance(PG_FUNCTION_ARGS)
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_FLOAT8(lseg_dt(l1, l2));
 }
 
 /* lseg_dt()
  * Distance between two line segments.
  * Must check both sets of endpoints to ensure minimum distance is found.
  * - thomas 1998-02-01
  */
-static double
+static float8
 lseg_dt(LSEG *l1, LSEG *l2)
 {
-	double		result,
-				d;
+	float8		result;
 
 	if (lseg_interpt_internal(NULL, l1, l2))
 		return 0.0;
 
-	d = dist_ps_internal(&l1->p[0], l2);
-	result = d;
-	d = dist_ps_internal(&l1->p[1], l2);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[0], l1);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[1], l1);
-	result = Min(result, d);
+	result = dist_ps_internal(&l1->p[0], l2);
+	result = float8_min(result, dist_ps_internal(&l1->p[1], l2));
+	result = float8_min(result, dist_ps_internal(&l2->p[0], l1));
+	result = float8_min(result, dist_ps_internal(&l2->p[1], l1));
 
 	return result;
 }
 
 
 Datum
 lseg_center(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
-	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
+	result->x = float8_div(float8_pl(lseg->p[0].x, lseg->p[1].x), 2.0);
+	result->y = float8_div(float8_pl(lseg->p[0].y, lseg->p[1].y), 2.0);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static bool
 lseg_interpt_internal(Point *result, LSEG *l1, LSEG *l2)
 {
 	Point		interpt;
 	LINE		tmp1,
 				tmp2;
@@ -2296,45 +2314,44 @@ lseg_interpt(PG_FUNCTION_ARGS)
  */
 Datum
 dist_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
 	PG_RETURN_FLOAT8(dist_pl_internal(pt, line));
 }
 
-static double
+static float8
 dist_pl_internal(Point *pt, LINE *line)
 {
-	return fabs(line_calculate_point(line, pt) /
-				hypot(line->A, line->B));
+	return float8_div(fabs(line_calculate_point(line, pt)),
+					  float8_hypot(line->A, line->B));
 }
 
 /*
  * Distance from a point to a lseg
  */
 Datum
 dist_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_FLOAT8(dist_ps_internal(pt, lseg));
 }
 
-static double
+static float8
 dist_ps_internal(Point *pt, LSEG *lseg)
 {
-	double		m;				/* slope of perp. */
-	double		result,
-				tmpdist;
+	float8		m;				/* slope of perp. */
+	float8		result;
 	Point		interpt;
 	LINE		ln;
 
 	/*
 	 * Construct a line perpendicular to the input segment and through the
 	 * input point
 	 */
 	m = float8_slope(lseg->p[0].y, lseg->p[1].y, lseg->p[1].x, lseg->p[0].x);
 	line_construct_pm(&ln, pt, m);
 
@@ -2354,24 +2371,22 @@ dist_ps_internal(Point *pt, LSEG *lseg)
 		/* yes, so use distance to the intersection point */
 		result = point_dt(pt, &interpt);
 #ifdef GEODEBUG
 		printf("dist_ps- distance is %f to intersection point is (%f,%f)\n",
 			   result, tmp.x, tmp.y);
 #endif
 	}
 	else
 	{
 		/* no, so use distance to the nearer endpoint */
-		result = point_dt(pt, &lseg->p[0]);
-		tmpdist = point_dt(pt, &lseg->p[1]);
-		if (tmpdist < result)
-			result = tmpdist;
+		result = float8_min(point_dt(pt, &lseg->p[0]),
+							point_dt(pt, &lseg->p[1]));
 	}
 
 	return result;
 }
 
 /*
  * Distance from a point to a path
  */
 Datum
 dist_ppath(PG_FUNCTION_ARGS)
@@ -2409,21 +2424,21 @@ dist_ppath(PG_FUNCTION_ARGS)
 					iprev = i - 1;
 				else
 				{
 					if (!path->closed)
 						continue;
 					iprev = path->npts - 1; /* include the closure segment */
 				}
 
 				statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
 				tmp = dist_ps_internal(pt, &lseg);
-				if (!have_min || tmp < result)
+				if (!have_min || float8_lt(tmp, result))
 				{
 					result = tmp;
 					have_min = true;
 				}
 			}
 			break;
 	}
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -2447,33 +2462,28 @@ dist_pb(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
-	float8		result,
-				d2;
+	float8		result;
 
 	if (lseg_interpt_line_internal(NULL, lseg, line))
 		result = 0.0;
 	else
-	{
-		result = dist_pl_internal(&lseg->p[0], line);
-		d2 = dist_pl_internal(&lseg->p[1], line);
 		/* XXX shouldn't we take the min not max? */
-		if (d2 > result)
-			result = d2;
-	}
+		result = float8_max(dist_pl_internal(&lseg->p[0], line),
+							dist_pl_internal(&lseg->p[1], line));
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
@@ -2515,25 +2525,22 @@ dist_lb(PG_FUNCTION_ARGS)
  * Distance from a circle to a polygon
  */
 Datum
 dist_cpoly(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	POLYGON    *poly = PG_GETARG_POLYGON_P(1);
 	float8		result;
 
 	/* calculate distance to center, and subtract radius */
-	result = dist_ppoly_internal(&circle->center, poly);
-
-	result -= circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_min(float8_mi(dist_ppoly_internal(&circle->center, poly),
+								  circle->radius), 0.0);
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a point to a polygon
  */
 Datum
 dist_ppoly(PG_FUNCTION_ARGS)
 {
@@ -2551,21 +2558,21 @@ dist_polyp(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	float8		result;
 
 	result = dist_ppoly_internal(point, poly);
 
 	PG_RETURN_FLOAT8(result);
 }
 
-static double
+static float8
 dist_ppoly_internal(Point *pt, POLYGON *poly)
 {
 	float8		result;
 	float8		d;
 	int			i;
 	LSEG		seg;
 
 	if (point_inside(pt, poly->npts, poly->p) != 0)
 	{
 #ifdef GEODEBUG
@@ -2588,21 +2595,21 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
 	for (i = 0; (i < poly->npts - 1); i++)
 	{
 		seg.p[0].x = poly->p[i].x;
 		seg.p[0].y = poly->p[i].y;
 		seg.p[1].x = poly->p[i + 1].x;
 		seg.p[1].y = poly->p[i + 1].y;
 		d = dist_ps_internal(pt, &seg);
 #ifdef GEODEBUG
 		printf("dist_ppoly_internal- segment %d distance is %f\n", (i + 1), d);
 #endif
-		if (d < result)
+		if (float8_lt(d, result))
 			result = d;
 	}
 
 	return result;
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
  *				Intersection point of objects.
@@ -2672,21 +2679,21 @@ close_pl(PG_FUNCTION_ARGS)
 		point_construct(result, pt->x, line->C);
 	else
 	{
 		LINE		tmp;
 
 		/*
 		 * Drop a perpendicular and find the intersection point
 		 *
 		 * We need to invert the slope to get the perpendicular.
 		 */
-		line_construct_pm(&tmp, pt, line->B / line->A);
+		line_construct_pm(&tmp, pt, float8_div(line->B, line->A));
 		line_interpt_internal(result, &tmp, line);
 	}
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_ps()
  * Closest point on line segment to specified point.
  * Take the closest endpoint if the point is left, right,
@@ -2696,21 +2703,21 @@ close_pl(PG_FUNCTION_ARGS)
  * Some tricky code here, relying on boolean expressions
  *	evaluating to only zero or one to use as an array index.
  *		bug fixes by gthaker@atl.lmco.com; May 1, 1998
  */
 Datum
 close_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
-	double		invm;
+	float8		invm;
 	int			xh,
 				yh;
 	LINE		tmp;
 
 	result = (Point *) palloc(sizeof(Point));
 
 #ifdef GEODEBUG
 	printf("close_sp:pt->x %f pt->y %f\nlseg(0).x %f lseg(0).y %f  lseg(1).x %f lseg(1).y %f\n",
 		   pt->x, pt->y, lseg->p[0].x, lseg->p[0].y,
 		   lseg->p[1].x, lseg->p[1].y);
@@ -2755,32 +2762,32 @@ close_ps(PG_FUNCTION_ARGS)
 	}
 
 	/*
 	 * vert. and horiz. cases are down, now check if the closest point is one
 	 * of the end points or someplace on the lseg.
 	 */
 
 	invm = float8_slope(lseg->p[0].y, lseg->p[1].y, lseg->p[1].x, lseg->p[0].x);
 	line_construct_pm(&tmp, &lseg->p[!yh], invm);	/* lower edge of the
 													 * "band" */
-	if (pt->y < (tmp.A * pt->x + tmp.C))
+	if (pt->y < float8_pl(float8_mul(tmp.A, pt->x), tmp.C))
 	{							/* we are below the lower edge */
 		*result = lseg->p[!yh]; /* below the lseg, take lower end pt */
 #ifdef GEODEBUG
 		printf("close_ps below: tmp A %f  B %f   C %f\n",
 			   tmp->A, tmp->B, tmp->C);
 #endif
 		PG_RETURN_POINT_P(result);
 	}
 	line_construct_pm(&tmp, &lseg->p[yh], invm);	/* upper edge of the
 													 * "band" */
-	if (pt->y > (tmp.A * pt->x + tmp.C))
+	if (pt->y > float8_pl(float8_mul(tmp.A, pt->x), tmp.C))
 	{							/* we are below the lower edge */
 		*result = lseg->p[yh];	/* above the lseg, take higher end pt */
 #ifdef GEODEBUG
 		printf("close_ps above: tmp A %f  B %f   C %f\n",
 			   tmp->A, tmp->B, tmp->C);
 #endif
 		PG_RETURN_POINT_P(result);
 	}
 
 	/*
@@ -2816,32 +2823,32 @@ close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 	double		dist,
 				dist0,
 				dist1;
 
 	dist0 = dist_ps_internal(&l1->p[0], l2);
 	dist1 = dist_ps_internal(&l1->p[1], l2);
-	dist = Min(dist0, dist1);
+	dist = float8_min(dist0, dist1);
 
-	if (dist_ps_internal(&l2->p[0], l1) < dist)
+	if (float8_lt(dist_ps_internal(&l2->p[0], l1), dist))
 	{
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(&l2->p[0]),
 													LsegPGetDatum(l1)));
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(result),
 													LsegPGetDatum(l2)));
 	}
-	else if (dist_ps_internal(&l2->p[1], l1) < dist)
+	else if (float8_lt(dist_ps_internal(&l2->p[1], l1), dist))
 	{
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(&l2->p[1]),
 													LsegPGetDatum(l1)));
 		result = DatumGetPointP(DirectFunctionCall2(close_ps,
 													PointPGetDatum(result),
 													LsegPGetDatum(l2)));
 	}
 	else
 	{
@@ -2856,52 +2863,55 @@ close_lseg(PG_FUNCTION_ARGS)
  * Closest point on or in box to specified point.
  */
 Datum
 close_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	LSEG		lseg,
 				seg;
 	Point		point;
-	double		dist,
+	float8		dist,
 				d;
 
 	if (DatumGetBool(DirectFunctionCall2(on_pb,
 										 PointPGetDatum(pt),
 										 BoxPGetDatum(box))))
 		PG_RETURN_POINT_P(pt);
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&lseg, &box->low, &point);
 	dist = dist_ps_internal(pt, &lseg);
 
 	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	d = dist_ps_internal(pt, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&lseg, &seg, sizeof(lseg));
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&seg, &box->low, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	d = dist_ps_internal(pt, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&lseg, &seg, sizeof(lseg));
 	}
 
 	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	d = dist_ps_internal(pt, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&lseg, &seg, sizeof(lseg));
 	}
 
 	PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
 										PointPGetDatum(pt),
 										LsegPGetDatum(&lseg)));
 }
 
@@ -2924,21 +2934,21 @@ close_sl(PG_FUNCTION_ARGS)
 	float8		d1,
 				d2;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (lseg_interpt_line_internal(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = dist_pl_internal(&lseg->p[0], line);
 	d2 = dist_pl_internal(&lseg->p[1], line);
-	if (d1 < d2)
+	if (float8_lt(d1, d2))
 		*result = lseg->p[0];
 	else
 		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
 
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_sl\" not implemented")));
@@ -2958,77 +2968,80 @@ close_ls(PG_FUNCTION_ARGS)
 	float8		d1,
 				d2;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (lseg_interpt_line_internal(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = dist_pl_internal(&lseg->p[0], line);
 	d2 = dist_pl_internal(&lseg->p[1], line);
-	if (d1 < d2)
+	if (float8_lt(d1, d2))
 		*result = lseg->p[0];
 	else
 		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 }
 
 /* close_sb()
  * Closest point on or in box to line segment.
  */
 Datum
 close_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	Point		point;
 	LSEG		bseg,
 				seg;
-	double		dist,
+	float8		dist,
 				d;
 
 	/* segment intersects box? then just return closest point to center */
 	if (DatumGetBool(DirectFunctionCall2(inter_sb,
 										 LsegPGetDatum(lseg),
 										 BoxPGetDatum(box))))
 	{
 		box_cn(&point, box);
 		PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
 											PointPGetDatum(&point),
 											LsegPGetDatum(lseg)));
 	}
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
 	dist = lseg_dt(lseg, &bseg);
 
 	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	d = lseg_dt(lseg, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&bseg, &seg, sizeof(bseg));
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&seg, &box->low, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	d = lseg_dt(lseg, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&bseg, &seg, sizeof(bseg));
 	}
 
 	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	d = lseg_dt(lseg, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&bseg, &seg, sizeof(bseg));
 	}
 
 	/* OK, we now have the closest line segment on the box boundary */
 	PG_RETURN_DATUM(DirectFunctionCall2(close_lseg,
 										LsegPGetDatum(lseg),
 										LsegPGetDatum(&bseg)));
 }
@@ -3076,50 +3089,55 @@ on_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_BOOL(on_ps_internal(pt, lseg));
 }
 
 static bool
 on_ps_internal(Point *pt, LSEG *lseg)
 {
-	return FPeq(point_dt(pt, &lseg->p[0]) + point_dt(pt, &lseg->p[1]),
+	return FPeq(float8_pl(point_dt(pt, &lseg->p[0]),
+						  point_dt(pt, &lseg->p[1])),
 				point_dt(&lseg->p[0], &lseg->p[1]));
 }
 
 
 /*
  * Check whether the point is in the box or on its border
  */
 Datum
 on_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_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);
+	PG_RETURN_BOOL(float8_le(pt->x, box->high.x) &&
+				   float8_ge(pt->x, box->low.x) &&
+				   float8_le(pt->y, box->high.y) &&
+				   float8_ge(pt->y, box->low.y));
 }
 
 
 /*
  * Commutator of on_pb()
  */
 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);
+	PG_RETURN_BOOL(float8_le(pt->x, box->high.x) &&
+				   float8_ge(pt->x, box->low.x) &&
+				   float8_le(pt->y, box->high.y) &&
+				   float8_ge(pt->y, box->low.y));
 }
 
 
 /* on_ppath -
  *		Whether a point lies within (on) a polyline.
  *		If open, we have to (groan) check each segment.
  * (uses same algorithm as for point intersecting segment - tgl 1997-07-09)
  *		If closed, we use the old O(n) ray method for point-in-polygon.
  *				The ray is horizontal, from pt out to the right.
  *				Each segment that crosses the ray counts as an
@@ -3127,33 +3145,32 @@ box_contain_pt(PG_FUNCTION_ARGS)
  *				but not cross.
  *				(we can do p-in-p in lg(n), but it takes preprocessing)
  */
 Datum
 on_ppath(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	PATH	   *path = PG_GETARG_PATH_P(1);
 	int			i,
 				n;
-	double		a,
+	float8		a,
 				b;
 
 	/*-- OPEN --*/
 	if (!path->closed)
 	{
 		n = path->npts - 1;
 		a = point_dt(pt, &path->p[0]);
 		for (i = 0; i < n; i++)
 		{
 			b = point_dt(pt, &path->p[i + 1]);
-			if (FPeq(a + b,
-					 point_dt(&path->p[i], &path->p[i + 1])))
+			if (FPeq(float8_pl(a, b), point_dt(&path->p[i], &path->p[i + 1])))
 				PG_RETURN_BOOL(true);
 			a = b;
 		}
 		PG_RETURN_BOOL(false);
 	}
 
 	/*-- CLOSED --*/
 	PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
 }
 
@@ -3223,24 +3240,24 @@ inter_sl(PG_FUNCTION_ARGS)
  */
 Datum
 inter_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	BOX			lbox;
 	LSEG		bseg;
 	Point		point;
 
-	lbox.low.x = Min(lseg->p[0].x, lseg->p[1].x);
-	lbox.low.y = Min(lseg->p[0].y, lseg->p[1].y);
-	lbox.high.x = Max(lseg->p[0].x, lseg->p[1].x);
-	lbox.high.y = Max(lseg->p[0].y, lseg->p[1].y);
+	lbox.low.x = float8_min(lseg->p[0].x, lseg->p[1].x);
+	lbox.low.y = float8_min(lseg->p[0].y, lseg->p[1].y);
+	lbox.high.x = float8_max(lseg->p[0].x, lseg->p[1].x);
+	lbox.high.y = float8_max(lseg->p[0].y, lseg->p[1].y);
 
 	/* nothing close to overlap? then not going to intersect */
 	if (!box_ov(&lbox, box))
 		PG_RETURN_BOOL(false);
 
 	/* an endpoint of segment is inside box? then clearly intersects */
 	if (DatumGetBool(DirectFunctionCall2(on_pb,
 										 PointPGetDatum(&lseg->p[0]),
 										 BoxPGetDatum(box))) ||
 		DatumGetBool(DirectFunctionCall2(on_pb,
@@ -3329,27 +3346,27 @@ make_bound_box(POLYGON *poly)
 {
 	int			i;
 	BOX		   *boundbox = &poly->boundbox;
 
 	if (poly->npts > 0)
 	{
 		boundbox->low.x = boundbox->high.x = poly->p[0].x;
 		boundbox->low.y = boundbox->high.y = poly->p[0].y;
 		for (i = 1; i < poly->npts; i++)
 		{
-			if (poly->p[i].x < boundbox->low.x)
+			if (float8_lt(poly->p[i].x, boundbox->low.x))
 				boundbox->low.x = poly->p[i].x;
-			if (poly->p[i].x > boundbox->high.x)
+			if (float8_gt(poly->p[i].x, boundbox->high.x))
 				boundbox->high.x = poly->p[i].x;
-			if (poly->p[i].y < boundbox->low.y)
+			if (float8_lt(poly->p[i].y, boundbox->low.y))
 				boundbox->low.y = poly->p[i].y;
-			if (poly->p[i].y > boundbox->high.y)
+			if (float8_gt(poly->p[i].y, boundbox->high.y))
 				boundbox->high.y = poly->p[i].y;
 		}
 	}
 	else
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("cannot create bounding box for empty polygon")));
 }
 
 /*------------------------------------------------------------------
@@ -3475,21 +3492,21 @@ poly_send(PG_FUNCTION_ARGS)
  * the right most point of A left of the left most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_left(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.high.x < polyb->boundbox.low.x;
+	result = float8_lt(polya->boundbox.high.x, polyb->boundbox.low.x);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3498,21 +3515,21 @@ poly_left(PG_FUNCTION_ARGS)
  * the right most point of A at or left of the right most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_overleft(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.high.x <= polyb->boundbox.high.x;
+	result = float8_le(polya->boundbox.high.x, polyb->boundbox.high.x);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3521,21 +3538,21 @@ poly_overleft(PG_FUNCTION_ARGS)
  * the left most point of A right of the right most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_right(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.low.x > polyb->boundbox.high.x;
+	result = float8_gt(polya->boundbox.low.x, polyb->boundbox.high.x);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3544,21 +3561,21 @@ poly_right(PG_FUNCTION_ARGS)
  * the left most point of A at or right of the left most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_overright(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.low.x >= polyb->boundbox.low.x;
+	result = float8_ge(polya->boundbox.low.x, polyb->boundbox.low.x);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3567,21 +3584,21 @@ poly_overright(PG_FUNCTION_ARGS)
  * the upper most point of A below the lower most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_below(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.high.y < polyb->boundbox.low.y;
+	result = float8_lt(polya->boundbox.high.y, polyb->boundbox.low.y);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3590,21 +3607,21 @@ poly_below(PG_FUNCTION_ARGS)
  * the upper most point of A at or below the upper most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_overbelow(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.high.y <= polyb->boundbox.high.y;
+	result = float8_le(polya->boundbox.high.y, polyb->boundbox.high.y);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3613,21 +3630,21 @@ poly_overbelow(PG_FUNCTION_ARGS)
  * the lower most point of A above the upper most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_above(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.low.y > polyb->boundbox.high.y;
+	result = float8_gt(polya->boundbox.low.y, polyb->boundbox.high.y);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3636,21 +3653,21 @@ poly_above(PG_FUNCTION_ARGS)
  * the lower most point of A at or above the lower most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_overabove(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.low.y >= polyb->boundbox.low.y;
+	result = float8_ge(polya->boundbox.low.y, polyb->boundbox.low.y);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3847,22 +3864,22 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 	}
 
 	if (res && !intersection)
 	{
 		Point		p;
 
 		/*
 		 * if X-intersection wasn't found  then check central point of tested
 		 * segment. In opposite case we already check all subsegments
 		 */
-		p.x = (t.p[0].x + t.p[1].x) / 2.0;
-		p.y = (t.p[0].y + t.p[1].y) / 2.0;
+		p.x = float8_div(float8_pl(t.p[0].x, t.p[1].x), 2.0);
+		p.y = float8_div(float8_pl(t.p[0].y, t.p[1].y), 2.0);
 
 		res = point_inside(&p, poly->npts, poly->p);
 	}
 
 	return res;
 }
 
 /*-----------------------------------------------------------------
  * Determine if polygon A contains polygon B.
  *-----------------------------------------------------------------*/
@@ -3989,22 +4006,22 @@ point_add(PG_FUNCTION_ARGS)
 
 	point_add_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static inline void
 point_add_internal(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x + pt2->x,
-					pt1->y + pt2->y);
+					float8_pl(pt1->x, pt2->x),
+					float8_pl(pt1->y, pt2->y));
 }
 
 
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
@@ -4012,22 +4029,22 @@ point_sub(PG_FUNCTION_ARGS)
 
 	point_sub_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static inline void
 point_sub_internal(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x - pt2->x,
-					pt1->y - pt2->y);
+					float8_mi(pt1->x, pt2->x),
+					float8_mi(pt1->y, pt2->y));
 }
 
 
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
@@ -4035,22 +4052,24 @@ point_mul(PG_FUNCTION_ARGS)
 
 	point_mul_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static inline void
 point_mul_internal(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					(pt1->x * pt2->x) - (pt1->y * pt2->y),
-					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+					float8_mi(float8_mul(pt1->x, pt2->x),
+							  float8_mul(pt1->y, pt2->y)),
+					float8_pl(float8_mul(pt1->x, pt2->y),
+							  float8_mul(pt1->y, pt2->x)));
 }
 
 
 Datum
 point_div(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
@@ -4059,24 +4078,26 @@ point_div(PG_FUNCTION_ARGS)
 	point_div_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static inline void
 point_div_internal(Point *result, Point *pt1, Point *pt2)
 {
 	float8		div;
 
-	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
+	div = float8_pl(float8_mul(pt2->x, pt2->x), float8_mul(pt2->y, pt2->y));
 	point_construct(result,
-					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
-					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+					float8_div(float8_pl(float8_mul(pt1->x, pt2->x),
+										 float8_mul(pt1->y, pt2->y)), div),
+					float8_div(float8_mi(float8_mul(pt1->y, pt2->x),
+										 float8_mul(pt1->x, pt2->y)), div));
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D boxes.
  **
  ***********************************************************************/
 
 Datum
@@ -4185,24 +4206,24 @@ point_box(PG_FUNCTION_ARGS)
  */
 Datum
 boxes_bound_box(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0),
 			   *box2 = PG_GETARG_BOX_P(1),
 			   *container;
 
 	container = (BOX *) palloc(sizeof(BOX));
 
-	container->high.x = Max(box1->high.x, box2->high.x);
-	container->low.x = Min(box1->low.x, box2->low.x);
-	container->high.y = Max(box1->high.y, box2->high.y);
-	container->low.y = Min(box1->low.y, box2->low.y);
+	container->high.x = float8_max(box1->high.x, box2->high.x);
+	container->low.x = float8_min(box1->low.x, box2->low.x);
+	container->high.y = float8_max(box1->high.y, box2->high.y);
+	container->low.y = float8_min(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(container);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D paths.
  **
  ***********************************************************************/
@@ -4511,21 +4532,21 @@ circle_in(PG_FUNCTION_ARGS)
 		if (*cp == LDELIM)
 			s = cp;
 	}
 
 	pair_decode(s, &circle->center.x, &circle->center.y, &s, "circle", str);
 
 	if (*s == DELIM)
 		s++;
 
 	circle->radius = single_decode(s, &s, "circle", str);
-	if (circle->radius < 0)
+	if (float8_lt(circle->radius, 0.0))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
 
 	while (depth > 0)
 	{
 		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
@@ -4578,21 +4599,21 @@ circle_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	circle->center.x = pq_getmsgfloat8(buf);
 	circle->center.y = pq_getmsgfloat8(buf);
 	circle->radius = pq_getmsgfloat8(buf);
 
-	if (circle->radius < 0)
+	if (float8_lt(circle->radius, 0.0))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
 				 errmsg("invalid radius in external \"circle\" value")));
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 /*
  *		circle_send			- converts circle to binary format
  */
@@ -4629,144 +4650,146 @@ circle_same(PG_FUNCTION_ARGS)
 
 /*		circle_overlap	-		does circle1 overlap circle2?
  */
 Datum
 circle_overlap(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle1->radius + circle2->radius));
+						float8_pl(circle1->radius, circle2->radius)));
 }
 
 /*		circle_overleft -		is the right edge of circle1 at or left of
  *								the right edge of circle2?
  */
 Datum
 circle_overleft(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.x + circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_left		-		is circle1 strictly left of circle2?
  */
 Datum
 circle_left(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.x + circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_right	-		is circle1 strictly right of circle2?
  */
 Datum
 circle_right(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.x - circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_overright	-	is the left edge of circle1 at or right of
  *								the left edge of circle2?
  */
 Datum
 circle_overright(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.x - circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_contained		-		is circle1 contained by circle2?
  */
 Datum
 circle_contained(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle1->radius), circle2->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						float8_mi(circle2->radius, circle1->radius)));
 }
 
 /*		circle_contain	-		does circle1 contain circle2?
  */
 Datum
 circle_contain(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle2->radius), circle1->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						float8_mi(circle1->radius, circle2->radius)));
 }
 
 
 /*		circle_below		-		is circle1 strictly below circle2?
  */
 Datum
 circle_below(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.y + circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_above	-		is circle1 strictly above circle2?
  */
 Datum
 circle_above(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.y - circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overbelow -		is the upper edge of circle1 at or below
  *								the upper edge of circle2?
  */
 Datum
 circle_overbelow(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.y + circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overabove	-	is the lower edge of circle1 at or above
  *								the lower edge of circle2?
  */
 Datum
 circle_overabove(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.y - circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 
 /*		circle_relop	-		is area(circle1) relop area(circle2), within
  *								our accuracy constraint?
  */
 Datum
 circle_eq(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
@@ -4865,36 +4888,38 @@ circle_sub_pt(PG_FUNCTION_ARGS)
 Datum
 circle_mul_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_mul_internal(&result->center, &circle->center, point);
-	result->radius *= hypot(point->x, point->y);
+	result->radius = float8_mul(circle->radius,
+								float8_hypot(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_div_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_div_internal(&result->center, &circle->center, point);
-	result->radius /= hypot(point->x, point->y);
+	result->radius = float8_div(circle->radius,
+								float8_hypot(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /*		circle_area		-		returns the area of the circle.
  */
 Datum
 circle_area(PG_FUNCTION_ARGS)
 {
@@ -4904,21 +4929,21 @@ circle_area(PG_FUNCTION_ARGS)
 }
 
 
 /*		circle_diameter -		returns the diameter of the circle.
  */
 Datum
 circle_diameter(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
-	PG_RETURN_FLOAT8(2 * circle->radius);
+	PG_RETURN_FLOAT8(float8_mul(circle->radius, 2.0));
 }
 
 
 /*		circle_radius	-		returns the radius of the circle.
  */
 Datum
 circle_radius(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
@@ -4929,81 +4954,84 @@ circle_radius(PG_FUNCTION_ARGS)
 /*		circle_distance -		returns the distance between
  *								  two circles.
  */
 Datum
 circle_distance(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(&circle1->center, &circle2->center) -
-		(circle1->radius + circle2->radius);
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(&circle1->center, &circle2->center),
+					   float8_pl(circle1->radius, circle2->radius));
+	if (float8_lt(result, 0.0))
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 
 Datum
 circle_contain_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
-	PG_RETURN_BOOL(d <= circle->radius);
+	PG_RETURN_BOOL(float8_le(d, circle->radius));
 }
 
 
 Datum
 pt_contained_circle(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
-	PG_RETURN_BOOL(d <= circle->radius);
+	PG_RETURN_BOOL(float8_le(d, circle->radius));
 }
 
 
 /*		dist_pc -		returns the distance between
  *						  a point and a circle.
  */
 Datum
 dist_pc(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center), circle->radius);
+	if (float8_lt(result, 0.0))
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a circle to a point
  */
 Datum
 dist_cpoint(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center), circle->radius);
+	if (float8_lt(result, 0.0))
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*		circle_center	-		returns the center point of the circle.
  */
 Datum
 circle_center(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *result;
@@ -5011,24 +5039,24 @@ circle_center(PG_FUNCTION_ARGS)
 	result = (Point *) palloc(sizeof(Point));
 	result->x = circle->center.x;
 	result->y = circle->center.y;
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		circle_ar		-		returns the area of the circle.
  */
-static double
+static float8
 circle_ar(CIRCLE *circle)
 {
-	return M_PI * (circle->radius * circle->radius);
+	return float8_mul(float8_mul(circle->radius, circle->radius), M_PI);
 }
 
 
 /*----------------------------------------------------------
  *	Conversion operators.
  *---------------------------------------------------------*/
 
 Datum
 cr_circle(PG_FUNCTION_ARGS)
 {
@@ -5043,65 +5071,65 @@ cr_circle(PG_FUNCTION_ARGS)
 	result->radius = radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_box(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	BOX		   *box;
-	double		delta;
+	float8		delta;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
-	delta = circle->radius / sqrt(2.0);
+	delta = float8_div(circle->radius, sqrt(2.0));
 
-	box->high.x = circle->center.x + delta;
-	box->low.x = circle->center.x - delta;
-	box->high.y = circle->center.y + delta;
-	box->low.y = circle->center.y - delta;
+	box->high.x = float8_pl(circle->center.x, delta);
+	box->low.x = float8_mi(circle->center.x, delta);
+	box->high.y = float8_pl(circle->center.y, delta);
+	box->low.y = float8_mi(circle->center.y, delta);
 
 	PG_RETURN_BOX_P(box);
 }
 
 /* box_circle()
  * Convert a box to a circle.
  */
 Datum
 box_circle(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	circle->center.x = (box->high.x + box->low.x) / 2;
-	circle->center.y = (box->high.y + box->low.y) / 2;
+	circle->center.x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	circle->center.y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 
 	circle->radius = point_dt(&circle->center, &box->high);
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 
 Datum
 circle_poly(PG_FUNCTION_ARGS)
 {
 	int32		npts = PG_GETARG_INT32(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	POLYGON    *poly;
 	int			base_size,
 				size;
 	int			i;
-	double		angle;
-	double		anglestep;
+	float8		angle;
+	float8		anglestep;
 
 	if (FPzero(circle->radius))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("cannot convert circle with radius zero to polygon")));
 
 	if (npts < 2)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("must request at least 2 points")));
@@ -5112,27 +5140,30 @@ circle_poly(PG_FUNCTION_ARGS)
 	/* Check for integer overflow */
 	if (base_size / npts != sizeof(poly->p[0]) || size <= base_size)
 		ereport(ERROR,
 				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 				 errmsg("too many points requested")));
 
 	poly = (POLYGON *) palloc0(size);	/* zero any holes */
 	SET_VARSIZE(poly, size);
 	poly->npts = npts;
 
-	anglestep = (2.0 * M_PI) / npts;
+	anglestep = float8_div(2.0 * M_PI, npts);
 
 	for (i = 0; i < npts; i++)
 	{
-		angle = i * anglestep;
-		poly->p[i].x = circle->center.x - (circle->radius * cos(angle));
-		poly->p[i].y = circle->center.y + (circle->radius * sin(angle));
+		angle = float8_mul(anglestep, i);
+
+		poly->p[i].x = float8_mi(circle->center.x,
+								 float8_mul(circle->radius, cos(angle)));
+		poly->p[i].y = float8_pl(circle->center.y,
+								 float8_mul(circle->radius, sin(angle)));
 	}
 
 	make_bound_box(poly);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
 /*		poly_circle		- convert polygon to circle
  *
  * XXX This algorithm should use weighted means of line segments
@@ -5151,29 +5182,30 @@ poly_circle(PG_FUNCTION_ARGS)
 				 errmsg("cannot convert empty polygon to circle")));
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	circle->center.x = 0;
 	circle->center.y = 0;
 	circle->radius = 0;
 
 	for (i = 0; i < poly->npts; i++)
 	{
-		circle->center.x += poly->p[i].x;
-		circle->center.y += poly->p[i].y;
+		circle->center.x = float8_pl(circle->center.x, poly->p[i].x);
+		circle->center.y = float8_pl(circle->center.y, poly->p[i].y);
 	}
-	circle->center.x /= poly->npts;
-	circle->center.y /= poly->npts;
+	circle->center.x = float8_div(circle->center.x, poly->npts);
+	circle->center.y = float8_div(circle->center.y, poly->npts);
 
 	for (i = 0; i < poly->npts; i++)
-		circle->radius += point_dt(&poly->p[i], &circle->center);
-	circle->radius /= poly->npts;
+		circle->radius = float8_pl(circle->radius, point_dt(&poly->p[i],
+															&circle->center));
+	circle->radius = float8_div(circle->radius, poly->npts);
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 
 /***********************************************************************
  **
  **		Private routines for multiple types.
  **
  ***********************************************************************/
@@ -5187,45 +5219,45 @@ poly_circle(PG_FUNCTION_ARGS)
  *	http://hopf.math.northwestern.edu/index.html
  *	Description of algorithm:  http://www.linuxjournal.com/article/2197
  *							   http://www.linuxjournal.com/article/2029
  */
 
 #define POINT_ON_POLYGON INT_MAX
 
 static int
 point_inside(Point *p, int npts, Point *plist)
 {
-	double		x0,
+	float8		x0,
 				y0;
-	double		prev_x,
+	float8		prev_x,
 				prev_y;
 	int			i = 0;
-	double		x,
+	float8		x,
 				y;
 	int			cross,
 				total_cross = 0;
 
 	if (npts <= 0)
 		return 0;
 
 	/* compute first polygon point relative to single point */
-	x0 = plist[0].x - p->x;
-	y0 = plist[0].y - p->y;
+	x0 = float8_mi(plist[0].x, p->x);
+	y0 = float8_mi(plist[0].y, p->y);
 
 	prev_x = x0;
 	prev_y = y0;
 	/* loop over polygon points and aggregate total_cross */
 	for (i = 1; i < npts; i++)
 	{
 		/* compute next polygon point relative to single point */
-		x = plist[i].x - p->x;
-		y = plist[i].y - p->y;
+		x = float8_mi(plist[i].x, p->x);
+		y = float8_mi(plist[i].y, p->y);
 
 		/* compute previous to current point crossing */
 		if ((cross = lseg_crossing(x, y, prev_x, prev_y)) == POINT_ON_POLYGON)
 			return 2;
 		total_cross += cross;
 
 		prev_x = x;
 		prev_y = y;
 	}
 
@@ -5243,69 +5275,74 @@ point_inside(Point *p, int npts, Point *plist)
 /* lseg_crossing()
  * Returns +/-2 if line segment crosses the positive X-axis in a +/- direction.
  * Returns +/-1 if one point is on the positive X-axis.
  * Returns 0 if both points are on the positive X-axis, or there is no crossing.
  * Returns POINT_ON_POLYGON if the segment contains (0,0).
  * Wow, that is one confusing API, but it is used above, and when summed,
  * can tell is if a point is in a polygon.
  */
 
 static int
-lseg_crossing(double x, double y, double prev_x, double prev_y)
+lseg_crossing(float8 x, float8 y, float8 prev_x, float8 prev_y)
 {
-	double		z;
+	float8		z;
 	int			y_sign;
 
 	if (FPzero(y))
 	{							/* y == 0, on X axis */
 		if (FPzero(x))			/* (x,y) is (0,0)? */
 			return POINT_ON_POLYGON;
 		else if (FPgt(x, 0))
 		{						/* x > 0 */
 			if (FPzero(prev_y)) /* y and prev_y are zero */
 				/* prev_x > 0? */
-				return FPgt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
-			return FPlt(prev_y, 0) ? 1 : -1;
+				return FPgt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
+			return FPlt(prev_y, 0.0) ? 1 : -1;
 		}
 		else
 		{						/* x < 0, x not on positive X axis */
 			if (FPzero(prev_y))
 				/* prev_x < 0? */
-				return FPlt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
+				return FPlt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
 			return 0;
 		}
 	}
 	else
 	{							/* y != 0 */
 		/* compute y crossing direction from previous point */
-		y_sign = FPgt(y, 0) ? 1 : -1;
+		y_sign = FPgt(y, 0.0) ? 1 : -1;
 
 		if (FPzero(prev_y))
 			/* previous point was on X axis, so new point is either off or on */
-			return FPlt(prev_x, 0) ? 0 : y_sign;
-		else if (FPgt(y_sign * prev_y, 0))
+			return FPlt(prev_x, 0.0) ? 0 : y_sign;
+		else if ((y_sign < 0 && FPlt(prev_y, 0.0)) ||
+				 (y_sign > 0 && FPgt(prev_y, 0.0)))
 			/* both above or below X axis */
 			return 0;			/* same sign */
 		else
 		{						/* y and prev_y cross X-axis */
-			if (FPge(x, 0) && FPgt(prev_x, 0))
+			if (FPge(x, 0.0) && FPgt(prev_x, 0.0))
 				/* both non-negative so cross positive X-axis */
 				return 2 * y_sign;
-			if (FPlt(x, 0) && FPle(prev_x, 0))
+			if (FPlt(x, 0.0) && FPle(prev_x, 0.0))
 				/* both non-positive so do not cross positive X-axis */
 				return 0;
 
 			/* x and y cross axises, see URL above point_inside() */
-			z = (x - prev_x) * y - (y - prev_y) * x;
+			z = float8_mi(float8_mul(float8_mi(x, prev_x), y),
+						  float8_mul(float8_mi(y, prev_y), x));
 			if (FPzero(z))
 				return POINT_ON_POLYGON;
-			return FPgt((y_sign * z), 0) ? 0 : 2 * y_sign;
+			if ((y_sign < 0 && FPlt(z, 0.0)) ||
+				(y_sign > 0 && FPgt(z, 0.0)))
+				return 0;
+			return 2 * y_sign;
 		}
 	}
 }
 
 
 static bool
 plist_same(int npts, Point *p1, Point *p2)
 {
 	int			i,
 				ii,
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index c800bb1338..f62be1061e 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -76,38 +76,38 @@
 #include "access/spgist.h"
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
 #include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
- * is going only going to be used in a place to effect the performance
+ * is only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
 compareDoubles(const void *a, const void *b)
 {
-	double		x = *(double *) a;
-	double		y = *(double *) b;
+	float8		x = *(float8 *) a;
+	float8		y = *(float8 *) b;
 
 	if (x == y)
 		return 0;
 	return (x > y) ? 1 : -1;
 }
 
 typedef struct
 {
-	double		low;
-	double		high;
+	float8		low;
+	float8		high;
 } Range;
 
 typedef struct
 {
 	Range		left;
 	Range		right;
 } RangeBox;
 
 typedef struct
 {
@@ -121,30 +121,30 @@ typedef struct
  * The quadrant is 8 bit unsigned integer with 4 least bits in use.
  * This function accepts BOXes as input.  They are not casted to
  * RangeBoxes, yet.  All 4 bits are set by comparing a corner of the box.
  * This makes 16 quadrants in total.
  */
 static uint8
 getQuadrant(BOX *centroid, BOX *inBox)
 {
 	uint8		quadrant = 0;
 
-	if (inBox->low.x > centroid->low.x)
+	if (float8_gt(inBox->low.x, centroid->low.x))
 		quadrant |= 0x8;
 
-	if (inBox->high.x > centroid->high.x)
+	if (float8_gt(inBox->high.x, centroid->high.x))
 		quadrant |= 0x4;
 
-	if (inBox->low.y > centroid->low.y)
+	if (float8_gt(inBox->low.y, centroid->low.y))
 		quadrant |= 0x2;
 
-	if (inBox->high.y > centroid->high.y)
+	if (float8_gt(inBox->high.y, centroid->high.y))
 		quadrant |= 0x1;
 
 	return quadrant;
 }
 
 /*
  * Get RangeBox using BOX
  *
  * We are turning the BOX to our structures to emphasize their function
  * of representing points in 4D space.  It also is more convenient to
@@ -167,21 +167,21 @@ getRangeBox(BOX *box)
 /*
  * Initialize the traversal value
  *
  * In the beginning, we don't have any restrictions.  We have to
  * initialize the struct to cover the whole 4D space.
  */
 static RectBox *
 initRectBox(void)
 {
 	RectBox    *rect_box = (RectBox *) palloc(sizeof(RectBox));
-	double		infinity = get_float8_infinity();
+	float8		infinity = get_float8_infinity();
 
 	rect_box->range_box_x.left.low = -infinity;
 	rect_box->range_box_x.left.high = infinity;
 
 	rect_box->range_box_x.right.low = -infinity;
 	rect_box->range_box_x.right.high = infinity;
 
 	rect_box->range_box_y.left.low = -infinity;
 	rect_box->range_box_y.left.high = infinity;
 
@@ -410,40 +410,40 @@ spg_box_quad_choose(PG_FUNCTION_ARGS)
  * point as the median of the coordinates of the boxes.
  */
 Datum
 spg_box_quad_picksplit(PG_FUNCTION_ARGS)
 {
 	spgPickSplitIn *in = (spgPickSplitIn *) PG_GETARG_POINTER(0);
 	spgPickSplitOut *out = (spgPickSplitOut *) PG_GETARG_POINTER(1);
 	BOX		   *centroid;
 	int			median,
 				i;
-	double	   *lowXs = palloc(sizeof(double) * in->nTuples);
-	double	   *highXs = palloc(sizeof(double) * in->nTuples);
-	double	   *lowYs = palloc(sizeof(double) * in->nTuples);
-	double	   *highYs = palloc(sizeof(double) * in->nTuples);
+	float8	   *lowXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *lowYs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highYs = palloc(sizeof(float8) * in->nTuples);
 
 	/* Calculate median of all 4D coordinates */
 	for (i = 0; i < in->nTuples; i++)
 	{
 		BOX		   *box = DatumGetBoxP(in->datums[i]);
 
 		lowXs[i] = box->low.x;
 		highXs[i] = box->high.x;
 		lowYs[i] = box->low.y;
 		highYs[i] = box->high.y;
 	}
 
-	qsort(lowXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(lowYs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highYs, in->nTuples, sizeof(double), compareDoubles);
+	qsort(lowXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(lowYs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highYs, in->nTuples, sizeof(float8), compareDoubles);
 
 	median = in->nTuples / 2;
 
 	centroid = palloc(sizeof(BOX));
 
 	centroid->low.x = lowXs[median];
 	centroid->high.x = highXs[median];
 	centroid->low.y = lowYs[median];
 	centroid->high.y = highYs[median];
 
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 22c68f5b62..eee0ceff11 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -1,23 +1,20 @@
 /*-------------------------------------------------------------------------
  *
  * geo_decls.h - Declarations for various 2D constructs.
  *
  *
  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * src/include/utils/geo_decls.h
  *
- * NOTE
- *	  These routines do *not* use the float types from adt/.
- *
  *	  XXX These routines were not written by a numerical analyst.
  *
  *	  XXX I have made some attempt to flesh out the operators
  *		and data types. There are still some more to do. - tgl 97/04/19
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEO_DECLS_H
 #define GEO_DECLS_H
 
@@ -28,43 +25,43 @@
 
 /*--------------------------------------------------------------------
  * Useful floating point utilities and constants.
  *-------------------------------------------------------------------*/
 
 
 #define EPSILON					1.0E-06
 
 #ifdef EPSILON
 #define FPzero(A)				(fabs(A) <= EPSILON)
-#define FPeq(A,B)				(fabs((A) - (B)) <= EPSILON)
-#define FPne(A,B)				(fabs((A) - (B)) > EPSILON)
-#define FPlt(A,B)				((B) - (A) > EPSILON)
-#define FPle(A,B)				((A) - (B) <= EPSILON)
-#define FPgt(A,B)				((A) - (B) > EPSILON)
-#define FPge(A,B)				((B) - (A) <= EPSILON)
+#define FPeq(A, B)				(float8_le(fabs(float8_mi(A, B)), EPSILON))
+#define FPne(A, B)				(float8_gt(fabs(float8_mi(A, B)), EPSILON))
+#define FPlt(A, B)				(float8_gt(float8_mi(B, A), EPSILON))
+#define FPle(A, B)				(float8_le(float8_mi(A, B), EPSILON))
+#define FPgt(A, B)				(float8_gt(float8_mi(A, B), EPSILON))
+#define FPge(A, B)				(float8_le(float8_mi(B, A), EPSILON))
 #else
-#define FPzero(A)				((A) == 0)
-#define FPeq(A,B)				((A) == (B))
-#define FPne(A,B)				((A) != (B))
-#define FPlt(A,B)				((A) < (B))
-#define FPle(A,B)				((A) <= (B))
-#define FPgt(A,B)				((A) > (B))
-#define FPge(A,B)				((A) >= (B))
+#define FPzero(A)				((A) == 0.0)
+#define FPeq(A, B)				(float8_eq(A, B))
+#define FPne(A, B)				(float8_ne(A, B))
+#define FPlt(A, B)				(float8_lt(A, B))
+#define FPle(A, B)				(float8_le(A, B))
+#define FPgt(A, B)				(float8_gt(A, B))
+#define FPge(A, B)				(float8_ge(A, B))
 #endif
 
 
 /*---------------------------------------------------------------------
  * Point - (x,y)
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		x,
+	float8		x,
 				y;
 } Point;
 
 
 /*---------------------------------------------------------------------
  * LSEG - A straight line, specified by endpoints.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		p[2];
@@ -72,66 +69,66 @@ typedef struct
 
 
 /*---------------------------------------------------------------------
  * PATH - Specified by vertex points.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	int32		vl_len_;		/* varlena header (do not touch directly!) */
 	int32		npts;
 	int32		closed;			/* is this a closed polygon? */
-	int32		dummy;			/* padding to make it double align */
+	int32		dummy;			/* padding to make it float8 align */
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } PATH;
 
 
 /*---------------------------------------------------------------------
  * LINE - Specified by its general equation (Ax+By+C=0).
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		A,
+	float8		A,
 				B,
 				C;
 } LINE;
 
 
 /*---------------------------------------------------------------------
  * BOX	- Specified by two corner points, which are
  *		 sorted to save calculation time later.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		high,
 				low;			/* corner POINTs */
 } BOX;
 
 /*---------------------------------------------------------------------
- * POLYGON - Specified by an array of doubles defining the points,
+ * POLYGON - Specified by an array of float8s defining the points,
  *		keeping the number of points and the bounding box for
  *		speed purposes.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	int32		vl_len_;		/* varlena header (do not touch directly!) */
 	int32		npts;
 	BOX			boundbox;
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } POLYGON;
 
 /*---------------------------------------------------------------------
  * CIRCLE - Specified by a center point and radius.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		center;
-	double		radius;
+	float8		radius;
 } CIRCLE;
 
 /*
  * fmgr interface macros
  *
  * Path and Polygon are toastable varlena types, the others are just
  * fixed-size pass-by-reference types.
  */
 
 #define DatumGetPointP(X)	 ((Point *) DatumGetPointer(X))
@@ -166,11 +163,11 @@ typedef struct
 #define PolygonPGetDatum(X)			PointerGetDatum(X)
 #define PG_GETARG_POLYGON_P(n)		DatumGetPolygonP(PG_GETARG_DATUM(n))
 #define PG_GETARG_POLYGON_P_COPY(n) DatumGetPolygonPCopy(PG_GETARG_DATUM(n))
 #define PG_RETURN_POLYGON_P(x)		return PolygonPGetDatum(x)
 
 #define DatumGetCircleP(X)	  ((CIRCLE *) DatumGetPointer(X))
 #define CirclePGetDatum(X)	  PointerGetDatum(X)
 #define PG_GETARG_CIRCLE_P(n) DatumGetCircleP(PG_GETARG_DATUM(n))
 #define PG_RETURN_CIRCLE_P(x) return CirclePGetDatum(x)
 
-#endif   /* GEO_DECLS_H */
+#endif							/* GEO_DECLS_H */
-- 
2.13.5 (Apple Git-94)

0004-line-fixes-v04.patchapplication/octet-stream; name=0004-line-fixes-v04.patchDownload
From 83049a69b87fc6e800e00823eb4424bcaa9bee90 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sun, 28 May 2017 11:35:17 +0200
Subject: [PATCH 4/4] line-fixes-v04

Fix obvious problems around the line datatype

I have noticed some line operators retuning wrong results, and Tom Lane
spotted similar problems on more places.  Source history reveals that
during 1990s, the internal format of the line datatype is changed, but
most functions haven't got the hint.  The fixes include:

* Reject invalid specification A=B=0 on receive
* Avoid division by zero on perpendicular operator
* Fix intersection and distance operators when neither A nor B are 1
* Avoid point to line operators crashing on floating point precision loss

The changes are also aiming make line operators more symmetric and less
sensitive to floating point precision loss.  The EPSILON interferes with
every minor change in different ways.  It is hard to guess which
behaviour is more expected, but we can assume threating both sides of
the operators more equally is more expected.

Previous discussion:
https://www.postgresql.org/message-id/flat/CAE2gYzw_-z%3DV2kh8QqFjenu%3D8MJXzOP44wRW%3DAzzeamrmTT1%3DQ%40mail.gmail.com
---
 src/backend/utils/adt/geo_ops.c | 108 ++++++++++++++++++++++++++--------------
 1 file changed, 70 insertions(+), 38 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index a4f6c1992e..7a444ad7a5 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -1003,20 +1003,25 @@ line_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LINE	   *line;
 
 	line = (LINE *) palloc(sizeof(LINE));
 
 	line->A = pq_getmsgfloat8(buf);
 	line->B = pq_getmsgfloat8(buf);
 	line->C = pq_getmsgfloat8(buf);
 
+	if (FPzero(line->A) && FPzero(line->B))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+				 errmsg("invalid line specification: A and B cannot both be zero")));
+
 	PG_RETURN_LINE_P(line);
 }
 
 /*
  *		line_send			- converts line to binary format
  */
 Datum
 line_send(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -1123,25 +1128,28 @@ line_parallel(PG_FUNCTION_ARGS)
 }
 
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
-	else if (FPzero(l1->B))
+	if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
+	if (FPzero(l2->A))
+		PG_RETURN_BOOL(FPzero(l1->B));
+	if (FPzero(l2->B))
+		PG_RETURN_BOOL(FPzero(l1->A));
 
-	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
-								   float8_mul(l1->B, l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(float8_mul(l1->A, l2->B), -float8_mul(l1->B, l2->A)));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
@@ -1153,20 +1161,21 @@ line_horizontal(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(FPzero(line->A));
 }
 
 Datum
 line_eq(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		ratio;
 
+	/* A and B cannot be both 0, but we never really know with the EPSILON. */
 	if (!FPzero(l2->A))
 		ratio = float8_div(l1->A, l2->A);
 	else if (!FPzero(l2->B))
 		ratio = float8_div(l1->B, l2->B);
 	else if (!FPzero(l2->C))
 		ratio = float8_div(l1->C, l2->C);
 	else
 		ratio = 1.0;
 
 	PG_RETURN_BOOL(FPeq(l1->A, float8_mul(ratio, l2->A)) &&
@@ -1180,30 +1189,36 @@ line_eq(PG_FUNCTION_ARGS)
  *---------------------------------------------------------*/
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	float8		result;
-	Point		tmp;
+	float8		ratio;
 
 	if (line_interpt_internal(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
-	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
-	point_construct(&tmp, 0.0, l1->C);
-	result = dist_pl_internal(&tmp, l2);
-	PG_RETURN_FLOAT8(result);
+
+	/* A and B cannot be both 0, but we never really know with the EPSILON. */
+	if (!FPzero(l2->A))
+		ratio = float8_div(l1->A, l2->A);
+	else if (!FPzero(l2->B))
+		ratio = float8_div(l1->B, l2->B);
+	else
+		ratio = 1.0;
+
+	PG_RETURN_FLOAT8(float8_div(fabs(float8_mi(l1->C,
+											   float8_mul(ratio, l2->C))),
+								float8_hypot(l1->A, l1->B)));
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
@@ -1226,38 +1241,62 @@ line_interpt(PG_FUNCTION_ARGS)
  * NOTE: If the lines are identical then we will find they are parallel
  * and report "no intersection".  This is a little weird, but since
  * there's no *unique* intersection, maybe it's appropriate behavior.
  */
 static bool
 line_interpt_internal(Point *result, LINE *l1, LINE *l2)
 {
 	float8		x,
 				y;
 
-	if (FPzero(l1->B))			/* l1 vertical? */
+	if (FPzero(l1->A))			/* l1 horizontal? */
+	{
+		if (FPzero(l2->A))		/* l2 horizontal? */
+			return false;
+
+		y = float8_div(-l1->C, l1->B);
+		x = float8_div(-float8_pl(float8_mul(l2->B, y), l2->C), l2->A);
+	}
+	else if (FPzero(l1->B))		/* l1 vertical? */
 	{
 		if (FPzero(l2->B))		/* l2 vertical? */
 			return false;
 
-		x = l1->C;
-		y = float8_pl(float8_mul(l2->A, x), l2->C);
+		x = float8_div(-l1->C, l1->A);
+		y = float8_div(-float8_pl(float8_mul(l2->A, x), l2->C), l2->B);
+	}
+	else if (FPzero(l2->A))		/* l2 horizontal? */
+	{
+		if (FPzero(l1->A))		/* l1 horizontal? */
+			return false;
+
+		y = float8_div(-l2->C, l2->B);
+		x = float8_div(-float8_pl(float8_mul(l1->B, y), l1->C), l1->A);
+	}
+	else if (FPzero(l2->B))		/* l2 vertical? */
+	{
+		if (FPzero(l1->B))		/* l1 vertical? */
+			return false;
+
+		x = float8_div(-l2->C, l2->A);
+		y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
 	}
 	else
 	{
-		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
+		if (FPeq(float8_mul(l1->A, l2->B), float8_mul(l2->A, l1->B)))
 			return false;
 
-		if (FPzero(l2->B))
-			x = l2->C;
-		else
-			x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
-		y = float8_pl(float8_mul(l1->A, x), l1->C);
+		x = float8_div(float8_mi(float8_mul(l1->B, l2->C),
+								 float8_mul(l2->B, l1->C)),
+					   float8_mi(float8_mul(l1->A, l2->B),
+								 float8_mul(l2->A, l1->B)));
+		y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
 	}
 	if (result != NULL)
 		point_construct(result, x, y);
 
 #ifdef GEODEBUG
 	printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
 		   DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
 	printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
 #endif
 
@@ -2061,46 +2100,35 @@ lseg_parallel(PG_FUNCTION_ARGS)
 
 	m1 = float8_slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y);
 	m2 = float8_slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y);
 
 	PG_RETURN_BOOL(FPeq(m1, m2));
 }
 
 /* lseg_perp()
  * Determine if two line segments are perpendicular.
  *
- * This code did not get the correct answer for
- *	'((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg
- * So, modified it to check explicitly for slope of vertical line
- *	returned by float8_slope() and the results seem better.
- * - thomas 1998-01-31
+ * We are comparing the slope of the first line segment with the inverse slope
+ * of the second line segment.
  */
 Datum
 lseg_perp(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	float8		m1,
 				m2;
 
 	m1 = float8_slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y);
-	m2 = float8_slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y);
+	m2 = float8_slope(l2->p[0].y, l2->p[1].y, l2->p[1].x, l2->p[0].x);
 
-#ifdef GEODEBUG
-	printf("lseg_perp- slopes are %g and %g\n", m1, m2);
-#endif
-	if (FPzero(m1))
-		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
-	else if (FPzero(m2))
-		PG_RETURN_BOOL(FPeq(m1, DBL_MAX));
-
-	PG_RETURN_BOOL(FPeq(float8_div(m1, m2), -1.0));
+	PG_RETURN_BOOL(FPeq(m1, m2));
 }
 
 Datum
 lseg_vertical(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 
 	PG_RETURN_BOOL(FPeq(lseg->p[0].x, lseg->p[1].x));
 }
 
@@ -2667,34 +2695,38 @@ lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line)
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (FPzero(line->B))		/* vertical? */
-		point_construct(result, line->C, pt->y);
+		point_construct(result, float8_div(-line->C, line->A), pt->y);
 	else if (FPzero(line->A))	/* horizontal? */
-		point_construct(result, pt->x, line->C);
+		point_construct(result, pt->x, float8_div(-line->C, line->B));
 	else
 	{
 		LINE		tmp;
 
 		/*
 		 * Drop a perpendicular and find the intersection point
 		 *
-		 * We need to invert the slope to get the perpendicular.
+		 * We need to invert the slope to get the perpendicular.  We might
+		 * lose some precision on the division. It shouldn't be as much
+		 * to turn the line.  If it happens anyway, we will assume the point
+		 * is on the line.
 		 */
 		line_construct_pm(&tmp, pt, float8_div(line->B, line->A));
-		line_interpt_internal(result, &tmp, line);
+		if (!line_interpt_internal(result, &tmp, line))
+			*result = *pt;
 	}
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_ps()
  * Closest point on line segment to specified point.
  * Take the closest endpoint if the point is left, right,
  *	above, or below the segment, otherwise find the intersection
-- 
2.13.5 (Apple Git-94)

#20Robert Haas
robertmhaas@gmail.com
In reply to: Kyotaro HORIGUCHI (#18)
Re: [PATCH] Improve geometric types

On Mon, Oct 2, 2017 at 4:23 AM, Kyotaro HORIGUCHI
<horiguchi.kyotaro@lab.ntt.co.jp> wrote:

For other potential reviewers:

I found the origin of the function here.

/messages/by-id/4A90BD76.7070804@netspace.net.au
/messages/by-id/AANLkTim4cHELcGPf5w7Zd43_dQi_2RJ_b5_F_idSSbZI@mail.gmail.com

And the reason for pg_hypot is seen here.

/messages/by-id/407d949e0908222139t35ad3ad2q3e6b15646a27dd64@mail.gmail.com

I think the replacement is now acceptable according to the discussion.
======

I think if we're going to do this it should be separated out as its
own patch. Also, I think someone should explain what the reasoning
behind the change is. Do we, for example, foresee that the built-in
code might be faster or less likely to overflow? Because we're
clearly taking a risk -- most trivially, that the BF will break, or
more seriously, that some machines will have versions of this function
that don't actually behave quite the same.

That brings up a related point. How good is our test case coverage
for hypot(), especially in strange corner cases, like this one
mentioned in pg_hypot()'s comment:

* This implementation conforms to IEEE Std 1003.1 and GLIBC, in that the
* case of hypot(inf,nan) results in INF, and not NAN.

I'm potentially willing to commit a patch that just makes the
pg_hypot() -> hypot() change and does nothing else, if there are not
objections to that change, but I want to be sure that we'll know right
away if that turns out to break.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

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

#21Kyotaro HORIGUCHI
horiguchi.kyotaro@lab.ntt.co.jp
In reply to: Emre Hasegeli (#19)
Re: [PATCH] Improve geometric types

Thanks.

At Mon, 2 Oct 2017 11:46:15 +0200, Emre Hasegeli <emre@hasegeli.com> wrote in <CAE2gYzz7wiUnyb1TxCk5GzXt6j7efzGmMgH0gTe8xwKZ=FAF5A@mail.gmail.com>

And this should be the last comment of mine on the patch set.

Thank you. The new versions of the patches are attached addressing
your comments.

By the way, I found that MAXDOUBLEWIDTH has two inconsistent
definitions in formatting.c(500) and float.c(128). The definition
in new float.h is according to float.c and it seems better to be
untouched and it would be another issue.

The last version of the patch don't move these declarations to the header file.

Yeah, it is not about the patch itself.

# The commit message of 0001 says that "using C11 hypot()" but it
# is sine C99. I suppose we shold follow C99 at the time so I
# suggest rewrite it in the next version if any.

Changed.

close_pl got a bug fix not only refactoring. I think it is
recommended to separate bugs and improvements, but I'm fine with
the current patch.

I split the refactoring to the first patch.

You added sanity check "A==0 && B==0" (in Ax + By + C) in
line_recv. I'm not sure the necessity of the check since it has
been checked in line_in but anyway the comparisons seem to be
typo(or thinko) of FPzero.

Tom Lane suggested [1] this one. I now made it use FPzero().

I see. It's fine with me. I suppose that Tom didn't intened the
suggestion to be teken literary so using FPzero() seems better
(at least for now).

dist_pl is changed to take the smaller distance of both ends of
the segment. It seems absorbing error, so it might be better
taking the mean of the two distances. If you have a firm reason
for the change, it is better to be written there, or it might be
better left alone.

I don't really, so I left that part out.

Mmm, sorry. It's my mistake.

[1] /messages/by-id/11053.1466362319@sss.pgh.pa.us

I'll look the new version further.

regards,

--
Kyotaro Horiguchi
NTT Open Source Software Center

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

#22Kyotaro HORIGUCHI
horiguchi.kyotaro@lab.ntt.co.jp
In reply to: Robert Haas (#20)
1 attachment(s)
Re: [PATCH] Improve geometric types

At Mon, 2 Oct 2017 08:23:49 -0400, Robert Haas <robertmhaas@gmail.com> wrote in <CA+TgmoYsgw0TcjJQ1CE_6vDOxgEhxYQkfNx93Mfwx23WOLM0NA@mail.gmail.com>

On Mon, Oct 2, 2017 at 4:23 AM, Kyotaro HORIGUCHI
<horiguchi.kyotaro@lab.ntt.co.jp> wrote:

For other potential reviewers:

I found the origin of the function here.

/messages/by-id/4A90BD76.7070804@netspace.net.au
/messages/by-id/AANLkTim4cHELcGPf5w7Zd43_dQi_2RJ_b5_F_idSSbZI@mail.gmail.com

And the reason for pg_hypot is seen here.

/messages/by-id/407d949e0908222139t35ad3ad2q3e6b15646a27dd64@mail.gmail.com

I think the replacement is now acceptable according to the discussion.
======

I think if we're going to do this it should be separated out as its
own patch.

+1

Also, I think someone should explain what the reasoning
behind the change is. Do we, for example, foresee that the built-in
code might be faster or less likely to overflow? Because we're
clearly taking a risk -- most trivially, that the BF will break, or
more seriously, that some machines will have versions of this function
that don't actually behave quite the same.

That brings up a related point. How good is our test case coverage
for hypot(), especially in strange corner cases, like this one
mentioned in pg_hypot()'s comment:

* This implementation conforms to IEEE Std 1003.1 and GLIBC, in that the
* case of hypot(inf,nan) results in INF, and not NAN.

I'm not sure how precise we practically need them to be
identical. FWIW as a rough confirmation on my box, I compared
hypot and pg_hypot for the following arbitrary choosed pairs of
parameters.

{2.2e-308, 2.2e-308},
{2.2e-308, 1.7e307},
{1.7e307, 1.7e307},
{1.7e308, 1.7e308},
{2.2e-308, DBL_MAX},
{1.7e308, DBL_MAX},
{DBL_MIN, DBL_MAX},
{DBL_MAX, DBL_MAX},
{1.7e307, INFINITY},
{2.2e-308, INFINITY},
{0, INFINITY},
{DBL_MIN, INFINITY},
{INFINITY, INFINITY},
{1, NAN},
{INFINITY, NAN},
{NAN, NAN},

Only the first pair gave slightly not-exactly-equal results but
it seems to do no harm. hypot set underflow flag.

0: hypot=3.111269837220809e-308 (== 0.0 is 0, < DBL_MIN is 0)
pg_hypot=3.11126983722081e-308 (== 0.0 is 0, < DBL_MIN is 0)
equal=0,
hypot(errno:0, inval:0, div0:0, of=0, uf=1),
pg_hypot(errno:0, inval:0, div0:0, of=0, uf=0)

But not sure how the both functions behave on other platforms.

I'm potentially willing to commit a patch that just makes the
pg_hypot() -> hypot() change and does nothing else, if there are not
objections to that change, but I want to be sure that we'll know right
away if that turns out to break.

--
Kyotaro Horiguchi
NTT Open Source Software Center

Attachments:

fptest.ctext/plain; charset=us-asciiDownload
#23Alvaro Herrera
alvherre@alvh.no-ip.org
In reply to: Robert Haas (#20)
Re: [PATCH] Improve geometric types

Robert Haas wrote:

I'm potentially willing to commit a patch that just makes the
pg_hypot() -> hypot() change and does nothing else, if there are not
objections to that change, but I want to be sure that we'll know right
away if that turns out to break.

Uh, I thought pg_hypot() was still needed on our oldest supported
platforms. Or is hypot() already supported there? If not, I suppose we
can keep the HYPOT() macro, and have it use hypot() on platforms that
have it and pg_hypot elsewhere? That particular fraction of 0001 seemed
a bit dubious to me, as the largest possible source of platform
dependency issues.

--
�lvaro Herrera https://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

#24Emre Hasegeli
emre@hasegeli.com
In reply to: Robert Haas (#20)
Re: [PATCH] Improve geometric types

I think if we're going to do this it should be separated out as its
own patch. Also, I think someone should explain what the reasoning
behind the change is. Do we, for example, foresee that the built-in
code might be faster or less likely to overflow? Because we're
clearly taking a risk -- most trivially, that the BF will break, or
more seriously, that some machines will have versions of this function
that don't actually behave quite the same.

I included removal of pg_hypot() on my patch simply because the
comment on the function header is suggesting it. I though if we are
going to clean this module up, we better deal it first. I understand
the risk. The patches include more changes. It may be a good idea to
have those together.

That brings up a related point. How good is our test case coverage
for hypot(), especially in strange corner cases, like this one
mentioned in pg_hypot()'s comment:

* This implementation conforms to IEEE Std 1003.1 and GLIBC, in that the
* case of hypot(inf,nan) results in INF, and not NAN.

I don't see any tests of geometric types with INF or NaN. Currently,
there isn't consistent behaviour for them. I don't think we can
easily add portable ones on the current state, but we should be able
to do so with my patches. I will look into it.

I'm potentially willing to commit a patch that just makes the
pg_hypot() -> hypot() change and does nothing else, if there are not
objections to that change, but I want to be sure that we'll know right
away if that turns out to break.

I can split this one into another patch.

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

#25Emre Hasegeli
emre@hasegeli.com
In reply to: Alvaro Herrera (#23)
Re: [PATCH] Improve geometric types

Uh, I thought pg_hypot() was still needed on our oldest supported
platforms. Or is hypot() already supported there? If not, I suppose we
can keep the HYPOT() macro, and have it use hypot() on platforms that
have it and pg_hypot elsewhere? That particular fraction of 0001 seemed
a bit dubious to me, as the largest possible source of platform
dependency issues.

What is our oldest supported platform?

We can also just keep pg_hypot(). I don't think getting rid of it
justifies much work.

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

#26Tom Lane
tgl@sss.pgh.pa.us
In reply to: Emre Hasegeli (#25)
Re: [PATCH] Improve geometric types

Emre Hasegeli <emre@hasegeli.com> writes:

Uh, I thought pg_hypot() was still needed on our oldest supported
platforms. Or is hypot() already supported there?

What is our oldest supported platform?

Our normal reference for such questions is SUS v2 (POSIX 1997):
http://pubs.opengroup.org/onlinepubs/007908799/

I looked into that, and noted that it does specify hypot(), but
it has different rules for edge conditions:

If the result would cause overflow, HUGE_VAL is returned and errno
may be set to [ERANGE].

If x or y is NaN, NaN is returned. and errno may be set to [EDOM].

If the correct result would cause underflow, 0 is returned and
errno may be set to [ERANGE].

whereas POSIX 2008 saith:

If the correct value would cause overflow, a range error shall
occur and hypot(), hypotf(), and hypotl() shall return the value
of the macro HUGE_VAL, HUGE_VALF, and HUGE_VALL, respectively.

[MX] If x or y is ±Inf, +Inf shall be returned (even if one of x
or y is NaN).

If x or y is NaN, and the other is not ±Inf, a NaN shall be
returned.

[MXX] If both arguments are subnormal and the correct result is
subnormal, a range error may occur and the correct result shall
be returned.

In short, the reason that the existing comment makes a point of the
Inf-and-NaN behavior is that the standard changed somewhere along the
line. While I believe we could get away with assuming that hypot()
exists everywhere, it's much less clear that we could rely on the result
being Inf and not NaN in this case.

Now, it's also not clear that anything in PG really cares. But if we
do care, I think we should keep pg_hypot() ... and maybe clarify the
comment a bit more.

regards, tom lane

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

#27Emre Hasegeli
emre@hasegeli.com
In reply to: Tom Lane (#26)
Re: [PATCH] Improve geometric types

Now, it's also not clear that anything in PG really cares. But if we
do care, I think we should keep pg_hypot() ... and maybe clarify the
comment a bit more.

I am not sure how useful NaNs are in geometric types context, but we
allow them, so inconsistent hypot() would be a problem. I will change
my patches to keep pg_hypot().

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

#28Emre Hasegeli
emre@hasegeli.com
In reply to: Emre Hasegeli (#27)
6 attachment(s)
Re: [PATCH] Improve geometric types

I am not sure how useful NaNs are in geometric types context, but we
allow them, so inconsistent hypot() would be a problem. I will change
my patches to keep pg_hypot().

New versions of the patches are attached with 2 additional ones. The
new versions leave pg_hypot() in place. One of the new patches
improves the test coverage. The line coverage of geo_ops.c increases
from 55% to 81%. The other one fixes -0 values to 0 on float
operators. I am not sure about performance implication of this, so
kept it separate. It may be a better idea to check this only on the
platforms that has tendency to produce -0.

While working on the tests, I found some unreachable code and removed
it. I also found that lseg ## lseg operator returning wrong results.
It is defined as "closest point to first segment on the second
segment", but:

# select '[(1,2),(3,4)]'::lseg ## '[(0,0),(6,6)]'::lseg;
?column?
----------
(1,2)
(1 row)

I appended the fix to the patches. This is also effecting lseg ## box operator.

I also changed recently band-aided point ## lseg operator to return
the point instead of NULL when it cannot find the correct result to
avoid the operators depending on this one to crash.

Attachments:

0001-geo-funcs-v05.patchapplication/octet-stream; name=0001-geo-funcs-v05.patchDownload
From d7ef3049ce5ec1c1227f2570624e53aeb4f77cd1 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 27 May 2017 11:27:18 -0400
Subject: [PATCH 1/6] geo-funcs-v05

Refactor geometric functions and operators code

Most of the geometric types were not using functions of each other's.
I believe the reason behind this is simpler types line point and line
being developed after more complicated ones.  This patch reduces duplicate
code and makes functions of different datatypes more compatible.  We can
do better than that, but it would require touching many more lines.
The changes can be summarised as:

* Re-use more functions to implement others
* Unify *_construct and *_interpt_internal functions to obtain
  pre-allocated memory
* Remove private functions from geo_decls.h
* Switch using C99 hypot() as the comment suggested
* Add comments to describe some functions
* Replace not-possible checks with Assert()
* Remove unreachable code
---
 src/backend/utils/adt/geo_ops.c | 1098 ++++++++++++++++++---------------------
 src/include/utils/geo_decls.h   |    3 -
 src/test/regress/regress.c      |   11 +-
 3 files changed, 512 insertions(+), 600 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index e13389a6cc..8655fad4e3 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -31,76 +31,92 @@
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
+/* Routines for two-dimensional points */
+static inline void point_construct(Point *result, float8 x, float8 y);
+static inline void point_add_internal(Point *result, Point *pt1, Point *pt2);
+static inline void point_sub_internal(Point *result, Point *pt1, Point *pt2);
+static inline void point_mul_internal(Point *result, Point *pt1, Point *pt2);
+static inline void point_div_internal(Point *result, Point *pt1, Point *pt2);
+static inline bool point_eq_internal(Point *pt1, Point *pt2);
+static float8 point_dt(Point *pt1, Point *pt2);
 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);
+
+/* Routines for two-dimensional boxes */
+static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
+static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
+static double box_ar(BOX *box);
 static double box_ht(BOX *box);
 static double box_wd(BOX *box);
+
+/* Routines for two-dimensional circles */
 static double circle_ar(CIRCLE *circle);
-static CIRCLE *circle_copy(CIRCLE *circle);
-static LINE *line_construct_pm(Point *pt, double m);
-static void line_construct_pts(LINE *line, Point *pt1, Point *pt2);
-static bool lseg_intersect_internal(LSEG *l1, LSEG *l2);
-static double lseg_dt(LSEG *l1, LSEG *l2);
+
+/* Routines for two-dimensional lines */
+static inline void line_construct_pm(LINE *result, Point *pt, float8 m);
+static inline void line_construct_pts(LINE *result, Point *pt1, Point *pt2);
+static bool line_interpt_internal(Point *result, LINE *l1, LINE *l2);
+static inline float8 line_calculate_point(LINE *line, Point *pt);
+
+/* Routines for two-dimensional line segments */
+static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
+static bool lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line);
+static bool lseg_interpt_internal(Point *result, LSEG *l1, LSEG *l2);
+static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
+static float8 lseg_dt(LSEG *l1, LSEG *l2);
+static int	lseg_crossing(double x, double y, double px, double py);
 static bool on_ps_internal(Point *pt, LSEG *lseg);
+
+/* Routines for two-dimensional polygons */
 static void make_bound_box(POLYGON *poly);
+
+/* Unsorted */
 static bool plist_same(int npts, Point *p1, Point *p2);
-static Point *point_construct(double x, double y);
-static Point *point_copy(Point *pt);
 static double single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
 static void pair_decode(char *str, double *x, double *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
 static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
-static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
-static double box_ar(BOX *box);
-static void box_cn(Point *center, BOX *box);
-static Point *interpt_sl(LSEG *lseg, LINE *line);
-static bool has_interpt_sl(LSEG *lseg, LINE *line);
 static double dist_pl_internal(Point *pt, LINE *line);
 static double dist_ps_internal(Point *pt, LSEG *lseg);
-static Point *line_interpt_internal(LINE *l1, LINE *l2);
-static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
-static Point *lseg_interpt_internal(LSEG *l1, LSEG *l2);
 static double dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 
 /*
  * Delimiters for input and output strings.
  * LDELIM, RDELIM, and DELIM are left, right, and separator delimiters, respectively.
  * LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints.
  */
 
 #define LDELIM			'('
 #define RDELIM			')'
 #define DELIM			','
 #define LDELIM_EP		'['
 #define RDELIM_EP		']'
 #define LDELIM_C		'<'
 #define RDELIM_C		'>'
+#define LDELIM_L		'{'
+#define RDELIM_L		'}'
 
 
 /*
  * Geometric data types are composed of points.
  * This code tries to support a common format throughout the data types,
  *	to allow for more predictable usage and data type conversion.
  * The fundamental unit is the point. Other units are line segments,
  *	open paths, boxes, closed paths, and polygons (which should be considered
  *	non-intersecting closed paths).
  *
@@ -230,26 +246,23 @@ path_decode(char *str, bool opentype, int npts, Point *p,
 	}
 
 	for (i = 0; i < npts; i++)
 	{
 		pair_decode(str, &(p->x), &(p->y), &str, type_name, orig_string);
 		if (*str == DELIM)
 			str++;
 		p++;
 	}
 
-	while (isspace((unsigned char) *str))
-		str++;
 	while (depth > 0)
 	{
-		if ((*str == RDELIM)
-			|| ((*str == RDELIM_EP) && (*isopen) && (depth == 1)))
+		if (*str == RDELIM || (*str == RDELIM_EP && *isopen && depth == 1))
 		{
 			depth--;
 			str++;
 			while (isspace((unsigned char) *str))
 				str++;
 		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
@@ -325,20 +338,38 @@ pair_count(char *s, char delim)
 
 	while ((s = strchr(s, delim)) != NULL)
 	{
 		ndelim++;
 		s++;
 	}
 	return (ndelim % 2) ? ((ndelim + 1) / 2) : -1;
 }
 
 
+/*
+ * Return slope of two points
+ *
+ * This function accepts x and y coordinates separately to let it be used
+ * to calculate inverse slope.  To achieve that pass the values in
+ * (y1, y2, x2, x1) order.
+ */
+static inline float8
+slope(float8 x1, float8 x2, float8 y1, float8 y2)
+{
+	if (FPeq(x1, x2))
+		return DBL_MAX;
+	if (FPeq(y1, y2))
+		return 0.0;
+	return (y1 - y2) / (x1 - x2);
+}
+
+
 /***********************************************************************
  **
  **		Routines for two-dimensional boxes.
  **
  ***********************************************************************/
 
 /*----------------------------------------------------------
  * Formatting and conversion routines.
  *---------------------------------------------------------*/
 
@@ -434,89 +465,61 @@ box_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, box->high.x);
 	pq_sendfloat8(&buf, box->high.y);
 	pq_sendfloat8(&buf, box->low.x);
 	pq_sendfloat8(&buf, box->low.y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*		box_construct	-		fill in a new box.
  */
-static BOX *
-box_construct(double x1, double x2, double y1, double y2)
+static inline void
+box_construct(BOX *result, Point *pt1, Point *pt2)
 {
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	return box_fill(result, x1, x2, y1, y2);
-}
-
-
-/*		box_fill		-		fill in a given box struct
- */
-static BOX *
-box_fill(BOX *result, double x1, double x2, double y1, double y2)
-{
-	if (x1 > x2)
+	if (pt1->x > pt2->x)
 	{
-		result->high.x = x1;
-		result->low.x = x2;
+		result->high.x = pt1->x;
+		result->low.x = pt2->x;
 	}
 	else
 	{
-		result->high.x = x2;
-		result->low.x = x1;
+		result->high.x = pt2->x;
+		result->low.x = pt1->x;
 	}
-	if (y1 > y2)
+	if (pt1->y > pt2->y)
 	{
-		result->high.y = y1;
-		result->low.y = y2;
+		result->high.y = pt1->y;
+		result->low.y = pt2->y;
 	}
 	else
 	{
-		result->high.y = y2;
-		result->low.y = y1;
+		result->high.y = pt2->y;
+		result->low.y = pt1->y;
 	}
-
-	return result;
-}
-
-
-/*		box_copy		-		copy a box
- */
-static BOX *
-box_copy(BOX *box)
-{
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	memcpy((char *) result, (char *) box, sizeof(BOX));
-
-	return result;
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for BOXes.
  *		<, >, <=, >=, and == are based on box area.
  *---------------------------------------------------------*/
 
 /*		box_same		-		are two boxes identical?
  */
 Datum
 box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPeq(box1->high.x, box2->high.x) &&
-				   FPeq(box1->low.x, box2->low.x) &&
-				   FPeq(box1->high.y, box2->high.y) &&
-				   FPeq(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(point_eq_internal(&box1->high, &box2->high) &&
+				   point_eq_internal(&box1->low, &box2->low));
 }
 
 /*		box_overlap		-		does box1 overlap box2?
  */
 Datum
 box_overlap(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
@@ -751,51 +754,51 @@ box_area(PG_FUNCTION_ARGS)
 
 
 /*		box_width		-		returns the width of the box
  *								  (horizontal magnitude).
  */
 Datum
 box_width(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.x - box->low.x);
+	PG_RETURN_FLOAT8(box_wd(box));
 }
 
 
 /*		box_height		-		returns the height of the box
  *								  (vertical magnitude).
  */
 Datum
 box_height(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.y - box->low.y);
+	PG_RETURN_FLOAT8(box_ht(box));
 }
 
 
 /*		box_distance	-		returns the distance between the
  *								  center points of two boxes.
  */
 Datum
 box_distance(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 	Point		a,
 				b;
 
 	box_cn(&a, box1);
 	box_cn(&b, box2);
 
-	PG_RETURN_FLOAT8(HYPOT(a.x - b.x, a.y - b.y));
+	PG_RETURN_FLOAT8(point_dt(&a, &b));
 }
 
 
 /*		box_center		-		returns the center point of the box.
  */
 Datum
 box_center(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *result = (Point *) palloc(sizeof(Point));
@@ -899,76 +902,77 @@ static bool
 line_decode(char *s, const char *str, LINE *line)
 {
 	/* s was already advanced over leading '{' */
 	line->A = single_decode(s, &s, "line", str);
 	if (*s++ != DELIM)
 		return false;
 	line->B = single_decode(s, &s, "line", str);
 	if (*s++ != DELIM)
 		return false;
 	line->C = single_decode(s, &s, "line", str);
-	if (*s++ != '}')
+	if (*s++ != RDELIM_L)
 		return false;
 	while (isspace((unsigned char) *s))
 		s++;
 	if (*s != '\0')
 		return false;
 	return true;
 }
 
 Datum
 line_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	LINE	   *line = (LINE *) palloc(sizeof(LINE));
 	LSEG		lseg;
 	bool		isopen;
 	char	   *s;
 
 	s = str;
 	while (isspace((unsigned char) *s))
 		s++;
-	if (*s == '{')
+	if (*s == LDELIM_L)
 	{
 		if (!line_decode(s + 1, str, line))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
 							"line", str)));
 		if (FPzero(line->A) && FPzero(line->B))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: A and B cannot both be zero")));
 	}
 	else
 	{
-		path_decode(s, true, 2, &(lseg.p[0]), &isopen, NULL, "line", str);
-		if (FPeq(lseg.p[0].x, lseg.p[1].x) && FPeq(lseg.p[0].y, lseg.p[1].y))
+		path_decode(s, true, 2, &lseg.p[0], &isopen, NULL, "line", str);
+		if (point_eq_internal(&lseg.p[0], &lseg.p[1]))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: must be two distinct points")));
 		line_construct_pts(line, &lseg.p[0], &lseg.p[1]);
 	}
 
 	PG_RETURN_LINE_P(line);
 }
 
 
 Datum
 line_out(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	char	   *astr = float8out_internal(line->A);
 	char	   *bstr = float8out_internal(line->B);
 	char	   *cstr = float8out_internal(line->C);
 
-	PG_RETURN_CSTRING(psprintf("{%s,%s,%s}", astr, bstr, cstr));
+	PG_RETURN_CSTRING(psprintf("%c%s%c%s%c%s%c", LDELIM_L, astr, DELIM, bstr,
+							   DELIM, cstr, RDELIM_L));
 }
 
 /*
  *		line_recv			- converts external binary format to line
  */
 Datum
 line_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LINE	   *line;
@@ -997,128 +1001,102 @@ line_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, line->C);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*----------------------------------------------------------
  *	Conversion routines from one line formula to internal.
  *		Internal form:	Ax+By+C=0
  *---------------------------------------------------------*/
 
-/* line_construct_pm()
- * point-slope
+/*
+ * Fill already-allocated LINE struct from the point and the slope
  */
-static LINE *
-line_construct_pm(Point *pt, double m)
+static inline void
+line_construct_pm(LINE *result, Point *pt, float8 m)
 {
-	LINE	   *result = (LINE *) palloc(sizeof(LINE));
-
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
 		result->A = -1;
 		result->B = 0;
 		result->C = pt->x;
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
 		result->C = pt->y - m * pt->x;
 	}
-
-	return result;
 }
 
 /*
  * Fill already-allocated LINE struct from two points on the line
  */
-static void
-line_construct_pts(LINE *line, Point *pt1, Point *pt2)
+static inline void
+line_construct_pts(LINE *result, Point *pt1, Point *pt2)
 {
-	if (FPeq(pt1->x, pt2->x))
-	{							/* vertical */
-		/* use "x = C" */
-		line->A = -1;
-		line->B = 0;
-		line->C = pt1->x;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is vertical\n");
-#endif
-	}
-	else if (FPeq(pt1->y, pt2->y))
-	{							/* horizontal */
-		/* use "y = C" */
-		line->A = 0;
-		line->B = -1;
-		line->C = pt1->y;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is horizontal\n");
-#endif
-	}
-	else
-	{
-		/* use "mx - y + yinter = 0" */
-		line->A = (pt2->y - pt1->y) / (pt2->x - pt1->x);
-		line->B = -1.0;
-		line->C = pt1->y - line->A * pt1->x;
-		/* on some platforms, the preceding expression tends to produce -0 */
-		if (line->C == 0.0)
-			line->C = 0.0;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is neither vertical nor horizontal (diffs x=%.*g, y=%.*g\n",
-			   DBL_DIG, (pt2->x - pt1->x), DBL_DIG, (pt2->y - pt1->y));
-#endif
-	}
+	float8		m;
+
+	m = slope(pt1->x, pt2->x, pt1->y, pt2->y);
+	line_construct_pm(result, pt1, m);
 }
 
-/* line_construct_pp()
- * two points
+/*
+ * Construct a line from 2 points
  */
 Datum
 line_construct_pp(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 	LINE	   *result = (LINE *) palloc(sizeof(LINE));
 
 	line_construct_pts(result, pt1, pt2);
 	PG_RETURN_LINE_P(result);
 }
 
 
+/*
+ * Calculate the line equation for a point
+ *
+ * This returns the result of the line equation Ax + By + C.  The result
+ * needs to be 0.0 for the point to be on the line.
+ */
+static inline float8
+line_calculate_point(LINE *line, Point *pt)
+{
+	return line->A * pt->x + line->B * pt->y + line->C;
+}
+
+
 /*----------------------------------------------------------
  *	Relative position routines.
  *---------------------------------------------------------*/
 
 Datum
 line_intersect(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(!DatumGetBool(DirectFunctionCall2(line_parallel,
-													 LinePGetDatum(l1),
-													 LinePGetDatum(l2))));
+	PG_RETURN_BOOL(line_interpt_internal(NULL, l1, l2));
 }
 
 Datum
 line_parallel(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
-	if (FPzero(l1->B))
-		PG_RETURN_BOOL(FPzero(l2->B));
-
-	PG_RETURN_BOOL(FPeq(l2->A, l1->A * (l2->B / l1->B)));
+	PG_RETURN_BOOL(!line_interpt_internal(NULL, l1, l2));
 }
 
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
@@ -1172,96 +1150,94 @@ line_eq(PG_FUNCTION_ARGS)
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
-	Point	   *tmp;
+	Point		tmp;
 
-	if (!DatumGetBool(DirectFunctionCall2(line_parallel,
-										  LinePGetDatum(l1),
-										  LinePGetDatum(l2))))
+	if (line_interpt_internal(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
 		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
-	tmp = point_construct(0.0, l1->C);
-	result = dist_pl_internal(tmp, l2);
+	point_construct(&tmp, 0.0, l1->C);
+	result = dist_pl_internal(&tmp, l2);
 	PG_RETURN_FLOAT8(result);
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
-	result = line_interpt_internal(l1, l2);
+	result = (Point *) palloc(sizeof(Point));
 
-	if (result == NULL)
+	if (!line_interpt_internal(result, l1, l2))
 		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
 
 /*
  * Internal version of line_interpt
  *
- * returns a NULL pointer if no intersection point
+ * This returns true if two lines intersect (they do, if they are not
+ * parallel), false if they do not.  This also sets the intersection point
+ * to *result, if it is not NULL.
+ *
+ * NOTE: If the lines are identical then we will find they are parallel
+ * and report "no intersection".  This is a little weird, but since
+ * there's no *unique* intersection, maybe it's appropriate behavior.
  */
-static Point *
-line_interpt_internal(LINE *l1, LINE *l2)
+static bool
+line_interpt_internal(Point *result, LINE *l1, LINE *l2)
 {
-	Point	   *result;
 	double		x,
 				y;
 
-	/*
-	 * NOTE: if the lines are identical then we will find they are parallel
-	 * and report "no intersection".  This is a little weird, but since
-	 * there's no *unique* intersection, maybe it's appropriate behavior.
-	 */
-	if (DatumGetBool(DirectFunctionCall2(line_parallel,
-										 LinePGetDatum(l1),
-										 LinePGetDatum(l2))))
-		return NULL;
-
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
+		if (FPzero(l2->B))		/* l2 vertical? */
+			return false;
+
 		x = l1->C;
 		y = (l2->A * x + l2->C);
 	}
-	else if (FPzero(l2->B))		/* l2 vertical? */
-	{
-		x = l2->C;
-		y = (l1->A * x + l1->C);
-	}
 	else
 	{
-		x = (l1->C - l2->C) / (l2->A - l1->A);
+		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+			return false;
+
+		if (FPzero(l2->B))
+			x = l2->C;
+		else
+			x = (l1->C - l2->C) / (l2->A - l1->A);
 		y = (l1->A * x + l1->C);
 	}
-	result = point_construct(x, y);
+	if (result != NULL)
+		point_construct(result, x, y);
 
 #ifdef GEODEBUG
 	printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
 		   DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
 	printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
 #endif
 
-	return result;
+	return true;
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D paths (sequences of line segments, also
  **				called `polylines').
  **
  **				This is not a general package for geometric paths,
  **				which of course include polygons; the emphasis here
@@ -1556,22 +1532,21 @@ path_inter(PG_FUNCTION_ARGS)
 {
 	PATH	   *p1 = PG_GETARG_PATH_P(0);
 	PATH	   *p2 = PG_GETARG_PATH_P(1);
 	BOX			b1,
 				b2;
 	int			i,
 				j;
 	LSEG		seg1,
 				seg2;
 
-	if (p1->npts <= 0 || p2->npts <= 0)
-		PG_RETURN_BOOL(false);
+	Assert(p1->npts > 0 && p2->npts > 0);
 
 	b1.high.x = b1.low.x = p1->p[0].x;
 	b1.high.y = b1.low.y = p1->p[0].y;
 	for (i = 1; i < p1->npts; i++)
 	{
 		b1.high.x = Max(p1->p[i].x, b1.high.x);
 		b1.high.y = Max(p1->p[i].y, b1.high.y);
 		b1.low.x = Min(p1->p[i].x, b1.low.x);
 		b1.low.y = Min(p1->p[i].y, b1.low.y);
 	}
@@ -1609,21 +1584,21 @@ path_inter(PG_FUNCTION_ARGS)
 				jprev = j - 1;
 			else
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
-			if (lseg_intersect_internal(&seg1, &seg2))
+			if (lseg_interpt_internal(NULL, &seg1, &seg2))
 				PG_RETURN_BOOL(true);
 		}
 	}
 
 	/* if we dropped through, no two segs intersected */
 	PG_RETURN_BOOL(false);
 }
 
 /* path_distance()
  * This essentially does a cartesian product of the lsegs in the
@@ -1664,23 +1639,21 @@ path_distance(PG_FUNCTION_ARGS)
 			else
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
-			tmp = DatumGetFloat8(DirectFunctionCall2(lseg_distance,
-													 LsegPGetDatum(&seg1),
-													 LsegPGetDatum(&seg2)));
+			tmp = lseg_dt(&seg1, &seg2);
 			if (!have_min || tmp < min)
 			{
 				min = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	if (!have_min)
 		PG_RETURN_NULL();
@@ -1774,44 +1747,31 @@ point_send(PG_FUNCTION_ARGS)
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	StringInfoData buf;
 
 	pq_begintypsend(&buf);
 	pq_sendfloat8(&buf, pt->x);
 	pq_sendfloat8(&buf, pt->y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
-static Point *
-point_construct(double x, double y)
+/*
+ * Initialize a point
+ *
+ * This function is over-simple, but it is, at least, useful when the new
+ * point is calculated using the existing one.
+ */
+static inline void
+point_construct(Point *result, float8 x, float8 y)
 {
-	Point	   *result = (Point *) palloc(sizeof(Point));
-
 	result->x = x;
 	result->y = y;
-	return result;
-}
-
-
-static Point *
-point_copy(Point *pt)
-{
-	Point	   *result;
-
-	if (!PointerIsValid(pt))
-		return NULL;
-
-	result = (Point *) palloc(sizeof(Point));
-
-	result->x = pt->x;
-	result->y = pt->y;
-	return result;
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for Points.
  *		Since we do have a sense of coordinates being
  *		"equal" to a given accuracy (point_vert, point_horiz),
  *		the other ops must preserve that sense.  This means
  *		that results may, strictly speaking, be a lie (unless
  *		EPSILON = 0.0).
@@ -1870,71 +1830,74 @@ point_horiz(PG_FUNCTION_ARGS)
 
 	PG_RETURN_BOOL(FPeq(pt1->y, pt2->y));
 }
 
 Datum
 point_eq(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y));
+	PG_RETURN_BOOL(point_eq_internal(pt1, pt2));
 }
 
 Datum
 point_ne(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPne(pt1->x, pt2->x) || FPne(pt1->y, pt2->y));
+	PG_RETURN_BOOL(!point_eq_internal(pt1, pt2));
 }
 
+static inline bool
+point_eq_internal(Point *pt1, Point *pt2)
+{
+	return FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y);
+}
+
+
 /*----------------------------------------------------------
  *	"Arithmetic" operators on points.
  *---------------------------------------------------------*/
 
 Datum
 point_distance(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_FLOAT8(HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
+	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
-double
+static float8
 point_dt(Point *pt1, Point *pt2)
 {
+	float8		result;
+
+	result = HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
+
 #ifdef GEODEBUG
 	printf("point_dt- segment (%f,%f),(%f,%f) length is %f\n",
-		   pt1->x, pt1->y, pt2->x, pt2->y, HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
+		   pt1->x, pt1->y, pt2->x, pt2->y, result);
 #endif
-	return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
+
+	return result;
 }
 
 Datum
 point_slope(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_FLOAT8(point_sl(pt1, pt2));
-}
-
-
-double
-point_sl(Point *pt1, Point *pt2)
-{
-	return (FPeq(pt1->x, pt2->x)
-			? (double) DBL_MAX
-			: (pt1->y - pt2->y) / (pt1->x - pt2->x));
+	PG_RETURN_FLOAT8(slope(pt1->x, pt2->x, pt1->y, pt2->y));
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D line segments.
  **
  ***********************************************************************/
 
 /*----------------------------------------------------------
@@ -1946,31 +1909,31 @@ point_sl(Point *pt1, Point *pt2)
  *		(old form)		"(x1, y1, x2, y2)"
  *---------------------------------------------------------*/
 
 Datum
 lseg_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	LSEG	   *lseg = (LSEG *) palloc(sizeof(LSEG));
 	bool		isopen;
 
-	path_decode(str, true, 2, &(lseg->p[0]), &isopen, NULL, "lseg", str);
+	path_decode(str, true, 2, &lseg->p[0], &isopen, NULL, "lseg", str);
 	PG_RETURN_LSEG_P(lseg);
 }
 
 
 Datum
 lseg_out(PG_FUNCTION_ARGS)
 {
 	LSEG	   *ls = PG_GETARG_LSEG_P(0);
 
-	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, (Point *) &(ls->p[0])));
+	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, &ls->p[0]));
 }
 
 /*
  *		lseg_recv			- converts external binary format to lseg
  */
 Datum
 lseg_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LSEG	   *lseg;
@@ -2015,21 +1978,21 @@ lseg_construct(PG_FUNCTION_ARGS)
 
 	result->p[0].x = pt1->x;
 	result->p[0].y = pt1->y;
 	result->p[1].x = pt2->x;
 	result->p[1].y = pt2->y;
 
 	PG_RETURN_LSEG_P(result);
 }
 
 /* like lseg_construct, but assume space already allocated */
-static void
+static inline void
 statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2)
 {
 	lseg->p[0].x = pt1->x;
 	lseg->p[0].y = pt1->y;
 	lseg->p[1].x = pt2->x;
 	lseg->p[1].y = pt2->y;
 }
 
 Datum
 lseg_length(PG_FUNCTION_ARGS)
@@ -2046,69 +2009,57 @@ lseg_length(PG_FUNCTION_ARGS)
 /*
  **  find intersection of the two lines, and see if it falls on
  **  both segments.
  */
 Datum
 lseg_intersect(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(lseg_intersect_internal(l1, l2));
+	PG_RETURN_BOOL(lseg_interpt_internal(NULL, l1, l2));
 }
 
-static bool
-lseg_intersect_internal(LSEG *l1, LSEG *l2)
-{
-	LINE		ln;
-	Point	   *interpt;
-	bool		retval;
-
-	line_construct_pts(&ln, &l2->p[0], &l2->p[1]);
-	interpt = interpt_sl(l1, &ln);
-
-	if (interpt != NULL && on_ps_internal(interpt, l2))
-		retval = true;			/* interpt on l1 and l2 */
-	else
-		retval = false;
-	return retval;
-}
 
 Datum
 lseg_parallel(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
+	float8		m1,
+				m2;
 
-	PG_RETURN_BOOL(FPeq(point_sl(&l1->p[0], &l1->p[1]),
-						point_sl(&l2->p[0], &l2->p[1])));
+	m1 = slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y);
+	m2 = slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y);
+
+	PG_RETURN_BOOL(FPeq(m1, m2));
 }
 
 /* lseg_perp()
  * Determine if two line segments are perpendicular.
  *
  * This code did not get the correct answer for
  *	'((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg
  * So, modified it to check explicitly for slope of vertical line
- *	returned by point_sl() and the results seem better.
+ *	returned by slope() and the results seem better.
  * - thomas 1998-01-31
  */
 Datum
 lseg_perp(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	double		m1,
 				m2;
 
-	m1 = point_sl(&(l1->p[0]), &(l1->p[1]));
-	m2 = point_sl(&(l2->p[0]), &(l2->p[1]));
+	m1 = slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y);
+	m2 = slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y);
 
 #ifdef GEODEBUG
 	printf("lseg_perp- slopes are %g and %g\n", m1, m2);
 #endif
 	if (FPzero(m1))
 		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
 	else if (FPzero(m2))
 		PG_RETURN_BOOL(FPeq(m1, DBL_MAX));
 
 	PG_RETURN_BOOL(FPeq(m1 / m2, -1.0));
@@ -2130,36 +2081,32 @@ lseg_horizontal(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(FPeq(lseg->p[0].y, lseg->p[1].y));
 }
 
 
 Datum
 lseg_eq(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPeq(l1->p[0].x, l2->p[0].x) &&
-				   FPeq(l1->p[0].y, l2->p[0].y) &&
-				   FPeq(l1->p[1].x, l2->p[1].x) &&
-				   FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(point_eq_internal(&l1->p[0], &l2->p[0]) &&
+				   point_eq_internal(&l1->p[1], &l2->p[1]));
 }
 
 Datum
 lseg_ne(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(!FPeq(l1->p[0].x, l2->p[0].x) ||
-				   !FPeq(l1->p[0].y, l2->p[0].y) ||
-				   !FPeq(l1->p[1].x, l2->p[1].x) ||
-				   !FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(!point_eq_internal(&l1->p[0], &l2->p[0]) ||
+				   !point_eq_internal(&l1->p[1], &l2->p[1]));
 }
 
 Datum
 lseg_lt(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_BOOL(FPlt(point_dt(&l1->p[0], &l1->p[1]),
 						point_dt(&l2->p[0], &l2->p[1])));
@@ -2218,21 +2165,21 @@ lseg_distance(PG_FUNCTION_ARGS)
  * Distance between two line segments.
  * Must check both sets of endpoints to ensure minimum distance is found.
  * - thomas 1998-02-01
  */
 static double
 lseg_dt(LSEG *l1, LSEG *l2)
 {
 	double		result,
 				d;
 
-	if (lseg_intersect_internal(l1, l2))
+	if (lseg_interpt_internal(NULL, l1, l2))
 		return 0.0;
 
 	d = dist_ps_internal(&l1->p[0], l2);
 	result = d;
 	d = dist_ps_internal(&l1->p[1], l2);
 	result = Min(result, d);
 	d = dist_ps_internal(&l2->p[0], l1);
 	result = Min(result, d);
 	d = dist_ps_internal(&l2->p[1], l1);
 	result = Min(result, d);
@@ -2248,82 +2195,86 @@ lseg_center(PG_FUNCTION_ARGS)
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
 	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
 
 	PG_RETURN_POINT_P(result);
 }
 
-static Point *
-lseg_interpt_internal(LSEG *l1, LSEG *l2)
+static bool
+lseg_interpt_internal(Point *result, LSEG *l1, LSEG *l2)
 {
-	Point	   *result;
+	Point		interpt;
 	LINE		tmp1,
 				tmp2;
 
 	/*
 	 * Find the intersection of the appropriate lines, if any.
 	 */
 	line_construct_pts(&tmp1, &l1->p[0], &l1->p[1]);
 	line_construct_pts(&tmp2, &l2->p[0], &l2->p[1]);
-	result = line_interpt_internal(&tmp1, &tmp2);
-	if (!PointerIsValid(result))
-		return NULL;
+	if (!line_interpt_internal(&interpt, &tmp1, &tmp2))
+		return false;
 
 	/*
 	 * If the line intersection point isn't within l1 (or equivalently l2),
 	 * there is no valid segment intersection point at all.
 	 */
-	if (!on_ps_internal(result, l1) ||
-		!on_ps_internal(result, l2))
-	{
-		pfree(result);
-		return NULL;
-	}
+	if (!on_ps_internal(&interpt, l1) ||
+		!on_ps_internal(&interpt, l2))
+		return false;
+
+	if (result == NULL)
+		return true;
 
 	/*
 	 * If there is an intersection, then check explicitly for matching
 	 * endpoints since there may be rounding effects with annoying lsb
 	 * residue. - tgl 1997-07-09
 	 */
 	if ((FPeq(l1->p[0].x, l2->p[0].x) && FPeq(l1->p[0].y, l2->p[0].y)) ||
 		(FPeq(l1->p[0].x, l2->p[1].x) && FPeq(l1->p[0].y, l2->p[1].y)))
 	{
 		result->x = l1->p[0].x;
 		result->y = l1->p[0].y;
 	}
 	else if ((FPeq(l1->p[1].x, l2->p[0].x) && FPeq(l1->p[1].y, l2->p[0].y)) ||
 			 (FPeq(l1->p[1].x, l2->p[1].x) && FPeq(l1->p[1].y, l2->p[1].y)))
 	{
 		result->x = l1->p[1].x;
 		result->y = l1->p[1].y;
 	}
+	else
+	{
+		result->x = interpt.x;
+		result->y = interpt.y;
+	}
 
-	return result;
+	return true;
 }
 
 /* lseg_interpt -
  *		Find the intersection point of two segments (if any).
  */
 Datum
 lseg_interpt(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
-	result = lseg_interpt_internal(l1, l2);
-	if (!PointerIsValid(result))
-		PG_RETURN_NULL();
+	result = (Point *) palloc(sizeof(Point));
 
+	if (!lseg_interpt_internal(result, l1, l2))
+		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
 
 /***********************************************************************
  **
  **		Routines for position comparisons of differently-typed
  **				2D objects.
  **
  ***********************************************************************/
 
@@ -2340,75 +2291,70 @@ dist_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
 	PG_RETURN_FLOAT8(dist_pl_internal(pt, line));
 }
 
 static double
 dist_pl_internal(Point *pt, LINE *line)
 {
-	return fabs((line->A * pt->x + line->B * pt->y + line->C) /
+	return fabs(line_calculate_point(line, pt) /
 				HYPOT(line->A, line->B));
 }
 
 /*
  * Distance from a point to a lseg
  */
 Datum
 dist_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_FLOAT8(dist_ps_internal(pt, lseg));
 }
 
 static double
 dist_ps_internal(Point *pt, LSEG *lseg)
 {
 	double		m;				/* slope of perp. */
-	LINE	   *ln;
 	double		result,
 				tmpdist;
-	Point	   *ip;
+	Point		interpt;
+	LINE		ln;
 
 	/*
 	 * Construct a line perpendicular to the input segment and through the
 	 * input point
 	 */
-	if (lseg->p[1].x == lseg->p[0].x)
-		m = 0;
-	else if (lseg->p[1].y == lseg->p[0].y)
-		m = (double) DBL_MAX;	/* slope is infinite */
-	else
-		m = (lseg->p[0].x - lseg->p[1].x) / (lseg->p[1].y - lseg->p[0].y);
-	ln = line_construct_pm(pt, m);
+	m = slope(lseg->p[0].y, lseg->p[1].y, lseg->p[1].x, lseg->p[0].x);
+	line_construct_pm(&ln, pt, m);
 
 #ifdef GEODEBUG
 	printf("dist_ps- line is A=%g B=%g C=%g from (point) slope (%f,%f) %g\n",
 		   ln->A, ln->B, ln->C, pt->x, pt->y, m);
 #endif
 
 	/*
 	 * Calculate distance to the line segment or to the nearest endpoint of
 	 * the segment.
 	 */
 
 	/* intersection is on the line segment? */
-	if ((ip = interpt_sl(lseg, ln)) != NULL)
+	if (lseg_interpt_line_internal(&interpt, lseg, &ln))
 	{
 		/* yes, so use distance to the intersection point */
-		result = point_dt(pt, ip);
+		result = point_dt(pt, &interpt);
 #ifdef GEODEBUG
 		printf("dist_ps- distance is %f to intersection point is (%f,%f)\n",
-			   result, ip->x, ip->y);
+			   result, tmp.x, tmp.y);
 #endif
 	}
 	else
 	{
 		/* no, so use distance to the nearer endpoint */
 		result = point_dt(pt, &lseg->p[0]);
 		tmpdist = point_dt(pt, &lseg->p[1]);
 		if (tmpdist < result)
 			result = tmpdist;
 	}
@@ -2418,65 +2364,60 @@ dist_ps_internal(Point *pt, LSEG *lseg)
 
 /*
  * Distance from a point to a path
  */
 Datum
 dist_ppath(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	PATH	   *path = PG_GETARG_PATH_P(1);
 	float8		result = 0.0;	/* keep compiler quiet */
-	bool		have_min = false;
-	float8		tmp;
-	int			i;
-	LSEG		lseg;
 
-	switch (path->npts)
+	Assert(path->npts > 0);
+
+	/* One point in path? then get distance between two points... */
+	if (path->npts == 1)
+		result = point_dt(pt, &path->p[0]);
+	else
 	{
-		case 0:
-			/* no points in path? then result is undefined... */
-			PG_RETURN_NULL();
-		case 1:
-			/* one point in path? then get distance between two points... */
-			result = point_dt(pt, &path->p[0]);
-			break;
-		default:
-			/* make sure the path makes sense... */
-			Assert(path->npts > 1);
+		bool		have_min = false;
+		float8		tmp;
+		int			i;
+		LSEG		lseg;
 
-			/*
-			 * the distance from a point to a path is the smallest distance
-			 * from the point to any of its constituent segments.
-			 */
-			for (i = 0; i < path->npts; i++)
+		/*
+		 * The distance from a point to a path is the smallest distance
+		 * from the point to any of its constituent segments.
+		 */
+		for (i = 0; i < path->npts; i++)
+		{
+			int			iprev;
+
+			if (i > 0)
+				iprev = i - 1;
+			else
 			{
-				int			iprev;
-
-				if (i > 0)
-					iprev = i - 1;
-				else
-				{
-					if (!path->closed)
-						continue;
-					iprev = path->npts - 1; /* include the closure segment */
-				}
-
-				statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
-				tmp = dist_ps_internal(pt, &lseg);
-				if (!have_min || tmp < result)
-				{
-					result = tmp;
-					have_min = true;
-				}
+				if (!path->closed)
+					continue;
+				iprev = path->npts - 1; /* Include the closure segment */
 			}
-			break;
+
+			statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
+			tmp = dist_ps_internal(pt, &lseg);
+			if (!have_min || tmp < result)
+			{
+				result = tmp;
+				have_min = true;
+			}
+		}
 	}
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a point to a box
  */
 Datum
 dist_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
@@ -2496,21 +2437,21 @@ dist_pb(PG_FUNCTION_ARGS)
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	float8		result,
 				d2;
 
-	if (has_interpt_sl(lseg, line))
+	if (lseg_interpt_line_internal(NULL, lseg, line))
 		result = 0.0;
 	else
 	{
 		result = dist_pl_internal(&lseg->p[0], line);
 		d2 = dist_pl_internal(&lseg->p[1], line);
 		/* XXX shouldn't we take the min not max? */
 		if (d2 > result)
 			result = d2;
 	}
 
@@ -2649,286 +2590,256 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
  *				Intersection point of objects.
  *				We choose to ignore the "point" of intersection between
  *				  lines and boxes, since there are typically two.
  *-------------------------------------------------------------------*/
 
-/* Get intersection point of lseg and line; returns NULL if no intersection */
-static Point *
-interpt_sl(LSEG *lseg, LINE *line)
+/*
+ * Check if the line segment intersects with the line
+ *
+ * It sets the intersection point to *result, if it is not NULL.
+ */
+static bool
+lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line)
 {
+	Point		interpt;
 	LINE		tmp;
-	Point	   *p;
 
 	line_construct_pts(&tmp, &lseg->p[0], &lseg->p[1]);
-	p = line_interpt_internal(&tmp, line);
 #ifdef GEODEBUG
-	printf("interpt_sl- segment is (%.*g %.*g) (%.*g %.*g)\n",
+	printf("lseg_interpt_line- segment is (%.*g %.*g) (%.*g %.*g)\n",
 		   DBL_DIG, lseg->p[0].x, DBL_DIG, lseg->p[0].y, DBL_DIG, lseg->p[1].x, DBL_DIG, lseg->p[1].y);
-	printf("interpt_sl- segment becomes line A=%.*g B=%.*g C=%.*g\n",
+	printf("lseg_interpt_line_- segment becomes line A=%.*g B=%.*g C=%.*g\n",
 		   DBL_DIG, tmp.A, DBL_DIG, tmp.B, DBL_DIG, tmp.C);
 #endif
-	if (PointerIsValid(p))
+	if (line_interpt_internal(&interpt, &tmp, line))
 	{
 #ifdef GEODEBUG
-		printf("interpt_sl- intersection point is (%.*g %.*g)\n", DBL_DIG, p->x, DBL_DIG, p->y);
+		printf("lseg_interpt_line- intersection point is (%.*g %.*g)\n", DBL_DIG, p->x, DBL_DIG, p->y);
 #endif
-		if (on_ps_internal(p, lseg))
+		if (on_ps_internal(&interpt, lseg))
 		{
 #ifdef GEODEBUG
-			printf("interpt_sl- intersection point is on segment\n");
+			printf("lseg_interpt_line- intersection point is on segment\n");
 #endif
+			if (result != NULL)
+				*result = interpt;
+			return true;
 		}
-		else
-			p = NULL;
 	}
 
-	return p;
-}
-
-/* variant: just indicate if intersection point exists */
-static bool
-has_interpt_sl(LSEG *lseg, LINE *line)
-{
-	Point	   *tmp;
-
-	tmp = interpt_sl(lseg, line);
-	if (tmp)
-		return true;
 	return false;
 }
 
 /*---------------------------------------------------------------------
  *		close_
  *				Point of closest proximity between objects.
  *-------------------------------------------------------------------*/
 
 /* close_pl -
  *		The intersection point of a perpendicular of the line
  *		through the point.
  */
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
-	LINE	   *tmp;
-	double		invm;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (FPzero(line->B))		/* vertical? */
+		point_construct(result, line->C, pt->y);
+	else if (FPzero(line->A))	/* horizontal? */
+		point_construct(result, pt->x, line->C);
+	else
 	{
-		result->x = line->C;
-		result->y = pt->y;
-		PG_RETURN_POINT_P(result);
-	}
-	if (FPzero(line->A))		/* horizontal? */
-	{
-		result->x = pt->x;
-		result->y = line->C;
-		PG_RETURN_POINT_P(result);
-	}
-	/* drop a perpendicular and find the intersection point */
+		LINE		tmp;
+
+		/*
+		 * Drop a perpendicular and find the intersection point
+		 *
+		 * We need to invert the slope to get the perpendicular.
+		 */
+		line_construct_pm(&tmp, pt, line->B / line->A);
+		line_interpt_internal(result, &tmp, line);
+	}
 
-	/* invert and flip the sign on the slope to get a perpendicular */
-	invm = line->B / line->A;
-	tmp = line_construct_pm(pt, invm);
-	result = line_interpt_internal(tmp, line);
-	Assert(result != NULL);
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_ps()
  * Closest point on line segment to specified point.
  * Take the closest endpoint if the point is left, right,
  *	above, or below the segment, otherwise find the intersection
  *	point of the segment and its perpendicular through the point.
  *
  * Some tricky code here, relying on boolean expressions
  *	evaluating to only zero or one to use as an array index.
  *		bug fixes by gthaker@atl.lmco.com; May 1, 1998
  */
 Datum
 close_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
-	LINE	   *tmp;
+	Point	   *result;
 	double		invm;
 	int			xh,
 				yh;
+	LINE		tmp;
+
+	result = (Point *) palloc(sizeof(Point));
 
 #ifdef GEODEBUG
 	printf("close_sp:pt->x %f pt->y %f\nlseg(0).x %f lseg(0).y %f  lseg(1).x %f lseg(1).y %f\n",
 		   pt->x, pt->y, lseg->p[0].x, lseg->p[0].y,
 		   lseg->p[1].x, lseg->p[1].y);
 #endif
 
 	/* xh (or yh) is the index of upper x( or y) end point of lseg */
 	/* !xh (or !yh) is the index of lower x( or y) end point of lseg */
 	xh = lseg->p[0].x < lseg->p[1].x;
 	yh = lseg->p[0].y < lseg->p[1].y;
 
 	if (FPeq(lseg->p[0].x, lseg->p[1].x))	/* vertical? */
 	{
 #ifdef GEODEBUG
 		printf("close_ps- segment is vertical\n");
 #endif
 		/* first check if point is below or above the entire lseg. */
 		if (pt->y < lseg->p[!yh].y)
-			result = point_copy(&lseg->p[!yh]); /* below the lseg */
+			*result = lseg->p[!yh]; /* below the lseg */
 		else if (pt->y > lseg->p[yh].y)
-			result = point_copy(&lseg->p[yh]);	/* above the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
+			*result = lseg->p[yh];	/* above the lseg */
+		else
+			/* point lines along (to left or right) of the vertical lseg. */
+			point_construct(result, lseg->p[0].x, pt->y);
 
-		/* point lines along (to left or right) of the vertical lseg. */
-
-		result = (Point *) palloc(sizeof(Point));
-		result->x = lseg->p[0].x;
-		result->y = pt->y;
 		PG_RETURN_POINT_P(result);
 	}
 	else if (FPeq(lseg->p[0].y, lseg->p[1].y))	/* horizontal? */
 	{
 #ifdef GEODEBUG
 		printf("close_ps- segment is horizontal\n");
 #endif
 		/* first check if point is left or right of the entire lseg. */
 		if (pt->x < lseg->p[!xh].x)
-			result = point_copy(&lseg->p[!xh]); /* left of the lseg */
+			*result = lseg->p[!xh]; /* left of the lseg */
 		else if (pt->x > lseg->p[xh].x)
-			result = point_copy(&lseg->p[xh]);	/* right of the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
+			*result = lseg->p[xh];	/* right of the lseg */
+		else
+			/* point lines along (at top or below) the horiz. lseg. */
+			point_construct(result, pt->x, lseg->p[0].y);
 
-		/* point lines along (at top or below) the horiz. lseg. */
-		result = (Point *) palloc(sizeof(Point));
-		result->x = pt->x;
-		result->y = lseg->p[0].y;
 		PG_RETURN_POINT_P(result);
 	}
 
 	/*
 	 * vert. and horiz. cases are down, now check if the closest point is one
 	 * of the end points or someplace on the lseg.
 	 */
 
-	invm = -1.0 / point_sl(&(lseg->p[0]), &(lseg->p[1]));
-	tmp = line_construct_pm(&lseg->p[!yh], invm);	/* lower edge of the
+	invm = slope(lseg->p[0].y, lseg->p[1].y, lseg->p[1].x, lseg->p[0].x);
+	line_construct_pm(&tmp, &lseg->p[!yh], invm);	/* lower edge of the
 													 * "band" */
-	if (pt->y < (tmp->A * pt->x + tmp->C))
+	if (pt->y < (tmp.A * pt->x + tmp.C))
 	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[!yh]); /* below the lseg, take lower end
-											 * pt */
+		*result = lseg->p[!yh]; /* below the lseg, take lower end pt */
 #ifdef GEODEBUG
 		printf("close_ps below: tmp A %f  B %f   C %f\n",
 			   tmp->A, tmp->B, tmp->C);
 #endif
 		PG_RETURN_POINT_P(result);
 	}
-	tmp = line_construct_pm(&lseg->p[yh], invm);	/* upper edge of the
+	line_construct_pm(&tmp, &lseg->p[yh], invm);	/* upper edge of the
 													 * "band" */
-	if (pt->y > (tmp->A * pt->x + tmp->C))
+	if (pt->y > (tmp.A * pt->x + tmp.C))
 	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[yh]);	/* above the lseg, take higher end
-											 * pt */
+		*result = lseg->p[yh];	/* above the lseg, take higher end pt */
 #ifdef GEODEBUG
 		printf("close_ps above: tmp A %f  B %f   C %f\n",
 			   tmp->A, tmp->B, tmp->C);
 #endif
 		PG_RETURN_POINT_P(result);
 	}
 
 	/*
 	 * at this point the "normal" from point will hit lseg. The closest point
 	 * will be somewhere on the lseg
 	 */
-	tmp = line_construct_pm(pt, invm);
+	line_construct_pm(&tmp, pt, invm);
 #ifdef GEODEBUG
 	printf("close_ps- tmp A %f  B %f   C %f\n",
 		   tmp->A, tmp->B, tmp->C);
 #endif
-	result = interpt_sl(lseg, tmp);
 
 	/*
 	 * ordinarily we should always find an intersection point, but that could
 	 * fail in the presence of NaN coordinates, and perhaps even from simple
 	 * roundoff issues.  Return a SQL NULL if so.
 	 */
-	if (result == NULL)
+	if (!lseg_interpt_line_internal(result, lseg, &tmp))
 		PG_RETURN_NULL();
 
 #ifdef GEODEBUG
 	printf("close_ps- result.x %f  result.y %f\n", result->x, result->y);
 #endif
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_lseg()
  * Closest point to l1 on l2.
  */
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
-	Point		point;
-	double		dist;
-	double		d;
+	int			closer_end1,
+				closer_end2;
+	float8		dists1[2],
+				dists2[2];
+	Datum		point;
 
-	d = dist_ps_internal(&l1->p[0], l2);
-	dist = d;
-	memcpy(&point, &l1->p[0], sizeof(Point));
+	dists1[0] = dist_ps_internal(&l1->p[0], l2);
+	dists1[1] = dist_ps_internal(&l1->p[1], l2);
+	if (dists1[0] <= dists1[1])
+		closer_end1 = 0;
+	else
+		closer_end1 = 1;
 
-	if ((d = dist_ps_internal(&l1->p[1], l2)) < dist)
+	dists2[0] = dist_ps_internal(&l2->p[0], l1);
+	dists2[1] = dist_ps_internal(&l2->p[1], l1);
+	if (dists2[0] <= dists2[1])
+		closer_end2 = 0;
+	else
+		closer_end2 = 1;
+
+	if (dists1[closer_end1] <= dists2[closer_end2])
+		point = PointPGetDatum(&l1->p[closer_end1]);
+	else
 	{
-		dist = d;
-		memcpy(&point, &l1->p[1], sizeof(Point));
+		point = DirectFunctionCall2(close_ps,
+									PointPGetDatum(&l2->p[closer_end2]),
+									LsegPGetDatum(l1));
+		point = DirectFunctionCall2(close_ps, point, LsegPGetDatum(l2));
 	}
 
-	if (dist_ps_internal(&l2->p[0], l1) < dist)
-	{
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&l2->p[0]),
-													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
-													LsegPGetDatum(l2)));
-	}
-
-	if (dist_ps_internal(&l2->p[1], l1) < dist)
-	{
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&l2->p[1]),
-													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
-													LsegPGetDatum(l2)));
-	}
-
-	if (result == NULL)
-		result = point_copy(&point);
-
-	PG_RETURN_POINT_P(result);
+	return point;
 }
 
 /* close_pb()
  * Closest point on or in box to specified point.
  */
 Datum
 close_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
@@ -2989,30 +2900,31 @@ close_pb(PG_FUNCTION_ARGS)
 Datum
 close_sl(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 	float8		d1,
 				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
+	result = (Point *) palloc(sizeof(Point));
+
+	if (lseg_interpt_line_internal(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = dist_pl_internal(&lseg->p[0], line);
 	d2 = dist_pl_internal(&lseg->p[1], line);
 	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
+		*result = lseg->p[0];
 	else
-		result = point_copy(&lseg->p[1]);
+		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
 
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_sl\" not implemented")));
 
 	PG_RETURN_NULL();
 }
@@ -3022,30 +2934,31 @@ close_sl(PG_FUNCTION_ARGS)
  */
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 	float8		d1,
 				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
+	result = (Point *) palloc(sizeof(Point));
+
+	if (lseg_interpt_line_internal(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = dist_pl_internal(&lseg->p[0], line);
 	d2 = dist_pl_internal(&lseg->p[1], line);
 	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
+		*result = lseg->p[0];
 	else
-		result = point_copy(&lseg->p[1]);
+		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 }
 
 /* close_sb()
  * Closest point on or in box to line segment.
  */
 Datum
 close_sb(PG_FUNCTION_ARGS)
 {
@@ -3126,64 +3039,76 @@ close_lb(PG_FUNCTION_ARGS)
 
 /* on_pl -
  *		Does the point satisfy the equation?
  */
 Datum
 on_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(FPzero(line->A * pt->x + line->B * pt->y + line->C));
+	PG_RETURN_BOOL(FPzero(line_calculate_point(line, pt)));
 }
 
 
 /* on_ps -
  *		Determine colinearity by detecting a triangle inequality.
  * This algorithm seems to behave nicely even with lsb residues - tgl 1997-07-09
  */
 Datum
 on_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_BOOL(on_ps_internal(pt, lseg));
 }
 
+/*
+ * Implementation of operator point on line segment
+ */
 static bool
 on_ps_internal(Point *pt, LSEG *lseg)
 {
 	return FPeq(point_dt(pt, &lseg->p[0]) + point_dt(pt, &lseg->p[1]),
 				point_dt(&lseg->p[0], &lseg->p[1]));
 }
 
+
+/*
+ * Check whether the point is in the box or on its border
+ */
 Datum
 on_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_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);
 }
 
+
+/*
+ * Commutator of on_pb()
+ */
 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.
  * (uses same algorithm as for point intersecting segment - tgl 1997-07-09)
  *		If closed, we use the old O(n) ray method for point-in-polygon.
  *				The ray is horizontal, from pt out to the right.
  *				Each segment that crosses the ray counts as an
  *				intersection; note that an endpoint or edge may touch
  *				but not cross.
  *				(we can do p-in-p in lg(n), but it takes preprocessing)
@@ -3211,34 +3136,46 @@ on_ppath(PG_FUNCTION_ARGS)
 				PG_RETURN_BOOL(true);
 			a = b;
 		}
 		PG_RETURN_BOOL(false);
 	}
 
 	/*-- CLOSED --*/
 	PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
 }
 
+
+/*
+ * Check whether the line segment is on the line or close enough
+ *
+ * It is, if both of its points are on the line or close enough.
+ */
 Datum
 on_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
 	PG_RETURN_BOOL(DatumGetBool(DirectFunctionCall2(on_pl,
 													PointPGetDatum(&lseg->p[0]),
 													LinePGetDatum(line))) &&
 				   DatumGetBool(DirectFunctionCall2(on_pl,
 													PointPGetDatum(&lseg->p[1]),
 													LinePGetDatum(line))));
 }
 
+
+/*
+ * Check whether the line segment is in the box or on its border
+ *
+ * It is, if both of its points are in the box or on its border.
+ */
 Datum
 on_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 
 	PG_RETURN_BOOL(DatumGetBool(DirectFunctionCall2(on_pb,
 													PointPGetDatum(&lseg->p[0]),
 													BoxPGetDatum(box))) &&
 				   DatumGetBool(DirectFunctionCall2(on_pb,
@@ -3250,21 +3187,21 @@ on_sb(PG_FUNCTION_ARGS)
  *		inter_
  *				Whether one object intersects another.
  *-------------------------------------------------------------------*/
 
 Datum
 inter_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(has_interpt_sl(lseg, line));
+	PG_RETURN_BOOL(lseg_interpt_line_internal(NULL, lseg, line));
 }
 
 /* inter_sb()
  * Do line segment and box intersect?
  *
  * Segment completely inside box counts as intersection.
  * If you want only segments crossing box boundaries,
  *	try converting box to path first.
  *
  * Optimize for non-intersection by checking for box intersection first.
@@ -3294,35 +3231,35 @@ inter_sb(PG_FUNCTION_ARGS)
 										 BoxPGetDatum(box))) ||
 		DatumGetBool(DirectFunctionCall2(on_pb,
 										 PointPGetDatum(&lseg->p[1]),
 										 BoxPGetDatum(box))))
 		PG_RETURN_BOOL(true);
 
 	/* pairwise check lseg intersections */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
+	if (lseg_interpt_internal(NULL, &bseg, lseg))
 		PG_RETURN_BOOL(true);
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
+	if (lseg_interpt_internal(NULL, &bseg, lseg))
 		PG_RETURN_BOOL(true);
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
+	if (lseg_interpt_internal(NULL, &bseg, lseg))
 		PG_RETURN_BOOL(true);
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
+	if (lseg_interpt_internal(NULL, &bseg, lseg))
 		PG_RETURN_BOOL(true);
 
 	/* if we dropped through, no two segs intersected */
 	PG_RETURN_BOOL(false);
 }
 
 /* inter_lb()
  * Do line and box intersect?
  */
 Datum
@@ -3333,36 +3270,36 @@ inter_lb(PG_FUNCTION_ARGS)
 	LSEG		bseg;
 	Point		p1,
 				p2;
 
 	/* pairwise check lseg intersections */
 	p1.x = box->low.x;
 	p1.y = box->low.y;
 	p2.x = box->low.x;
 	p2.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line_internal(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->high.x;
 	p1.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line_internal(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p2.x = box->high.x;
 	p2.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line_internal(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->low.x;
 	p1.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line_internal(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 
 	/* if we dropped through, no intersection */
 	PG_RETURN_BOOL(false);
 }
 
 /*------------------------------------------------------------------
  * The following routines define a data type and operator class for
  * POLYGONS .... Part of which (the polygon's bounding box) is built on
  * top of the BOX data type.
@@ -3370,47 +3307,37 @@ inter_lb(PG_FUNCTION_ARGS)
  * make_bound_box - create the bounding box for the input polygon
  *------------------------------------------------------------------*/
 
 /*---------------------------------------------------------------------
  * Make the smallest bounding box for the given polygon.
  *---------------------------------------------------------------------*/
 static void
 make_bound_box(POLYGON *poly)
 {
 	int			i;
-	double		x1,
-				y1,
-				x2,
-				y2;
+	BOX		   *boundbox = &poly->boundbox;
 
-	if (poly->npts > 0)
+	Assert(poly->npts > 0);
+
+	boundbox->low.x = boundbox->high.x = poly->p[0].x;
+	boundbox->low.y = boundbox->high.y = poly->p[0].y;
+	for (i = 1; i < poly->npts; i++)
 	{
-		x2 = x1 = poly->p[0].x;
-		y2 = y1 = poly->p[0].y;
-		for (i = 1; i < poly->npts; i++)
-		{
-			if (poly->p[i].x < x1)
-				x1 = poly->p[i].x;
-			if (poly->p[i].x > x2)
-				x2 = poly->p[i].x;
-			if (poly->p[i].y < y1)
-				y1 = poly->p[i].y;
-			if (poly->p[i].y > y2)
-				y2 = poly->p[i].y;
-		}
-
-		box_fill(&(poly->boundbox), x1, x2, y1, y2);
+		if (poly->p[i].x < boundbox->low.x)
+			boundbox->low.x = poly->p[i].x;
+		if (poly->p[i].x > boundbox->high.x)
+			boundbox->high.x = poly->p[i].x;
+		if (poly->p[i].y < boundbox->low.y)
+			boundbox->low.y = poly->p[i].y;
+		if (poly->p[i].y > boundbox->high.y)
+			boundbox->high.y = poly->p[i].y;
 	}
-	else
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot create bounding box for empty polygon")));
 }
 
 /*------------------------------------------------------------------
  * poly_in - read in the polygon from a string specification
  *
  *		External format:
  *				"((x0,y0),...,(xn,yn))"
  *				"x0,y0,...,xn,yn"
  *				also supports the older style "(x1,...,xn,y1,...yn)"
  *------------------------------------------------------------------*/
@@ -3742,21 +3669,21 @@ poly_same(PG_FUNCTION_ARGS)
  *-----------------------------------------------------------------*/
 Datum
 poly_overlap(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
 	/* Quick check by bounding box */
 	result = (polya->npts > 0 && polyb->npts > 0 &&
-			  box_ov(&polya->boundbox, &polyb->boundbox)) ? true : false;
+			  box_ov(&polya->boundbox, &polyb->boundbox));
 
 	/*
 	 * Brute-force algorithm - try to find intersected edges, if so then
 	 * polygons are overlapped else check is one polygon inside other or not
 	 * by testing single point of them.
 	 */
 	if (result)
 	{
 		int			ia,
 					ib;
@@ -3771,34 +3698,33 @@ poly_overlap(PG_FUNCTION_ARGS)
 		{
 			/* Second point of polya's edge is a current one */
 			sa.p[1] = polya->p[ia];
 
 			/* Init first of polyb's edge with last point */
 			sb.p[0] = polyb->p[polyb->npts - 1];
 
 			for (ib = 0; ib < polyb->npts && result == false; ib++)
 			{
 				sb.p[1] = polyb->p[ib];
-				result = lseg_intersect_internal(&sa, &sb);
+				result = lseg_interpt_internal(NULL, &sa, &sb);
 				sb.p[0] = sb.p[1];
 			}
 
 			/*
 			 * move current endpoint to the first point of next edge
 			 */
 			sa.p[0] = sa.p[1];
 		}
 
 		if (result == false)
 		{
-			result = (point_inside(polya->p, polyb->npts, polyb->p)
-					  ||
+			result = (point_inside(polya->p, polyb->npts, polyb->p) ||
 					  point_inside(polyb->p, polya->npts, polya->p));
 		}
 	}
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
@@ -3818,27 +3744,26 @@ poly_overlap(PG_FUNCTION_ARGS)
 
 static bool
 touched_lseg_inside_poly(Point *a, Point *b, LSEG *s, POLYGON *poly, int start)
 {
 	/* point a is on s, b is not */
 	LSEG		t;
 
 	t.p[0] = *a;
 	t.p[1] = *b;
 
-#define POINTEQ(pt1, pt2)	(FPeq((pt1)->x, (pt2)->x) && FPeq((pt1)->y, (pt2)->y))
-	if (POINTEQ(a, s->p))
+	if (point_eq_internal(a, s->p))
 	{
 		if (on_ps_internal(s->p + 1, &t))
 			return lseg_inside_poly(b, s->p + 1, poly, start);
 	}
-	else if (POINTEQ(a, s->p + 1))
+	else if (point_eq_internal(a, s->p + 1))
 	{
 		if (on_ps_internal(s->p, &t))
 			return lseg_inside_poly(b, s->p, poly, start);
 	}
 	else if (on_ps_internal(s->p, &t))
 	{
 		return lseg_inside_poly(b, s->p, poly, start);
 	}
 	else if (on_ps_internal(s->p + 1, &t))
 	{
@@ -3861,50 +3786,49 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 	int			i;
 	bool		res = true,
 				intersection = false;
 
 	t.p[0] = *a;
 	t.p[1] = *b;
 	s.p[0] = poly->p[(start == 0) ? (poly->npts - 1) : (start - 1)];
 
 	for (i = start; i < poly->npts && res; i++)
 	{
-		Point	   *interpt;
+		Point		interpt;
 
 		CHECK_FOR_INTERRUPTS();
 
 		s.p[1] = poly->p[i];
 
 		if (on_ps_internal(t.p, &s))
 		{
 			if (on_ps_internal(t.p + 1, &s))
 				return true;	/* t is contained by s */
 
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p, t.p + 1, &s, poly, i + 1);
 		}
 		else if (on_ps_internal(t.p + 1, &s))
 		{
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p + 1, t.p, &s, poly, i + 1);
 		}
-		else if ((interpt = lseg_interpt_internal(&t, &s)) != NULL)
+		else if (lseg_interpt_internal(&interpt, &t, &s))
 		{
 			/*
 			 * segments are X-crossing, go to check each subsegment
 			 */
 
 			intersection = true;
-			res = lseg_inside_poly(t.p, interpt, poly, i + 1);
+			res = lseg_inside_poly(t.p, &interpt, poly, i + 1);
 			if (res)
-				res = lseg_inside_poly(t.p + 1, interpt, poly, i + 1);
-			pfree(interpt);
+				res = lseg_inside_poly(t.p + 1, &interpt, poly, i + 1);
 		}
 
 		s.p[0] = s.p[1];
 	}
 
 	if (res && !intersection)
 	{
 		Point		p;
 
 		/*
@@ -4019,170 +3943,208 @@ poly_distance(PG_FUNCTION_ARGS)
  **
  **		Routines for 2D points.
  **
  ***********************************************************************/
 
 Datum
 construct_point(PG_FUNCTION_ARGS)
 {
 	float8		x = PG_GETARG_FLOAT8(0);
 	float8		y = PG_GETARG_FLOAT8(1);
+	Point	   *result;
 
-	PG_RETURN_POINT_P(point_construct(x, y));
+	result = (Point *) palloc(sizeof(Point));
+
+	point_construct(result, x, y);
+
+	PG_RETURN_POINT_P(result);
 }
 
 Datum
 point_add(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x + p2->x);
-	result->y = (p1->y + p2->y);
+	point_add_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+static inline void
+point_add_internal(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x + pt2->x,
+					pt1->y + pt2->y);
+}
+
+
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x - p2->x);
-	result->y = (p1->y - p2->y);
+	point_sub_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+static inline void
+point_sub_internal(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x - pt2->x,
+					pt1->y - pt2->y);
+}
+
+
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x * p2->x) - (p1->y * p2->y);
-	result->y = (p1->x * p2->y) + (p1->y * p2->x);
+	point_mul_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+static inline void
+point_mul_internal(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					(pt1->x * pt2->x) - (pt1->y * pt2->y),
+					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+}
+
+
 Datum
 point_div(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
-	double		div;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	div = (p2->x * p2->x) + (p2->y * p2->y);
-
-	if (div == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result->x = ((p1->x * p2->x) + (p1->y * p2->y)) / div;
-	result->y = ((p2->x * p1->y) - (p2->y * p1->x)) / div;
+	point_div_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+static inline void
+point_div_internal(Point *result, Point *pt1, Point *pt2)
+{
+	float8		div;
+
+	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
+	point_construct(result,
+					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
+					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+}
+
 
 /***********************************************************************
  **
  **		Routines for 2D boxes.
  **
  ***********************************************************************/
 
 Datum
 points_box(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct(p1->x, p2->x, p1->y, p2->y));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	box_construct(result, p1, p2);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_add(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct((box->high.x + p->x),
-								  (box->low.x + p->x),
-								  (box->high.y + p->y),
-								  (box->low.y + p->y)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_add_internal(&result->high, &box->high, p);
+	point_add_internal(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_sub(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct((box->high.x - p->x),
-								  (box->low.x - p->x),
-								  (box->high.y - p->y),
-								  (box->low.y - p->y)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_sub_internal(&result->high, &box->high, p);
+	point_sub_internal(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_mul(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
 
-	high = DatumGetPointP(DirectFunctionCall2(point_mul,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_mul,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	result = (BOX *) palloc(sizeof(BOX));
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	point_mul_internal(&high, &box->high, p);
+	point_mul_internal(&low, &box->low, p);
+
+	box_construct(result, &high, &low);
 
 	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_div(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
 
-	high = DatumGetPointP(DirectFunctionCall2(point_div,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_div,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	result = (BOX *) palloc(sizeof(BOX));
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	point_div_internal(&high, &box->high, p);
+	point_div_internal(&low, &box->low, p);
+
+	box_construct(result, &high, &low);
 
 	PG_RETURN_BOX_P(result);
 }
 
 /*
  * Convert point to empty box
  */
 Datum
 point_box(PG_FUNCTION_ARGS)
 {
@@ -4278,83 +4240,63 @@ path_add(PG_FUNCTION_ARGS)
  * Translation operators.
  */
 Datum
 path_add_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x += point->x;
-		path->p[i].y += point->y;
-	}
+		point_add_internal(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_sub_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x -= point->x;
-		path->p[i].y -= point->y;
-	}
+		point_sub_internal(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 /* path_mul_pt()
  * Rotation and scaling operators.
  */
 Datum
 path_mul_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_mul,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_mul_internal(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_div_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_div,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_div_internal(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 
 Datum
 path_center(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	PATH	   *path = PG_GETARG_PATH_P(0);
@@ -4433,24 +4375,24 @@ poly_center(PG_FUNCTION_ARGS)
 	PG_RETURN_DATUM(result);
 }
 
 
 Datum
 poly_box(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	BOX		   *box;
 
-	if (poly->npts < 1)
-		PG_RETURN_NULL();
+	Assert(poly->npts > 0);
 
-	box = box_copy(&poly->boundbox);
+	box = (BOX *) palloc(sizeof(BOX));
+	*box = poly->boundbox;
 
 	PG_RETURN_BOX_P(box);
 }
 
 
 /* box_poly()
  * Convert a box to a polygon.
  */
 Datum
 box_poly(PG_FUNCTION_ARGS)
@@ -4468,22 +4410,21 @@ box_poly(PG_FUNCTION_ARGS)
 
 	poly->p[0].x = box->low.x;
 	poly->p[0].y = box->low.y;
 	poly->p[1].x = box->low.x;
 	poly->p[1].y = box->high.y;
 	poly->p[2].x = box->high.x;
 	poly->p[2].y = box->high.y;
 	poly->p[3].x = box->high.x;
 	poly->p[3].y = box->low.y;
 
-	box_fill(&poly->boundbox, box->high.x, box->low.x,
-			 box->high.y, box->low.y);
+	box_construct(&poly->boundbox, &box->high, &box->low);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
 
 Datum
 poly_path(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	PATH	   *path;
@@ -4492,21 +4433,21 @@ poly_path(PG_FUNCTION_ARGS)
 
 	/*
 	 * Never overflows: the old size fit in MaxAllocSize, and the new size is
 	 * smaller by a small constant.
 	 */
 	size = offsetof(PATH, p) + sizeof(path->p[0]) * poly->npts;
 	path = (PATH *) palloc(size);
 
 	SET_VARSIZE(path, size);
 	path->npts = poly->npts;
-	path->closed = TRUE;
+	path->closed = true;
 	/* prevent instability in unused pad bytes */
 	path->dummy = 0;
 
 	for (i = 0; i < poly->npts; i++)
 	{
 		path->p[i].x = poly->p[i].x;
 		path->p[i].y = poly->p[i].y;
 	}
 
 	PG_RETURN_PATH_P(path);
@@ -4558,22 +4499,21 @@ circle_in(PG_FUNCTION_ARGS)
 
 	circle->radius = single_decode(s, &s, "circle", str);
 	if (circle->radius < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
 
 	while (depth > 0)
 	{
-		if ((*s == RDELIM)
-			|| ((*s == RDELIM_C) && (depth == 1)))
+		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
 			s++;
 			while (isspace((unsigned char) *s))
 				s++;
 		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
@@ -4657,22 +4597,21 @@ circle_send(PG_FUNCTION_ARGS)
 
 /*		circles identical?
  */
 Datum
 circle_same(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPeq(circle1->radius, circle2->radius) &&
-				   FPeq(circle1->center.x, circle2->center.x) &&
-				   FPeq(circle1->center.y, circle2->center.y));
+				   point_eq_internal(&circle1->center, &circle2->center));
 }
 
 /*		circle_overlap	-		does circle1 overlap circle2?
  */
 Datum
 circle_overlap(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
@@ -4859,106 +4798,82 @@ circle_ge(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPge(circle_ar(circle1), circle_ar(circle2)));
 }
 
 
 /*----------------------------------------------------------
  *	"Arithmetic" operators on circles.
  *---------------------------------------------------------*/
 
-static CIRCLE *
-circle_copy(CIRCLE *circle)
-{
-	CIRCLE	   *result;
-
-	if (!PointerIsValid(circle))
-		return NULL;
-
-	result = (CIRCLE *) palloc(sizeof(CIRCLE));
-	memcpy((char *) result, (char *) circle, sizeof(CIRCLE));
-	return result;
-}
-
-
 /* circle_add_pt()
  * Translation operator.
  */
 Datum
 circle_add_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x += point->x;
-	result->center.y += point->y;
+	point_add_internal(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_sub_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x -= point->x;
-	result->center.y -= point->y;
+	point_sub_internal(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /* circle_mul_pt()
  * Rotation and scaling operators.
  */
 Datum
 circle_mul_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_mul,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
+	point_mul_internal(&result->center, &circle->center, point);
 	result->radius *= HYPOT(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_div_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_div,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
+	point_div_internal(&result->center, &circle->center, point);
 	result->radius /= HYPOT(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /*		circle_area		-		returns the area of the circle.
  */
 Datum
 circle_area(PG_FUNCTION_ARGS)
@@ -4994,22 +4909,22 @@ circle_radius(PG_FUNCTION_ARGS)
 /*		circle_distance -		returns the distance between
  *								  two circles.
  */
 Datum
 circle_distance(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(&circle1->center, &circle2->center)
-		- (circle1->radius + circle2->radius);
+	result = point_dt(&circle1->center, &circle2->center) -
+		(circle1->radius + circle2->radius);
 	if (result < 0)
 		result = 0;
 	PG_RETURN_FLOAT8(result);
 }
 
 
 Datum
 circle_contain_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
@@ -5203,24 +5118,21 @@ circle_poly(PG_FUNCTION_ARGS)
  * XXX This algorithm should use weighted means of line segments
  *	rather than straight average values of points - tgl 97/01/21.
  */
 Datum
 poly_circle(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	CIRCLE	   *circle;
 	int			i;
 
-	if (poly->npts < 1)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot convert empty polygon to circle")));
+	Assert(poly->npts > 0);
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	circle->center.x = 0;
 	circle->center.y = 0;
 	circle->radius = 0;
 
 	for (i = 0; i < poly->npts; i++)
 	{
 		circle->center.x += poly->p[i].x;
@@ -5262,22 +5174,21 @@ point_inside(Point *p, int npts, Point *plist)
 	double		x0,
 				y0;
 	double		prev_x,
 				prev_y;
 	int			i = 0;
 	double		x,
 				y;
 	int			cross,
 				total_cross = 0;
 
-	if (npts <= 0)
-		return 0;
+	Assert(npts > 0);
 
 	/* compute first polygon point relative to single point */
 	x0 = plist[0].x - p->x;
 	y0 = plist[0].y - p->y;
 
 	prev_x = x0;
 	prev_y = y0;
 	/* loop over polygon points and aggregate total_cross */
 	for (i = 1; i < npts; i++)
 	{
@@ -5372,67 +5283,64 @@ lseg_crossing(double x, double y, double prev_x, double prev_y)
 static bool
 plist_same(int npts, Point *p1, Point *p2)
 {
 	int			i,
 				ii,
 				j;
 
 	/* find match for first point */
 	for (i = 0; i < npts; i++)
 	{
-		if ((FPeq(p2[i].x, p1[0].x))
-			&& (FPeq(p2[i].y, p1[0].y)))
+		if (point_eq_internal(&p2[i], &p1[0]))
 		{
 
 			/* match found? then look forward through remaining points */
 			for (ii = 1, j = i + 1; ii < npts; ii++, j++)
 			{
 				if (j >= npts)
 					j = 0;
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_internal(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed forward match with %d\n", j, ii);
 #endif
 					break;
 				}
 			}
 #ifdef GEODEBUG
 			printf("plist_same- ii = %d/%d after forward match\n", ii, npts);
 #endif
 			if (ii == npts)
-				return TRUE;
+				return true;
 
 			/* match not found forwards? then look backwards */
 			for (ii = 1, j = i - 1; ii < npts; ii++, j--)
 			{
 				if (j < 0)
 					j = (npts - 1);
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_internal(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed reverse match with %d\n", j, ii);
 #endif
 					break;
 				}
 			}
 #ifdef GEODEBUG
 			printf("plist_same- ii = %d/%d after reverse match\n", ii, npts);
 #endif
 			if (ii == npts)
-				return TRUE;
+				return true;
 		}
 	}
 
-	return FALSE;
+	return false;
 }
 
 
 /*-------------------------------------------------------------------------
  * Determine the hypotenuse.
  *
  * If required, x and y are swapped to make x the larger number. The
  * traditional formula of x^2+y^2 is rearranged to factor x outside the
  * sqrt. This allows computation of the hypotenuse for significantly
  * larger values, and with a higher precision than when using the naive
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 44c6381b85..19ecf4e712 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -171,16 +171,13 @@ typedef struct
 #define DatumGetCircleP(X)	  ((CIRCLE *) DatumGetPointer(X))
 #define CirclePGetDatum(X)	  PointerGetDatum(X)
 #define PG_GETARG_CIRCLE_P(n) DatumGetCircleP(PG_GETARG_DATUM(n))
 #define PG_RETURN_CIRCLE_P(x) return CirclePGetDatum(x)
 
 
 /*
  * 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 */
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index 0e9e46e667..51dfd52a44 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -62,21 +62,23 @@ regress_dist_ptpath(PG_FUNCTION_ARGS)
 	float8		result = 0.0;	/* keep compiler quiet */
 	float8		tmp;
 	int			i;
 	LSEG		lseg;
 
 	switch (path->npts)
 	{
 		case 0:
 			PG_RETURN_NULL();
 		case 1:
-			result = point_dt(pt, &path->p[0]);
+			result = DatumGetFloat8(DirectFunctionCall2(point_distance,
+														PointPGetDatum(pt),
+												PointPGetDatum(&path->p[0])));
 			break;
 		default:
 
 			/*
 			 * the distance from a point to a path is the smallest distance
 			 * from the point to any of its constituent segments.
 			 */
 			Assert(path->npts > 1);
 			for (i = 0; i < path->npts - 1; ++i)
 			{
@@ -280,22 +282,27 @@ widget_out(PG_FUNCTION_ARGS)
 	PG_RETURN_CSTRING(str);
 }
 
 PG_FUNCTION_INFO_V1(pt_in_widget);
 
 Datum
 pt_in_widget(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	WIDGET	   *widget = (WIDGET *) PG_GETARG_POINTER(1);
+	float8		distance;
 
-	PG_RETURN_BOOL(point_dt(point, &widget->center) < widget->radius);
+	distance = DatumGetFloat8(DirectFunctionCall2(point_distance,
+												  PointPGetDatum(point),
+											PointPGetDatum(&widget->center)));
+
+	PG_RETURN_BOOL(distance < widget->radius);
 }
 
 PG_FUNCTION_INFO_V1(boxarea);
 
 Datum
 boxarea(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	double		width,
 				height;
-- 
2.13.6 (Apple Git-96)

0002-float-header-v09.patchapplication/octet-stream; name=0002-float-header-v09.patchDownload
From e1b869d99e4ef6d2b9ebb713c4ab16b091d00151 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 28 May 2016 18:16:05 +0200
Subject: [PATCH 2/6] float-header-v09

Provide header file for built-in float datatypes

Even though, some datatypes under adt/ have separate header files,
most of the simple ones do not.  Their public functions were on
the builtins.h.  We would need to make more functions of floats public
to let the geometric types built on top of them.  This is a good
opportunity to make a separate header file for floats.

1acf7572554515b99ef6e783750aaea8777524ec made _cmp functions public
to solve NaN problem locally for GiST indexes.  This patch reworks it
in favour of a more extensive API.  Kevin Grittner suggested to design
the API using inline functions.  They are easier to use compared
to macros, and avoid double-evaluation hazards.
---
 contrib/btree_gin/btree_gin.c                 |   1 +
 contrib/btree_gist/btree_ts.c                 |   1 +
 contrib/cube/cube.c                           |   2 +-
 contrib/cube/cubeparse.y                      |   2 +-
 contrib/postgres_fdw/postgres_fdw.c           |   1 +
 src/backend/access/gist/gistget.c             |   2 +-
 src/backend/access/gist/gistproc.c            |  55 +--
 src/backend/access/gist/gistutil.c            |   2 +-
 src/backend/utils/adt/float.c                 | 589 ++++++--------------------
 src/backend/utils/adt/formatting.c            |   1 +
 src/backend/utils/adt/geo_ops.c               |   6 +-
 src/backend/utils/adt/geo_spgist.c            |   2 +-
 src/backend/utils/adt/numeric.c               |   1 +
 src/backend/utils/adt/rangetypes_gist.c       |   3 +-
 src/backend/utils/adt/rangetypes_selfuncs.c   |   3 +-
 src/backend/utils/adt/rangetypes_typanalyze.c |   3 +-
 src/backend/utils/adt/timestamp.c             |   1 +
 src/backend/utils/misc/guc.c                  |   1 +
 src/include/utils/builtins.h                  |  14 -
 src/include/utils/float.h                     | 376 ++++++++++++++++
 src/include/utils/geo_decls.h                 |   1 +
 21 files changed, 554 insertions(+), 513 deletions(-)
 create mode 100644 src/include/utils/float.h

diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index 2473f79ca1..301caefd47 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -3,20 +3,21 @@
  */
 #include "postgres.h"
 
 #include <limits.h>
 
 #include "access/stratnum.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/cash.h"
 #include "utils/date.h"
+#include "utils/float.h"
 #include "utils/inet.h"
 #include "utils/numeric.h"
 #include "utils/timestamp.h"
 #include "utils/varbit.h"
 
 PG_MODULE_MAGIC;
 
 typedef struct QueryInfo
 {
 	StrategyNumber strategy;
diff --git a/contrib/btree_gist/btree_ts.c b/contrib/btree_gist/btree_ts.c
index 1582cff102..6e77ebab0d 100644
--- a/contrib/btree_gist/btree_ts.c
+++ b/contrib/btree_gist/btree_ts.c
@@ -2,20 +2,21 @@
  * contrib/btree_gist/btree_ts.c
  */
 #include "postgres.h"
 
 #include <limits.h>
 
 #include "btree_gist.h"
 #include "btree_utils_num.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 typedef struct
 {
 	Timestamp	lower;
 	Timestamp	upper;
 } tsKEY;
 
 /*
 ** timestamp ops
 */
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c
index b7702716fe..f5a39cb53b 100644
--- a/contrib/cube/cube.c
+++ b/contrib/cube/cube.c
@@ -7,21 +7,21 @@
 ******************************************************************************/
 
 #include "postgres.h"
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 
 #include "cubedata.h"
 
 PG_MODULE_MAGIC;
 
 /*
  * Taken from the intarray contrib header
  */
 #define ARRPTR(x)  ( (double *) ARR_DATA_PTR(x) )
 #define ARRNELEMS(x)  ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x))
diff --git a/contrib/cube/cubeparse.y b/contrib/cube/cubeparse.y
index 1b65fa967c..deb2efdc0d 100644
--- a/contrib/cube/cubeparse.y
+++ b/contrib/cube/cubeparse.y
@@ -1,20 +1,20 @@
 %{
 /* contrib/cube/cubeparse.y */
 
 /* NdBox = [(lowerleft),(upperright)] */
 /* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */
 
 #include "postgres.h"
 
 #include "cubedata.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 
 /* All grammar constructs return strings */
 #define YYSTYPE char *
 
 /*
  * Bison doesn't allocate anything that needs to live across parser calls,
  * so we can easily have it use palloc instead of malloc.  This prevents
  * memory leaks if we error out during parsing.  Note this only works with
  * bison >= 2.0.  However, in bison 1.875 the default is to use alloca()
  * if possible, so there's not really much problem anyhow, at least if
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index fb65e2eb20..33bf0fe142 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -28,20 +28,21 @@
 #include "optimizer/cost.h"
 #include "optimizer/clauses.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
 #include "optimizer/planmain.h"
 #include "optimizer/restrictinfo.h"
 #include "optimizer/var.h"
 #include "optimizer/tlist.h"
 #include "parser/parsetree.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 #include "utils/sampling.h"
 #include "utils/selfuncs.h"
 
 PG_MODULE_MAGIC;
 
 /* Default CPU cost to start up a foreign query. */
diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c
index 06dac0bb53..56dca026ee 100644
--- a/src/backend/access/gist/gistget.c
+++ b/src/backend/access/gist/gistget.c
@@ -13,21 +13,21 @@
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/gist_private.h"
 #include "access/relscan.h"
 #include "catalog/pg_type.h"
 #include "miscadmin.h"
 #include "pgstat.h"
 #include "lib/pairingheap.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 
 /*
  * gistkillitems() -- set LP_DEAD state for items an indexscan caller has
  * told us were killed.
  *
  * We re-read page here, so it's important to check page LSN. If the page
  * has been modified since the last read (as determined by LSN), we cannot
  * flag any entries because it is possible that the old entry was vacuumed
diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index d1919fc74b..13524b4da0 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -27,62 +27,53 @@
 
 
 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
 						 StrategyNumber strategy);
 static bool rtree_internal_consistent(BOX *key, BOX *query,
 						  StrategyNumber strategy);
 
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
 
-/* Convenience macros for NaN-aware comparisons */
-#define FLOAT8_EQ(a,b)	(float8_cmp_internal(a, b) == 0)
-#define FLOAT8_LT(a,b)	(float8_cmp_internal(a, b) < 0)
-#define FLOAT8_LE(a,b)	(float8_cmp_internal(a, b) <= 0)
-#define FLOAT8_GT(a,b)	(float8_cmp_internal(a, b) > 0)
-#define FLOAT8_GE(a,b)	(float8_cmp_internal(a, b) >= 0)
-#define FLOAT8_MAX(a,b)  (FLOAT8_GT(a, b) ? (a) : (b))
-#define FLOAT8_MIN(a,b)  (FLOAT8_LT(a, b) ? (a) : (b))
-
 
 /**************************************************
  * Box ops
  **************************************************/
 
 /*
  * Calculates union of two boxes, a and b. The result is stored in *n.
  */
 static void
 rt_box_union(BOX *n, const BOX *a, const BOX *b)
 {
-	n->high.x = FLOAT8_MAX(a->high.x, b->high.x);
-	n->high.y = FLOAT8_MAX(a->high.y, b->high.y);
-	n->low.x = FLOAT8_MIN(a->low.x, b->low.x);
-	n->low.y = FLOAT8_MIN(a->low.y, b->low.y);
+	n->high.x = float8_max(a->high.x, b->high.x);
+	n->high.y = float8_max(a->high.y, b->high.y);
+	n->low.x = float8_min(a->low.x, b->low.x);
+	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
 static double
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
-	if (FLOAT8_LE(box->high.x, box->low.x) ||
-		FLOAT8_LE(box->high.y, box->low.y))
+	if (float8_le(box->high.x, box->low.x) ||
+		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
 	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
@@ -137,27 +128,27 @@ gist_box_consistent(PG_FUNCTION_ARGS)
 												 query,
 												 strategy));
 }
 
 /*
  * Increase BOX b to include addon.
  */
 static void
 adjustBox(BOX *b, const BOX *addon)
 {
-	if (FLOAT8_LT(b->high.x, addon->high.x))
+	if (float8_lt(b->high.x, addon->high.x))
 		b->high.x = addon->high.x;
-	if (FLOAT8_GT(b->low.x, addon->low.x))
+	if (float8_gt(b->low.x, addon->low.x))
 		b->low.x = addon->low.x;
-	if (FLOAT8_LT(b->high.y, addon->high.y))
+	if (float8_lt(b->high.y, addon->high.y))
 		b->high.y = addon->high.y;
-	if (FLOAT8_GT(b->low.y, addon->low.y))
+	if (float8_gt(b->low.y, addon->low.y))
 		b->low.y = addon->low.y;
 }
 
 /*
  * The GiST Union method for boxes
  *
  * returns the minimal bounding box that encloses all the entries in entryvec
  */
 Datum
 gist_box_union(PG_FUNCTION_ARGS)
@@ -609,36 +600,36 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		i1 = 0;
 		i2 = 0;
 		rightLower = intervalsLower[i1].lower;
 		leftUpper = intervalsUpper[i2].lower;
 		while (true)
 		{
 			/*
 			 * Find next lower bound of right group.
 			 */
 			while (i1 < nentries &&
-				   FLOAT8_EQ(rightLower, intervalsLower[i1].lower))
+				   float8_eq(rightLower, intervalsLower[i1].lower))
 			{
-				if (FLOAT8_LT(leftUpper, intervalsLower[i1].upper))
+				if (float8_lt(leftUpper, intervalsLower[i1].upper))
 					leftUpper = intervalsLower[i1].upper;
 				i1++;
 			}
 			if (i1 >= nentries)
 				break;
 			rightLower = intervalsLower[i1].lower;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * left group.
 			 */
 			while (i2 < nentries &&
-				   FLOAT8_LE(intervalsUpper[i2].upper, leftUpper))
+				   float8_le(intervalsUpper[i2].upper, leftUpper))
 				i2++;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim, rightLower, i1, leftUpper, i2);
 		}
 
 		/*
 		 * Iterate over upper bound of left group finding greatest possible
@@ -646,35 +637,35 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		 */
 		i1 = nentries - 1;
 		i2 = nentries - 1;
 		rightLower = intervalsLower[i1].upper;
 		leftUpper = intervalsUpper[i2].upper;
 		while (true)
 		{
 			/*
 			 * Find next upper bound of left group.
 			 */
-			while (i2 >= 0 && FLOAT8_EQ(leftUpper, intervalsUpper[i2].upper))
+			while (i2 >= 0 && float8_eq(leftUpper, intervalsUpper[i2].upper))
 			{
-				if (FLOAT8_GT(rightLower, intervalsUpper[i2].lower))
+				if (float8_gt(rightLower, intervalsUpper[i2].lower))
 					rightLower = intervalsUpper[i2].lower;
 				i2--;
 			}
 			if (i2 < 0)
 				break;
 			leftUpper = intervalsUpper[i2].upper;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * right group.
 			 */
-			while (i1 >= 0 && FLOAT8_GE(intervalsLower[i1].lower, rightLower))
+			while (i1 >= 0 && float8_ge(intervalsLower[i1].lower, rightLower))
 				i1--;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim,
 								 rightLower, i1 + 1, leftUpper, i2 + 1);
 		}
 	}
 
@@ -748,42 +739,42 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
 		}
 		else
 		{
 			lower = box->low.y;
 			upper = box->high.y;
 		}
 
-		if (FLOAT8_LE(upper, context.leftUpper))
+		if (float8_le(upper, context.leftUpper))
 		{
 			/* Fits to the left group */
-			if (FLOAT8_GE(lower, context.rightLower))
+			if (float8_ge(lower, context.rightLower))
 			{
 				/* Fits also to the right group, so "common entry" */
 				commonEntries[commonEntriesCount++].index = i;
 			}
 			else
 			{
 				/* Doesn't fit to the right group, so join to the left group */
 				PLACE_LEFT(box, i);
 			}
 		}
 		else
 		{
 			/*
 			 * Each entry should fit on either left or right group. Since this
 			 * entry didn't fit on the left group, it better fit in the right
 			 * group.
 			 */
-			Assert(FLOAT8_GE(lower, context.rightLower));
+			Assert(float8_ge(lower, context.rightLower));
 
 			/* Doesn't fit to the left group, so join to the right group */
 			PLACE_RIGHT(box, i);
 		}
 	}
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
@@ -853,24 +844,24 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
  * equivalent to box_same().
  */
 Datum
 gist_box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *b1 = PG_GETARG_BOX_P(0);
 	BOX		   *b2 = PG_GETARG_BOX_P(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
 	if (b1 && b2)
-		*result = (FLOAT8_EQ(b1->low.x, b2->low.x) &&
-				   FLOAT8_EQ(b1->low.y, b2->low.y) &&
-				   FLOAT8_EQ(b1->high.x, b2->high.x) &&
-				   FLOAT8_EQ(b1->high.y, b2->high.y));
+		*result = (float8_eq(b1->low.x, b2->low.x) &&
+				   float8_eq(b1->low.y, b2->low.y) &&
+				   float8_eq(b1->high.x, b2->high.x) &&
+				   float8_eq(b1->high.y, b2->high.y));
 	else
 		*result = (b1 == NULL && b2 == NULL);
 	PG_RETURN_POINTER(result);
 }
 
 /*
  * Leaf-level consistency for boxes: just apply the query operator
  */
 static bool
 gist_box_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy)
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 26d89f79ae..6a08756988 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -15,21 +15,21 @@
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist_private.h"
 #include "access/htup_details.h"
 #include "access/reloptions.h"
 #include "catalog/pg_opclass.h"
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/syscache.h"
 
 
 /*
  * Write itup vector to page, has no control of free space.
  */
 void
 gistfillbuffer(Page page, IndexTuple *itup, int len, OffsetNumber off)
 {
 	OffsetNumber l = InvalidOffsetNumber;
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index 18b3b949ac..dfd82bb80e 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -15,62 +15,29 @@
 #include "postgres.h"
 
 #include <ctype.h>
 #include <float.h>
 #include <math.h>
 #include <limits.h>
 
 #include "catalog/pg_type.h"
 #include "libpq/pqformat.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/sortsupport.h"
 
 
-#ifndef M_PI
-/* from my RH5.2 gcc math.h file - thomas 2000-04-03 */
-#define M_PI 3.14159265358979323846
-#endif
-
-/* Radians per degree, a.k.a. PI / 180 */
-#define RADIANS_PER_DEGREE 0.0174532925199432957692
-
-/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0.  NAN definition from
- * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfNotNumberNANItems.asp
- */
-#if defined(WIN32) && !defined(NAN)
-static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
-
-#define NAN (*(const double *) nan)
-#endif
-
 /* not sure what the following should be, but better to make it over-sufficient */
 #define MAXFLOATWIDTH	64
 #define MAXDOUBLEWIDTH	128
 
-/*
- * check to see if a float4/8 val has underflowed or overflowed
- */
-#define CHECKFLOATVAL(val, inf_is_valid, zero_is_valid)			\
-do {															\
-	if (isinf(val) && !(inf_is_valid))							\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		  errmsg("value out of range: overflow")));				\
-																\
-	if ((val) == 0.0 && !(zero_is_valid))						\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		 errmsg("value out of range: underflow")));				\
-} while(0)
-
-
 /* Configurable GUC parameter */
 int			extra_float_digits = 0; /* Added to DBL_DIG or FLT_DIG */
 
 /* Cached constants for degree-based trig functions */
 static bool degree_consts_set = false;
 static float8 sin_30 = 0;
 static float8 one_minus_cos_60 = 0;
 static float8 asin_0_5 = 0;
 static float8 acos_0_5 = 0;
 static float8 atan_1_0 = 0;
@@ -102,100 +69,20 @@ static void init_degree_constants(void);
  * their compilers spit up at the mismatch between extern declaration
  * and static definition.  We work around that here by the expedient
  * of a #define to make the actual name of the static function different.
  */
 #define cbrt my_cbrt
 static double cbrt(double x);
 #endif							/* HAVE_CBRT */
 
 
 /*
- * Routines to provide reasonably platform-independent handling of
- * infinity and NaN.  We assume that isinf() and isnan() are available
- * and work per spec.  (On some platforms, we have to supply our own;
- * see src/port.)  However, generating an Infinity or NaN in the first
- * place is less well standardized; pre-C99 systems tend not to have C99's
- * INFINITY and NAN macros.  We centralize our workarounds for this here.
- */
-
-double
-get_float8_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (double) INFINITY;
-#else
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (double) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-/*
-* The funny placements of the two #pragmas is necessary because of a
-* long lived bug in the Microsoft compilers.
-* See http://support.microsoft.com/kb/120968/en-us for details
-*/
-#if (_MSC_VER >= 1800)
-#pragma warning(disable:4756)
-#endif
-float
-get_float4_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (float) INFINITY;
-#else
-#if (_MSC_VER >= 1800)
-#pragma warning(default:4756)
-#endif
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (float) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-double
-get_float8_nan(void)
-{
-	/* (double) NAN doesn't work on some NetBSD/MIPS releases */
-#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
-	/* C99 standard way */
-	return (double) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (double) (0.0 / 0.0);
-#endif
-}
-
-float
-get_float4_nan(void)
-{
-#ifdef NAN
-	/* C99 standard way */
-	return (float) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (float) (0.0 / 0.0);
-#endif
-}
-
-
-/*
  * Returns -1 if 'val' represents negative infinity, 1 if 'val'
  * represents (positive) infinity, and 0 otherwise. On some platforms,
  * this is equivalent to the isinf() macro, but not everywhere: C99
  * does not specify that isinf() needs to distinguish between positive
  * and negative infinity.
  */
 int
 is_infinite(double val)
 {
 	int			inf = isinf(val);
@@ -339,21 +226,21 @@ float4in(PG_FUNCTION_ARGS)
 	if (*endptr != '\0')
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"real", orig_num)));
 
 	/*
 	 * if we get here, we have a legal double, still need to check to see if
 	 * it's a legal float4
 	 */
-	CHECKFLOATVAL((float4) val, isinf(val), val == 0);
+	check_float4_val((float4) val, isinf(val), val == 0);
 
 	PG_RETURN_FLOAT4((float4) val);
 }
 
 /*
  *		float4out		- converts a float4 number to a string
  *						  using a standard output format
  */
 Datum
 float4out(PG_FUNCTION_ARGS)
@@ -689,35 +576,35 @@ float4up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT4(arg);
 }
 
 Datum
 float4larger(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) > 0)
+	if (float4_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 Datum
 float4smaller(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) < 0)
+	if (float4_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 /*
  *		======================
  *		FLOAT8 BASE OPERATIONS
  *		======================
@@ -756,35 +643,35 @@ float8up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT8(arg);
 }
 
 Datum
 float8larger(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) > 0)
+	if (float8_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 Datum
 float8smaller(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) < 0)
+	if (float8_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		====================
  *		ARITHMETIC OPERATORS
@@ -795,234 +682,165 @@ float8smaller(PG_FUNCTION_ARGS)
  *		float4pl		- returns arg1 + arg2
  *		float4mi		- returns arg1 - arg2
  *		float4mul		- returns arg1 * arg2
  *		float4div		- returns arg1 / arg2
  */
 Datum
 float4pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 + arg2;
-
-	/*
-	 * There isn't any way to check for underflow of addition/subtraction
-	 * because numbers near the underflow value have already been rounded to
-	 * the point where we can't detect that the two values were originally
-	 * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
-	 * 1.4013e-45.
-	 */
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_pl(arg1, arg2));
 }
 
 Datum
 float4mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mi(arg1, arg2));
 }
 
 Datum
 float4mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mul(arg1, arg2));
 }
 
 Datum
 float4div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_div(arg1, arg2));
 }
 
 /*
  *		float8pl		- returns arg1 + arg2
  *		float8mi		- returns arg1 - arg2
  *		float8mul		- returns arg1 * arg2
  *		float8div		- returns arg1 / arg2
  */
 Datum
 float8pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 + arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, arg2));
 }
 
 Datum
 float8mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 - arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, arg2));
 }
 
 Datum
 float8mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 * arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, arg2));
 }
 
 Datum
 float8div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, arg2));
 }
 
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float4{eq,ne,lt,le,gt,ge}		- float4/float4 comparison operations
  */
 int
 float4_cmp_internal(float4 a, float4 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float4_gt(a, b))
+		return 1;
+	if (float4_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
 float4eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float4_eq(arg1, arg2));
 }
 
 Datum
 float4ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float4_ne(arg1, arg2));
 }
 
 Datum
 float4lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float4_lt(arg1, arg2));
 }
 
 Datum
 float4le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float4_le(arg1, arg2));
 }
 
 Datum
 float4gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float4_gt(arg1, arg2));
 }
 
 Datum
 float4ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float4_ge(arg1, arg2));
 }
 
 Datum
 btfloat4cmp(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
 	PG_RETURN_INT32(float4_cmp_internal(arg1, arg2));
 }
@@ -1044,99 +862,79 @@ btfloat4sortsupport(PG_FUNCTION_ARGS)
 	ssup->comparator = btfloat4fastcmp;
 	PG_RETURN_VOID();
 }
 
 /*
  *		float8{eq,ne,lt,le,gt,ge}		- float8/float8 comparison operations
  */
 int
 float8_cmp_internal(float8 a, float8 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float8_gt(a, b))
+		return 1;
+	if (float8_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
 float8eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, arg2));
 }
 
 Datum
 float8ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, arg2));
 }
 
 Datum
 float8lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, arg2));
 }
 
 Datum
 float8le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, arg2));
 }
 
 Datum
 float8gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, arg2));
 }
 
 Datum
 float8ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, arg2));
 }
 
 Datum
 btfloat8cmp(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
 	PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
 }
@@ -1199,21 +997,21 @@ ftod(PG_FUNCTION_ARGS)
 
 
 /*
  *		dtof			- converts a float8 number to a float4 number
  */
 Datum
 dtof(PG_FUNCTION_ARGS)
 {
 	float8		num = PG_GETARG_FLOAT8(0);
 
-	CHECKFLOATVAL((float4) num, isinf(num), num == 0);
+	check_float4_val((float4) num, isinf(num), num == 0);
 
 	PG_RETURN_FLOAT4((float4) num);
 }
 
 
 /*
  *		dtoi4			- converts a float8 number to an int4 number
  */
 Datum
 dtoi4(PG_FUNCTION_ARGS)
@@ -1424,36 +1222,36 @@ dsqrt(PG_FUNCTION_ARGS)
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
 				 errmsg("cannot take square root of a negative number")));
 
 	result = sqrt(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcbrt			- returns cube root of arg1
  */
 Datum
 dcbrt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	result = cbrt(arg1);
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dpow			- returns pow(arg1,arg2)
  */
 Datum
 dpow(PG_FUNCTION_ARGS)
 {
@@ -1492,40 +1290,40 @@ dpow(PG_FUNCTION_ARGS)
 			/* The sign of Inf is not significant in this case. */
 			result = get_float8_infinity();
 		else if (fabs(arg1) != 1)
 			result = 0;
 		else
 			result = 1;
 	}
 	else if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
+	check_float8_val(result, isinf(arg1) || isinf(arg2), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dexp			- returns the exponential function of arg1
  */
 Datum
 dexp(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	errno = 0;
 	result = exp(arg1);
 	if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1), false);
+	check_float8_val(result, isinf(arg1), false);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dlog1			- returns the natural logarithm of arg1
  */
 Datum
 dlog1(PG_FUNCTION_ARGS)
 {
@@ -1540,21 +1338,21 @@ dlog1(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of zero")));
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of a negative number")));
 
 	result = log(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dlog10			- returns the base 10 logarithm of arg1
  */
 Datum
 dlog10(PG_FUNCTION_ARGS)
 {
@@ -1570,21 +1368,21 @@ dlog10(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of zero")));
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of a negative number")));
 
 	result = log10(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dacos			- returns the arccos of arg1 (radians)
  */
 Datum
 dacos(PG_FUNCTION_ARGS)
 {
@@ -1600,21 +1398,21 @@ dacos(PG_FUNCTION_ARGS)
 	 * range [-1, 1] to values in the range [0, Pi], so we should reject any
 	 * inputs outside that range and the result will always be finite.
 	 */
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = acos(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dasin			- returns the arcsin of arg1 (radians)
  */
 Datum
 dasin(PG_FUNCTION_ARGS)
 {
@@ -1630,21 +1428,21 @@ dasin(PG_FUNCTION_ARGS)
 	 * range [-1, 1] to values in the range [-Pi/2, Pi/2], so we should reject
 	 * any inputs outside that range and the result will always be finite.
 	 */
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = asin(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		datan			- returns the arctan of arg1 (radians)
  */
 Datum
 datan(PG_FUNCTION_ARGS)
 {
@@ -1655,21 +1453,21 @@ datan(PG_FUNCTION_ARGS)
 	if (isnan(arg1))
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/*
 	 * The principal branch of the inverse tangent function maps all inputs to
 	 * values in the range [-Pi/2, Pi/2], so the result should always be
 	 * finite, even if the input is infinite.
 	 */
 	result = atan(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		atan2			- returns the arctan of arg1/arg2 (radians)
  */
 Datum
 datan2(PG_FUNCTION_ARGS)
 {
@@ -1680,21 +1478,21 @@ datan2(PG_FUNCTION_ARGS)
 	/* Per the POSIX spec, return NaN if either input is NaN */
 	if (isnan(arg1) || isnan(arg2))
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/*
 	 * atan2 maps all inputs to values in the range [-Pi, Pi], so the result
 	 * should always be finite, even if the inputs are infinite.
 	 */
 	result = atan2(arg1, arg2);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcos			- returns the cosine of arg1 (radians)
  */
 Datum
 dcos(PG_FUNCTION_ARGS)
 {
@@ -1720,21 +1518,21 @@ dcos(PG_FUNCTION_ARGS)
 	 * platform reports via errno, so also explicitly test for infinite
 	 * inputs.
 	 */
 	errno = 0;
 	result = cos(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcot			- returns the cotangent of arg1 (radians)
  */
 Datum
 dcot(PG_FUNCTION_ARGS)
 {
@@ -1747,21 +1545,21 @@ dcot(PG_FUNCTION_ARGS)
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = tan(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = 1.0 / result;
-	CHECKFLOATVAL(result, true /* cot(0) == Inf */ , true);
+	check_float8_val(result, true /* cot(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dsin			- returns the sine of arg1 (radians)
  */
 Datum
 dsin(PG_FUNCTION_ARGS)
 {
@@ -1773,21 +1571,21 @@ dsin(PG_FUNCTION_ARGS)
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = sin(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dtan			- returns the tangent of arg1 (radians)
  */
 Datum
 dtan(PG_FUNCTION_ARGS)
 {
@@ -1799,21 +1597,21 @@ dtan(PG_FUNCTION_ARGS)
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = tan(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, true /* tan(pi/2) == Inf */ , true);
+	check_float8_val(result, true /* tan(pi/2) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /* ========== DEGREE-BASED TRIGONOMETRIC FUNCTIONS ========== */
 
 
 /*
  * Initialize the cached constants declared at the head of this file
  * (sin_30 etc).  The fact that we need those at all, let alone need this
@@ -1951,21 +1749,21 @@ dacosd(PG_FUNCTION_ARGS)
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	if (arg1 >= 0.0)
 		result = acosd_q1(arg1);
 	else
 		result = 90.0 + asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dasind			- returns the arcsin of arg1 (degrees)
  */
 Datum
 dasind(PG_FUNCTION_ARGS)
 {
@@ -1986,21 +1784,21 @@ dasind(PG_FUNCTION_ARGS)
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	if (arg1 >= 0.0)
 		result = asind_q1(arg1);
 	else
 		result = -asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		datand			- returns the arctan of arg1 (degrees)
  */
 Datum
 datand(PG_FUNCTION_ARGS)
 {
@@ -2016,21 +1814,21 @@ datand(PG_FUNCTION_ARGS)
 
 	/*
 	 * The principal branch of the inverse tangent function maps all inputs to
 	 * values in the range [-90, 90], so the result should always be finite,
 	 * even if the input is infinite.  Additionally, we take care to ensure
 	 * than when arg1 is 1, the result is exactly 45.
 	 */
 	atan_arg1 = atan(arg1);
 	result = (atan_arg1 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		atan2d			- returns the arctan of arg1/arg2 (degrees)
  */
 Datum
 datan2d(PG_FUNCTION_ARGS)
 {
@@ -2050,21 +1848,21 @@ datan2d(PG_FUNCTION_ARGS)
 	 * result should always be finite, even if the inputs are infinite.
 	 *
 	 * Note: this coding assumes that atan(1.0) is a suitable scaling constant
 	 * to get an exact result from atan2().  This might well fail on us at
 	 * some point, requiring us to decide exactly what inputs we think we're
 	 * going to guarantee an exact result for.
 	 */
 	atan2_arg1_arg2 = atan2(arg1, arg2);
 	result = (atan2_arg1_arg2 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		sind_0_to_30	- returns the sine of an angle that lies between 0 and
  *						  30 degrees.  This will return exactly 0 when x is 0,
  *						  and exactly 0.5 when x is 30 degrees.
  */
 static double
@@ -2171,21 +1969,21 @@ dcosd(PG_FUNCTION_ARGS)
 
 	if (arg1 > 90.0)
 	{
 		/* cosd(180-x) = -cosd(x) */
 		arg1 = 180.0 - arg1;
 		sign = -sign;
 	}
 
 	result = sign * cosd_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcotd			- returns the cotangent of arg1 (degrees)
  */
 Datum
 dcotd(PG_FUNCTION_ARGS)
 {
@@ -2236,21 +2034,21 @@ dcotd(PG_FUNCTION_ARGS)
 	result = sign * (cot_arg1 / cot_45);
 
 	/*
 	 * On some machines we get cotd(270) = minus zero, but this isn't always
 	 * true.  For portability, and because the user constituency for this
 	 * function probably doesn't want minus zero, force it to plain zero.
 	 */
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* cotd(0) == Inf */ , true);
+	check_float8_val(result, true /* cotd(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dsind			- returns the sine of arg1 (degrees)
  */
 Datum
 dsind(PG_FUNCTION_ARGS)
 {
@@ -2290,21 +2088,21 @@ dsind(PG_FUNCTION_ARGS)
 	}
 
 	if (arg1 > 90.0)
 	{
 		/* sind(180-x) = sind(x) */
 		arg1 = 180.0 - arg1;
 	}
 
 	result = sign * sind_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dtand			- returns the tangent of arg1 (degrees)
  */
 Datum
 dtand(PG_FUNCTION_ARGS)
 {
@@ -2355,64 +2153,56 @@ dtand(PG_FUNCTION_ARGS)
 	result = sign * (tan_arg1 / tan_45);
 
 	/*
 	 * On some machines we get tand(180) = minus zero, but this isn't always
 	 * true.  For portability, and because the user constituency for this
 	 * function probably doesn't want minus zero, force it to plain zero.
 	 */
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* tand(90) == Inf */ , true);
+	check_float8_val(result, true /* tand(90) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		degrees		- returns degrees converted from radians
  */
 Datum
 degrees(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
 
-	result = arg1 / RADIANS_PER_DEGREE;
-
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, RADIANS_PER_DEGREE));
 }
 
 
 /*
  *		dpi				- returns the constant PI
  */
 Datum
 dpi(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_FLOAT8(M_PI);
 }
 
 
 /*
  *		radians		- returns radians converted from degrees
  */
 Datum
 radians(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
 
-	result = arg1 * RADIANS_PER_DEGREE;
-
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, RADIANS_PER_DEGREE));
 }
 
 
 /*
  *		drandom		- returns a random number
  */
 Datum
 drandom(PG_FUNCTION_ARGS)
 {
 	float8		result;
@@ -2490,144 +2280,105 @@ check_float8_array(ArrayType *transarray, const char *caller, int n)
  * This function is used only in two stage aggregation and
  * shouldn't be called outside aggregate context.
  */
 Datum
 float8_combine(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_combine", 3);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-
 	transvalues2 = check_float8_array(transarray2, "float8_combine", 3);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
 
 Datum
 float8_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8		newval = PG_GETARG_FLOAT8(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float8_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
 	else
 	{
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
 								 sizeof(float8), FLOAT8PASSBYVAL, 'd');
 
 		PG_RETURN_ARRAYTYPE_P(result);
 	}
 }
 
 Datum
 float4_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 
 	/* do computations as float8 */
 	float8		newval = PG_GETARG_FLOAT4(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float4_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
 	else
 	{
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
 								 sizeof(float8), FLOAT8PASSBYVAL, 'd');
 
 		PG_RETURN_ARRAYTYPE_P(result);
 	}
 }
 
 Datum
@@ -2663,21 +2414,21 @@ float8_var_pop(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_var_pop", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Population variance is undefined when N is 0, so return NULL */
 	if (N == 0.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / (N * N));
 }
 
 Datum
 float8_var_samp(PG_FUNCTION_ARGS)
@@ -2692,21 +2443,21 @@ float8_var_samp(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_var_samp", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Sample variance is undefined when N is 0 or 1, so return NULL */
 	if (N <= 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
 }
 
 Datum
 float8_stddev_pop(PG_FUNCTION_ARGS)
@@ -2721,21 +2472,21 @@ float8_stddev_pop(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_stddev_pop", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Population stddev is undefined when N is 0, so return NULL */
 	if (N == 0.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(sqrt(numerator / (N * N)));
 }
 
 Datum
 float8_stddev_samp(PG_FUNCTION_ARGS)
@@ -2750,21 +2501,21 @@ float8_stddev_samp(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_stddev_samp", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Sample stddev is undefined when N is 0 or 1, so return NULL */
 	if (N <= 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(sqrt(numerator / (N * (N - 1.0))));
 }
 
 /*
  *		=========================
@@ -2799,30 +2550,30 @@ float8_regr_accum(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_accum", 6);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	N += 1.0;
 	sumX += newvalX;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
+	check_float8_val(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
 	sumX2 += newvalX * newvalX;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
+	check_float8_val(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
 	sumY += newvalY;
-	CHECKFLOATVAL(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
+	check_float8_val(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
 	sumY2 += newvalY * newvalY;
-	CHECKFLOATVAL(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
+	check_float8_val(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
 	sumXY += newvalX * newvalY;
-	CHECKFLOATVAL(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
-				  isinf(newvalY), true);
+	check_float8_val(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
+					 isinf(newvalY), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
 		transvalues[0] = N;
 		transvalues[1] = sumX;
@@ -2861,63 +2612,33 @@ float8_regr_accum(PG_FUNCTION_ARGS)
  * This function is used only in two stage aggregation and
  * shouldn't be called outside aggregate context.
  */
 Datum
 float8_regr_combine(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2,
-				sumY,
-				sumY2,
-				sumXY;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_regr_combine", 6);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-	sumY = transvalues1[3];
-	sumY2 = transvalues1[4];
-	sumXY = transvalues1[5];
-
 	transvalues2 = check_float8_array(transarray2, "float8_regr_combine", 6);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-	sumY += transvalues2[3];
-	CHECKFLOATVAL(sumY, isinf(transvalues1[3]) || isinf(transvalues2[3]),
-				  true);
-	sumY2 += transvalues2[4];
-	CHECKFLOATVAL(sumY2, isinf(transvalues1[4]) || isinf(transvalues2[4]),
-				  true);
-	sumXY += transvalues2[5];
-	CHECKFLOATVAL(sumXY, isinf(transvalues1[5]) || isinf(transvalues2[5]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
-	transvalues1[3] = sumY;
-	transvalues1[4] = sumY2;
-	transvalues1[5] = sumXY;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
+	transvalues1[3] = float8_pl(transvalues1[3], transvalues2[3]);
+	transvalues1[4] = float8_pl(transvalues1[4], transvalues2[4]);
+	transvalues1[5] = float8_pl(transvalues1[5], transvalues2[5]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
 
 
 Datum
 float8_regr_sxx(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
@@ -2929,21 +2650,21 @@ float8_regr_sxx(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_sxx", 6);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_syy(PG_FUNCTION_ARGS)
@@ -2958,21 +2679,21 @@ float8_regr_syy(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_syy", 6);
 	N = transvalues[0];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumY2) || isinf(sumY), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_sxy(PG_FUNCTION_ARGS)
@@ -2989,22 +2710,22 @@ float8_regr_sxy(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	/* A negative result is valid here */
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_avgx(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3057,22 +2778,22 @@ float8_covar_pop(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * N));
 }
 
 Datum
 float8_covar_samp(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
 	float8		N,
@@ -3085,22 +2806,22 @@ float8_covar_samp(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is <= 1 we should return NULL */
 	if (N < 2.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
 }
 
 Datum
 float8_corr(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
 	float8		N,
@@ -3119,26 +2840,26 @@ float8_corr(PG_FUNCTION_ARGS)
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0 || numeratorY <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXY / sqrt(numeratorX * numeratorY));
 }
 
 Datum
 float8_regr_r2(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3159,26 +2880,26 @@ float8_regr_r2(PG_FUNCTION_ARGS)
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 	/* per spec, horizontal line produces 1.0 */
 	if (numeratorY <= 0)
 		PG_RETURN_FLOAT8(1.0);
 
 	PG_RETURN_FLOAT8((numeratorXY * numeratorXY) /
 					 (numeratorX * numeratorY));
 }
 
@@ -3200,24 +2921,24 @@ float8_regr_slope(PG_FUNCTION_ARGS)
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXY / numeratorX);
 }
 
 Datum
 float8_regr_intercept(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3235,24 +2956,24 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXXY = sumY * sumX2 - sumX * sumXY;
-	CHECKFLOATVAL(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
-				  isinf(sumX) || isinf(sumXY), true);
+	check_float8_val(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
+					 isinf(sumX) || isinf(sumXY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXXY / numeratorX);
 }
 
 
 /*
  *		====================================
  *		MIXED-PRECISION ARITHMETIC OPERATORS
@@ -3263,251 +2984,211 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
  *		float48pl		- returns arg1 + arg2
  *		float48mi		- returns arg1 - arg2
  *		float48mul		- returns arg1 * arg2
  *		float48div		- returns arg1 / arg2
  */
 Datum
 float48pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 + arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl((float8) arg1, arg2));
 }
 
 Datum
 float48mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi((float8) arg1, arg2));
 }
 
 Datum
 float48mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul((float8) arg1, arg2));
 }
 
 Datum
 float48div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div((float8) arg1, arg2));
 }
 
 /*
  *		float84pl		- returns arg1 + arg2
  *		float84mi		- returns arg1 - arg2
  *		float84mul		- returns arg1 * arg2
  *		float84div		- returns arg1 / arg2
  */
 Datum
 float84pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 + arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, (float8) arg2));
 }
 
 Datum
 float84mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 - arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, (float8) arg2));
 }
 
 Datum
 float84mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 * arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, (float8) arg2));
 }
 
 Datum
 float84div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, (float8) arg2));
 }
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float48{eq,ne,lt,le,gt,ge}		- float4/float8 comparison operations
  */
 Datum
 float48eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq((float8) arg1, arg2));
 }
 
 Datum
 float48ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne((float8) arg1, arg2));
 }
 
 Datum
 float48lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt((float8) arg1, arg2));
 }
 
 Datum
 float48le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le((float8) arg1, arg2));
 }
 
 Datum
 float48gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt((float8) arg1, arg2));
 }
 
 Datum
 float48ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge((float8) arg1, arg2));
 }
 
 /*
  *		float84{eq,ne,lt,le,gt,ge}		- float8/float4 comparison operations
  */
 Datum
 float84eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, (float8) arg2));
 }
 
 Datum
 float84ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, (float8) arg2));
 }
 
 Datum
 float84lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, (float8) arg2));
 }
 
 Datum
 float84le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, (float8) arg2));
 }
 
 Datum
 float84gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, (float8) arg2));
 }
 
 Datum
 float84ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, (float8) arg2));
 }
 
 /*
  * Implements the float8 version of the width_bucket() function
  * defined by SQL2003. See also width_bucket_numeric().
  *
  * 'bound1' and 'bound2' are the lower and upper bounds of the
  * histogram's range, respectively. 'count' is the number of buckets
  * in the histogram. width_bucket() returns an integer indicating the
  * bucket number that 'operand' belongs to in an equiwidth histogram
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c
index 7877af2d6b..4cb5aba044 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -84,20 +84,21 @@
 
 #ifdef USE_ICU
 #include <unicode/ustring.h>
 #endif
 
 #include "catalog/pg_collation.h"
 #include "mb/pg_wchar.h"
 #include "utils/builtins.h"
 #include "utils/date.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 #include "utils/formatting.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/pg_locale.h"
 
 /* ----------
  * Routines type
  * ----------
  */
 #define DCH_TYPE		1		/* DATE-TIME version	*/
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 8655fad4e3..d16dc350cf 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -14,27 +14,23 @@
  */
 #include "postgres.h"
 
 #include <math.h>
 #include <limits.h>
 #include <float.h>
 #include <ctype.h>
 
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
-#include "utils/builtins.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index f6334bae14..c800bb1338 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -69,21 +69,21 @@
  *			src/backend/utils/adt/geo_spgist.c
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
 
 #include "access/spgist.h"
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
  * is going only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 2cd14f3401..b456f4b704 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -28,20 +28,21 @@
 
 #include "access/hash.h"
 #include "catalog/pg_type.h"
 #include "funcapi.h"
 #include "lib/hyperloglog.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/sortsupport.h"
 
 /* ----------
  * Uncomment the following to enable compilation of dump_numeric()
  * and dump_var() and to get a dump of any result produced by make_result().
  * ----------
 #define NUMERIC_DEBUG
diff --git a/src/backend/utils/adt/rangetypes_gist.c b/src/backend/utils/adt/rangetypes_gist.c
index 29fa1ae325..d8c1525acc 100644
--- a/src/backend/utils/adt/rangetypes_gist.c
+++ b/src/backend/utils/adt/rangetypes_gist.c
@@ -9,21 +9,22 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_gist.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/gist.h"
 #include "access/stratnum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/datum.h"
 #include "utils/rangetypes.h"
 
 
 /*
  * Range class properties used to segregate different classes of ranges in
  * GiST.  Each unique combination of properties is a class.  CLS_EMPTY cannot
  * be combined with anything else.
  */
 #define CLS_NORMAL			0	/* Ordinary finite range (no bits set) */
diff --git a/src/backend/utils/adt/rangetypes_selfuncs.c b/src/backend/utils/adt/rangetypes_selfuncs.c
index cba8974dbe..97308aea9a 100644
--- a/src/backend/utils/adt/rangetypes_selfuncs.c
+++ b/src/backend/utils/adt/rangetypes_selfuncs.c
@@ -14,21 +14,22 @@
  *	  src/backend/utils/adt/rangetypes_selfuncs.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/htup_details.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 #include "utils/selfuncs.h"
 #include "utils/typcache.h"
 
 static double calc_rangesel(TypeCacheEntry *typcache, VariableStatData *vardata,
 			  RangeType *constval, Oid operator);
 static double default_range_selectivity(Oid operator);
 static double calc_hist_selectivity(TypeCacheEntry *typcache,
 					  VariableStatData *vardata, RangeType *constval,
diff --git a/src/backend/utils/adt/rangetypes_typanalyze.c b/src/backend/utils/adt/rangetypes_typanalyze.c
index 3efd982d1b..8a7ad4f3f7 100644
--- a/src/backend/utils/adt/rangetypes_typanalyze.c
+++ b/src/backend/utils/adt/rangetypes_typanalyze.c
@@ -19,21 +19,22 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_typanalyze.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "catalog/pg_operator.h"
 #include "commands/vacuum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 
 static int	float8_qsort_cmp(const void *a1, const void *a2);
 static int	range_bound_qsort_cmp(const void *a1, const void *a2, void *arg);
 static void compute_range_stats(VacAttrStats *stats,
 					AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows);
 
 /*
  * range_typanalyze -- typanalyze function for range columns
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 5797aaad34..74a2ef55ec 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -27,20 +27,21 @@
 #include "common/int128.h"
 #include "funcapi.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
 #include "parser/scansup.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 /*
  * gcc's -ffast-math switch breaks routines that expect exact results from
  * expressions like timeval / SECS_PER_HOUR, where timeval is double.
  */
 #ifdef __FAST_MATH__
 #error -ffast-math is known to break this code
 #endif
 
 #define SAMESIGN(a,b)	(((a) < 0) == ((b) < 0))
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 65372d7cc5..9c9e570b39 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -72,20 +72,21 @@
 #include "storage/standby.h"
 #include "storage/fd.h"
 #include "storage/pg_shmem.h"
 #include "storage/proc.h"
 #include "storage/predicate.h"
 #include "tcop/tcopprot.h"
 #include "tsearch/ts_cache.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/guc_tables.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/pg_locale.h"
 #include "utils/plancache.h"
 #include "utils/portal.h"
 #include "utils/ps_status.h"
 #include "utils/rls.h"
 #include "utils/snapmgr.h"
 #include "utils/tzparser.h"
 #include "utils/varlena.h"
 #include "utils/xml.h"
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 762532f636..668e037737 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -43,34 +43,20 @@ extern int	namestrcmp(Name name, const char *str);
 
 /* numutils.c */
 extern int32 pg_atoi(const char *s, int size, int c);
 extern void pg_itoa(int16 i, char *a);
 extern void pg_ltoa(int32 l, char *a);
 extern void pg_lltoa(int64 ll, char *a);
 extern char *pg_ltostr_zeropad(char *str, int32 value, int32 minwidth);
 extern char *pg_ltostr(char *str, int32 value);
 extern uint64 pg_strtouint64(const char *str, char **endptr, int base);
 
-/* float.c */
-extern PGDLLIMPORT int extra_float_digits;
-
-extern double get_float8_infinity(void);
-extern float get_float4_infinity(void);
-extern double get_float8_nan(void);
-extern float get_float4_nan(void);
-extern int	is_infinite(double val);
-extern double float8in_internal(char *num, char **endptr_p,
-				  const char *type_name, const char *orig_string);
-extern char *float8out_internal(double num);
-extern int	float4_cmp_internal(float4 a, float4 b);
-extern int	float8_cmp_internal(float8 a, float8 b);
-
 /* oid.c */
 extern oidvector *buildoidvector(const Oid *oids, int n);
 extern Oid	oidparse(Node *node);
 extern int	oid_cmp(const void *p1, const void *p2);
 
 /* regexp.c */
 extern char *regexp_fixed_prefix(text *text_re, bool case_insensitive,
 					Oid collation, bool *exact);
 
 /* ruleutils.c */
diff --git a/src/include/utils/float.h b/src/include/utils/float.h
new file mode 100644
index 0000000000..c9f5fd30ca
--- /dev/null
+++ b/src/include/utils/float.h
@@ -0,0 +1,376 @@
+/*-------------------------------------------------------------------------
+ *
+ * float.h
+ *	  Definitions for the built-in floating-point types
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/include/utils/float.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef FLOAT_H
+#define FLOAT_H
+
+#include <math.h>
+
+#ifndef M_PI
+/* From my RH5.2 gcc math.h file - thomas 2000-04-03 */
+#define M_PI 3.14159265358979323846
+#endif
+
+/* Radians per degree, a.k.a. PI / 180 */
+#define RADIANS_PER_DEGREE 0.0174532925199432957692
+
+/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0.  NAN definition from
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfNotNumberNANItems.asp
+ */
+#if defined(WIN32) && !defined(NAN)
+static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
+
+#define NAN (*(const float8 *) nan)
+#endif
+
+extern PGDLLIMPORT int extra_float_digits;
+
+/*
+ * Utility functions in float.c
+ */
+extern int	is_infinite(float8 val);
+extern float8 float8in_internal(char *num, char **endptr_p,
+				  const char *type_name, const char *orig_string);
+extern char *float8out_internal(float8 num);
+extern int	float4_cmp_internal(float4 a, float4 b);
+extern int	float8_cmp_internal(float8 a, float8 b);
+
+/*
+ * Routines to provide reasonably platform-independent handling of
+ * infinity and NaN
+ *
+ * We assume that isinf() and isnan() are available and work per spec.
+ * (On some platforms, we have to supply our own; see src/port.)  However,
+ * generating an Infinity or NaN in the first place is less well standardized;
+ * pre-C99 systems tend not to have C99's INFINITY and NAN macros.  We
+ * centralize our workarounds for this here.
+ */
+
+/*
+ * The funny placements of the two #pragmas is necessary because of a
+ * long lived bug in the Microsoft compilers.
+ * See http://support.microsoft.com/kb/120968/en-us for details
+ */
+#if (_MSC_VER >= 1800)
+#pragma warning(disable:4756)
+#endif
+static inline float
+get_float4_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float) INFINITY;
+#else
+#if (_MSC_VER >= 1800)
+#pragma warning(default:4756)
+#endif
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float8
+get_float8_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float8) INFINITY;
+#else
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float8) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float4
+get_float4_nan(void)
+{
+#ifdef NAN
+	/* C99 standard way */
+	return (float) NAN;
+#else
+	/* Assume we can get a NAN via zero divide */
+	return (float) (0.0 / 0.0);
+#endif
+}
+
+static inline float8
+get_float8_nan(void)
+{
+	/* (float8) NAN doesn't work on some NetBSD/MIPS releases */
+#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
+	/* C99 standard way */
+	return (float8) NAN;
+#else
+	/* Assume we can get a NAN via zero divide */
+	return (float8) (0.0 / 0.0);
+#endif
+}
+
+/*
+ * Checks to see if a float4/8 val has underflowed or overflowed
+ */
+
+static inline void
+check_float4_val(float4 val, bool inf_is_valid, bool zero_is_valid)
+{
+	if (isinf(val) && !inf_is_valid)
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if (val == 0.0 && !zero_is_valid)
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+static inline void
+check_float8_val(float8 val, bool inf_is_valid, bool zero_is_valid)
+{
+	if (isinf(val) && !inf_is_valid)
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if (val == 0.0 && !zero_is_valid)
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+/*
+ * Routines for operations with the checks above
+ *
+ * There isn't any way to check for underflow of addition/subtraction
+ * because numbers near the underflow value have already been rounded to
+ * the point where we can't detect that the two values were originally
+ * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
+ * 1.4013e-45.
+ */
+
+static inline float4
+float4_pl(float4 val1, float4 val2)
+{
+	float4		result;
+
+	result = val1 + val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_pl(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = val1 + val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mi(float4 val1, float4 val2)
+{
+	float4		result;
+
+	result = val1 - val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_mi(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = val1 - val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mul(float4 val1, float4 val2)
+{
+	float4		result;
+
+	result = val1 * val2;
+	check_float4_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0f || val2 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_mul(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = val1 * val2;
+	check_float8_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0 || val2 == 0.0);
+
+	return result;
+}
+
+static inline float4
+float4_div(float4 val1, float4 val2)
+{
+	float4		result;
+
+	if (val2 == 0.0f)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), val1 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_div(float8 val1, float8 val2)
+{
+	float8		result;
+
+	if (val2 == 0.0)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
+
+	return result;
+}
+
+/*
+ * Routines for NaN-aware comparisons
+ *
+ * We consider all NANs to be equal and larger than any non-NAN. This is
+ * somewhat arbitrary; the important thing is to have a consistent sort
+ * order.
+ */
+
+static inline bool
+float4_eq(float4 val1, float4 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float8_eq(float8 val1, float8 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float4_ne(float4 val1, float4 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float8_ne(float8 val1, float8 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float4_lt(float4 val1, float4 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float8_lt(float8 val1, float8 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float4_le(float4 val1, float4 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float8_le(float8 val1, float8 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float4_gt(float4 val1, float4 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float8_gt(float8 val1, float8 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float4_ge(float4 val1, float4 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline bool
+float8_ge(float8 val1, float8 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline float4
+float4_min(float4 val1, float4 val2)
+{
+	return float4_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_min(float8 val1, float8 val2)
+{
+	return float8_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float4
+float4_max(float4 val1, float4 val2)
+{
+	return float4_gt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_max(float8 val1, float8 val2)
+{
+	return float8_gt(val1, val2) ? val1 : val2;
+}
+
+#endif							/* FLOAT_H */
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 19ecf4e712..ea2e3690ea 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -17,20 +17,21 @@
  *		and data types. There are still some more to do. - tgl 97/04/19
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEO_DECLS_H
 #define GEO_DECLS_H
 
 #include <math.h>
 
 #include "fmgr.h"
+#include "utils/float.h"
 
 /*--------------------------------------------------------------------
  * Useful floating point utilities and constants.
  *-------------------------------------------------------------------*/
 
 
 #define EPSILON					1.0E-06
 
 #ifdef EPSILON
 #define FPzero(A)				(fabs(A) <= EPSILON)
-- 
2.13.6 (Apple Git-96)

0003-geo-float-v06.patchapplication/octet-stream; name=0003-geo-float-v06.patchDownload
From af4eb5699b44c3d1bb7fd80d77e496441e43aa0e Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 27 May 2017 16:17:42 -0400
Subject: [PATCH 3/6] geo-float-v06

Use the built-in float datatype to implement geometric types

This will provide:

* Check for underflow and overflow
* Check for division by zero
* Handle NaNs consistently

The patch also replaces all occurrences of "double" as "float8".  They
are the same, but were randomly spread on the same file.
---
 src/backend/access/gist/gistproc.c | 156 +++++------
 src/backend/utils/adt/geo_ops.c    | 521 +++++++++++++++++++------------------
 src/backend/utils/adt/geo_spgist.c |  36 +--
 src/include/utils/geo_decls.h      |  41 ++-
 4 files changed, 386 insertions(+), 368 deletions(-)

diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index 13524b4da0..6fa97602c5 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -16,20 +16,21 @@
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/geo_decls.h"
 
 
 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
 						 StrategyNumber strategy);
 static bool rtree_internal_consistent(BOX *key, BOX *query,
 						  StrategyNumber strategy);
 
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
@@ -48,55 +49,56 @@ rt_box_union(BOX *n, const BOX *a, const BOX *b)
 	n->high.x = float8_max(a->high.x, b->high.x);
 	n->high.y = float8_max(a->high.y, b->high.y);
 	n->low.x = float8_min(a->low.x, b->low.x);
 	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
 	if (float8_le(box->high.x, box->low.x) ||
 		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
-	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
+	return float8_mul(float8_mi(box->high.x, box->low.x),
+					  float8_mi(box->high.y, box->low.y));
 }
 
 /*
  * Return amount by which the union of the two boxes is larger than
  * the original BOX's area.  The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 box_penalty(const BOX *original, const BOX *new)
 {
 	BOX			unionbox;
 
 	rt_box_union(&unionbox, original, new);
-	return size_box(&unionbox) - size_box(original);
+	return float8_mi(size_box(&unionbox), size_box(original));
 }
 
 /*
  * The GiST Consistent method for boxes
  *
  * Should return false if for all data items x below entry,
  * the predicate x op query must be FALSE, where op is the oper
  * corresponding to strategy in the pg_amop table.
  */
 Datum
@@ -256,74 +258,74 @@ fallbackSplit(GistEntryVector *entryvec, GIST_SPLITVEC *v)
 
 /*
  * Represents information about an entry that can be placed to either group
  * without affecting overlap over selected axis ("common entry").
  */
 typedef struct
 {
 	/* Index of entry in the initial array */
 	int			index;
 	/* Delta between penalties of entry insertion into different groups */
-	double		delta;
+	float8		delta;
 } CommonEntry;
 
 /*
  * Context for g_box_consider_split. Contains information about currently
  * selected split and some general information.
  */
 typedef struct
 {
 	int			entriesCount;	/* total number of entries being split */
 	BOX			boundingBox;	/* minimum bounding box across all entries */
 
 	/* Information about currently selected split follows */
 
 	bool		first;			/* true if no split was selected yet */
 
-	double		leftUpper;		/* upper bound of left interval */
-	double		rightLower;		/* lower bound of right interval */
+	float8		leftUpper;		/* upper bound of left interval */
+	float8		rightLower;		/* lower bound of right interval */
 
 	float4		ratio;
 	float4		overlap;
 	int			dim;			/* axis of this split */
-	double		range;			/* width of general MBR projection to the
+	float8		range;			/* width of general MBR projection to the
 								 * selected axis */
 } ConsiderSplitContext;
 
 /*
  * Interval represents projection of box to axis.
  */
 typedef struct
 {
-	double		lower,
+	float8		lower,
 				upper;
 } SplitInterval;
 
 /*
  * Interval comparison function by lower bound of the interval;
  */
 static int
 interval_cmp_lower(const void *i1, const void *i2)
 {
-	double		lower1 = ((const SplitInterval *) i1)->lower,
+	float8		lower1 = ((const SplitInterval *) i1)->lower,
 				lower2 = ((const SplitInterval *) i2)->lower;
 
 	return float8_cmp_internal(lower1, lower2);
 }
 
 /*
  * Interval comparison function by upper bound of the interval;
  */
 static int
 interval_cmp_upper(const void *i1, const void *i2)
 {
-	double		upper1 = ((const SplitInterval *) i1)->upper,
+	float8		upper1 = ((const SplitInterval *) i1)->upper,
 				upper2 = ((const SplitInterval *) i2)->upper;
 
 	return float8_cmp_internal(upper1, upper2);
 }
 
 /*
  * Replace negative (or NaN) value with zero.
  */
 static inline float
 non_negative(float val)
@@ -332,28 +334,28 @@ non_negative(float val)
 		return val;
 	else
 		return 0.0f;
 }
 
 /*
  * Consider replacement of currently selected split with the better one.
  */
 static inline void
 g_box_consider_split(ConsiderSplitContext *context, int dimNum,
-					 double rightLower, int minLeftCount,
-					 double leftUpper, int maxLeftCount)
+					 float8 rightLower, int minLeftCount,
+					 float8 leftUpper, int maxLeftCount)
 {
 	int			leftCount,
 				rightCount;
 	float4		ratio,
 				overlap;
-	double		range;
+	float8		range;
 
 	/*
 	 * Calculate entries distribution ratio assuming most uniform distribution
 	 * of common entries.
 	 */
 	if (minLeftCount >= (context->entriesCount + 1) / 2)
 	{
 		leftCount = minLeftCount;
 	}
 	else
@@ -362,52 +364,54 @@ g_box_consider_split(ConsiderSplitContext *context, int dimNum,
 			leftCount = maxLeftCount;
 		else
 			leftCount = context->entriesCount / 2;
 	}
 	rightCount = context->entriesCount - leftCount;
 
 	/*
 	 * Ratio of split - quotient between size of lesser group and total
 	 * entries count.
 	 */
-	ratio = ((float4) Min(leftCount, rightCount)) /
-		((float4) context->entriesCount);
+	ratio = float4_div(Min(leftCount, rightCount), context->entriesCount);
 
-	if (ratio > LIMIT_RATIO)
+	if (float4_gt(ratio, LIMIT_RATIO))
 	{
 		bool		selectthis = false;
 
 		/*
 		 * The ratio is acceptable, so compare current split with previously
 		 * selected one. Between splits of one dimension we search for minimal
 		 * overlap (allowing negative values) and minimal ration (between same
 		 * overlaps. We switch dimension if find less overlap (non-negative)
 		 * or less range with same overlap.
 		 */
 		if (dimNum == 0)
-			range = context->boundingBox.high.x - context->boundingBox.low.x;
+			range = float8_mi(context->boundingBox.high.x,
+							  context->boundingBox.low.x);
 		else
-			range = context->boundingBox.high.y - context->boundingBox.low.y;
+			range = float8_mi(context->boundingBox.high.y,
+							  context->boundingBox.low.y);
 
-		overlap = (leftUpper - rightLower) / range;
+		overlap = float8_div(float8_mi(leftUpper, rightLower), range);
 
 		/* If there is no previous selection, select this */
 		if (context->first)
 			selectthis = true;
 		else if (context->dim == dimNum)
 		{
 			/*
 			 * Within the same dimension, choose the new split if it has a
 			 * smaller overlap, or same overlap but better ratio.
 			 */
-			if (overlap < context->overlap ||
-				(overlap == context->overlap && ratio > context->ratio))
+			if (float4_lt(overlap, context->overlap) ||
+				(float4_eq(overlap, context->overlap) &&
+				 float4_gt(ratio, context->ratio)))
 				selectthis = true;
 		}
 		else
 		{
 			/*
 			 * Across dimensions, choose the new split if it has a smaller
 			 * *non-negative* overlap, or same *non-negative* overlap but
 			 * bigger range. This condition differs from the one described in
 			 * the article. On the datasets where leaf MBRs don't overlap
 			 * themselves, non-overlapping splits (i.e. splits which have zero
@@ -416,55 +420,49 @@ g_box_consider_split(ConsiderSplitContext *context, int dimNum,
 			 * non-overlapping splits (i.e. having lowest negative overlap)
 			 * appears to be in the same dimension as in the previous split.
 			 * Therefore MBRs appear to be very prolonged along another
 			 * dimension, which leads to bad search performance. Using range
 			 * as the second split criteria makes MBRs more quadratic. Using
 			 * *non-negative* overlap instead of overlap as the first split
 			 * criteria gives to range criteria a chance to matter, because
 			 * non-overlapping splits are equivalent in this criteria.
 			 */
 			if (non_negative(overlap) < non_negative(context->overlap) ||
-				(range > context->range &&
+				(float4_gt(range, context->range) &&
 				 non_negative(overlap) <= non_negative(context->overlap)))
 				selectthis = true;
 		}
 
 		if (selectthis)
 		{
 			/* save information about selected split */
 			context->first = false;
 			context->ratio = ratio;
 			context->range = range;
 			context->overlap = overlap;
 			context->rightLower = rightLower;
 			context->leftUpper = leftUpper;
 			context->dim = dimNum;
 		}
 	}
 }
 
 /*
  * Compare common entries by their deltas.
- * (We assume the deltas can't be NaN.)
  */
 static int
 common_entry_cmp(const void *i1, const void *i2)
 {
-	double		delta1 = ((const CommonEntry *) i1)->delta,
+	float8		delta1 = ((const CommonEntry *) i1)->delta,
 				delta2 = ((const CommonEntry *) i2)->delta;
 
-	if (delta1 < delta2)
-		return -1;
-	else if (delta1 > delta2)
-		return 1;
-	else
-		return 0;
+	return float8_cmp_internal(delta1, delta2);
 }
 
 /*
  * --------------------------------------------------------------------------
  * Double sorting split algorithm. This is used for both boxes and points.
  *
  * The algorithm finds split of boxes by considering splits along each axis.
  * Each entry is first projected as an interval on the X-axis, and different
  * ways to split the intervals into two groups are considered, trying to
  * minimize the overlap of the groups. Then the same is repeated for the
@@ -524,21 +522,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		else
 			adjustBox(&context.boundingBox, box);
 	}
 
 	/*
 	 * Iterate over axes for optimal split searching.
 	 */
 	context.first = true;		/* nothing selected yet */
 	for (dim = 0; dim < 2; dim++)
 	{
-		double		leftUpper,
+		float8		leftUpper,
 					rightLower;
 		int			i1,
 					i2;
 
 		/* Project each entry as an interval on the selected axis. */
 		for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 		{
 			box = DatumGetBoxP(entryvec->vector[i].key);
 			if (dim == 0)
 			{
@@ -721,21 +719,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 			*rightBox = *(box);					\
 		v->spl_right[v->spl_nright++] = off;	\
 	} while(0)
 
 	/*
 	 * Distribute entries which can be distributed unambiguously, and collect
 	 * common entries.
 	 */
 	for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 	{
-		double		lower,
+		float8		lower,
 					upper;
 
 		/*
 		 * Get upper and lower bounds along selected axis.
 		 */
 		box = DatumGetBoxP(entryvec->vector[i].key);
 		if (context.dim == 0)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
@@ -776,31 +774,31 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
 	{
 		/*
 		 * Calculate minimum number of entries that must be placed in both
 		 * groups, to reach LIMIT_RATIO.
 		 */
-		int			m = ceil(LIMIT_RATIO * (double) nentries);
+		int			m = ceil(LIMIT_RATIO * (float8) nentries);
 
 		/*
 		 * Calculate delta between penalties of join "common entries" to
 		 * different groups.
 		 */
 		for (i = 0; i < commonEntriesCount; i++)
 		{
 			box = DatumGetBoxP(entryvec->vector[commonEntries[i].index].key);
-			commonEntries[i].delta = Abs(box_penalty(leftBox, box) -
-										 box_penalty(rightBox, box));
+			commonEntries[i].delta = Abs(float8_mi(box_penalty(leftBox, box),
+												   box_penalty(rightBox, box)));
 		}
 
 		/*
 		 * Sort "common entries" by calculated deltas in order to distribute
 		 * the most ambiguous entries first.
 		 */
 		qsort(commonEntries, commonEntriesCount, sizeof(CommonEntry), common_entry_cmp);
 
 		/*
 		 * Distribute "common entries" between groups.
@@ -1100,24 +1098,24 @@ gist_circle_compress(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	GISTENTRY  *retval;
 
 	if (entry->leafkey)
 	{
 		CIRCLE	   *in = DatumGetCircleP(entry->key);
 		BOX		   *r;
 
 		r = (BOX *) palloc(sizeof(BOX));
-		r->high.x = in->center.x + in->radius;
-		r->low.x = in->center.x - in->radius;
-		r->high.y = in->center.y + in->radius;
-		r->low.y = in->center.y - in->radius;
+		r->high.x = float8_pl(in->center.x, in->radius);
+		r->low.x = float8_mi(in->center.x, in->radius);
+		r->high.y = float8_pl(in->center.y, in->radius);
+		r->low.y = float8_mi(in->center.y, in->radius);
 
 		retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
 		gistentryinit(*retval, PointerGetDatum(r),
 					  entry->rel, entry->page,
 					  entry->offset, FALSE);
 	}
 	else
 		retval = entry;
 	PG_RETURN_POINTER(retval);
 }
@@ -1141,24 +1139,24 @@ gist_circle_consistent(PG_FUNCTION_ARGS)
 	*recheck = true;
 
 	if (DatumGetBoxP(entry->key) == NULL || query == NULL)
 		PG_RETURN_BOOL(FALSE);
 
 	/*
 	 * Since the operators require recheck anyway, we can just use
 	 * rtree_internal_consistent even at leaf nodes.  (This works in part
 	 * because the index entries are bounding boxes not circles.)
 	 */
-	bbox.high.x = query->center.x + query->radius;
-	bbox.low.x = query->center.x - query->radius;
-	bbox.high.y = query->center.y + query->radius;
-	bbox.low.y = query->center.y - query->radius;
+	bbox.high.x = float8_pl(query->center.x, query->radius);
+	bbox.low.x = float8_mi(query->center.x, query->radius);
+	bbox.high.y = float8_pl(query->center.y, query->radius);
+	bbox.low.y = float8_mi(query->center.y, query->radius);
 
 	result = rtree_internal_consistent(DatumGetBoxP(entry->key),
 									   &bbox, strategy);
 
 	PG_RETURN_BOOL(result);
 }
 
 /**************************************************
  * Point ops
  **************************************************/
@@ -1209,80 +1207,84 @@ gist_point_fetch(PG_FUNCTION_ARGS)
 				  entry->offset, FALSE);
 
 	PG_RETURN_POINTER(retval);
 }
 
 
 #define point_point_distance(p1,p2) \
 	DatumGetFloat8(DirectFunctionCall2(point_distance, \
 									   PointPGetDatum(p1), PointPGetDatum(p2)))
 
-static double
+static float8
 computeDistance(bool isLeaf, BOX *box, Point *point)
 {
-	double		result = 0.0;
+	float8		result = 0.0;
 
 	if (isLeaf)
 	{
 		/* simple point to point distance */
 		result = point_point_distance(point, &box->low);
 	}
-	else if (point->x <= box->high.x && point->x >= box->low.x &&
-			 point->y <= box->high.y && point->y >= box->low.y)
+	else if (float8_le(point->x, box->high.x) &&
+			 float8_ge(point->x, box->low.x) &&
+			 float8_le(point->y, box->high.y) &&
+			 float8_ge(point->y, box->low.y))
 	{
 		/* point inside the box */
 		result = 0.0;
 	}
-	else if (point->x <= box->high.x && point->x >= box->low.x)
+	else if (float8_le(point->x, box->high.x) &&
+			 float8_ge(point->x, box->low.x))
 	{
 		/* point is over or below box */
-		Assert(box->low.y <= box->high.y);
-		if (point->y > box->high.y)
-			result = point->y - box->high.y;
-		else if (point->y < box->low.y)
-			result = box->low.y - point->y;
+		Assert(float8_le(box->low.y, box->high.y));
+		if (float8_gt(point->y, box->high.y))
+			result = float8_mi(point->y, box->high.y);
+		else if (float8_lt(point->y, box->low.y))
+			result = float8_mi(box->low.y, point->y);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
-	else if (point->y <= box->high.y && point->y >= box->low.y)
+	else if (float8_le(point->y, box->high.y) &&
+			 float8_ge(point->y, box->low.y))
 	{
 		/* point is to left or right of box */
-		Assert(box->low.x <= box->high.x);
-		if (point->x > box->high.x)
-			result = point->x - box->high.x;
-		else if (point->x < box->low.x)
-			result = box->low.x - point->x;
+		Assert(float8_lt(box->low.x, box->high.x));
+		if (float8_gt(point->x, box->high.x))
+			result = float8_mi(point->x, box->high.x);
+		else if (float8_lt(point->x, box->low.x))
+			result = float8_mi(box->low.x, point->x);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
 	else
 	{
 		/* closest point will be a vertex */
 		Point		p;
-		double		subresult;
+		float8		subresult;
 
 		result = point_point_distance(point, &box->low);
 
 		subresult = point_point_distance(point, &box->high);
-		if (result > subresult)
+		if (float8_gt(result, subresult))
 			result = subresult;
 
 		p.x = box->low.x;
 		p.y = box->high.y;
 		subresult = point_point_distance(point, &p);
-		if (result > subresult)
+		if (float8_gt(result, subresult))
 			result = subresult;
 
 		p.x = box->high.x;
 		p.y = box->low.y;
 		subresult = point_point_distance(point, &p);
-		if (result > subresult)
+		if (float8_gt(result, subresult))
 			result = subresult;
 	}
 
 	return result;
 }
 
 static bool
 gist_point_consistent_internal(StrategyNumber strategy,
 							   bool isLeaf, BOX *key, Point *query)
 {
@@ -1363,24 +1365,24 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 				 * Instead we write a non-fuzzy overlap test.  The same code
 				 * will also serve for leaf-page tests, since leaf keys have
 				 * high == low.
 				 */
 				BOX		   *query,
 						   *key;
 
 				query = PG_GETARG_BOX_P(1);
 				key = DatumGetBoxP(entry->key);
 
-				result = (key->high.x >= query->low.x &&
-						  key->low.x <= query->high.x &&
-						  key->high.y >= query->low.y &&
-						  key->low.y <= query->high.y);
+				result = (float8_ge(key->high.x, query->low.x) &&
+						  float8_le(key->low.x, query->high.x) &&
+						  float8_ge(key->high.y, query->low.y) &&
+						  float8_le(key->low.y, query->high.y));
 				*recheck = false;
 			}
 			break;
 		case PolygonStrategyNumberGroup:
 			{
 				POLYGON    *query = PG_GETARG_POLYGON_P(1);
 
 				result = DatumGetBool(DirectFunctionCall5(
 														  gist_poly_consistent,
 														  PointerGetDatum(entry),
@@ -1389,22 +1391,22 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 														  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);
+					Assert(float8_eq(box->high.x, box->low.x) &&
+						   float8_eq(box->high.y, box->low.y));
 					result = DatumGetBool(DirectFunctionCall2(
 															  poly_contain_pt,
 															  PolygonPGetDatum(query),
 															  PointPGetDatum(&box->high)));
 					*recheck = false;
 				}
 			}
 			break;
 		case CircleStrategyNumberGroup:
 			{
@@ -1418,22 +1420,22 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 														  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);
+					Assert(float8_eq(box->high.x, box->low.x) &&
+						   float8_eq(box->high.y, box->low.y));
 					result = DatumGetBool(DirectFunctionCall2(
 															  circle_contain_pt,
 															  CirclePGetDatum(query),
 															  PointPGetDatum(&box->high)));
 					*recheck = false;
 				}
 			}
 			break;
 		default:
 			elog(ERROR, "unrecognized strategy number: %d", strategy);
@@ -1442,21 +1444,21 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 	}
 
 	PG_RETURN_BOOL(result);
 }
 
 Datum
 gist_point_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(GIST_LEAF(entry),
 									   DatumGetBoxP(entry->key),
 									   PG_GETARG_POINT_P(1));
 			break;
 		default:
@@ -1471,25 +1473,25 @@ gist_point_distance(PG_FUNCTION_ARGS)
 /*
  * The inexact GiST distance method for geometric types that store bounding
  * boxes.
  *
  * Compute lossy distance from point to index entries.  The result is inexact
  * because index entries are bounding boxes, not the exact shapes of the
  * indexed geometric types.  We use distance from point to MBR of index entry.
  * This is a lower bound estimate of distance from point to indexed geometric
  * type.
  */
-static double
+static float8
 gist_bbox_distance(GISTENTRY *entry, Datum query,
 				   StrategyNumber strategy, bool *recheck)
 {
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	/* Bounding box distance is always inexact. */
 	*recheck = true;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(false,
 									   DatumGetBoxP(entry->key),
@@ -1505,32 +1507,32 @@ gist_bbox_distance(GISTENTRY *entry, Datum query,
 
 Datum
 gist_circle_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
 
 Datum
 gist_poly_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index d16dc350cf..2daa8e12cb 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -41,61 +41,61 @@ static inline void point_sub_internal(Point *result, Point *pt1, Point *pt2);
 static inline void point_mul_internal(Point *result, Point *pt1, Point *pt2);
 static inline void point_div_internal(Point *result, Point *pt1, Point *pt2);
 static inline bool point_eq_internal(Point *pt1, Point *pt2);
 static float8 point_dt(Point *pt1, Point *pt2);
 static int	point_inside(Point *p, int npts, Point *plist);
 
 /* Routines for two-dimensional boxes */
 static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
 static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
-static double box_ar(BOX *box);
-static double box_ht(BOX *box);
-static double box_wd(BOX *box);
+static float8 box_ar(BOX *box);
+static float8 box_ht(BOX *box);
+static float8 box_wd(BOX *box);
 
 /* Routines for two-dimensional circles */
-static double circle_ar(CIRCLE *circle);
+static float8 circle_ar(CIRCLE *circle);
 
 /* Routines for two-dimensional lines */
 static inline void line_construct_pm(LINE *result, Point *pt, float8 m);
 static inline void line_construct_pts(LINE *result, Point *pt1, Point *pt2);
 static bool line_interpt_internal(Point *result, LINE *l1, LINE *l2);
 static inline float8 line_calculate_point(LINE *line, Point *pt);
 
 /* Routines for two-dimensional line segments */
 static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
 static bool lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line);
 static bool lseg_interpt_internal(Point *result, LSEG *l1, LSEG *l2);
 static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
 static float8 lseg_dt(LSEG *l1, LSEG *l2);
-static int	lseg_crossing(double x, double y, double px, double py);
+static int	lseg_crossing(float8 x, float8 y, float8 px, float8 py);
 static bool on_ps_internal(Point *pt, LSEG *lseg);
 
 /* Routines for two-dimensional polygons */
 static void make_bound_box(POLYGON *poly);
 
 /* Unsorted */
 static bool plist_same(int npts, Point *p1, Point *p2);
-static double single_decode(char *num, char **endptr_p,
+static float8 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
-static void pair_decode(char *str, double *x, double *y, char **endptr_p,
+static void pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
 static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
-static double dist_pl_internal(Point *pt, LINE *line);
-static double dist_ps_internal(Point *pt, LSEG *lseg);
-static double dist_ppoly_internal(Point *pt, POLYGON *poly);
+static float8 dist_pl_internal(Point *pt, LINE *line);
+static float8 dist_ps_internal(Point *pt, LSEG *lseg);
+static float8 dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 
 /*
  * Delimiters for input and output strings.
  * LDELIM, RDELIM, and DELIM are left, right, and separator delimiters, respectively.
  * LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints.
  */
 
 #define LDELIM			'('
 #define RDELIM			')'
@@ -126,38 +126,38 @@ static double dist_ppoly_internal(Point *pt, POLYGON *poly);
  *
  * For boxes, the points are opposite corners with the first point at the top right.
  * For closed paths and polygons, the points should be reordered to allow
  *	fast and correct equality comparisons.
  *
  * XXX perhaps points in complex shapes should be reordered internally
  *	to allow faster internal operations, but should keep track of input order
  *	and restore that order for text output - tgl 97/01/16
  */
 
-static double
+static float8
 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string)
 {
 	return float8in_internal(num, endptr_p, type_name, orig_string);
 }								/* single_decode() */
 
 static void
 single_encode(float8 x, StringInfo str)
 {
 	char	   *xstr = float8out_internal(x);
 
 	appendStringInfoString(str, xstr);
 	pfree(xstr);
 }								/* single_encode() */
 
 static void
-pair_decode(char *str, double *x, double *y, char **endptr_p,
+pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string)
 {
 	bool		has_delim;
 
 	while (isspace((unsigned char) *str))
 		str++;
 	if ((has_delim = (*str == LDELIM)))
 		str++;
 
 	*x = float8in_internal(str, &str, type_name, orig_string);
@@ -348,21 +348,21 @@ pair_count(char *s, char delim)
  * to calculate inverse slope.  To achieve that pass the values in
  * (y1, y2, x2, x1) order.
  */
 static inline float8
 slope(float8 x1, float8 x2, float8 y1, float8 y2)
 {
 	if (FPeq(x1, x2))
 		return DBL_MAX;
 	if (FPeq(y1, y2))
 		return 0.0;
-	return (y1 - y2) / (x1 - x2);
+	return float8_div(float8_mi(y1, y2), float8_mi(x1, x2));
 }
 
 
 /***********************************************************************
  **
  **		Routines for two-dimensional boxes.
  **
  ***********************************************************************/
 
 /*----------------------------------------------------------
@@ -374,33 +374,33 @@ slope(float8 x1, float8 x2, float8 y1, float8 y2)
  *		External format: (two corners of box)
  *				"(f8, f8), (f8, f8)"
  *				also supports the older style "(f8, f8, f8, f8)"
  */
 Datum
 box_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	BOX		   *box = (BOX *) palloc(sizeof(BOX));
 	bool		isopen;
-	double		x,
+	float8		x,
 				y;
 
 	path_decode(str, false, 2, &(box->high), &isopen, NULL, "box", str);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*		box_out -		convert a box to external form.
@@ -414,38 +414,38 @@ box_out(PG_FUNCTION_ARGS)
 }
 
 /*
  *		box_recv			- converts external binary format to box
  */
 Datum
 box_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	BOX		   *box;
-	double		x,
+	float8		x,
 				y;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
 	box->high.x = pq_getmsgfloat8(buf);
 	box->high.y = pq_getmsgfloat8(buf);
 	box->low.x = pq_getmsgfloat8(buf);
 	box->low.y = pq_getmsgfloat8(buf);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*
@@ -464,31 +464,31 @@ box_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, box->low.y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*		box_construct	-		fill in a new box.
  */
 static inline void
 box_construct(BOX *result, Point *pt1, Point *pt2)
 {
-	if (pt1->x > pt2->x)
+	if (float8_gt(pt1->x, pt2->x))
 	{
 		result->high.x = pt1->x;
 		result->low.x = pt2->x;
 	}
 	else
 	{
 		result->high.x = pt2->x;
 		result->low.x = pt1->x;
 	}
-	if (pt1->y > pt2->y)
+	if (float8_gt(pt1->y, pt2->y))
 	{
 		result->high.y = pt1->y;
 		result->low.y = pt2->y;
 	}
 	else
 	{
 		result->high.y = pt2->y;
 		result->low.y = pt1->y;
 	}
 }
@@ -800,54 +800,54 @@ box_center(PG_FUNCTION_ARGS)
 	Point	   *result = (Point *) palloc(sizeof(Point));
 
 	box_cn(result, box);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		box_ar	-		returns the area of the box.
  */
-static double
+static float8
 box_ar(BOX *box)
 {
-	return box_wd(box) * box_ht(box);
+	return float8_mul(box_wd(box), box_ht(box));
 }
 
 
 /*		box_cn	-		stores the centerpoint of the box into *center.
  */
 static void
 box_cn(Point *center, BOX *box)
 {
-	center->x = (box->high.x + box->low.x) / 2.0;
-	center->y = (box->high.y + box->low.y) / 2.0;
+	center->x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	center->y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 }
 
 
 /*		box_wd	-		returns the width (length) of the box
  *								  (horizontal magnitude).
  */
-static double
+static float8
 box_wd(BOX *box)
 {
-	return box->high.x - box->low.x;
+	return float8_mi(box->high.x, box->low.x);
 }
 
 
 /*		box_ht	-		returns the height of the box
  *								  (vertical magnitude).
  */
-static double
+static float8
 box_ht(BOX *box)
 {
-	return box->high.y - box->low.y;
+	return float8_mi(box->high.y, box->low.y);
 }
 
 
 /*----------------------------------------------------------
  *	Funky operations.
  *---------------------------------------------------------*/
 
 /*		box_intersect	-
  *				returns the overlapping portion of two boxes,
  *				  or NULL if they do not intersect.
@@ -857,24 +857,24 @@ box_intersect(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 	BOX		   *result;
 
 	if (!box_ov(box1, box2))
 		PG_RETURN_NULL();
 
 	result = (BOX *) palloc(sizeof(BOX));
 
-	result->high.x = Min(box1->high.x, box2->high.x);
-	result->low.x = Max(box1->low.x, box2->low.x);
-	result->high.y = Min(box1->high.y, box2->high.y);
-	result->low.y = Max(box1->low.y, box2->low.y);
+	result->high.x = float8_min(box1->high.x, box2->high.x);
+	result->low.x = float8_max(box1->low.x, box2->low.x);
+	result->high.y = float8_min(box1->high.y, box2->high.y);
+	result->low.y = float8_max(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(result);
 }
 
 
 /*		box_diagonal	-
  *				returns a line segment which happens to be the
  *				  positive-slope diagonal of "box".
  */
 Datum
@@ -1006,30 +1006,30 @@ line_send(PG_FUNCTION_ARGS)
 
 /*
  * Fill already-allocated LINE struct from the point and the slope
  */
 static inline void
 line_construct_pm(LINE *result, Point *pt, float8 m)
 {
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
-		result->A = -1;
-		result->B = 0;
+		result->A = -1.0;
+		result->B = 0.0;
 		result->C = pt->x;
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
-		result->C = pt->y - m * pt->x;
+		result->C = float8_mi(pt->y, float8_mul(m, pt->x));
 	}
 }
 
 /*
  * Fill already-allocated LINE struct from two points on the line
  */
 static inline void
 line_construct_pts(LINE *result, Point *pt1, Point *pt2)
 {
 	float8		m;
@@ -1055,21 +1055,22 @@ line_construct_pp(PG_FUNCTION_ARGS)
 
 /*
  * Calculate the line equation for a point
  *
  * This returns the result of the line equation Ax + By + C.  The result
  * needs to be 0.0 for the point to be on the line.
  */
 static inline float8
 line_calculate_point(LINE *line, Point *pt)
 {
-	return line->A * pt->x + line->B * pt->y + line->C;
+	return float8_pl(float8_pl(float8_mul(line->A, pt->x),
+							   float8_mul(line->B, pt->y)), line->C);
 }
 
 
 /*----------------------------------------------------------
  *	Relative position routines.
  *---------------------------------------------------------*/
 
 Datum
 line_intersect(PG_FUNCTION_ARGS)
 {
@@ -1092,21 +1093,22 @@ Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
 	else if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
 
-	PG_RETURN_BOOL(FPeq(((l1->A * l2->B) / (l1->B * l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
+								   float8_mul(l1->B, l2->A)), -1.0));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
@@ -1116,34 +1118,34 @@ line_horizontal(PG_FUNCTION_ARGS)
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->A));
 }
 
 Datum
 line_eq(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	double		k;
+	float8		ratio;
 
 	if (!FPzero(l2->A))
-		k = l1->A / l2->A;
+		ratio = float8_div(l1->A, l2->A);
 	else if (!FPzero(l2->B))
-		k = l1->B / l2->B;
+		ratio = float8_div(l1->B, l2->B);
 	else if (!FPzero(l2->C))
-		k = l1->C / l2->C;
+		ratio = float8_div(l1->C, l2->C);
 	else
-		k = 1.0;
+		ratio = 1.0;
 
-	PG_RETURN_BOOL(FPeq(l1->A, k * l2->A) &&
-				   FPeq(l1->B, k * l2->B) &&
-				   FPeq(l1->C, k * l2->C));
+	PG_RETURN_BOOL(FPeq(l1->A, float8_mul(ratio, l2->A)) &&
+				   FPeq(l1->B, float8_mul(ratio, l2->B)) &&
+				   FPeq(l1->C, float8_mul(ratio, l2->C)));
 }
 
 
 /*----------------------------------------------------------
  *	Line arithmetic routines.
  *---------------------------------------------------------*/
 
 /* line_distance()
  * Distance between two lines.
  */
@@ -1151,21 +1153,21 @@ Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
 	Point		tmp;
 
 	if (line_interpt_internal(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
+		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
 	point_construct(&tmp, 0.0, l1->C);
 	result = dist_pl_internal(&tmp, l2);
 	PG_RETURN_FLOAT8(result);
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
@@ -1188,41 +1190,41 @@ line_interpt(PG_FUNCTION_ARGS)
  * parallel), false if they do not.  This also sets the intersection point
  * to *result, if it is not NULL.
  *
  * NOTE: If the lines are identical then we will find they are parallel
  * and report "no intersection".  This is a little weird, but since
  * there's no *unique* intersection, maybe it's appropriate behavior.
  */
 static bool
 line_interpt_internal(Point *result, LINE *l1, LINE *l2)
 {
-	double		x,
+	float8		x,
 				y;
 
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
 		if (FPzero(l2->B))		/* l2 vertical? */
 			return false;
 
 		x = l1->C;
-		y = (l2->A * x + l2->C);
+		y = float8_pl(float8_mul(l2->A, x), l2->C);
 	}
 	else
 	{
-		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
 			return false;
 
 		if (FPzero(l2->B))
 			x = l2->C;
 		else
-			x = (l1->C - l2->C) / (l2->A - l1->A);
-		y = (l1->A * x + l1->C);
+			x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
+		y = float8_pl(float8_mul(l1->A, x), l1->C);
 	}
 	if (result != NULL)
 		point_construct(result, x, y);
 
 #ifdef GEODEBUG
 	printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
 		   DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
 	printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
 #endif
 
@@ -1249,36 +1251,35 @@ line_interpt_internal(Point *result, LINE *l1, LINE *l2)
  *				"(xcoord, ycoord),... "
  *				"[xcoord, ycoord,... ]"
  *		Also support older format:
  *				"(closed, npts, xcoord, ycoord,... )"
  *---------------------------------------------------------*/
 
 Datum
 path_area(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P(0);
-	double		area = 0.0;
+	float8		area = 0.0;
 	int			i,
 				j;
 
 	if (!path->closed)
 		PG_RETURN_NULL();
 
 	for (i = 0; i < path->npts; i++)
 	{
 		j = (i + 1) % path->npts;
-		area += path->p[i].x * path->p[j].y;
-		area -= path->p[i].y * path->p[j].x;
+		area = float8_pl(area, float8_mul(path->p[i].x, path->p[j].y));
+		area = float8_mi(area, float8_mul(path->p[i].y, path->p[j].x));
 	}
 
-	area *= 0.5;
-	PG_RETURN_FLOAT8(area < 0.0 ? -area : area);
+	PG_RETURN_FLOAT8(float8_div(fabs(area), 2.0));
 }
 
 
 Datum
 path_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	PATH	   *path;
 	bool		isopen;
 	char	   *s;
@@ -1495,31 +1496,31 @@ path_npoints(PG_FUNCTION_ARGS)
 
 	PG_RETURN_INT32(path->npts);
 }
 
 
 Datum
 path_close(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 
-	path->closed = TRUE;
+	path->closed = true;
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_open(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 
-	path->closed = FALSE;
+	path->closed = false;
 
 	PG_RETURN_PATH_P(path);
 }
 
 
 /* path_inter -
  *		Does p1 intersect p2 at any point?
  *		Use bounding boxes for a quick (O(n)) check, then do a
  *		O(n^2) iterative edge check.
  */
@@ -1534,33 +1535,33 @@ path_inter(PG_FUNCTION_ARGS)
 				j;
 	LSEG		seg1,
 				seg2;
 
 	Assert(p1->npts > 0 && p2->npts > 0);
 
 	b1.high.x = b1.low.x = p1->p[0].x;
 	b1.high.y = b1.low.y = p1->p[0].y;
 	for (i = 1; i < p1->npts; i++)
 	{
-		b1.high.x = Max(p1->p[i].x, b1.high.x);
-		b1.high.y = Max(p1->p[i].y, b1.high.y);
-		b1.low.x = Min(p1->p[i].x, b1.low.x);
-		b1.low.y = Min(p1->p[i].y, b1.low.y);
+		b1.high.x = float8_max(p1->p[i].x, b1.high.x);
+		b1.high.y = float8_max(p1->p[i].y, b1.high.y);
+		b1.low.x = float8_min(p1->p[i].x, b1.low.x);
+		b1.low.y = float8_min(p1->p[i].y, b1.low.y);
 	}
 	b2.high.x = b2.low.x = p2->p[0].x;
 	b2.high.y = b2.low.y = p2->p[0].y;
 	for (i = 1; i < p2->npts; i++)
 	{
-		b2.high.x = Max(p2->p[i].x, b2.high.x);
-		b2.high.y = Max(p2->p[i].y, b2.high.y);
-		b2.low.x = Min(p2->p[i].x, b2.low.x);
-		b2.low.y = Min(p2->p[i].y, b2.low.y);
+		b2.high.x = float8_max(p2->p[i].x, b2.high.x);
+		b2.high.y = float8_max(p2->p[i].y, b2.high.y);
+		b2.low.x = float8_min(p2->p[i].x, b2.low.x);
+		b2.low.y = float8_min(p2->p[i].y, b2.low.y);
 	}
 	if (!box_ov(&b1, &b2))
 		PG_RETURN_BOOL(false);
 
 	/* pairwise check lseg intersections */
 	for (i = 0; i < p1->npts; i++)
 	{
 		int			iprev;
 
 		if (i > 0)
@@ -1636,21 +1637,21 @@ path_distance(PG_FUNCTION_ARGS)
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
 			tmp = lseg_dt(&seg1, &seg2);
-			if (!have_min || tmp < min)
+			if (!have_min || float8_lt(tmp, min))
 			{
 				min = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	if (!have_min)
 		PG_RETURN_NULL();
 
@@ -1675,21 +1676,21 @@ path_length(PG_FUNCTION_ARGS)
 
 		if (i > 0)
 			iprev = i - 1;
 		else
 		{
 			if (!path->closed)
 				continue;
 			iprev = path->npts - 1; /* include the closure segment */
 		}
 
-		result += point_dt(&path->p[iprev], &path->p[i]);
+		result = float8_pl(result, point_dt(&path->p[iprev], &path->p[i]));
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /***********************************************************************
  **
  **		Routines for 2D points.
  **
  ***********************************************************************/
@@ -1863,21 +1864,21 @@ point_distance(PG_FUNCTION_ARGS)
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
 static float8
 point_dt(Point *pt1, Point *pt2)
 {
 	float8		result;
 
-	result = HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
+	result = HYPOT(float8_mi(pt1->x, pt2->x), float8_mi(pt1->y, pt2->y));
 
 #ifdef GEODEBUG
 	printf("point_dt- segment (%f,%f),(%f,%f) length is %f\n",
 		   pt1->x, pt1->y, pt2->x, pt2->y, result);
 #endif
 
 	return result;
 }
 
 Datum
@@ -2037,35 +2038,35 @@ lseg_parallel(PG_FUNCTION_ARGS)
  *	'((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg
  * So, modified it to check explicitly for slope of vertical line
  *	returned by slope() and the results seem better.
  * - thomas 1998-01-31
  */
 Datum
 lseg_perp(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	double		m1,
+	float8		m1,
 				m2;
 
 	m1 = slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y);
 	m2 = slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y);
 
 #ifdef GEODEBUG
 	printf("lseg_perp- slopes are %g and %g\n", m1, m2);
 #endif
 	if (FPzero(m1))
 		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
 	else if (FPzero(m2))
 		PG_RETURN_BOOL(FPeq(m1, DBL_MAX));
 
-	PG_RETURN_BOOL(FPeq(m1 / m2, -1.0));
+	PG_RETURN_BOOL(FPeq(float8_div(m1, m2), -1.0));
 }
 
 Datum
 lseg_vertical(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 
 	PG_RETURN_BOOL(FPeq(lseg->p[0].x, lseg->p[1].x));
 }
 
@@ -2155,52 +2156,47 @@ lseg_distance(PG_FUNCTION_ARGS)
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_FLOAT8(lseg_dt(l1, l2));
 }
 
 /* lseg_dt()
  * Distance between two line segments.
  * Must check both sets of endpoints to ensure minimum distance is found.
  * - thomas 1998-02-01
  */
-static double
+static float8
 lseg_dt(LSEG *l1, LSEG *l2)
 {
-	double		result,
-				d;
+	float8		result;
 
 	if (lseg_interpt_internal(NULL, l1, l2))
 		return 0.0;
 
-	d = dist_ps_internal(&l1->p[0], l2);
-	result = d;
-	d = dist_ps_internal(&l1->p[1], l2);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[0], l1);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[1], l1);
-	result = Min(result, d);
+	result = dist_ps_internal(&l1->p[0], l2);
+	result = float8_min(result, dist_ps_internal(&l1->p[1], l2));
+	result = float8_min(result, dist_ps_internal(&l2->p[0], l1));
+	result = float8_min(result, dist_ps_internal(&l2->p[1], l1));
 
 	return result;
 }
 
 
 Datum
 lseg_center(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
-	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
+	result->x = float8_div(float8_pl(lseg->p[0].x, lseg->p[1].x), 2.0);
+	result->y = float8_div(float8_pl(lseg->p[0].y, lseg->p[1].y), 2.0);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static bool
 lseg_interpt_internal(Point *result, LSEG *l1, LSEG *l2)
 {
 	Point		interpt;
 	LINE		tmp1,
 				tmp2;
@@ -2284,45 +2280,44 @@ lseg_interpt(PG_FUNCTION_ARGS)
  */
 Datum
 dist_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
 	PG_RETURN_FLOAT8(dist_pl_internal(pt, line));
 }
 
-static double
+static float8
 dist_pl_internal(Point *pt, LINE *line)
 {
-	return fabs(line_calculate_point(line, pt) /
-				HYPOT(line->A, line->B));
+	return float8_div(fabs(line_calculate_point(line, pt)),
+					  HYPOT(line->A, line->B));
 }
 
 /*
  * Distance from a point to a lseg
  */
 Datum
 dist_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_FLOAT8(dist_ps_internal(pt, lseg));
 }
 
-static double
+static float8
 dist_ps_internal(Point *pt, LSEG *lseg)
 {
-	double		m;				/* slope of perp. */
-	double		result,
-				tmpdist;
+	float8		m;				/* slope of perp. */
+	float8		result;
 	Point		interpt;
 	LINE		ln;
 
 	/*
 	 * Construct a line perpendicular to the input segment and through the
 	 * input point
 	 */
 	m = slope(lseg->p[0].y, lseg->p[1].y, lseg->p[1].x, lseg->p[0].x);
 	line_construct_pm(&ln, pt, m);
 
@@ -2342,24 +2337,22 @@ dist_ps_internal(Point *pt, LSEG *lseg)
 		/* yes, so use distance to the intersection point */
 		result = point_dt(pt, &interpt);
 #ifdef GEODEBUG
 		printf("dist_ps- distance is %f to intersection point is (%f,%f)\n",
 			   result, tmp.x, tmp.y);
 #endif
 	}
 	else
 	{
 		/* no, so use distance to the nearer endpoint */
-		result = point_dt(pt, &lseg->p[0]);
-		tmpdist = point_dt(pt, &lseg->p[1]);
-		if (tmpdist < result)
-			result = tmpdist;
+		result = float8_min(point_dt(pt, &lseg->p[0]),
+							point_dt(pt, &lseg->p[1]));
 	}
 
 	return result;
 }
 
 /*
  * Distance from a point to a path
  */
 Datum
 dist_ppath(PG_FUNCTION_ARGS)
@@ -2392,21 +2385,21 @@ dist_ppath(PG_FUNCTION_ARGS)
 				iprev = i - 1;
 			else
 			{
 				if (!path->closed)
 					continue;
 				iprev = path->npts - 1; /* Include the closure segment */
 			}
 
 			statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
 			tmp = dist_ps_internal(pt, &lseg);
-			if (!have_min || tmp < result)
+			if (!have_min || float8_lt(tmp, result))
 			{
 				result = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -2430,33 +2423,28 @@ dist_pb(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
-	float8		result,
-				d2;
+	float8		result;
 
 	if (lseg_interpt_line_internal(NULL, lseg, line))
 		result = 0.0;
 	else
-	{
-		result = dist_pl_internal(&lseg->p[0], line);
-		d2 = dist_pl_internal(&lseg->p[1], line);
 		/* XXX shouldn't we take the min not max? */
-		if (d2 > result)
-			result = d2;
-	}
+		result = float8_max(dist_pl_internal(&lseg->p[0], line),
+							dist_pl_internal(&lseg->p[1], line));
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
@@ -2498,25 +2486,22 @@ dist_lb(PG_FUNCTION_ARGS)
  * Distance from a circle to a polygon
  */
 Datum
 dist_cpoly(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	POLYGON    *poly = PG_GETARG_POLYGON_P(1);
 	float8		result;
 
 	/* calculate distance to center, and subtract radius */
-	result = dist_ppoly_internal(&circle->center, poly);
-
-	result -= circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_min(float8_mi(dist_ppoly_internal(&circle->center, poly),
+								  circle->radius), 0.0);
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a point to a polygon
  */
 Datum
 dist_ppoly(PG_FUNCTION_ARGS)
 {
@@ -2534,21 +2519,21 @@ dist_polyp(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	float8		result;
 
 	result = dist_ppoly_internal(point, poly);
 
 	PG_RETURN_FLOAT8(result);
 }
 
-static double
+static float8
 dist_ppoly_internal(Point *pt, POLYGON *poly)
 {
 	float8		result;
 	float8		d;
 	int			i;
 	LSEG		seg;
 
 	if (point_inside(pt, poly->npts, poly->p) != 0)
 	{
 #ifdef GEODEBUG
@@ -2571,21 +2556,21 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
 	for (i = 0; (i < poly->npts - 1); i++)
 	{
 		seg.p[0].x = poly->p[i].x;
 		seg.p[0].y = poly->p[i].y;
 		seg.p[1].x = poly->p[i + 1].x;
 		seg.p[1].y = poly->p[i + 1].y;
 		d = dist_ps_internal(pt, &seg);
 #ifdef GEODEBUG
 		printf("dist_ppoly_internal- segment %d distance is %f\n", (i + 1), d);
 #endif
-		if (d < result)
+		if (float8_lt(d, result))
 			result = d;
 	}
 
 	return result;
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
  *				Intersection point of objects.
@@ -2654,21 +2639,21 @@ close_pl(PG_FUNCTION_ARGS)
 		point_construct(result, pt->x, line->C);
 	else
 	{
 		LINE		tmp;
 
 		/*
 		 * Drop a perpendicular and find the intersection point
 		 *
 		 * We need to invert the slope to get the perpendicular.
 		 */
-		line_construct_pm(&tmp, pt, line->B / line->A);
+		line_construct_pm(&tmp, pt, float8_div(line->B, line->A));
 		line_interpt_internal(result, &tmp, line);
 	}
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_ps()
  * Closest point on line segment to specified point.
  * Take the closest endpoint if the point is left, right,
@@ -2678,21 +2663,21 @@ close_pl(PG_FUNCTION_ARGS)
  * Some tricky code here, relying on boolean expressions
  *	evaluating to only zero or one to use as an array index.
  *		bug fixes by gthaker@atl.lmco.com; May 1, 1998
  */
 Datum
 close_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
-	double		invm;
+	float8		invm;
 	int			xh,
 				yh;
 	LINE		tmp;
 
 	result = (Point *) palloc(sizeof(Point));
 
 #ifdef GEODEBUG
 	printf("close_sp:pt->x %f pt->y %f\nlseg(0).x %f lseg(0).y %f  lseg(1).x %f lseg(1).y %f\n",
 		   pt->x, pt->y, lseg->p[0].x, lseg->p[0].y,
 		   lseg->p[1].x, lseg->p[1].y);
@@ -2737,32 +2722,32 @@ close_ps(PG_FUNCTION_ARGS)
 	}
 
 	/*
 	 * vert. and horiz. cases are down, now check if the closest point is one
 	 * of the end points or someplace on the lseg.
 	 */
 
 	invm = slope(lseg->p[0].y, lseg->p[1].y, lseg->p[1].x, lseg->p[0].x);
 	line_construct_pm(&tmp, &lseg->p[!yh], invm);	/* lower edge of the
 													 * "band" */
-	if (pt->y < (tmp.A * pt->x + tmp.C))
+	if (pt->y < float8_pl(float8_mul(tmp.A, pt->x), tmp.C))
 	{							/* we are below the lower edge */
 		*result = lseg->p[!yh]; /* below the lseg, take lower end pt */
 #ifdef GEODEBUG
 		printf("close_ps below: tmp A %f  B %f   C %f\n",
 			   tmp->A, tmp->B, tmp->C);
 #endif
 		PG_RETURN_POINT_P(result);
 	}
 	line_construct_pm(&tmp, &lseg->p[yh], invm);	/* upper edge of the
 													 * "band" */
-	if (pt->y > (tmp.A * pt->x + tmp.C))
+	if (pt->y > float8_pl(float8_mul(tmp.A, pt->x), tmp.C))
 	{							/* we are below the lower edge */
 		*result = lseg->p[yh];	/* above the lseg, take higher end pt */
 #ifdef GEODEBUG
 		printf("close_ps above: tmp A %f  B %f   C %f\n",
 			   tmp->A, tmp->B, tmp->C);
 #endif
 		PG_RETURN_POINT_P(result);
 	}
 
 	/*
@@ -2806,26 +2791,26 @@ close_lseg(PG_FUNCTION_ARGS)
 
 	dists1[0] = dist_ps_internal(&l1->p[0], l2);
 	dists1[1] = dist_ps_internal(&l1->p[1], l2);
 	if (dists1[0] <= dists1[1])
 		closer_end1 = 0;
 	else
 		closer_end1 = 1;
 
 	dists2[0] = dist_ps_internal(&l2->p[0], l1);
 	dists2[1] = dist_ps_internal(&l2->p[1], l1);
-	if (dists2[0] <= dists2[1])
+	if (float8_le(dists2[0], dists2[1]))
 		closer_end2 = 0;
 	else
 		closer_end2 = 1;
 
-	if (dists1[closer_end1] <= dists2[closer_end2])
+	if (float8_le(dists1[closer_end1], dists2[closer_end2]))
 		point = PointPGetDatum(&l1->p[closer_end1]);
 	else
 	{
 		point = DirectFunctionCall2(close_ps,
 									PointPGetDatum(&l2->p[closer_end2]),
 									LsegPGetDatum(l1));
 		point = DirectFunctionCall2(close_ps, point, LsegPGetDatum(l2));
 	}
 
 	return point;
@@ -2835,52 +2820,55 @@ close_lseg(PG_FUNCTION_ARGS)
  * Closest point on or in box to specified point.
  */
 Datum
 close_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	LSEG		lseg,
 				seg;
 	Point		point;
-	double		dist,
+	float8		dist,
 				d;
 
 	if (DatumGetBool(DirectFunctionCall2(on_pb,
 										 PointPGetDatum(pt),
 										 BoxPGetDatum(box))))
 		PG_RETURN_POINT_P(pt);
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&lseg, &box->low, &point);
 	dist = dist_ps_internal(pt, &lseg);
 
 	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	d = dist_ps_internal(pt, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&lseg, &seg, sizeof(lseg));
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&seg, &box->low, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	d = dist_ps_internal(pt, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&lseg, &seg, sizeof(lseg));
 	}
 
 	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	d = dist_ps_internal(pt, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&lseg, &seg, sizeof(lseg));
 	}
 
 	PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
 										PointPGetDatum(pt),
 										LsegPGetDatum(&lseg)));
 }
 
@@ -2903,21 +2891,21 @@ close_sl(PG_FUNCTION_ARGS)
 	float8		d1,
 				d2;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (lseg_interpt_line_internal(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = dist_pl_internal(&lseg->p[0], line);
 	d2 = dist_pl_internal(&lseg->p[1], line);
-	if (d1 < d2)
+	if (float8_lt(d1, d2))
 		*result = lseg->p[0];
 	else
 		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
 
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_sl\" not implemented")));
@@ -2937,77 +2925,80 @@ close_ls(PG_FUNCTION_ARGS)
 	float8		d1,
 				d2;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (lseg_interpt_line_internal(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = dist_pl_internal(&lseg->p[0], line);
 	d2 = dist_pl_internal(&lseg->p[1], line);
-	if (d1 < d2)
+	if (float8_lt(d1, d2))
 		*result = lseg->p[0];
 	else
 		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 }
 
 /* close_sb()
  * Closest point on or in box to line segment.
  */
 Datum
 close_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	Point		point;
 	LSEG		bseg,
 				seg;
-	double		dist,
+	float8		dist,
 				d;
 
 	/* segment intersects box? then just return closest point to center */
 	if (DatumGetBool(DirectFunctionCall2(inter_sb,
 										 LsegPGetDatum(lseg),
 										 BoxPGetDatum(box))))
 	{
 		box_cn(&point, box);
 		PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
 											PointPGetDatum(&point),
 											LsegPGetDatum(lseg)));
 	}
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
 	dist = lseg_dt(lseg, &bseg);
 
 	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	d = lseg_dt(lseg, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&bseg, &seg, sizeof(bseg));
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&seg, &box->low, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	d = lseg_dt(lseg, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&bseg, &seg, sizeof(bseg));
 	}
 
 	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	d = lseg_dt(lseg, &seg);
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		memcpy(&bseg, &seg, sizeof(bseg));
 	}
 
 	/* OK, we now have the closest line segment on the box boundary */
 	PG_RETURN_DATUM(DirectFunctionCall2(close_lseg,
 										LsegPGetDatum(lseg),
 										LsegPGetDatum(&bseg)));
 }
@@ -3058,50 +3049,55 @@ on_ps(PG_FUNCTION_ARGS)
 
 	PG_RETURN_BOOL(on_ps_internal(pt, lseg));
 }
 
 /*
  * Implementation of operator point on line segment
  */
 static bool
 on_ps_internal(Point *pt, LSEG *lseg)
 {
-	return FPeq(point_dt(pt, &lseg->p[0]) + point_dt(pt, &lseg->p[1]),
+	return FPeq(float8_pl(point_dt(pt, &lseg->p[0]),
+						  point_dt(pt, &lseg->p[1])),
 				point_dt(&lseg->p[0], &lseg->p[1]));
 }
 
 
 /*
  * Check whether the point is in the box or on its border
  */
 Datum
 on_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_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);
+	PG_RETURN_BOOL(float8_le(pt->x, box->high.x) &&
+				   float8_ge(pt->x, box->low.x) &&
+				   float8_le(pt->y, box->high.y) &&
+				   float8_ge(pt->y, box->low.y));
 }
 
 
 /*
  * Commutator of on_pb()
  */
 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);
+	PG_RETURN_BOOL(float8_le(pt->x, box->high.x) &&
+				   float8_ge(pt->x, box->low.x) &&
+				   float8_le(pt->y, box->high.y) &&
+				   float8_ge(pt->y, box->low.y));
 }
 
 
 /* on_ppath -
  *		Whether a point lies within (on) a polyline.
  *		If open, we have to (groan) check each segment.
  * (uses same algorithm as for point intersecting segment - tgl 1997-07-09)
  *		If closed, we use the old O(n) ray method for point-in-polygon.
  *				The ray is horizontal, from pt out to the right.
  *				Each segment that crosses the ray counts as an
@@ -3109,33 +3105,32 @@ box_contain_pt(PG_FUNCTION_ARGS)
  *				but not cross.
  *				(we can do p-in-p in lg(n), but it takes preprocessing)
  */
 Datum
 on_ppath(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	PATH	   *path = PG_GETARG_PATH_P(1);
 	int			i,
 				n;
-	double		a,
+	float8		a,
 				b;
 
 	/*-- OPEN --*/
 	if (!path->closed)
 	{
 		n = path->npts - 1;
 		a = point_dt(pt, &path->p[0]);
 		for (i = 0; i < n; i++)
 		{
 			b = point_dt(pt, &path->p[i + 1]);
-			if (FPeq(a + b,
-					 point_dt(&path->p[i], &path->p[i + 1])))
+			if (FPeq(float8_pl(a, b), point_dt(&path->p[i], &path->p[i + 1])))
 				PG_RETURN_BOOL(true);
 			a = b;
 		}
 		PG_RETURN_BOOL(false);
 	}
 
 	/*-- CLOSED --*/
 	PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
 }
 
@@ -3205,24 +3200,24 @@ inter_sl(PG_FUNCTION_ARGS)
  */
 Datum
 inter_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	BOX			lbox;
 	LSEG		bseg;
 	Point		point;
 
-	lbox.low.x = Min(lseg->p[0].x, lseg->p[1].x);
-	lbox.low.y = Min(lseg->p[0].y, lseg->p[1].y);
-	lbox.high.x = Max(lseg->p[0].x, lseg->p[1].x);
-	lbox.high.y = Max(lseg->p[0].y, lseg->p[1].y);
+	lbox.low.x = float8_min(lseg->p[0].x, lseg->p[1].x);
+	lbox.low.y = float8_min(lseg->p[0].y, lseg->p[1].y);
+	lbox.high.x = float8_max(lseg->p[0].x, lseg->p[1].x);
+	lbox.high.y = float8_max(lseg->p[0].y, lseg->p[1].y);
 
 	/* nothing close to overlap? then not going to intersect */
 	if (!box_ov(&lbox, box))
 		PG_RETURN_BOOL(false);
 
 	/* an endpoint of segment is inside box? then clearly intersects */
 	if (DatumGetBool(DirectFunctionCall2(on_pb,
 										 PointPGetDatum(&lseg->p[0]),
 										 BoxPGetDatum(box))) ||
 		DatumGetBool(DirectFunctionCall2(on_pb,
@@ -3311,27 +3306,27 @@ make_bound_box(POLYGON *poly)
 {
 	int			i;
 	BOX		   *boundbox = &poly->boundbox;
 
 	Assert(poly->npts > 0);
 
 	boundbox->low.x = boundbox->high.x = poly->p[0].x;
 	boundbox->low.y = boundbox->high.y = poly->p[0].y;
 	for (i = 1; i < poly->npts; i++)
 	{
-		if (poly->p[i].x < boundbox->low.x)
+		if (float8_lt(poly->p[i].x, boundbox->low.x))
 			boundbox->low.x = poly->p[i].x;
-		if (poly->p[i].x > boundbox->high.x)
+		if (float8_gt(poly->p[i].x, boundbox->high.x))
 			boundbox->high.x = poly->p[i].x;
-		if (poly->p[i].y < boundbox->low.y)
+		if (float8_lt(poly->p[i].y, boundbox->low.y))
 			boundbox->low.y = poly->p[i].y;
-		if (poly->p[i].y > boundbox->high.y)
+		if (float8_gt(poly->p[i].y, boundbox->high.y))
 			boundbox->high.y = poly->p[i].y;
 	}
 }
 
 /*------------------------------------------------------------------
  * poly_in - read in the polygon from a string specification
  *
  *		External format:
  *				"((x0,y0),...,(xn,yn))"
  *				"x0,y0,...,xn,yn"
@@ -3452,21 +3447,21 @@ poly_send(PG_FUNCTION_ARGS)
  * the right most point of A left of the left most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_left(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.high.x < polyb->boundbox.low.x;
+	result = float8_lt(polya->boundbox.high.x, polyb->boundbox.low.x);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3475,21 +3470,21 @@ poly_left(PG_FUNCTION_ARGS)
  * the right most point of A at or left of the right most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_overleft(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.high.x <= polyb->boundbox.high.x;
+	result = float8_le(polya->boundbox.high.x, polyb->boundbox.high.x);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3498,21 +3493,21 @@ poly_overleft(PG_FUNCTION_ARGS)
  * the left most point of A right of the right most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_right(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.low.x > polyb->boundbox.high.x;
+	result = float8_gt(polya->boundbox.low.x, polyb->boundbox.high.x);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3521,21 +3516,21 @@ poly_right(PG_FUNCTION_ARGS)
  * the left most point of A at or right of the left most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_overright(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.low.x >= polyb->boundbox.low.x;
+	result = float8_ge(polya->boundbox.low.x, polyb->boundbox.low.x);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3544,21 +3539,21 @@ poly_overright(PG_FUNCTION_ARGS)
  * the upper most point of A below the lower most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_below(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.high.y < polyb->boundbox.low.y;
+	result = float8_lt(polya->boundbox.high.y, polyb->boundbox.low.y);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3567,21 +3562,21 @@ poly_below(PG_FUNCTION_ARGS)
  * the upper most point of A at or below the upper most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_overbelow(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.high.y <= polyb->boundbox.high.y;
+	result = float8_le(polya->boundbox.high.y, polyb->boundbox.high.y);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3590,21 +3585,21 @@ poly_overbelow(PG_FUNCTION_ARGS)
  * the lower most point of A above the upper most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_above(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.low.y > polyb->boundbox.high.y;
+	result = float8_gt(polya->boundbox.low.y, polyb->boundbox.high.y);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3613,21 +3608,21 @@ poly_above(PG_FUNCTION_ARGS)
  * the lower most point of A at or above the lower most point
  * of B?
  *-------------------------------------------------------*/
 Datum
 poly_overabove(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	result = polya->boundbox.low.y >= polyb->boundbox.low.y;
+	result = float8_ge(polya->boundbox.low.y, polyb->boundbox.low.y);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
@@ -3824,22 +3819,22 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 	}
 
 	if (res && !intersection)
 	{
 		Point		p;
 
 		/*
 		 * if X-intersection wasn't found  then check central point of tested
 		 * segment. In opposite case we already check all subsegments
 		 */
-		p.x = (t.p[0].x + t.p[1].x) / 2.0;
-		p.y = (t.p[0].y + t.p[1].y) / 2.0;
+		p.x = float8_div(float8_pl(t.p[0].x, t.p[1].x), 2.0);
+		p.y = float8_div(float8_pl(t.p[0].y, t.p[1].y), 2.0);
 
 		res = point_inside(&p, poly->npts, poly->p);
 	}
 
 	return res;
 }
 
 /*-----------------------------------------------------------------
  * Determine if polygon A contains polygon B.
  *-----------------------------------------------------------------*/
@@ -3966,22 +3961,22 @@ point_add(PG_FUNCTION_ARGS)
 
 	point_add_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static inline void
 point_add_internal(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x + pt2->x,
-					pt1->y + pt2->y);
+					float8_pl(pt1->x, pt2->x),
+					float8_pl(pt1->y, pt2->y));
 }
 
 
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
@@ -3989,22 +3984,22 @@ point_sub(PG_FUNCTION_ARGS)
 
 	point_sub_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static inline void
 point_sub_internal(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x - pt2->x,
-					pt1->y - pt2->y);
+					float8_mi(pt1->x, pt2->x),
+					float8_mi(pt1->y, pt2->y));
 }
 
 
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
@@ -4012,22 +4007,24 @@ point_mul(PG_FUNCTION_ARGS)
 
 	point_mul_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static inline void
 point_mul_internal(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					(pt1->x * pt2->x) - (pt1->y * pt2->y),
-					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+					float8_mi(float8_mul(pt1->x, pt2->x),
+							  float8_mul(pt1->y, pt2->y)),
+					float8_pl(float8_mul(pt1->x, pt2->y),
+							  float8_mul(pt1->y, pt2->x)));
 }
 
 
 Datum
 point_div(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
@@ -4036,24 +4033,26 @@ point_div(PG_FUNCTION_ARGS)
 	point_div_internal(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 static inline void
 point_div_internal(Point *result, Point *pt1, Point *pt2)
 {
 	float8		div;
 
-	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
+	div = float8_pl(float8_mul(pt2->x, pt2->x), float8_mul(pt2->y, pt2->y));
 	point_construct(result,
-					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
-					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+					float8_div(float8_pl(float8_mul(pt1->x, pt2->x),
+										 float8_mul(pt1->y, pt2->y)), div),
+					float8_div(float8_mi(float8_mul(pt1->y, pt2->x),
+										 float8_mul(pt1->x, pt2->y)), div));
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D boxes.
  **
  ***********************************************************************/
 
 Datum
@@ -4162,24 +4161,24 @@ point_box(PG_FUNCTION_ARGS)
  */
 Datum
 boxes_bound_box(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0),
 			   *box2 = PG_GETARG_BOX_P(1),
 			   *container;
 
 	container = (BOX *) palloc(sizeof(BOX));
 
-	container->high.x = Max(box1->high.x, box2->high.x);
-	container->low.x = Min(box1->low.x, box2->low.x);
-	container->high.y = Max(box1->high.y, box2->high.y);
-	container->low.y = Min(box1->low.y, box2->low.y);
+	container->high.x = float8_max(box1->high.x, box2->high.x);
+	container->low.x = float8_min(box1->low.x, box2->low.x);
+	container->high.y = float8_max(box1->high.y, box2->high.y);
+	container->low.y = float8_min(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(container);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D paths.
  **
  ***********************************************************************/
@@ -4487,21 +4486,21 @@ circle_in(PG_FUNCTION_ARGS)
 		if (*cp == LDELIM)
 			s = cp;
 	}
 
 	pair_decode(s, &circle->center.x, &circle->center.y, &s, "circle", str);
 
 	if (*s == DELIM)
 		s++;
 
 	circle->radius = single_decode(s, &s, "circle", str);
-	if (circle->radius < 0)
+	if (float8_lt(circle->radius, 0.0))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
 
 	while (depth > 0)
 	{
 		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
@@ -4554,21 +4553,21 @@ circle_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	circle->center.x = pq_getmsgfloat8(buf);
 	circle->center.y = pq_getmsgfloat8(buf);
 	circle->radius = pq_getmsgfloat8(buf);
 
-	if (circle->radius < 0)
+	if (float8_lt(circle->radius, 0.0))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
 				 errmsg("invalid radius in external \"circle\" value")));
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 /*
  *		circle_send			- converts circle to binary format
  */
@@ -4605,144 +4604,146 @@ circle_same(PG_FUNCTION_ARGS)
 
 /*		circle_overlap	-		does circle1 overlap circle2?
  */
 Datum
 circle_overlap(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle1->radius + circle2->radius));
+						float8_pl(circle1->radius, circle2->radius)));
 }
 
 /*		circle_overleft -		is the right edge of circle1 at or left of
  *								the right edge of circle2?
  */
 Datum
 circle_overleft(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.x + circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_left		-		is circle1 strictly left of circle2?
  */
 Datum
 circle_left(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.x + circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_right	-		is circle1 strictly right of circle2?
  */
 Datum
 circle_right(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.x - circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_overright	-	is the left edge of circle1 at or right of
  *								the left edge of circle2?
  */
 Datum
 circle_overright(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.x - circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_contained		-		is circle1 contained by circle2?
  */
 Datum
 circle_contained(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle1->radius), circle2->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						float8_mi(circle2->radius, circle1->radius)));
 }
 
 /*		circle_contain	-		does circle1 contain circle2?
  */
 Datum
 circle_contain(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle2->radius), circle1->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						float8_mi(circle1->radius, circle2->radius)));
 }
 
 
 /*		circle_below		-		is circle1 strictly below circle2?
  */
 Datum
 circle_below(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.y + circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_above	-		is circle1 strictly above circle2?
  */
 Datum
 circle_above(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.y - circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overbelow -		is the upper edge of circle1 at or below
  *								the upper edge of circle2?
  */
 Datum
 circle_overbelow(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.y + circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overabove	-	is the lower edge of circle1 at or above
  *								the lower edge of circle2?
  */
 Datum
 circle_overabove(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.y - circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 
 /*		circle_relop	-		is area(circle1) relop area(circle2), within
  *								our accuracy constraint?
  */
 Datum
 circle_eq(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
@@ -4841,36 +4842,36 @@ circle_sub_pt(PG_FUNCTION_ARGS)
 Datum
 circle_mul_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_mul_internal(&result->center, &circle->center, point);
-	result->radius *= HYPOT(point->x, point->y);
+	result->radius = float8_mul(circle->radius, HYPOT(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_div_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_div_internal(&result->center, &circle->center, point);
-	result->radius /= HYPOT(point->x, point->y);
+	result->radius = float8_div(circle->radius, HYPOT(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /*		circle_area		-		returns the area of the circle.
  */
 Datum
 circle_area(PG_FUNCTION_ARGS)
 {
@@ -4880,21 +4881,21 @@ circle_area(PG_FUNCTION_ARGS)
 }
 
 
 /*		circle_diameter -		returns the diameter of the circle.
  */
 Datum
 circle_diameter(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
-	PG_RETURN_FLOAT8(2 * circle->radius);
+	PG_RETURN_FLOAT8(float8_mul(circle->radius, 2.0));
 }
 
 
 /*		circle_radius	-		returns the radius of the circle.
  */
 Datum
 circle_radius(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
@@ -4905,81 +4906,84 @@ circle_radius(PG_FUNCTION_ARGS)
 /*		circle_distance -		returns the distance between
  *								  two circles.
  */
 Datum
 circle_distance(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(&circle1->center, &circle2->center) -
-		(circle1->radius + circle2->radius);
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(&circle1->center, &circle2->center),
+					   float8_pl(circle1->radius, circle2->radius));
+	if (float8_lt(result, 0.0))
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 
 Datum
 circle_contain_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
-	PG_RETURN_BOOL(d <= circle->radius);
+	PG_RETURN_BOOL(float8_le(d, circle->radius));
 }
 
 
 Datum
 pt_contained_circle(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
-	PG_RETURN_BOOL(d <= circle->radius);
+	PG_RETURN_BOOL(float8_le(d, circle->radius));
 }
 
 
 /*		dist_pc -		returns the distance between
  *						  a point and a circle.
  */
 Datum
 dist_pc(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center), circle->radius);
+	if (float8_lt(result, 0.0))
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a circle to a point
  */
 Datum
 dist_cpoint(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center), circle->radius);
+	if (float8_lt(result, 0.0))
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*		circle_center	-		returns the center point of the circle.
  */
 Datum
 circle_center(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *result;
@@ -4987,24 +4991,24 @@ circle_center(PG_FUNCTION_ARGS)
 	result = (Point *) palloc(sizeof(Point));
 	result->x = circle->center.x;
 	result->y = circle->center.y;
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		circle_ar		-		returns the area of the circle.
  */
-static double
+static float8
 circle_ar(CIRCLE *circle)
 {
-	return M_PI * (circle->radius * circle->radius);
+	return float8_mul(float8_mul(circle->radius, circle->radius), M_PI);
 }
 
 
 /*----------------------------------------------------------
  *	Conversion operators.
  *---------------------------------------------------------*/
 
 Datum
 cr_circle(PG_FUNCTION_ARGS)
 {
@@ -5019,65 +5023,65 @@ cr_circle(PG_FUNCTION_ARGS)
 	result->radius = radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_box(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	BOX		   *box;
-	double		delta;
+	float8		delta;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
-	delta = circle->radius / sqrt(2.0);
+	delta = float8_div(circle->radius, sqrt(2.0));
 
-	box->high.x = circle->center.x + delta;
-	box->low.x = circle->center.x - delta;
-	box->high.y = circle->center.y + delta;
-	box->low.y = circle->center.y - delta;
+	box->high.x = float8_pl(circle->center.x, delta);
+	box->low.x = float8_mi(circle->center.x, delta);
+	box->high.y = float8_pl(circle->center.y, delta);
+	box->low.y = float8_mi(circle->center.y, delta);
 
 	PG_RETURN_BOX_P(box);
 }
 
 /* box_circle()
  * Convert a box to a circle.
  */
 Datum
 box_circle(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	circle->center.x = (box->high.x + box->low.x) / 2;
-	circle->center.y = (box->high.y + box->low.y) / 2;
+	circle->center.x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	circle->center.y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 
 	circle->radius = point_dt(&circle->center, &box->high);
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 
 Datum
 circle_poly(PG_FUNCTION_ARGS)
 {
 	int32		npts = PG_GETARG_INT32(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	POLYGON    *poly;
 	int			base_size,
 				size;
 	int			i;
-	double		angle;
-	double		anglestep;
+	float8		angle;
+	float8		anglestep;
 
 	if (FPzero(circle->radius))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("cannot convert circle with radius zero to polygon")));
 
 	if (npts < 2)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("must request at least 2 points")));
@@ -5088,27 +5092,30 @@ circle_poly(PG_FUNCTION_ARGS)
 	/* Check for integer overflow */
 	if (base_size / npts != sizeof(poly->p[0]) || size <= base_size)
 		ereport(ERROR,
 				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 				 errmsg("too many points requested")));
 
 	poly = (POLYGON *) palloc0(size);	/* zero any holes */
 	SET_VARSIZE(poly, size);
 	poly->npts = npts;
 
-	anglestep = (2.0 * M_PI) / npts;
+	anglestep = float8_div(2.0 * M_PI, npts);
 
 	for (i = 0; i < npts; i++)
 	{
-		angle = i * anglestep;
-		poly->p[i].x = circle->center.x - (circle->radius * cos(angle));
-		poly->p[i].y = circle->center.y + (circle->radius * sin(angle));
+		angle = float8_mul(anglestep, i);
+
+		poly->p[i].x = float8_mi(circle->center.x,
+								 float8_mul(circle->radius, cos(angle)));
+		poly->p[i].y = float8_pl(circle->center.y,
+								 float8_mul(circle->radius, sin(angle)));
 	}
 
 	make_bound_box(poly);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
 /*		poly_circle		- convert polygon to circle
  *
  * XXX This algorithm should use weighted means of line segments
@@ -5124,29 +5131,30 @@ poly_circle(PG_FUNCTION_ARGS)
 	Assert(poly->npts > 0);
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	circle->center.x = 0;
 	circle->center.y = 0;
 	circle->radius = 0;
 
 	for (i = 0; i < poly->npts; i++)
 	{
-		circle->center.x += poly->p[i].x;
-		circle->center.y += poly->p[i].y;
+		circle->center.x = float8_pl(circle->center.x, poly->p[i].x);
+		circle->center.y = float8_pl(circle->center.y, poly->p[i].y);
 	}
-	circle->center.x /= poly->npts;
-	circle->center.y /= poly->npts;
+	circle->center.x = float8_div(circle->center.x, poly->npts);
+	circle->center.y = float8_div(circle->center.y, poly->npts);
 
 	for (i = 0; i < poly->npts; i++)
-		circle->radius += point_dt(&poly->p[i], &circle->center);
-	circle->radius /= poly->npts;
+		circle->radius = float8_pl(circle->radius, point_dt(&poly->p[i],
+															&circle->center));
+	circle->radius = float8_div(circle->radius, poly->npts);
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 
 /***********************************************************************
  **
  **		Private routines for multiple types.
  **
  ***********************************************************************/
@@ -5160,44 +5168,44 @@ poly_circle(PG_FUNCTION_ARGS)
  *	http://hopf.math.northwestern.edu/index.html
  *	Description of algorithm:  http://www.linuxjournal.com/article/2197
  *							   http://www.linuxjournal.com/article/2029
  */
 
 #define POINT_ON_POLYGON INT_MAX
 
 static int
 point_inside(Point *p, int npts, Point *plist)
 {
-	double		x0,
+	float8		x0,
 				y0;
-	double		prev_x,
+	float8		prev_x,
 				prev_y;
 	int			i = 0;
-	double		x,
+	float8		x,
 				y;
 	int			cross,
 				total_cross = 0;
 
 	Assert(npts > 0);
 
 	/* compute first polygon point relative to single point */
-	x0 = plist[0].x - p->x;
-	y0 = plist[0].y - p->y;
+	x0 = float8_mi(plist[0].x, p->x);
+	y0 = float8_mi(plist[0].y, p->y);
 
 	prev_x = x0;
 	prev_y = y0;
 	/* loop over polygon points and aggregate total_cross */
 	for (i = 1; i < npts; i++)
 	{
 		/* compute next polygon point relative to single point */
-		x = plist[i].x - p->x;
-		y = plist[i].y - p->y;
+		x = float8_mi(plist[i].x, p->x);
+		y = float8_mi(plist[i].y, p->y);
 
 		/* compute previous to current point crossing */
 		if ((cross = lseg_crossing(x, y, prev_x, prev_y)) == POINT_ON_POLYGON)
 			return 2;
 		total_cross += cross;
 
 		prev_x = x;
 		prev_y = y;
 	}
 
@@ -5215,69 +5223,74 @@ point_inside(Point *p, int npts, Point *plist)
 /* lseg_crossing()
  * Returns +/-2 if line segment crosses the positive X-axis in a +/- direction.
  * Returns +/-1 if one point is on the positive X-axis.
  * Returns 0 if both points are on the positive X-axis, or there is no crossing.
  * Returns POINT_ON_POLYGON if the segment contains (0,0).
  * Wow, that is one confusing API, but it is used above, and when summed,
  * can tell is if a point is in a polygon.
  */
 
 static int
-lseg_crossing(double x, double y, double prev_x, double prev_y)
+lseg_crossing(float8 x, float8 y, float8 prev_x, float8 prev_y)
 {
-	double		z;
+	float8		z;
 	int			y_sign;
 
 	if (FPzero(y))
 	{							/* y == 0, on X axis */
 		if (FPzero(x))			/* (x,y) is (0,0)? */
 			return POINT_ON_POLYGON;
 		else if (FPgt(x, 0))
 		{						/* x > 0 */
 			if (FPzero(prev_y)) /* y and prev_y are zero */
 				/* prev_x > 0? */
-				return FPgt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
-			return FPlt(prev_y, 0) ? 1 : -1;
+				return FPgt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
+			return FPlt(prev_y, 0.0) ? 1 : -1;
 		}
 		else
 		{						/* x < 0, x not on positive X axis */
 			if (FPzero(prev_y))
 				/* prev_x < 0? */
-				return FPlt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
+				return FPlt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
 			return 0;
 		}
 	}
 	else
 	{							/* y != 0 */
 		/* compute y crossing direction from previous point */
-		y_sign = FPgt(y, 0) ? 1 : -1;
+		y_sign = FPgt(y, 0.0) ? 1 : -1;
 
 		if (FPzero(prev_y))
 			/* previous point was on X axis, so new point is either off or on */
-			return FPlt(prev_x, 0) ? 0 : y_sign;
-		else if (FPgt(y_sign * prev_y, 0))
+			return FPlt(prev_x, 0.0) ? 0 : y_sign;
+		else if ((y_sign < 0 && FPlt(prev_y, 0.0)) ||
+				 (y_sign > 0 && FPgt(prev_y, 0.0)))
 			/* both above or below X axis */
 			return 0;			/* same sign */
 		else
 		{						/* y and prev_y cross X-axis */
-			if (FPge(x, 0) && FPgt(prev_x, 0))
+			if (FPge(x, 0.0) && FPgt(prev_x, 0.0))
 				/* both non-negative so cross positive X-axis */
 				return 2 * y_sign;
-			if (FPlt(x, 0) && FPle(prev_x, 0))
+			if (FPlt(x, 0.0) && FPle(prev_x, 0.0))
 				/* both non-positive so do not cross positive X-axis */
 				return 0;
 
 			/* x and y cross axises, see URL above point_inside() */
-			z = (x - prev_x) * y - (y - prev_y) * x;
+			z = float8_mi(float8_mul(float8_mi(x, prev_x), y),
+						  float8_mul(float8_mi(y, prev_y), x));
 			if (FPzero(z))
 				return POINT_ON_POLYGON;
-			return FPgt((y_sign * z), 0) ? 0 : 2 * y_sign;
+			if ((y_sign < 0 && FPlt(z, 0.0)) ||
+				(y_sign > 0 && FPgt(z, 0.0)))
+				return 0;
+			return 2 * y_sign;
 		}
 	}
 }
 
 
 static bool
 plist_same(int npts, Point *p1, Point *p2)
 {
 	int			i,
 				ii,
@@ -5347,47 +5360,53 @@ plist_same(int npts, Point *p1, Point *p2)
  *					 = x * sqrt( 1 + y^2/x^2 )
  *					 = x * sqrt( 1 + y/x * y/x )
  *
  * It is expected that this routine will eventually be replaced with the
  * C99 hypot() function.
  *
  * This implementation conforms to IEEE Std 1003.1 and GLIBC, in that the
  * case of hypot(inf,nan) results in INF, and not NAN.
  *-----------------------------------------------------------------------
  */
-double
-pg_hypot(double x, double y)
+float8
+pg_hypot(float8 x, float8 y)
 {
-	double		yx;
+	float8		yx,
+				result;
 
 	/* Handle INF and NaN properly */
 	if (isinf(x) || isinf(y))
 		return get_float8_infinity();
 
 	if (isnan(x) || isnan(y))
 		return get_float8_nan();
 
 	/* Else, drop any minus signs */
 	x = fabs(x);
 	y = fabs(y);
 
 	/* Swap x and y if needed to make x the larger one */
 	if (x < y)
 	{
-		double		temp = x;
+		float8		temp = x;
 
 		x = y;
 		y = temp;
 	}
 
 	/*
 	 * If y is zero, the hypotenuse is x.  This test saves a few cycles in
 	 * such cases, but more importantly it also protects against
 	 * divide-by-zero errors, since now x >= y.
 	 */
 	if (y == 0.0)
 		return x;
 
 	/* Determine the hypotenuse */
 	yx = y / x;
-	return x * sqrt(1.0 + (yx * yx));
+	result = x * sqrt(1.0 + (yx * yx));
+
+	check_float8_val(result, false, false);
+	Assert(result >= 0.0);
+
+	return result;
 }
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index c800bb1338..f62be1061e 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -76,38 +76,38 @@
 #include "access/spgist.h"
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
 #include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
- * is going only going to be used in a place to effect the performance
+ * is only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
 compareDoubles(const void *a, const void *b)
 {
-	double		x = *(double *) a;
-	double		y = *(double *) b;
+	float8		x = *(float8 *) a;
+	float8		y = *(float8 *) b;
 
 	if (x == y)
 		return 0;
 	return (x > y) ? 1 : -1;
 }
 
 typedef struct
 {
-	double		low;
-	double		high;
+	float8		low;
+	float8		high;
 } Range;
 
 typedef struct
 {
 	Range		left;
 	Range		right;
 } RangeBox;
 
 typedef struct
 {
@@ -121,30 +121,30 @@ typedef struct
  * The quadrant is 8 bit unsigned integer with 4 least bits in use.
  * This function accepts BOXes as input.  They are not casted to
  * RangeBoxes, yet.  All 4 bits are set by comparing a corner of the box.
  * This makes 16 quadrants in total.
  */
 static uint8
 getQuadrant(BOX *centroid, BOX *inBox)
 {
 	uint8		quadrant = 0;
 
-	if (inBox->low.x > centroid->low.x)
+	if (float8_gt(inBox->low.x, centroid->low.x))
 		quadrant |= 0x8;
 
-	if (inBox->high.x > centroid->high.x)
+	if (float8_gt(inBox->high.x, centroid->high.x))
 		quadrant |= 0x4;
 
-	if (inBox->low.y > centroid->low.y)
+	if (float8_gt(inBox->low.y, centroid->low.y))
 		quadrant |= 0x2;
 
-	if (inBox->high.y > centroid->high.y)
+	if (float8_gt(inBox->high.y, centroid->high.y))
 		quadrant |= 0x1;
 
 	return quadrant;
 }
 
 /*
  * Get RangeBox using BOX
  *
  * We are turning the BOX to our structures to emphasize their function
  * of representing points in 4D space.  It also is more convenient to
@@ -167,21 +167,21 @@ getRangeBox(BOX *box)
 /*
  * Initialize the traversal value
  *
  * In the beginning, we don't have any restrictions.  We have to
  * initialize the struct to cover the whole 4D space.
  */
 static RectBox *
 initRectBox(void)
 {
 	RectBox    *rect_box = (RectBox *) palloc(sizeof(RectBox));
-	double		infinity = get_float8_infinity();
+	float8		infinity = get_float8_infinity();
 
 	rect_box->range_box_x.left.low = -infinity;
 	rect_box->range_box_x.left.high = infinity;
 
 	rect_box->range_box_x.right.low = -infinity;
 	rect_box->range_box_x.right.high = infinity;
 
 	rect_box->range_box_y.left.low = -infinity;
 	rect_box->range_box_y.left.high = infinity;
 
@@ -410,40 +410,40 @@ spg_box_quad_choose(PG_FUNCTION_ARGS)
  * point as the median of the coordinates of the boxes.
  */
 Datum
 spg_box_quad_picksplit(PG_FUNCTION_ARGS)
 {
 	spgPickSplitIn *in = (spgPickSplitIn *) PG_GETARG_POINTER(0);
 	spgPickSplitOut *out = (spgPickSplitOut *) PG_GETARG_POINTER(1);
 	BOX		   *centroid;
 	int			median,
 				i;
-	double	   *lowXs = palloc(sizeof(double) * in->nTuples);
-	double	   *highXs = palloc(sizeof(double) * in->nTuples);
-	double	   *lowYs = palloc(sizeof(double) * in->nTuples);
-	double	   *highYs = palloc(sizeof(double) * in->nTuples);
+	float8	   *lowXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *lowYs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highYs = palloc(sizeof(float8) * in->nTuples);
 
 	/* Calculate median of all 4D coordinates */
 	for (i = 0; i < in->nTuples; i++)
 	{
 		BOX		   *box = DatumGetBoxP(in->datums[i]);
 
 		lowXs[i] = box->low.x;
 		highXs[i] = box->high.x;
 		lowYs[i] = box->low.y;
 		highYs[i] = box->high.y;
 	}
 
-	qsort(lowXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(lowYs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highYs, in->nTuples, sizeof(double), compareDoubles);
+	qsort(lowXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(lowYs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highYs, in->nTuples, sizeof(float8), compareDoubles);
 
 	median = in->nTuples / 2;
 
 	centroid = palloc(sizeof(BOX));
 
 	centroid->low.x = lowXs[median];
 	centroid->high.x = highXs[median];
 	centroid->low.y = lowYs[median];
 	centroid->high.y = highYs[median];
 
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index ea2e3690ea..1ea8722f47 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -1,23 +1,20 @@
 /*-------------------------------------------------------------------------
  *
  * geo_decls.h - Declarations for various 2D constructs.
  *
  *
  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * src/include/utils/geo_decls.h
  *
- * NOTE
- *	  These routines do *not* use the float types from adt/.
- *
  *	  XXX These routines were not written by a numerical analyst.
  *
  *	  XXX I have made some attempt to flesh out the operators
  *		and data types. There are still some more to do. - tgl 97/04/19
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEO_DECLS_H
 #define GEO_DECLS_H
 
@@ -28,44 +25,44 @@
 
 /*--------------------------------------------------------------------
  * Useful floating point utilities and constants.
  *-------------------------------------------------------------------*/
 
 
 #define EPSILON					1.0E-06
 
 #ifdef EPSILON
 #define FPzero(A)				(fabs(A) <= EPSILON)
-#define FPeq(A,B)				(fabs((A) - (B)) <= EPSILON)
-#define FPne(A,B)				(fabs((A) - (B)) > EPSILON)
-#define FPlt(A,B)				((B) - (A) > EPSILON)
-#define FPle(A,B)				((A) - (B) <= EPSILON)
-#define FPgt(A,B)				((A) - (B) > EPSILON)
-#define FPge(A,B)				((B) - (A) <= EPSILON)
+#define FPeq(A, B)				(float8_le(fabs(float8_mi(A, B)), EPSILON))
+#define FPne(A, B)				(float8_gt(fabs(float8_mi(A, B)), EPSILON))
+#define FPlt(A, B)				(float8_gt(float8_mi(B, A), EPSILON))
+#define FPle(A, B)				(float8_le(float8_mi(A, B), EPSILON))
+#define FPgt(A, B)				(float8_gt(float8_mi(A, B), EPSILON))
+#define FPge(A, B)				(float8_le(float8_mi(B, A), EPSILON))
 #else
-#define FPzero(A)				((A) == 0)
-#define FPeq(A,B)				((A) == (B))
-#define FPne(A,B)				((A) != (B))
-#define FPlt(A,B)				((A) < (B))
-#define FPle(A,B)				((A) <= (B))
-#define FPgt(A,B)				((A) > (B))
-#define FPge(A,B)				((A) >= (B))
+#define FPzero(A)				((A) == 0.0)
+#define FPeq(A, B)				(float8_eq(A, B))
+#define FPne(A, B)				(float8_ne(A, B))
+#define FPlt(A, B)				(float8_lt(A, B))
+#define FPle(A, B)				(float8_le(A, B))
+#define FPgt(A, B)				(float8_gt(A, B))
+#define FPge(A, B)				(float8_ge(A, B))
 #endif
 
 #define HYPOT(A, B)				pg_hypot(A, B)
 
 /*---------------------------------------------------------------------
  * Point - (x,y)
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		x,
+	float8		x,
 				y;
 } Point;
 
 
 /*---------------------------------------------------------------------
  * LSEG - A straight line, specified by endpoints.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		p[2];
@@ -73,66 +70,66 @@ typedef struct
 
 
 /*---------------------------------------------------------------------
  * PATH - Specified by vertex points.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	int32		vl_len_;		/* varlena header (do not touch directly!) */
 	int32		npts;
 	int32		closed;			/* is this a closed polygon? */
-	int32		dummy;			/* padding to make it double align */
+	int32		dummy;			/* padding to make it float8 align */
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } PATH;
 
 
 /*---------------------------------------------------------------------
  * LINE - Specified by its general equation (Ax+By+C=0).
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		A,
+	float8		A,
 				B,
 				C;
 } LINE;
 
 
 /*---------------------------------------------------------------------
  * BOX	- Specified by two corner points, which are
  *		 sorted to save calculation time later.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		high,
 				low;			/* corner POINTs */
 } BOX;
 
 /*---------------------------------------------------------------------
- * POLYGON - Specified by an array of doubles defining the points,
+ * POLYGON - Specified by an array of float8s defining the points,
  *		keeping the number of points and the bounding box for
  *		speed purposes.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	int32		vl_len_;		/* varlena header (do not touch directly!) */
 	int32		npts;
 	BOX			boundbox;
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } POLYGON;
 
 /*---------------------------------------------------------------------
  * CIRCLE - Specified by a center point and radius.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		center;
-	double		radius;
+	float8		radius;
 } CIRCLE;
 
 /*
  * fmgr interface macros
  *
  * Path and Polygon are toastable varlena types, the others are just
  * fixed-size pass-by-reference types.
  */
 
 #define DatumGetPointP(X)	 ((Point *) DatumGetPointer(X))
@@ -172,13 +169,13 @@ typedef struct
 #define DatumGetCircleP(X)	  ((CIRCLE *) DatumGetPointer(X))
 #define CirclePGetDatum(X)	  PointerGetDatum(X)
 #define PG_GETARG_CIRCLE_P(n) DatumGetCircleP(PG_GETARG_DATUM(n))
 #define PG_RETURN_CIRCLE_P(x) return CirclePGetDatum(x)
 
 
 /*
  * in geo_ops.c
  */
 
-extern double pg_hypot(double x, double y);
+extern float8 pg_hypot(float8 x, float8 y);
 
 #endif							/* GEO_DECLS_H */
-- 
2.13.6 (Apple Git-96)

0004-line-fixes-v05.patchapplication/octet-stream; name=0004-line-fixes-v05.patchDownload
From 7c0daa810e2d4500638d2c7062c51f1dc9dcefcd Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sun, 28 May 2017 11:35:17 +0200
Subject: [PATCH 4/6] line-fixes-v05

Fix obvious problems around the line datatype

I have noticed some line operators retuning wrong results, and Tom Lane
spotted similar problems on more places.  Source history reveals that
during 1990s, the internal format of the line datatype is changed, but
most functions haven't got the hint.  The fixes include:

* Reject invalid specification A=B=0 on receive
* Avoid division by zero on perpendicular operator
* Fix intersection and distance operators when neither A nor B are 1
* Avoid point to line operators crashing on floating point precision loss
* Don't return NULL for closest point to line segment
* Fix closest point to line segment from line segment

The changes are also aiming make line operators more symmetric and less
sensitive to floating point precision loss.  The EPSILON interferes with
every minor change in different ways.  It is hard to guess which
behaviour is more expected, but we can assume threating both sides of
the operators more equally is more expected.

Previous discussion:
https://www.postgresql.org/message-id/flat/CAE2gYzw_-z%3DV2kh8QqFjenu%3D8MJXzOP44wRW%3DAzzeamrmTT1%3DQ%40mail.gmail.com
---
 src/backend/utils/adt/geo_ops.c | 115 ++++++++++++++++++++++++----------------
 1 file changed, 68 insertions(+), 47 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 2daa8e12cb..77dc0df5a7 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -972,20 +972,25 @@ line_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LINE	   *line;
 
 	line = (LINE *) palloc(sizeof(LINE));
 
 	line->A = pq_getmsgfloat8(buf);
 	line->B = pq_getmsgfloat8(buf);
 	line->C = pq_getmsgfloat8(buf);
 
+	if (FPzero(line->A) && FPzero(line->B))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+				 errmsg("invalid line specification: A and B cannot both be zero")));
+
 	PG_RETURN_LINE_P(line);
 }
 
 /*
  *		line_send			- converts line to binary format
  */
 Datum
 line_send(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -1090,25 +1095,28 @@ line_parallel(PG_FUNCTION_ARGS)
 }
 
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
-	else if (FPzero(l1->B))
+	if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
+	if (FPzero(l2->A))
+		PG_RETURN_BOOL(FPzero(l1->B));
+	if (FPzero(l2->B))
+		PG_RETURN_BOOL(FPzero(l1->A));
 
-	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
-								   float8_mul(l1->B, l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(float8_mul(l1->A, l2->B), -float8_mul(l1->B, l2->A)));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
@@ -1120,25 +1128,25 @@ line_horizontal(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(FPzero(line->A));
 }
 
 Datum
 line_eq(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		ratio;
 
-	if (!FPzero(l2->A))
+	if (!FPzero(l1->A) && !FPzero(l2->A))
 		ratio = float8_div(l1->A, l2->A);
-	else if (!FPzero(l2->B))
+	else if (!FPzero(l1->B) && !FPzero(l2->B))
 		ratio = float8_div(l1->B, l2->B);
-	else if (!FPzero(l2->C))
+	else if (!FPzero(l1->C) && !FPzero(l2->C))
 		ratio = float8_div(l1->C, l2->C);
 	else
 		ratio = 1.0;
 
 	PG_RETURN_BOOL(FPeq(l1->A, float8_mul(ratio, l2->A)) &&
 				   FPeq(l1->B, float8_mul(ratio, l2->B)) &&
 				   FPeq(l1->C, float8_mul(ratio, l2->C)));
 }
 
 
@@ -1147,30 +1155,35 @@ line_eq(PG_FUNCTION_ARGS)
  *---------------------------------------------------------*/
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	float8		result;
-	Point		tmp;
+	float8		ratio;
 
 	if (line_interpt_internal(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
-	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
-	point_construct(&tmp, 0.0, l1->C);
-	result = dist_pl_internal(&tmp, l2);
-	PG_RETURN_FLOAT8(result);
+
+	if (!FPzero(l1->A) && !FPzero(l2->A))
+		ratio = float8_div(l1->A, l2->A);
+	else if (!FPzero(l1->B) && !FPzero(l2->B))
+		ratio = float8_div(l1->B, l2->B);
+	else
+		ratio = 1.0;
+
+	PG_RETURN_FLOAT8(float8_div(fabs(float8_mi(l1->C,
+											   float8_mul(ratio, l2->C))),
+								HYPOT(l1->A, l1->B)));
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
@@ -1193,38 +1206,56 @@ line_interpt(PG_FUNCTION_ARGS)
  * NOTE: If the lines are identical then we will find they are parallel
  * and report "no intersection".  This is a little weird, but since
  * there's no *unique* intersection, maybe it's appropriate behavior.
  */
 static bool
 line_interpt_internal(Point *result, LINE *l1, LINE *l2)
 {
 	float8		x,
 				y;
 
-	if (FPzero(l1->B))			/* l1 vertical? */
+	if (FPzero(l1->A))			/* l1 horizontal? */
+	{
+		if (FPzero(l2->A))		/* l2 horizontal? */
+			return false;
+
+		y = float8_div(-l1->C, l1->B);
+		x = float8_div(-float8_pl(float8_mul(l2->B, y), l2->C), l2->A);
+	}
+	else if (FPzero(l2->A))		/* l2 horizontal? */
+	{
+		y = float8_div(-l2->C, l2->B);
+		x = float8_div(-float8_pl(float8_mul(l1->B, y), l1->C), l1->A);
+	}
+	else if (FPzero(l1->B))		/* l1 vertical? */
 	{
 		if (FPzero(l2->B))		/* l2 vertical? */
 			return false;
 
-		x = l1->C;
-		y = float8_pl(float8_mul(l2->A, x), l2->C);
+		x = float8_div(-l1->C, l1->A);
+		y = float8_div(-float8_pl(float8_mul(l2->A, x), l2->C), l2->B);
+	}
+	else if (FPzero(l2->B))		/* l2 vertical? */
+	{
+		x = float8_div(-l2->C, l2->A);
+		y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
 	}
 	else
 	{
-		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
+		if (FPeq(float8_mul(l1->A, l2->B), float8_mul(l2->A, l1->B)))
 			return false;
 
-		if (FPzero(l2->B))
-			x = l2->C;
-		else
-			x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
-		y = float8_pl(float8_mul(l1->A, x), l1->C);
+		x = float8_div(float8_mi(float8_mul(l1->B, l2->C),
+								 float8_mul(l2->B, l1->C)),
+					   float8_mi(float8_mul(l1->A, l2->B),
+								 float8_mul(l2->A, l1->B)));
+		y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
 	}
 	if (result != NULL)
 		point_construct(result, x, y);
 
 #ifdef GEODEBUG
 	printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
 		   DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
 	printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
 #endif
 
@@ -2027,46 +2058,35 @@ lseg_parallel(PG_FUNCTION_ARGS)
 
 	m1 = slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y);
 	m2 = slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y);
 
 	PG_RETURN_BOOL(FPeq(m1, m2));
 }
 
 /* lseg_perp()
  * Determine if two line segments are perpendicular.
  *
- * This code did not get the correct answer for
- *	'((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg
- * So, modified it to check explicitly for slope of vertical line
- *	returned by slope() and the results seem better.
- * - thomas 1998-01-31
+ * We are comparing the slope of the first line segment with the inverse slope
+ * of the second line segment.
  */
 Datum
 lseg_perp(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	float8		m1,
 				m2;
 
 	m1 = slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y);
-	m2 = slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y);
+	m2 = slope(l2->p[0].y, l2->p[1].y, l2->p[1].x, l2->p[0].x);
 
-#ifdef GEODEBUG
-	printf("lseg_perp- slopes are %g and %g\n", m1, m2);
-#endif
-	if (FPzero(m1))
-		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
-	else if (FPzero(m2))
-		PG_RETURN_BOOL(FPeq(m1, DBL_MAX));
-
-	PG_RETURN_BOOL(FPeq(float8_div(m1, m2), -1.0));
+	PG_RETURN_BOOL(FPeq(m1, m2));
 }
 
 Datum
 lseg_vertical(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 
 	PG_RETURN_BOOL(FPeq(lseg->p[0].x, lseg->p[1].x));
 }
 
@@ -2627,34 +2647,38 @@ lseg_interpt_line_internal(Point *result, LSEG *lseg, LINE *line)
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (FPzero(line->B))		/* vertical? */
-		point_construct(result, line->C, pt->y);
+		point_construct(result, float8_div(-line->C, line->A), pt->y);
 	else if (FPzero(line->A))	/* horizontal? */
-		point_construct(result, pt->x, line->C);
+		point_construct(result, pt->x, float8_div(-line->C, line->B));
 	else
 	{
 		LINE		tmp;
 
 		/*
 		 * Drop a perpendicular and find the intersection point
 		 *
-		 * We need to invert the slope to get the perpendicular.
+		 * We need to invert the slope to get the perpendicular.  We might
+		 * lose some precision on the division. It shouldn't be as much
+		 * to turn the line.  If it happens anyway, we will assume the point
+		 * is on the line.
 		 */
 		line_construct_pm(&tmp, pt, float8_div(line->B, line->A));
-		line_interpt_internal(result, &tmp, line);
+		if (!line_interpt_internal(result, &tmp, line))
+			*result = *pt;
 	}
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_ps()
  * Closest point on line segment to specified point.
  * Take the closest endpoint if the point is left, right,
  *	above, or below the segment, otherwise find the intersection
@@ -2756,24 +2780,24 @@ close_ps(PG_FUNCTION_ARGS)
 	 */
 	line_construct_pm(&tmp, pt, invm);
 #ifdef GEODEBUG
 	printf("close_ps- tmp A %f  B %f   C %f\n",
 		   tmp->A, tmp->B, tmp->C);
 #endif
 
 	/*
 	 * ordinarily we should always find an intersection point, but that could
 	 * fail in the presence of NaN coordinates, and perhaps even from simple
-	 * roundoff issues.  Return a SQL NULL if so.
+	 * roundoff issues.  In this case, assume the point is on the line segment.
 	 */
 	if (!lseg_interpt_line_internal(result, lseg, &tmp))
-		PG_RETURN_NULL();
+		*result = *pt;
 
 #ifdef GEODEBUG
 	printf("close_ps- result.x %f  result.y %f\n", result->x, result->y);
 #endif
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_lseg()
  * Closest point to l1 on l2.
@@ -2799,28 +2823,25 @@ close_lseg(PG_FUNCTION_ARGS)
 	dists2[0] = dist_ps_internal(&l2->p[0], l1);
 	dists2[1] = dist_ps_internal(&l2->p[1], l1);
 	if (float8_le(dists2[0], dists2[1]))
 		closer_end2 = 0;
 	else
 		closer_end2 = 1;
 
 	if (float8_le(dists1[closer_end1], dists2[closer_end2]))
 		point = PointPGetDatum(&l1->p[closer_end1]);
 	else
-	{
 		point = DirectFunctionCall2(close_ps,
 									PointPGetDatum(&l2->p[closer_end2]),
 									LsegPGetDatum(l1));
-		point = DirectFunctionCall2(close_ps, point, LsegPGetDatum(l2));
-	}
 
-	return point;
+	return DirectFunctionCall2(close_ps, point, LsegPGetDatum(l2));
 }
 
 /* close_pb()
  * Closest point on or in box to specified point.
  */
 Datum
 close_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
-- 
2.13.6 (Apple Git-96)

0005-float-zero-v01.patchapplication/octet-stream; name=0005-float-zero-v01.patchDownload
From 4d642810ecb432520198cf7fe7e07f33fa2b61a7 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Thu, 2 Nov 2017 12:21:19 +0100
Subject: [PATCH 5/6] float-zero-v01

Check for float -0 after multiplications and divisions
---
 src/include/utils/float.h | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/src/include/utils/float.h b/src/include/utils/float.h
index c9f5fd30ca..021732d5c6 100644
--- a/src/include/utils/float.h
+++ b/src/include/utils/float.h
@@ -215,64 +215,76 @@ float8_mi(float8 val1, float8 val2)
 
 static inline float4
 float4_mul(float4 val1, float4 val2)
 {
 	float4		result;
 
 	result = val1 * val2;
 	check_float4_val(result, isinf(val1) || isinf(val2),
 					 val1 == 0.0f || val2 == 0.0f);
 
+	if (result == -0.0f)
+		result = 0.0f;
+
 	return result;
 }
 
 static inline float8
 float8_mul(float8 val1, float8 val2)
 {
 	float8		result;
 
 	result = val1 * val2;
 	check_float8_val(result, isinf(val1) || isinf(val2),
 					 val1 == 0.0 || val2 == 0.0);
 
+	if (result == -0.0)
+		result = 0.0;
+
 	return result;
 }
 
 static inline float4
 float4_div(float4 val1, float4 val2)
 {
 	float4		result;
 
 	if (val2 == 0.0f)
 		ereport(ERROR,
 				(errcode(ERRCODE_DIVISION_BY_ZERO),
 				 errmsg("division by zero")));
 
 	result = val1 / val2;
 	check_float4_val(result, isinf(val1) || isinf(val2), val1 == 0.0f);
 
+	if (result == -0.0f)
+		result = 0.0f;
+
 	return result;
 }
 
 static inline float8
 float8_div(float8 val1, float8 val2)
 {
 	float8		result;
 
 	if (val2 == 0.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_DIVISION_BY_ZERO),
 				 errmsg("division by zero")));
 
 	result = val1 / val2;
 	check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
 
+	if (result == -0.0)
+		result = 0.0;
+
 	return result;
 }
 
 /*
  * Routines for NaN-aware comparisons
  *
  * We consider all NANs to be equal and larger than any non-NAN. This is
  * somewhat arbitrary; the important thing is to have a consistent sort
  * order.
  */
-- 
2.13.6 (Apple Git-96)

0006-geo-tests-v01.patchapplication/octet-stream; name=0006-geo-tests-v01.patchDownload
From 4bae8b52a478751b453436b7ddc12bce92589601 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Tue, 24 Oct 2017 11:28:21 +0200
Subject: [PATCH 6/6] geo-tests-v01

Improve test coverage of geometric types

The tests for the geometric functions and operators were in sad state.
This commit increases test coverage of geo_ops.c significantly.  It
removes the alternative results to expect -0 on some platforms.  We
better try to return the same results on different platforms, but if we
can't we can add them back using the results from build farm.

The tests are added to geometric.sql file.  It is not clear where to
put them as there are many cross datatype operators.  Organising them
on a single file sorted by the left hand side of the operators appear
to be a simple solution.  We may take this further and remove the other
tests later.
---
 src/test/regress/expected/box.out          |   44 +-
 src/test/regress/expected/circle.out       |   31 +-
 src/test/regress/expected/create_index.out |   81 +-
 src/test/regress/expected/geometry.out     | 4933 ++++++++++++++++++++++++++--
 src/test/regress/expected/geometry_1.out   |  563 ----
 src/test/regress/expected/geometry_2.out   |  563 ----
 src/test/regress/expected/line.out         |  265 +-
 src/test/regress/expected/lseg.out         |   22 +-
 src/test/regress/expected/path.out         |   49 +-
 src/test/regress/expected/point.out        |  420 ++-
 src/test/regress/expected/polygon.out      |  200 +-
 src/test/regress/sql/box.sql               |    9 +
 src/test/regress/sql/circle.sql            |    8 +-
 src/test/regress/sql/geometry.sql          |  607 +++-
 src/test/regress/sql/line.sql              |   75 +-
 src/test/regress/sql/lseg.sql              |    8 +-
 src/test/regress/sql/path.sql              |   22 +-
 src/test/regress/sql/point.sql             |   10 +
 src/test/regress/sql/polygon.sql           |   91 +-
 19 files changed, 5774 insertions(+), 2227 deletions(-)
 delete mode 100644 src/test/regress/expected/geometry_1.out
 delete mode 100644 src/test/regress/expected/geometry_2.out

diff --git a/src/test/regress/expected/box.out b/src/test/regress/expected/box.out
index 49af242c8c..998b52223c 100644
--- a/src/test/regress/expected/box.out
+++ b/src/test/regress/expected/box.out
@@ -11,92 +11,109 @@
 -- 1	| o-+-o
 --	|   |
 -- 0	+---+
 --
 --	0 1 2 3
 --
 -- boxes are specified by two points, given by four floats x1,y1,x2,y2
 CREATE TABLE BOX_TBL (f1 box);
 INSERT INTO BOX_TBL (f1) VALUES ('(2.0,2.0,0.0,0.0)');
 INSERT INTO BOX_TBL (f1) VALUES ('(1.0,1.0,3.0,3.0)');
+INSERT INTO BOX_TBL (f1) VALUES ('((-8, 2), (-2, -10))');
 -- degenerate cases where the box is a line or a point
 -- note that lines and points boxes all have zero area
 INSERT INTO BOX_TBL (f1) VALUES ('(2.5, 2.5, 2.5,3.5)');
 INSERT INTO BOX_TBL (f1) VALUES ('(3.0, 3.0,3.0,3.0)');
 -- badly formatted box inputs
 INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
 ERROR:  invalid input syntax for type box: "(2.3, 4.5)"
 LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
                                          ^
+INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+ERROR:  invalid input syntax for type box: "[1, 2, 3, 4)"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+                                         ^
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+ERROR:  invalid input syntax for type box: "(1, 2, 3, 4]"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+                                         ^
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+ERROR:  invalid input syntax for type box: "(1, 2, 3, 4) x"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+                                         ^
 INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
 ERROR:  invalid input syntax for type box: "asdfasdf(ad"
 LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
                                          ^
 SELECT '' AS four, * FROM BOX_TBL;
  four |         f1          
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
+      | (-2,2),(-8,-10)
       | (2.5,3.5),(2.5,2.5)
       | (3,3),(3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, b.*, area(b.f1) as barea
    FROM BOX_TBL b;
  four |         f1          | barea 
 ------+---------------------+-------
       | (2,2),(0,0)         |     4
       | (3,3),(1,1)         |     4
+      | (-2,2),(-8,-10)     |    72
       | (2.5,3.5),(2.5,2.5) |     0
       | (3,3),(3,3)         |     0
-(4 rows)
+(5 rows)
 
 -- overlap
 SELECT '' AS three, b.f1
    FROM BOX_TBL b
    WHERE b.f1 && box '(2.5,2.5,1.0,1.0)';
  three |         f1          
 -------+---------------------
        | (2,2),(0,0)
        | (3,3),(1,1)
        | (2.5,3.5),(2.5,2.5)
 (3 rows)
 
 -- left-or-overlap (x only)
 SELECT '' AS two, b1.*
    FROM BOX_TBL b1
    WHERE b1.f1 &< box '(2.0,2.0,2.5,2.5)';
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- right-or-overlap (x only)
 SELECT '' AS two, b1.*
    FROM BOX_TBL b1
    WHERE b1.f1 &> box '(2.0,2.0,2.5,2.5)';
  two |         f1          
 -----+---------------------
      | (2.5,3.5),(2.5,2.5)
      | (3,3),(3,3)
 (2 rows)
 
 -- left of
 SELECT '' AS two, b.f1
    FROM BOX_TBL b
    WHERE b.f1 << box '(3.0,3.0,5.0,5.0)';
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- area <=
 SELECT '' AS four, b.f1
    FROM BOX_TBL b
    WHERE b.f1 <= box '(3.0,3.0,5.0,5.0)';
  four |         f1          
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
       | (2.5,3.5),(2.5,2.5)
@@ -120,47 +137,50 @@ SELECT '' AS two, b.f1
  two |     f1      
 -----+-------------
      | (2,2),(0,0)
      | (3,3),(1,1)
 (2 rows)
 
 -- area >
 SELECT '' AS two, b.f1
    FROM BOX_TBL b				-- zero area
    WHERE b.f1 > box '(3.5,3.0,4.5,3.0)';
- two |     f1      
------+-------------
+ two |       f1        
+-----+-----------------
      | (2,2),(0,0)
      | (3,3),(1,1)
-(2 rows)
+     | (-2,2),(-8,-10)
+(3 rows)
 
 -- area >=
 SELECT '' AS four, b.f1
    FROM BOX_TBL b				-- zero area
    WHERE b.f1 >= box '(3.5,3.0,4.5,3.0)';
  four |         f1          
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
+      | (-2,2),(-8,-10)
       | (2.5,3.5),(2.5,2.5)
       | (3,3),(3,3)
-(4 rows)
+(5 rows)
 
 -- right of
 SELECT '' AS two, b.f1
    FROM BOX_TBL b
    WHERE box '(3.0,3.0,5.0,5.0)' >> b.f1;
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- contained in
 SELECT '' AS three, b.f1
    FROM BOX_TBL b
    WHERE b.f1 <@ box '(0,0,3,3)';
  three |     f1      
 -------+-------------
        | (2,2),(0,0)
        | (3,3),(1,1)
        | (3,3),(3,3)
@@ -186,41 +206,43 @@ SELECT '' AS one, b.f1
      | (3,3),(1,1)
 (1 row)
 
 -- center of box, left unary operator
 SELECT '' AS four, @@(b1.f1) AS p
    FROM BOX_TBL b1;
  four |    p    
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 -- wholly-contained
 SELECT '' AS one, b1.*, b2.*
    FROM BOX_TBL b1, BOX_TBL b2
    WHERE b1.f1 @> b2.f1 and not b1.f1 ~= b2.f1;
  one |     f1      |     f1      
 -----+-------------+-------------
      | (3,3),(1,1) | (3,3),(3,3)
 (1 row)
 
 SELECT '' AS four, height(f1), width(f1) FROM BOX_TBL;
  four | height | width 
 ------+--------+-------
       |      2 |     2
       |      2 |     2
+      |     12 |     6
       |      1 |     0
       |      0 |     0
-(4 rows)
+(5 rows)
 
 --
 -- Test the SP-GiST index
 --
 CREATE TEMPORARY TABLE box_temp (f1 box);
 INSERT INTO box_temp
 	SELECT box(point(i, i), point(i * 2, i * 2))
 	FROM generate_series(1, 50) AS i;
 CREATE INDEX box_spgist ON box_temp USING spgist (f1);
 INSERT INTO box_temp
diff --git a/src/test/regress/expected/circle.out b/src/test/regress/expected/circle.out
index 9ba4a0495d..0dd75cd849 100644
--- a/src/test/regress/expected/circle.out
+++ b/src/test/regress/expected/circle.out
@@ -1,99 +1,116 @@
 --
 -- CIRCLE
 --
 CREATE TABLE CIRCLE_TBL (f1 circle);
 INSERT INTO CIRCLE_TBL VALUES ('<(5,1),3>');
 INSERT INTO CIRCLE_TBL VALUES ('<(1,2),100>');
 INSERT INTO CIRCLE_TBL VALUES ('1,3,5');
 INSERT INTO CIRCLE_TBL VALUES ('((1,2),3)');
 INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10>');
-INSERT INTO CIRCLE_TBL VALUES ('<(100,1),115>');
+INSERT INTO CIRCLE_TBL VALUES (' < ( 100 , 1 ) , 115 > ');
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),0>');	-- Zero radius
 -- bad values
 INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
 ERROR:  invalid input syntax for type circle: "<(-100,0),-100>"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
                                        ^
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+ERROR:  invalid input syntax for type circle: "<(100,200),10"
+LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+                                       ^
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+ERROR:  invalid input syntax for type circle: "<(100,200),10> x"
+LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+                                       ^
 INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
 ERROR:  invalid input syntax for type circle: "1abc,3,5"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
                                        ^
 INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
 ERROR:  invalid input syntax for type circle: "(3,(1,2),3)"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
                                        ^
 SELECT * FROM CIRCLE_TBL;
        f1       
 ----------------
  <(5,1),3>
  <(1,2),100>
  <(1,3),5>
  <(1,2),3>
  <(100,200),10>
  <(100,1),115>
-(6 rows)
+ <(3,5),0>
+(7 rows)
 
 SELECT '' AS six, center(f1) AS center
   FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+(7 rows)
 
 SELECT '' AS six, radius(f1) AS radius
   FROM CIRCLE_TBL;
  six | radius 
 -----+--------
      |      3
      |    100
      |      5
      |      3
      |     10
      |    115
-(6 rows)
+     |      0
+(7 rows)
 
 SELECT '' AS six, diameter(f1) AS diameter
   FROM CIRCLE_TBL;
  six | diameter 
 -----+----------
      |        6
      |      200
      |       10
      |        6
      |       20
      |      230
-(6 rows)
+     |        0
+(7 rows)
 
 SELECT '' AS two, f1 FROM CIRCLE_TBL WHERE radius(f1) < 5;
  two |    f1     
 -----+-----------
      | <(5,1),3>
      | <(1,2),3>
-(2 rows)
+     | <(3,5),0>
+(3 rows)
 
 SELECT '' AS four, f1 FROM CIRCLE_TBL WHERE diameter(f1) >= 10;
  four |       f1       
 ------+----------------
       | <(1,2),100>
       | <(1,3),5>
       | <(100,200),10>
       | <(100,1),115>
 (4 rows)
 
 SELECT '' as five, c1.f1 AS one, c2.f1 AS two, (c1.f1 <-> c2.f1) AS distance
   FROM CIRCLE_TBL c1, CIRCLE_TBL c2
   WHERE (c1.f1 < c2.f1) AND ((c1.f1 <-> c2.f1) > 0)
   ORDER BY distance, area(c1.f1), area(c2.f1);
  five |      one       |      two       |     distance     
 ------+----------------+----------------+------------------
+      | <(3,5),0>      | <(1,2),3>      | 0.60555127546399
+      | <(3,5),0>      | <(5,1),3>      | 1.47213595499958
       | <(100,200),10> | <(100,1),115>  |               74
       | <(100,200),10> | <(1,2),100>    | 111.370729772479
       | <(1,3),5>      | <(100,200),10> | 205.476756144497
       | <(5,1),3>      | <(100,200),10> |  207.51303816328
+      | <(3,5),0>      | <(100,200),10> | 207.793480159531
       | <(1,2),3>      | <(100,200),10> | 208.370729772479
-(5 rows)
+(8 rows)
 
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 031a0bcec9..ee41f47140 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -150,96 +150,103 @@ SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)';
 
 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
+     4
 (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
+     4
 (1 row)
 
 SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)';
  count 
 -------
-     2
+     4
 (1 row)
 
 SELECT count(*) FROM point_tbl p WHERE p.f1 <^ '(0.0, 0.0)';
  count 
 -------
-     1
+     2
 (1 row)
 
 SELECT count(*) FROM point_tbl p WHERE p.f1 >^ '(0.0, 0.0)';
  count 
 -------
-     3
+     5
 (1 row)
 
 SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
  count 
 -------
      1
 (1 row)
 
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
  (-5,-12)
  (5.1,34.5)
+ (1e+300,Infinity)
+ (NaN,NaN)
  
-(7 rows)
+(10 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NULL;
  f1 
 ----
  
 (1 row)
 
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (1e-300,-1e-300)
  (0,0)
  (-3,4)
  (-10,0)
  (10,10)
  (-5,-12)
  (5.1,34.5)
-(6 rows)
+ (1e+300,Infinity)
+ (NaN,NaN)
+(9 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
  count 
 -------
      3
 (1 row)
 
 SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
  count 
 -------
@@ -561,21 +568,21 @@ SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,
                                        QUERY PLAN                                       
 ----------------------------------------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     4
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>';
                      QUERY PLAN                     
 ----------------------------------------------------
  Aggregate
    ->  Index Only Scan using gpointind on point_tbl
          Index Cond: (f1 <@ '<(50,50),50>'::circle)
 (3 rows)
@@ -591,66 +598,66 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 << '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     4
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     4
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl p WHERE p.f1 <^ '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     2
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl p WHERE p.f1 >^ '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     5
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only Scan using gpointind on point_tbl p
          Index Cond: (f1 ~= '(-5,-12)'::point)
 (3 rows)
@@ -663,30 +670,33 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
                   QUERY PLAN                  
 ----------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Order By: (f1 <-> '(0,1)'::point)
 (2 rows)
 
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (10,10)
+ (NaN,NaN)
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
- (10,10)
  (-5,-12)
  (5.1,34.5)
  
-(7 rows)
+ (1e+300,Infinity)
+(10 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 IS NULL;
                   QUERY PLAN                  
 ----------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Index Cond: (f1 IS NULL)
 (2 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NULL;
@@ -698,47 +708,51 @@ SELECT * FROM point_tbl WHERE f1 IS NULL;
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
                   QUERY PLAN                  
 ----------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Index Cond: (f1 IS NOT NULL)
    Order By: (f1 <-> '(0,1)'::point)
 (3 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (10,10)
+ (NaN,NaN)
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
- (10,10)
  (-5,-12)
  (5.1,34.5)
-(6 rows)
+ (1e+300,Infinity)
+(9 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
                    QUERY PLAN                   
 ------------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Index Cond: (f1 <@ '(10,10),(-10,-10)'::box)
    Order By: (f1 <-> '(0,1)'::point)
 (3 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
                         QUERY PLAN                         
 -----------------------------------------------------------
  Aggregate
    ->  Index Only Scan using sp_quad_ind on quad_point_tbl
          Index Cond: (p IS NULL)
 (3 rows)
 
@@ -1240,27 +1254,28 @@ SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0
 ------------------------------------------------------------
  Sort
    Sort Key: ((f1 <-> '(0,1)'::point))
    ->  Bitmap Heap Scan on point_tbl
          Recheck Cond: (f1 <@ '(10,10),(-10,-10)'::box)
          ->  Bitmap Index Scan on gpointind
                Index Cond: (f1 <@ '(10,10),(-10,-10)'::box)
 (6 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
                   QUERY PLAN                  
 ----------------------------------------------
  Aggregate
    ->  Bitmap Heap Scan on quad_point_tbl
          Recheck Cond: (p IS NULL)
          ->  Bitmap Index Scan on sp_quad_ind
                Index Cond: (p IS NULL)
diff --git a/src/test/regress/expected/geometry.out b/src/test/regress/expected/geometry.out
index e4c0039040..91aac4c487 100644
--- a/src/test/regress/expected/geometry.out
+++ b/src/test/regress/expected/geometry.out
@@ -6,558 +6,4939 @@
 SET extra_float_digits TO -3;
 --
 -- Points
 --
 SELECT '' AS four, center(f1) AS center
    FROM BOX_TBL;
  four | center  
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, (@@ f1) AS center
    FROM BOX_TBL;
  four | center  
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS six, point(f1) AS center
    FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+(7 rows)
 
 SELECT '' AS six, (@@ f1) AS center
    FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+(7 rows)
 
 SELECT '' AS two, (@@ f1) AS center
    FROM POLYGON_TBL
    WHERE (# f1) > 2;
  two |            center             
 -----+-------------------------------
      | (1.33333333333,1.33333333333)
      | (2.33333333333,1.33333333333)
-(2 rows)
+     | (4,5)
+     | (4,5)
+     | (4,3)
+(5 rows)
 
 -- "is horizontal" function
 SELECT '' AS two, p1.f1
    FROM POINT_TBL p1
    WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 -- "is horizontal" operator
 SELECT '' AS two, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 -- "is vertical" function
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE isvertical(p1.f1, point '(5.1,34.5)');
  one |     f1     
 -----+------------
      | (5.1,34.5)
 (1 row)
 
 -- "is vertical" operator
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?| point '(5.1,34.5)';
  one |     f1     
 -----+------------
      | (5.1,34.5)
 (1 row)
 
+-- Slope
+SELECT p1.f1, p2.f1, slope(p1.f1, p2.f1)
+FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |       slope        
+-------------------+-------------------+--------------------
+ (0,0)             | (0,0)             | 1.79769313486e+308
+ (0,0)             | (-10,0)           |                  0
+ (0,0)             | (-3,4)            |     -1.33333333333
+ (0,0)             | (5.1,34.5)        |      6.76470588235
+ (0,0)             | (-5,-12)          |                2.4
+ (0,0)             | (1e-300,-1e-300)  | 1.79769313486e+308
+ (0,0)             | (1e+300,Infinity) |           Infinity
+ (0,0)             | (NaN,NaN)         |                NaN
+ (0,0)             | (10,10)           |                  1
+ (-10,0)           | (0,0)             |                  0
+ (-10,0)           | (-10,0)           | 1.79769313486e+308
+ (-10,0)           | (-3,4)            |     0.571428571429
+ (-10,0)           | (5.1,34.5)        |      2.28476821192
+ (-10,0)           | (-5,-12)          |               -2.4
+ (-10,0)           | (1e-300,-1e-300)  |                  0
+ (-10,0)           | (1e+300,Infinity) |           Infinity
+ (-10,0)           | (NaN,NaN)         |                NaN
+ (-10,0)           | (10,10)           |                0.5
+ (-3,4)            | (0,0)             |     -1.33333333333
+ (-3,4)            | (-10,0)           |     0.571428571429
+ (-3,4)            | (-3,4)            | 1.79769313486e+308
+ (-3,4)            | (5.1,34.5)        |      3.76543209877
+ (-3,4)            | (-5,-12)          |                  8
+ (-3,4)            | (1e-300,-1e-300)  |     -1.33333333333
+ (-3,4)            | (1e+300,Infinity) |           Infinity
+ (-3,4)            | (NaN,NaN)         |                NaN
+ (-3,4)            | (10,10)           |     0.461538461538
+ (5.1,34.5)        | (0,0)             |      6.76470588235
+ (5.1,34.5)        | (-10,0)           |      2.28476821192
+ (5.1,34.5)        | (-3,4)            |      3.76543209877
+ (5.1,34.5)        | (5.1,34.5)        | 1.79769313486e+308
+ (5.1,34.5)        | (-5,-12)          |      4.60396039604
+ (5.1,34.5)        | (1e-300,-1e-300)  |      6.76470588235
+ (5.1,34.5)        | (1e+300,Infinity) |           Infinity
+ (5.1,34.5)        | (NaN,NaN)         |                NaN
+ (5.1,34.5)        | (10,10)           |                 -5
+ (-5,-12)          | (0,0)             |                2.4
+ (-5,-12)          | (-10,0)           |               -2.4
+ (-5,-12)          | (-3,4)            |                  8
+ (-5,-12)          | (5.1,34.5)        |      4.60396039604
+ (-5,-12)          | (-5,-12)          | 1.79769313486e+308
+ (-5,-12)          | (1e-300,-1e-300)  |                2.4
+ (-5,-12)          | (1e+300,Infinity) |           Infinity
+ (-5,-12)          | (NaN,NaN)         |                NaN
+ (-5,-12)          | (10,10)           |      1.46666666667
+ (1e-300,-1e-300)  | (0,0)             | 1.79769313486e+308
+ (1e-300,-1e-300)  | (-10,0)           |                  0
+ (1e-300,-1e-300)  | (-3,4)            |     -1.33333333333
+ (1e-300,-1e-300)  | (5.1,34.5)        |      6.76470588235
+ (1e-300,-1e-300)  | (-5,-12)          |                2.4
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | 1.79769313486e+308
+ (1e-300,-1e-300)  | (1e+300,Infinity) |           Infinity
+ (1e-300,-1e-300)  | (NaN,NaN)         |                NaN
+ (1e-300,-1e-300)  | (10,10)           |                  1
+ (1e+300,Infinity) | (0,0)             |           Infinity
+ (1e+300,Infinity) | (-10,0)           |           Infinity
+ (1e+300,Infinity) | (-3,4)            |           Infinity
+ (1e+300,Infinity) | (5.1,34.5)        |           Infinity
+ (1e+300,Infinity) | (-5,-12)          |           Infinity
+ (1e+300,Infinity) | (1e-300,-1e-300)  |           Infinity
+ (1e+300,Infinity) | (1e+300,Infinity) | 1.79769313486e+308
+ (1e+300,Infinity) | (NaN,NaN)         |                NaN
+ (1e+300,Infinity) | (10,10)           |           Infinity
+ (NaN,NaN)         | (0,0)             |                NaN
+ (NaN,NaN)         | (-10,0)           |                NaN
+ (NaN,NaN)         | (-3,4)            |                NaN
+ (NaN,NaN)         | (5.1,34.5)        |                NaN
+ (NaN,NaN)         | (-5,-12)          |                NaN
+ (NaN,NaN)         | (1e-300,-1e-300)  |                NaN
+ (NaN,NaN)         | (1e+300,Infinity) |                NaN
+ (NaN,NaN)         | (NaN,NaN)         |                NaN
+ (NaN,NaN)         | (10,10)           |                NaN
+ (10,10)           | (0,0)             |                  1
+ (10,10)           | (-10,0)           |                0.5
+ (10,10)           | (-3,4)            |     0.461538461538
+ (10,10)           | (5.1,34.5)        |                 -5
+ (10,10)           | (-5,-12)          |      1.46666666667
+ (10,10)           | (1e-300,-1e-300)  |                  1
+ (10,10)           | (1e+300,Infinity) |           Infinity
+ (10,10)           | (NaN,NaN)         |                NaN
+ (10,10)           | (10,10)           | 1.79769313486e+308
+(81 rows)
+
+-- Add point
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1
+FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |     ?column?      
+-------------------+-------------------+-------------------
+ (0,0)             | (0,0)             | (0,0)
+ (0,0)             | (-10,0)           | (-10,0)
+ (0,0)             | (-3,4)            | (-3,4)
+ (0,0)             | (5.1,34.5)        | (5.1,34.5)
+ (0,0)             | (-5,-12)          | (-5,-12)
+ (0,0)             | (1e-300,-1e-300)  | (1e-300,-1e-300)
+ (0,0)             | (1e+300,Infinity) | (1e+300,Infinity)
+ (0,0)             | (NaN,NaN)         | (NaN,NaN)
+ (0,0)             | (10,10)           | (10,10)
+ (-10,0)           | (0,0)             | (-10,0)
+ (-10,0)           | (-10,0)           | (-20,0)
+ (-10,0)           | (-3,4)            | (-13,4)
+ (-10,0)           | (5.1,34.5)        | (-4.9,34.5)
+ (-10,0)           | (-5,-12)          | (-15,-12)
+ (-10,0)           | (1e-300,-1e-300)  | (-10,-1e-300)
+ (-10,0)           | (1e+300,Infinity) | (1e+300,Infinity)
+ (-10,0)           | (NaN,NaN)         | (NaN,NaN)
+ (-10,0)           | (10,10)           | (0,10)
+ (-3,4)            | (0,0)             | (-3,4)
+ (-3,4)            | (-10,0)           | (-13,4)
+ (-3,4)            | (-3,4)            | (-6,8)
+ (-3,4)            | (5.1,34.5)        | (2.1,38.5)
+ (-3,4)            | (-5,-12)          | (-8,-8)
+ (-3,4)            | (1e-300,-1e-300)  | (-3,4)
+ (-3,4)            | (1e+300,Infinity) | (1e+300,Infinity)
+ (-3,4)            | (NaN,NaN)         | (NaN,NaN)
+ (-3,4)            | (10,10)           | (7,14)
+ (5.1,34.5)        | (0,0)             | (5.1,34.5)
+ (5.1,34.5)        | (-10,0)           | (-4.9,34.5)
+ (5.1,34.5)        | (-3,4)            | (2.1,38.5)
+ (5.1,34.5)        | (5.1,34.5)        | (10.2,69)
+ (5.1,34.5)        | (-5,-12)          | (0.1,22.5)
+ (5.1,34.5)        | (1e-300,-1e-300)  | (5.1,34.5)
+ (5.1,34.5)        | (1e+300,Infinity) | (1e+300,Infinity)
+ (5.1,34.5)        | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5)        | (10,10)           | (15.1,44.5)
+ (-5,-12)          | (0,0)             | (-5,-12)
+ (-5,-12)          | (-10,0)           | (-15,-12)
+ (-5,-12)          | (-3,4)            | (-8,-8)
+ (-5,-12)          | (5.1,34.5)        | (0.1,22.5)
+ (-5,-12)          | (-5,-12)          | (-10,-24)
+ (-5,-12)          | (1e-300,-1e-300)  | (-5,-12)
+ (-5,-12)          | (1e+300,Infinity) | (1e+300,Infinity)
+ (-5,-12)          | (NaN,NaN)         | (NaN,NaN)
+ (-5,-12)          | (10,10)           | (5,-2)
+ (1e-300,-1e-300)  | (0,0)             | (1e-300,-1e-300)
+ (1e-300,-1e-300)  | (-10,0)           | (-10,-1e-300)
+ (1e-300,-1e-300)  | (-3,4)            | (-3,4)
+ (1e-300,-1e-300)  | (5.1,34.5)        | (5.1,34.5)
+ (1e-300,-1e-300)  | (-5,-12)          | (-5,-12)
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | (2e-300,-2e-300)
+ (1e-300,-1e-300)  | (1e+300,Infinity) | (1e+300,Infinity)
+ (1e-300,-1e-300)  | (NaN,NaN)         | (NaN,NaN)
+ (1e-300,-1e-300)  | (10,10)           | (10,10)
+ (1e+300,Infinity) | (0,0)             | (1e+300,Infinity)
+ (1e+300,Infinity) | (-10,0)           | (1e+300,Infinity)
+ (1e+300,Infinity) | (-3,4)            | (1e+300,Infinity)
+ (1e+300,Infinity) | (5.1,34.5)        | (1e+300,Infinity)
+ (1e+300,Infinity) | (-5,-12)          | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e-300,-1e-300)  | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e+300,Infinity) | (2e+300,Infinity)
+ (1e+300,Infinity) | (NaN,NaN)         | (NaN,NaN)
+ (1e+300,Infinity) | (10,10)           | (1e+300,Infinity)
+ (NaN,NaN)         | (0,0)             | (NaN,NaN)
+ (NaN,NaN)         | (-10,0)           | (NaN,NaN)
+ (NaN,NaN)         | (-3,4)            | (NaN,NaN)
+ (NaN,NaN)         | (5.1,34.5)        | (NaN,NaN)
+ (NaN,NaN)         | (-5,-12)          | (NaN,NaN)
+ (NaN,NaN)         | (1e-300,-1e-300)  | (NaN,NaN)
+ (NaN,NaN)         | (1e+300,Infinity) | (NaN,NaN)
+ (NaN,NaN)         | (NaN,NaN)         | (NaN,NaN)
+ (NaN,NaN)         | (10,10)           | (NaN,NaN)
+ (10,10)           | (0,0)             | (10,10)
+ (10,10)           | (-10,0)           | (0,10)
+ (10,10)           | (-3,4)            | (7,14)
+ (10,10)           | (5.1,34.5)        | (15.1,44.5)
+ (10,10)           | (-5,-12)          | (5,-2)
+ (10,10)           | (1e-300,-1e-300)  | (10,10)
+ (10,10)           | (1e+300,Infinity) | (1e+300,Infinity)
+ (10,10)           | (NaN,NaN)         | (NaN,NaN)
+ (10,10)           | (10,10)           | (20,20)
+(81 rows)
+
+-- Subtract point
+SELECT p1.f1, p2.f1, p1.f1 - p2.f1
+FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |      ?column?       
+-------------------+-------------------+---------------------
+ (0,0)             | (0,0)             | (0,0)
+ (0,0)             | (-10,0)           | (10,0)
+ (0,0)             | (-3,4)            | (3,-4)
+ (0,0)             | (5.1,34.5)        | (-5.1,-34.5)
+ (0,0)             | (-5,-12)          | (5,12)
+ (0,0)             | (1e-300,-1e-300)  | (-1e-300,1e-300)
+ (0,0)             | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (0,0)             | (NaN,NaN)         | (NaN,NaN)
+ (0,0)             | (10,10)           | (-10,-10)
+ (-10,0)           | (0,0)             | (-10,0)
+ (-10,0)           | (-10,0)           | (0,0)
+ (-10,0)           | (-3,4)            | (-7,-4)
+ (-10,0)           | (5.1,34.5)        | (-15.1,-34.5)
+ (-10,0)           | (-5,-12)          | (-5,12)
+ (-10,0)           | (1e-300,-1e-300)  | (-10,1e-300)
+ (-10,0)           | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-10,0)           | (NaN,NaN)         | (NaN,NaN)
+ (-10,0)           | (10,10)           | (-20,-10)
+ (-3,4)            | (0,0)             | (-3,4)
+ (-3,4)            | (-10,0)           | (7,4)
+ (-3,4)            | (-3,4)            | (0,0)
+ (-3,4)            | (5.1,34.5)        | (-8.1,-30.5)
+ (-3,4)            | (-5,-12)          | (2,16)
+ (-3,4)            | (1e-300,-1e-300)  | (-3,4)
+ (-3,4)            | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-3,4)            | (NaN,NaN)         | (NaN,NaN)
+ (-3,4)            | (10,10)           | (-13,-6)
+ (5.1,34.5)        | (0,0)             | (5.1,34.5)
+ (5.1,34.5)        | (-10,0)           | (15.1,34.5)
+ (5.1,34.5)        | (-3,4)            | (8.1,30.5)
+ (5.1,34.5)        | (5.1,34.5)        | (0,0)
+ (5.1,34.5)        | (-5,-12)          | (10.1,46.5)
+ (5.1,34.5)        | (1e-300,-1e-300)  | (5.1,34.5)
+ (5.1,34.5)        | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (5.1,34.5)        | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5)        | (10,10)           | (-4.9,24.5)
+ (-5,-12)          | (0,0)             | (-5,-12)
+ (-5,-12)          | (-10,0)           | (5,-12)
+ (-5,-12)          | (-3,4)            | (-2,-16)
+ (-5,-12)          | (5.1,34.5)        | (-10.1,-46.5)
+ (-5,-12)          | (-5,-12)          | (0,0)
+ (-5,-12)          | (1e-300,-1e-300)  | (-5,-12)
+ (-5,-12)          | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-5,-12)          | (NaN,NaN)         | (NaN,NaN)
+ (-5,-12)          | (10,10)           | (-15,-22)
+ (1e-300,-1e-300)  | (0,0)             | (1e-300,-1e-300)
+ (1e-300,-1e-300)  | (-10,0)           | (10,-1e-300)
+ (1e-300,-1e-300)  | (-3,4)            | (3,-4)
+ (1e-300,-1e-300)  | (5.1,34.5)        | (-5.1,-34.5)
+ (1e-300,-1e-300)  | (-5,-12)          | (5,12)
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | (0,0)
+ (1e-300,-1e-300)  | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (1e-300,-1e-300)  | (NaN,NaN)         | (NaN,NaN)
+ (1e-300,-1e-300)  | (10,10)           | (-10,-10)
+ (1e+300,Infinity) | (0,0)             | (1e+300,Infinity)
+ (1e+300,Infinity) | (-10,0)           | (1e+300,Infinity)
+ (1e+300,Infinity) | (-3,4)            | (1e+300,Infinity)
+ (1e+300,Infinity) | (5.1,34.5)        | (1e+300,Infinity)
+ (1e+300,Infinity) | (-5,-12)          | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e-300,-1e-300)  | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e+300,Infinity) | (0,NaN)
+ (1e+300,Infinity) | (NaN,NaN)         | (NaN,NaN)
+ (1e+300,Infinity) | (10,10)           | (1e+300,Infinity)
+ (NaN,NaN)         | (0,0)             | (NaN,NaN)
+ (NaN,NaN)         | (-10,0)           | (NaN,NaN)
+ (NaN,NaN)         | (-3,4)            | (NaN,NaN)
+ (NaN,NaN)         | (5.1,34.5)        | (NaN,NaN)
+ (NaN,NaN)         | (-5,-12)          | (NaN,NaN)
+ (NaN,NaN)         | (1e-300,-1e-300)  | (NaN,NaN)
+ (NaN,NaN)         | (1e+300,Infinity) | (NaN,NaN)
+ (NaN,NaN)         | (NaN,NaN)         | (NaN,NaN)
+ (NaN,NaN)         | (10,10)           | (NaN,NaN)
+ (10,10)           | (0,0)             | (10,10)
+ (10,10)           | (-10,0)           | (20,10)
+ (10,10)           | (-3,4)            | (13,6)
+ (10,10)           | (5.1,34.5)        | (4.9,-24.5)
+ (10,10)           | (-5,-12)          | (15,22)
+ (10,10)           | (1e-300,-1e-300)  | (10,10)
+ (10,10)           | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (10,10)           | (NaN,NaN)         | (NaN,NaN)
+ (10,10)           | (10,10)           | (0,0)
+(81 rows)
+
+-- Multiply with point
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1
+FROM POINT_TBL p1, POINT_TBL p2
+WHERE p1.f1[0] BETWEEN 1 AND 1000;
+     f1     |        f1         |       ?column?        
+------------+-------------------+-----------------------
+ (5.1,34.5) | (0,0)             | (0,0)
+ (10,10)    | (0,0)             | (0,0)
+ (5.1,34.5) | (-10,0)           | (-51,-345)
+ (10,10)    | (-10,0)           | (-100,-100)
+ (5.1,34.5) | (-3,4)            | (-153.3,-83.1)
+ (10,10)    | (-3,4)            | (-70,10)
+ (5.1,34.5) | (5.1,34.5)        | (-1164.24,351.9)
+ (10,10)    | (5.1,34.5)        | (-294,396)
+ (5.1,34.5) | (-5,-12)          | (388.5,-233.7)
+ (10,10)    | (-5,-12)          | (70,-170)
+ (5.1,34.5) | (1e-300,-1e-300)  | (3.96e-299,2.94e-299)
+ (10,10)    | (1e-300,-1e-300)  | (2e-299,0)
+ (5.1,34.5) | (1e+300,Infinity) | (-Infinity,Infinity)
+ (10,10)    | (1e+300,Infinity) | (-Infinity,Infinity)
+ (5.1,34.5) | (NaN,NaN)         | (NaN,NaN)
+ (10,10)    | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5) | (10,10)           | (-294,396)
+ (10,10)    | (10,10)           | (0,200)
+(18 rows)
+
+-- Underflow error
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1
+FROM POINT_TBL p1, POINT_TBL p2
+WHERE p1.f1[0] < 1;
+ERROR:  value out of range: underflow
+-- Divide by point
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1
+FROM POINT_TBL p1, POINT_TBL p2
+WHERE p2.f1[0] BETWEEN 1 AND 1000;
+        f1         |     f1     |                 ?column?                  
+-------------------+------------+-------------------------------------------
+ (0,0)             | (5.1,34.5) | (0,0)
+ (0,0)             | (10,10)    | (0,0)
+ (-10,0)           | (5.1,34.5) | (-0.0419318237877,0.283656455034)
+ (-10,0)           | (10,10)    | (-0.5,0.5)
+ (-3,4)            | (5.1,34.5) | (0.100883034877,0.101869666025)
+ (-3,4)            | (10,10)    | (0.05,0.35)
+ (5.1,34.5)        | (5.1,34.5) | (1,0)
+ (5.1,34.5)        | (10,10)    | (1.98,1.47)
+ (-5,-12)          | (5.1,34.5) | (-0.361353657935,0.0915100389719)
+ (-5,-12)          | (10,10)    | (-0.85,-0.35)
+ (1e-300,-1e-300)  | (5.1,34.5) | (-2.41724631247e-302,-3.25588278822e-302)
+ (1e-300,-1e-300)  | (10,10)    | (0,-1e-301)
+ (1e+300,Infinity) | (5.1,34.5) | (Infinity,Infinity)
+ (1e+300,Infinity) | (10,10)    | (Infinity,Infinity)
+ (NaN,NaN)         | (5.1,34.5) | (NaN,NaN)
+ (NaN,NaN)         | (10,10)    | (NaN,NaN)
+ (10,10)           | (5.1,34.5) | (0.325588278822,-0.241724631247)
+ (10,10)           | (10,10)    | (1,0)
+(18 rows)
+
+-- Overflow error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1
+FROM POINT_TBL p1, POINT_TBL p2
+WHERE p2.f1[0] > 1000;
+ERROR:  value out of range: overflow
+-- Division by 0 error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1
+FROM POINT_TBL p1, POINT_TBL p2
+WHERE p2.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to line
+SELECT p.f1, l.s, p.f1 <-> l.s
+FROM POINT_TBL p, LINE_TBL l;
+        f1         |                   s                   |      ?column?      
+-------------------+---------------------------------------+--------------------
+ (0,0)             | {0,-1,5}                              |                  5
+ (0,0)             | {1,0,5}                               |                  5
+ (0,0)             | {0,3,0}                               |                  0
+ (0,0)             | {1,-1,0}                              |                  0
+ (0,0)             | {-0.4,-1,-6}                          |      5.57086014531
+ (0,0)             | {-0.000184615384615,-1,15.3846153846} |      15.3846151224
+ (0,0)             | {-1,0,1}                              |                  1
+ (0,0)             | {3,NaN,5}                             |                NaN
+ (0,0)             | {0,-1,3}                              |                  3
+ (0,0)             | {-1,0,3}                              |                  3
+ (-10,0)           | {0,-1,5}                              |                  5
+ (-10,0)           | {1,0,5}                               |                  5
+ (-10,0)           | {0,3,0}                               |                  0
+ (-10,0)           | {1,-1,0}                              |      7.07106781187
+ (-10,0)           | {-0.4,-1,-6}                          |      1.85695338177
+ (-10,0)           | {-0.000184615384615,-1,15.3846153846} |      15.3864612763
+ (-10,0)           | {-1,0,1}                              |                 11
+ (-10,0)           | {3,NaN,5}                             |                NaN
+ (-10,0)           | {0,-1,3}                              |                  3
+ (-10,0)           | {-1,0,3}                              |                 13
+ (-3,4)            | {0,-1,5}                              |                  1
+ (-3,4)            | {1,0,5}                               |                  2
+ (-3,4)            | {0,3,0}                               |                  4
+ (-3,4)            | {1,-1,0}                              |      4.94974746831
+ (-3,4)            | {-0.4,-1,-6}                          |      8.17059487979
+ (-3,4)            | {-0.000184615384615,-1,15.3846153846} |      11.3851690367
+ (-3,4)            | {-1,0,1}                              |                  4
+ (-3,4)            | {3,NaN,5}                             |                NaN
+ (-3,4)            | {0,-1,3}                              |                  1
+ (-3,4)            | {-1,0,3}                              |                  6
+ (5.1,34.5)        | {0,-1,5}                              |               29.5
+ (5.1,34.5)        | {1,0,5}                               |               10.1
+ (5.1,34.5)        | {0,3,0}                               |               34.5
+ (5.1,34.5)        | {1,-1,0}                              |      20.7889393669
+ (5.1,34.5)        | {-0.4,-1,-6}                          |      39.4973984303
+ (5.1,34.5)        | {-0.000184615384615,-1,15.3846153846} |      19.1163258281
+ (5.1,34.5)        | {-1,0,1}                              |                4.1
+ (5.1,34.5)        | {3,NaN,5}                             |                NaN
+ (5.1,34.5)        | {0,-1,3}                              |               31.5
+ (5.1,34.5)        | {-1,0,3}                              |                2.1
+ (-5,-12)          | {0,-1,5}                              |                 17
+ (-5,-12)          | {1,0,5}                               |                  0
+ (-5,-12)          | {0,3,0}                               |                 12
+ (-5,-12)          | {1,-1,0}                              |      4.94974746831
+ (-5,-12)          | {-0.4,-1,-6}                          |      7.42781352708
+ (-5,-12)          | {-0.000184615384615,-1,15.3846153846} |      27.3855379949
+ (-5,-12)          | {-1,0,1}                              |                  6
+ (-5,-12)          | {3,NaN,5}                             |                NaN
+ (-5,-12)          | {0,-1,3}                              |                 15
+ (-5,-12)          | {-1,0,3}                              |                  8
+ (1e-300,-1e-300)  | {0,-1,5}                              |                  5
+ (1e-300,-1e-300)  | {1,0,5}                               |                  5
+ (1e-300,-1e-300)  | {0,3,0}                               |             1e-300
+ (1e-300,-1e-300)  | {1,-1,0}                              | 1.41421356237e-300
+ (1e-300,-1e-300)  | {-0.4,-1,-6}                          |      5.57086014531
+ (1e-300,-1e-300)  | {-0.000184615384615,-1,15.3846153846} |      15.3846151224
+ (1e-300,-1e-300)  | {-1,0,1}                              |                  1
+ (1e-300,-1e-300)  | {3,NaN,5}                             |                NaN
+ (1e-300,-1e-300)  | {0,-1,3}                              |                  3
+ (1e-300,-1e-300)  | {-1,0,3}                              |                  3
+ (1e+300,Infinity) | {0,-1,5}                              |           Infinity
+ (1e+300,Infinity) | {1,0,5}                               |                NaN
+ (1e+300,Infinity) | {0,3,0}                               |           Infinity
+ (1e+300,Infinity) | {1,-1,0}                              |           Infinity
+ (1e+300,Infinity) | {-0.4,-1,-6}                          |           Infinity
+ (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} |           Infinity
+ (1e+300,Infinity) | {-1,0,1}                              |                NaN
+ (1e+300,Infinity) | {3,NaN,5}                             |                NaN
+ (1e+300,Infinity) | {0,-1,3}                              |           Infinity
+ (1e+300,Infinity) | {-1,0,3}                              |                NaN
+ (NaN,NaN)         | {0,-1,5}                              |                NaN
+ (NaN,NaN)         | {1,0,5}                               |                NaN
+ (NaN,NaN)         | {0,3,0}                               |                NaN
+ (NaN,NaN)         | {1,-1,0}                              |                NaN
+ (NaN,NaN)         | {-0.4,-1,-6}                          |                NaN
+ (NaN,NaN)         | {-0.000184615384615,-1,15.3846153846} |                NaN
+ (NaN,NaN)         | {-1,0,1}                              |                NaN
+ (NaN,NaN)         | {3,NaN,5}                             |                NaN
+ (NaN,NaN)         | {0,-1,3}                              |                NaN
+ (NaN,NaN)         | {-1,0,3}                              |                NaN
+ (10,10)           | {0,-1,5}                              |                  5
+ (10,10)           | {1,0,5}                               |                 15
+ (10,10)           | {0,3,0}                               |                 10
+ (10,10)           | {1,-1,0}                              |                  0
+ (10,10)           | {-0.4,-1,-6}                          |      18.5695338177
+ (10,10)           | {-0.000184615384615,-1,15.3846153846} |      5.38276913904
+ (10,10)           | {-1,0,1}                              |                  9
+ (10,10)           | {3,NaN,5}                             |                NaN
+ (10,10)           | {0,-1,3}                              |                  7
+ (10,10)           | {-1,0,3}                              |                  7
+(90 rows)
+
+-- Distance to line segment
+SELECT p.f1, l.s, p.f1 <-> l.s
+FROM POINT_TBL p, LSEG_TBL l;
+        f1         |               s               |      ?column?      
+-------------------+-------------------------------+--------------------
+ (0,0)             | [(1,2),(3,4)]                 |       2.2360679775
+ (0,0)             | [(0,0),(6,6)]                 |                  0
+ (0,0)             | [(10,-10),(-3,-4)]            |      4.88901207039
+ (0,0)             | [(-1000000,200),(300000,-40)] |      15.3846151224
+ (0,0)             | [(11,22),(33,44)]             |      24.5967477525
+ (0,0)             | [(-10,2),(-10,3)]             |      10.1980390272
+ (0,0)             | [(0,-20),(30,-20)]            |                 20
+ (-10,0)           | [(1,2),(3,4)]                 |      11.1803398875
+ (-10,0)           | [(0,0),(6,6)]                 |                 10
+ (-10,0)           | [(10,-10),(-3,-4)]            |       8.0622577483
+ (-10,0)           | [(-1000000,200),(300000,-40)] |      15.3864612763
+ (-10,0)           | [(11,22),(33,44)]             |      30.4138126515
+ (-10,0)           | [(-10,2),(-10,3)]             |                  2
+ (-10,0)           | [(0,-20),(30,-20)]            |       22.360679775
+ (-3,4)            | [(1,2),(3,4)]                 |        4.472135955
+ (-3,4)            | [(0,0),(6,6)]                 |      4.94974746831
+ (-3,4)            | [(10,-10),(-3,-4)]            |                  8
+ (-3,4)            | [(-1000000,200),(300000,-40)] |      11.3851690367
+ (-3,4)            | [(11,22),(33,44)]             |       22.803508502
+ (-3,4)            | [(-10,2),(-10,3)]             |      7.07106781187
+ (-3,4)            | [(0,-20),(30,-20)]            |      24.1867732449
+ (5.1,34.5)        | [(1,2),(3,4)]                 |      30.5722096028
+ (5.1,34.5)        | [(0,0),(6,6)]                 |      28.5142069853
+ (5.1,34.5)        | [(10,-10),(-3,-4)]            |      39.3428519556
+ (5.1,34.5)        | [(-1000000,200),(300000,-40)] |      19.1163258281
+ (5.1,34.5)        | [(11,22),(33,44)]             |      13.0107647738
+ (5.1,34.5)        | [(-10,2),(-10,3)]             |       34.932220084
+ (5.1,34.5)        | [(0,-20),(30,-20)]            |               54.5
+ (-5,-12)          | [(1,2),(3,4)]                 |      15.2315462117
+ (-5,-12)          | [(0,0),(6,6)]                 |                 13
+ (-5,-12)          | [(10,-10),(-3,-4)]            |      8.10179143093
+ (-5,-12)          | [(-1000000,200),(300000,-40)] |      27.3855379949
+ (-5,-12)          | [(11,22),(33,44)]             |      37.5765884561
+ (-5,-12)          | [(-10,2),(-10,3)]             |      14.8660687473
+ (-5,-12)          | [(0,-20),(30,-20)]            |      9.43398113206
+ (1e-300,-1e-300)  | [(1,2),(3,4)]                 |       2.2360679775
+ (1e-300,-1e-300)  | [(0,0),(6,6)]                 | 1.41421356237e-300
+ (1e-300,-1e-300)  | [(10,-10),(-3,-4)]            |      4.88901207039
+ (1e-300,-1e-300)  | [(-1000000,200),(300000,-40)] |      15.3846151224
+ (1e-300,-1e-300)  | [(11,22),(33,44)]             |      24.5967477525
+ (1e-300,-1e-300)  | [(-10,2),(-10,3)]             |      10.1980390272
+ (1e-300,-1e-300)  | [(0,-20),(30,-20)]            |                 20
+ (1e+300,Infinity) | [(1,2),(3,4)]                 |           Infinity
+ (1e+300,Infinity) | [(0,0),(6,6)]                 |           Infinity
+ (1e+300,Infinity) | [(10,-10),(-3,-4)]            |           Infinity
+ (1e+300,Infinity) | [(-1000000,200),(300000,-40)] |           Infinity
+ (1e+300,Infinity) | [(11,22),(33,44)]             |           Infinity
+ (1e+300,Infinity) | [(-10,2),(-10,3)]             |           Infinity
+ (1e+300,Infinity) | [(0,-20),(30,-20)]            |           Infinity
+ (NaN,NaN)         | [(1,2),(3,4)]                 |                NaN
+ (NaN,NaN)         | [(0,0),(6,6)]                 |                NaN
+ (NaN,NaN)         | [(10,-10),(-3,-4)]            |                NaN
+ (NaN,NaN)         | [(-1000000,200),(300000,-40)] |                NaN
+ (NaN,NaN)         | [(11,22),(33,44)]             |                NaN
+ (NaN,NaN)         | [(-10,2),(-10,3)]             |                NaN
+ (NaN,NaN)         | [(0,-20),(30,-20)]            |                NaN
+ (10,10)           | [(1,2),(3,4)]                 |      9.21954445729
+ (10,10)           | [(0,0),(6,6)]                 |      5.65685424949
+ (10,10)           | [(10,-10),(-3,-4)]            |        18.15918769
+ (10,10)           | [(-1000000,200),(300000,-40)] |      5.38276913904
+ (10,10)           | [(11,22),(33,44)]             |      12.0415945788
+ (10,10)           | [(-10,2),(-10,3)]             |      21.1896201004
+ (10,10)           | [(0,-20),(30,-20)]            |                 30
+(63 rows)
+
+-- Distance to box
+SELECT p.f1, b.f1, p.f1 <-> b.f1
+FROM POINT_TBL p, BOX_TBL b;
+        f1         |         f1          |      ?column?      
+-------------------+---------------------+--------------------
+ (0,0)             | (2,2),(0,0)         |                  0
+ (0,0)             | (3,3),(1,1)         |      1.41421356237
+ (0,0)             | (-2,2),(-8,-10)     |                  2
+ (0,0)             | (2.5,3.5),(2.5,2.5) |      3.53553390593
+ (0,0)             | (3,3),(3,3)         |      4.24264068712
+ (-10,0)           | (2,2),(0,0)         |                 10
+ (-10,0)           | (3,3),(1,1)         |      11.0453610172
+ (-10,0)           | (-2,2),(-8,-10)     |                  2
+ (-10,0)           | (2.5,3.5),(2.5,2.5) |       12.747548784
+ (-10,0)           | (3,3),(3,3)         |      13.3416640641
+ (-3,4)            | (2,2),(0,0)         |      3.60555127546
+ (-3,4)            | (3,3),(1,1)         |      4.12310562562
+ (-3,4)            | (-2,2),(-8,-10)     |                  2
+ (-3,4)            | (2.5,3.5),(2.5,2.5) |      5.52268050859
+ (-3,4)            | (3,3),(3,3)         |       6.0827625303
+ (5.1,34.5)        | (2,2),(0,0)         |      32.6475113906
+ (5.1,34.5)        | (3,3),(1,1)         |      31.5699223946
+ (5.1,34.5)        | (-2,2),(-8,-10)     |      33.2664996656
+ (5.1,34.5)        | (2.5,3.5),(2.5,2.5) |       31.108841187
+ (5.1,34.5)        | (3,3),(3,3)         |      31.5699223946
+ (-5,-12)          | (2,2),(0,0)         |                 13
+ (-5,-12)          | (3,3),(1,1)         |      14.3178210633
+ (-5,-12)          | (-2,2),(-8,-10)     |                  2
+ (-5,-12)          | (2.5,3.5),(2.5,2.5) |      16.3248277173
+ (-5,-12)          | (3,3),(3,3)         |                 17
+ (1e-300,-1e-300)  | (2,2),(0,0)         | 1.41421356237e-300
+ (1e-300,-1e-300)  | (3,3),(1,1)         |      1.41421356237
+ (1e-300,-1e-300)  | (-2,2),(-8,-10)     |                  2
+ (1e-300,-1e-300)  | (2.5,3.5),(2.5,2.5) |      3.53553390593
+ (1e-300,-1e-300)  | (3,3),(3,3)         |      4.24264068712
+ (1e+300,Infinity) | (2,2),(0,0)         |           Infinity
+ (1e+300,Infinity) | (3,3),(1,1)         |           Infinity
+ (1e+300,Infinity) | (-2,2),(-8,-10)     |           Infinity
+ (1e+300,Infinity) | (2.5,3.5),(2.5,2.5) |           Infinity
+ (1e+300,Infinity) | (3,3),(3,3)         |           Infinity
+ (NaN,NaN)         | (2,2),(0,0)         |                NaN
+ (NaN,NaN)         | (3,3),(1,1)         |                NaN
+ (NaN,NaN)         | (-2,2),(-8,-10)     |                NaN
+ (NaN,NaN)         | (2.5,3.5),(2.5,2.5) |                NaN
+ (NaN,NaN)         | (3,3),(3,3)         |                NaN
+ (10,10)           | (2,2),(0,0)         |       11.313708499
+ (10,10)           | (3,3),(1,1)         |      9.89949493661
+ (10,10)           | (-2,2),(-8,-10)     |      14.4222051019
+ (10,10)           | (2.5,3.5),(2.5,2.5) |      9.92471662064
+ (10,10)           | (3,3),(3,3)         |      9.89949493661
+(45 rows)
+
+-- Distance to path
+SELECT p.f1, p.f1, p.f1 <-> p1.f1
+FROM POINT_TBL p, PATH_TBL p1;
+        f1         |        f1         |   ?column?    
+-------------------+-------------------+---------------
+ (0,0)             | (0,0)             |  2.2360679775
+ (0,0)             | (0,0)             |  2.2360679775
+ (0,0)             | (0,0)             |             0
+ (0,0)             | (0,0)             |  2.2360679775
+ (0,0)             | (0,0)             |  2.2360679775
+ (0,0)             | (0,0)             |  2.2360679775
+ (0,0)             | (0,0)             |  22.360679775
+ (0,0)             | (0,0)             | 16.2788205961
+ (0,0)             | (0,0)             | 16.2788205961
+ (-10,0)           | (-10,0)           | 11.1803398875
+ (-10,0)           | (-10,0)           | 11.1803398875
+ (-10,0)           | (-10,0)           |            10
+ (-10,0)           | (-10,0)           | 11.1803398875
+ (-10,0)           | (-10,0)           | 11.1803398875
+ (-10,0)           | (-10,0)           | 11.1803398875
+ (-10,0)           | (-10,0)           | 28.2842712475
+ (-10,0)           | (-10,0)           | 24.1867732449
+ (-10,0)           | (-10,0)           | 24.1867732449
+ (-3,4)            | (-3,4)            |   4.472135955
+ (-3,4)            | (-3,4)            |   4.472135955
+ (-3,4)            | (-3,4)            |   4.472135955
+ (-3,4)            | (-3,4)            |   4.472135955
+ (-3,4)            | (-3,4)            |   4.472135955
+ (-3,4)            | (-3,4)            |   4.472135955
+ (-3,4)            | (-3,4)            | 20.6155281281
+ (-3,4)            | (-3,4)            | 16.1245154966
+ (-3,4)            | (-3,4)            | 16.1245154966
+ (5.1,34.5)        | (5.1,34.5)        | 30.5722096028
+ (5.1,34.5)        | (5.1,34.5)        | 30.5722096028
+ (5.1,34.5)        | (5.1,34.5)        |  28.793402022
+ (5.1,34.5)        | (5.1,34.5)        | 30.5722096028
+ (5.1,34.5)        | (5.1,34.5)        | 30.5722096028
+ (5.1,34.5)        | (5.1,34.5)        | 30.5722096028
+ (5.1,34.5)        | (5.1,34.5)        | 15.3055545473
+ (5.1,34.5)        | (5.1,34.5)        | 21.9695243462
+ (5.1,34.5)        | (5.1,34.5)        | 21.9695243462
+ (-5,-12)          | (-5,-12)          | 15.2315462117
+ (-5,-12)          | (-5,-12)          | 15.2315462117
+ (-5,-12)          | (-5,-12)          |            13
+ (-5,-12)          | (-5,-12)          | 15.2315462117
+ (-5,-12)          | (-5,-12)          | 15.2315462117
+ (-5,-12)          | (-5,-12)          | 15.2315462117
+ (-5,-12)          | (-5,-12)          | 35.3411940941
+ (-5,-12)          | (-5,-12)          | 28.8444102037
+ (-5,-12)          | (-5,-12)          | 28.8444102037
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  |  2.2360679775
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  |  2.2360679775
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  |        1e-300
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  |  2.2360679775
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  |  2.2360679775
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  |  2.2360679775
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  |  22.360679775
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | 16.2788205961
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | 16.2788205961
+ (1e+300,Infinity) | (1e+300,Infinity) |      Infinity
+ (1e+300,Infinity) | (1e+300,Infinity) |      Infinity
+ (1e+300,Infinity) | (1e+300,Infinity) |      Infinity
+ (1e+300,Infinity) | (1e+300,Infinity) |      Infinity
+ (1e+300,Infinity) | (1e+300,Infinity) |      Infinity
+ (1e+300,Infinity) | (1e+300,Infinity) |      Infinity
+ (1e+300,Infinity) | (1e+300,Infinity) |      Infinity
+ (1e+300,Infinity) | (1e+300,Infinity) |      Infinity
+ (1e+300,Infinity) | (1e+300,Infinity) |      Infinity
+ (NaN,NaN)         | (NaN,NaN)         |           NaN
+ (NaN,NaN)         | (NaN,NaN)         |           NaN
+ (NaN,NaN)         | (NaN,NaN)         |           NaN
+ (NaN,NaN)         | (NaN,NaN)         |           NaN
+ (NaN,NaN)         | (NaN,NaN)         |           NaN
+ (NaN,NaN)         | (NaN,NaN)         |           NaN
+ (NaN,NaN)         | (NaN,NaN)         |           NaN
+ (NaN,NaN)         | (NaN,NaN)         |           NaN
+ (NaN,NaN)         | (NaN,NaN)         |           NaN
+ (10,10)           | (10,10)           | 9.21954445729
+ (10,10)           | (10,10)           | 9.21954445729
+ (10,10)           | (10,10)           | 7.81024967591
+ (10,10)           | (10,10)           | 9.21954445729
+ (10,10)           | (10,10)           | 9.21954445729
+ (10,10)           | (10,10)           | 9.21954445729
+ (10,10)           | (10,10)           |            10
+ (10,10)           | (10,10)           |  2.2360679775
+ (10,10)           | (10,10)           |  2.2360679775
+(81 rows)
+
+-- Distance to polygon
+SELECT p.f1, p.f1, p.f1 <-> p1.f1
+FROM POINT_TBL p, POLYGON_TBL p1;
+        f1         |        f1         |   ?column?    
+-------------------+-------------------+---------------
+ (0,0)             | (0,0)             |             0
+ (0,0)             | (0,0)             |             1
+ (0,0)             | (0,0)             |  2.2360679775
+ (0,0)             | (0,0)             |  2.2360679775
+ (0,0)             | (0,0)             | 1.58113883008
+ (0,0)             | (0,0)             |             0
+ (0,0)             | (0,0)             |             1
+ (-10,0)           | (-10,0)           |            10
+ (-10,0)           | (-10,0)           |            11
+ (-10,0)           | (-10,0)           | 11.1803398875
+ (-10,0)           | (-10,0)           | 11.1803398875
+ (-10,0)           | (-10,0)           | 11.1803398875
+ (-10,0)           | (-10,0)           |            10
+ (-10,0)           | (-10,0)           | 10.0498756211
+ (-3,4)            | (-3,4)            |   4.472135955
+ (-3,4)            | (-3,4)            | 5.54700196225
+ (-3,4)            | (-3,4)            |   4.472135955
+ (-3,4)            | (-3,4)            |   4.472135955
+ (-3,4)            | (-3,4)            |   4.472135955
+ (-3,4)            | (-3,4)            |             5
+ (-3,4)            | (-3,4)            | 4.24264068712
+ (5.1,34.5)        | (5.1,34.5)        | 30.6571362002
+ (5.1,34.5)        | (5.1,34.5)        | 31.5699223946
+ (5.1,34.5)        | (5.1,34.5)        | 26.5680258958
+ (5.1,34.5)        | (5.1,34.5)        | 26.5680258958
+ (5.1,34.5)        | (5.1,34.5)        | 26.5680258958
+ (5.1,34.5)        | (5.1,34.5)        | 34.8749193547
+ (5.1,34.5)        | (5.1,34.5)        | 33.8859853037
+ (-5,-12)          | (-5,-12)          |            13
+ (-5,-12)          | (-5,-12)          |  13.416407865
+ (-5,-12)          | (-5,-12)          | 15.2315462117
+ (-5,-12)          | (-5,-12)          | 15.2315462117
+ (-5,-12)          | (-5,-12)          |  11.313708499
+ (-5,-12)          | (-5,-12)          |            13
+ (-5,-12)          | (-5,-12)          | 13.9283882772
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  |             0
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  |             1
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  |  2.2360679775
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  |  2.2360679775
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | 1.58113883008
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  |             0
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  |             1
+ (1e+300,Infinity) | (1e+300,Infinity) |      Infinity
+ (1e+300,Infinity) | (1e+300,Infinity) |      Infinity
+ (1e+300,Infinity) | (1e+300,Infinity) |      Infinity
+ (1e+300,Infinity) | (1e+300,Infinity) |      Infinity
+ (1e+300,Infinity) | (1e+300,Infinity) |      Infinity
+ (1e+300,Infinity) | (1e+300,Infinity) |      Infinity
+ (1e+300,Infinity) | (1e+300,Infinity) |      Infinity
+ (NaN,NaN)         | (NaN,NaN)         |           NaN
+ (NaN,NaN)         | (NaN,NaN)         |           NaN
+ (NaN,NaN)         | (NaN,NaN)         |           NaN
+ (NaN,NaN)         | (NaN,NaN)         |           NaN
+ (NaN,NaN)         | (NaN,NaN)         |           NaN
+ (NaN,NaN)         | (NaN,NaN)         |           NaN
+ (NaN,NaN)         | (NaN,NaN)         |           NaN
+ (10,10)           | (10,10)           |            10
+ (10,10)           | (10,10)           | 9.89949493661
+ (10,10)           | (10,10)           | 3.60555127546
+ (10,10)           | (10,10)           | 3.60555127546
+ (10,10)           | (10,10)           | 3.60555127546
+ (10,10)           | (10,10)           | 14.1421356237
+ (10,10)           | (10,10)           | 13.4536240471
+(63 rows)
+
+-- Closest point to line
+SELECT p.f1, l.s, p.f1 ## l.s
+FROM POINT_TBL p, LINE_TBL l;
+        f1         |                   s                   |             ?column?             
+-------------------+---------------------------------------+----------------------------------
+ (0,0)             | {0,-1,5}                              | (0,5)
+ (0,0)             | {1,0,5}                               | (-5,0)
+ (0,0)             | {0,3,0}                               | (0,0)
+ (0,0)             | {1,-1,0}                              | (0,0)
+ (0,0)             | {-0.4,-1,-6}                          | (-2.06896551724,-5.1724137931)
+ (0,0)             | {-0.000184615384615,-1,15.3846153846} | (0.00284023658959,15.3846148603)
+ (0,0)             | {-1,0,1}                              | (1,0)
+ (0,0)             | {3,NaN,5}                             | (NaN,NaN)
+ (0,0)             | {0,-1,3}                              | (0,3)
+ (0,0)             | {-1,0,3}                              | (3,0)
+ (-10,0)           | {0,-1,5}                              | (-10,5)
+ (-10,0)           | {1,0,5}                               | (-5,0)
+ (-10,0)           | {0,3,0}                               | (-10,0)
+ (-10,0)           | {1,-1,0}                              | (-5,-5)
+ (-10,0)           | {-0.4,-1,-6}                          | (-10.6896551724,-1.72413793103)
+ (-10,0)           | {-0.000184615384615,-1,15.3846153846} | (-9.99715942258,15.386461014)
+ (-10,0)           | {-1,0,1}                              | (1,0)
+ (-10,0)           | {3,NaN,5}                             | (NaN,NaN)
+ (-10,0)           | {0,-1,3}                              | (-10,3)
+ (-10,0)           | {-1,0,3}                              | (3,0)
+ (-3,4)            | {0,-1,5}                              | (-3,5)
+ (-3,4)            | {1,0,5}                               | (-5,4)
+ (-3,4)            | {0,3,0}                               | (-3,0)
+ (-3,4)            | {1,-1,0}                              | (0.5,0.5)
+ (-3,4)            | {-0.4,-1,-6}                          | (-6.03448275862,-3.58620689655)
+ (-3,4)            | {-0.000184615384615,-1,15.3846153846} | (-2.99789812268,15.3851688427)
+ (-3,4)            | {-1,0,1}                              | (1,4)
+ (-3,4)            | {3,NaN,5}                             | (NaN,NaN)
+ (-3,4)            | {0,-1,3}                              | (-3,3)
+ (-3,4)            | {-1,0,3}                              | (3,4)
+ (5.1,34.5)        | {0,-1,5}                              | (5.1,5)
+ (5.1,34.5)        | {1,0,5}                               | (-5,34.5)
+ (5.1,34.5)        | {0,3,0}                               | (5.1,0)
+ (5.1,34.5)        | {1,-1,0}                              | (19.8,19.8)
+ (5.1,34.5)        | {-0.4,-1,-6}                          | (-9.56896551724,-2.1724137931)
+ (5.1,34.5)        | {-0.000184615384615,-1,15.3846153846} | (5.09647083221,15.3836744977)
+ (5.1,34.5)        | {-1,0,1}                              | (1,34.5)
+ (5.1,34.5)        | {3,NaN,5}                             | (NaN,NaN)
+ (5.1,34.5)        | {0,-1,3}                              | (5.1,3)
+ (5.1,34.5)        | {-1,0,3}                              | (3,34.5)
+ (-5,-12)          | {0,-1,5}                              | (-5,5)
+ (-5,-12)          | {1,0,5}                               | (-5,-12)
+ (-5,-12)          | {0,3,0}                               | (-5,0)
+ (-5,-12)          | {1,-1,0}                              | (-8.5,-8.5)
+ (-5,-12)          | {-0.4,-1,-6}                          | (-2.24137931034,-5.10344827586)
+ (-5,-12)          | {-0.000184615384615,-1,15.3846153846} | (-4.99494420846,15.3855375282)
+ (-5,-12)          | {-1,0,1}                              | (1,-12)
+ (-5,-12)          | {3,NaN,5}                             | (NaN,NaN)
+ (-5,-12)          | {0,-1,3}                              | (-5,3)
+ (-5,-12)          | {-1,0,3}                              | (3,-12)
+ (1e-300,-1e-300)  | {0,-1,5}                              | (1e-300,5)
+ (1e-300,-1e-300)  | {1,0,5}                               | (-5,-1e-300)
+ (1e-300,-1e-300)  | {0,3,0}                               | (1e-300,0)
+ (1e-300,-1e-300)  | {1,-1,0}                              | (0,0)
+ (1e-300,-1e-300)  | {-0.4,-1,-6}                          | (-2.06896551724,-5.1724137931)
+ (1e-300,-1e-300)  | {-0.000184615384615,-1,15.3846153846} | (0.00284023658959,15.3846148603)
+ (1e-300,-1e-300)  | {-1,0,1}                              | (1,-1e-300)
+ (1e-300,-1e-300)  | {3,NaN,5}                             | (NaN,NaN)
+ (1e-300,-1e-300)  | {0,-1,3}                              | (1e-300,3)
+ (1e-300,-1e-300)  | {-1,0,3}                              | (3,-1e-300)
+ (1e+300,Infinity) | {0,-1,5}                              | (1e+300,5)
+ (1e+300,Infinity) | {1,0,5}                               | (-5,Infinity)
+ (1e+300,Infinity) | {0,3,0}                               | (1e+300,0)
+ (1e+300,Infinity) | {1,-1,0}                              | (Infinity,NaN)
+ (1e+300,Infinity) | {-0.4,-1,-6}                          | (-Infinity,NaN)
+ (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} | (-Infinity,NaN)
+ (1e+300,Infinity) | {-1,0,1}                              | (1,Infinity)
+ (1e+300,Infinity) | {3,NaN,5}                             | (NaN,NaN)
+ (1e+300,Infinity) | {0,-1,3}                              | (1e+300,3)
+ (1e+300,Infinity) | {-1,0,3}                              | (3,Infinity)
+ (NaN,NaN)         | {0,-1,5}                              | (NaN,5)
+ (NaN,NaN)         | {1,0,5}                               | (-5,NaN)
+ (NaN,NaN)         | {0,3,0}                               | (NaN,0)
+ (NaN,NaN)         | {1,-1,0}                              | (NaN,NaN)
+ (NaN,NaN)         | {-0.4,-1,-6}                          | (NaN,NaN)
+ (NaN,NaN)         | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ (NaN,NaN)         | {-1,0,1}                              | (1,NaN)
+ (NaN,NaN)         | {3,NaN,5}                             | (NaN,NaN)
+ (NaN,NaN)         | {0,-1,3}                              | (NaN,3)
+ (NaN,NaN)         | {-1,0,3}                              | (3,NaN)
+ (10,10)           | {0,-1,5}                              | (10,5)
+ (10,10)           | {1,0,5}                               | (-5,10)
+ (10,10)           | {0,3,0}                               | (10,0)
+ (10,10)           | {1,-1,0}                              | (10,10)
+ (10,10)           | {-0.4,-1,-6}                          | (3.10344827586,-7.24137931034)
+ (10,10)           | {-0.000184615384615,-1,15.3846153846} | (10.000993742,15.3827690473)
+ (10,10)           | {-1,0,1}                              | (1,10)
+ (10,10)           | {3,NaN,5}                             | (NaN,NaN)
+ (10,10)           | {0,-1,3}                              | (10,3)
+ (10,10)           | {-1,0,3}                              | (3,10)
+(90 rows)
+
+-- Closest point to line segment
+SELECT p.f1, l.s, p.f1 ## l.s
+FROM POINT_TBL p, LSEG_TBL l;
+        f1         |               s               |             ?column?             
+-------------------+-------------------------------+----------------------------------
+ (0,0)             | [(1,2),(3,4)]                 | (1,2)
+ (0,0)             | [(0,0),(6,6)]                 | (0,0)
+ (0,0)             | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ (0,0)             | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
+ (0,0)             | [(11,22),(33,44)]             | (11,22)
+ (0,0)             | [(-10,2),(-10,3)]             | (-10,2)
+ (0,0)             | [(0,-20),(30,-20)]            | (0,-20)
+ (-10,0)           | [(1,2),(3,4)]                 | (1,2)
+ (-10,0)           | [(0,0),(6,6)]                 | (0,0)
+ (-10,0)           | [(10,-10),(-3,-4)]            | (-3,-4)
+ (-10,0)           | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
+ (-10,0)           | [(11,22),(33,44)]             | (11,22)
+ (-10,0)           | [(-10,2),(-10,3)]             | (-10,2)
+ (-10,0)           | [(0,-20),(30,-20)]            | (0,-20)
+ (-3,4)            | [(1,2),(3,4)]                 | (1,2)
+ (-3,4)            | [(0,0),(6,6)]                 | (0.5,0.5)
+ (-3,4)            | [(10,-10),(-3,-4)]            | (-3,-4)
+ (-3,4)            | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
+ (-3,4)            | [(11,22),(33,44)]             | (11,22)
+ (-3,4)            | [(-10,2),(-10,3)]             | (-10,3)
+ (-3,4)            | [(0,-20),(30,-20)]            | (0,-20)
+ (5.1,34.5)        | [(1,2),(3,4)]                 | (3,4)
+ (5.1,34.5)        | [(0,0),(6,6)]                 | (6,6)
+ (5.1,34.5)        | [(10,-10),(-3,-4)]            | (-3,-4)
+ (5.1,34.5)        | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
+ (5.1,34.5)        | [(11,22),(33,44)]             | (14.3,25.3)
+ (5.1,34.5)        | [(-10,2),(-10,3)]             | (-10,3)
+ (5.1,34.5)        | [(0,-20),(30,-20)]            | (5.1,-20)
+ (-5,-12)          | [(1,2),(3,4)]                 | (1,2)
+ (-5,-12)          | [(0,0),(6,6)]                 | (0,0)
+ (-5,-12)          | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
+ (-5,-12)          | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
+ (-5,-12)          | [(11,22),(33,44)]             | (11,22)
+ (-5,-12)          | [(-10,2),(-10,3)]             | (-10,2)
+ (-5,-12)          | [(0,-20),(30,-20)]            | (0,-20)
+ (1e-300,-1e-300)  | [(1,2),(3,4)]                 | (1,2)
+ (1e-300,-1e-300)  | [(0,0),(6,6)]                 | (0,0)
+ (1e-300,-1e-300)  | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ (1e-300,-1e-300)  | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
+ (1e-300,-1e-300)  | [(11,22),(33,44)]             | (11,22)
+ (1e-300,-1e-300)  | [(-10,2),(-10,3)]             | (-10,2)
+ (1e-300,-1e-300)  | [(0,-20),(30,-20)]            | (1e-300,-20)
+ (1e+300,Infinity) | [(1,2),(3,4)]                 | (3,4)
+ (1e+300,Infinity) | [(0,0),(6,6)]                 | (6,6)
+ (1e+300,Infinity) | [(10,-10),(-3,-4)]            | (-3,-4)
+ (1e+300,Infinity) | [(-1000000,200),(300000,-40)] | (-1000000,200)
+ (1e+300,Infinity) | [(11,22),(33,44)]             | (33,44)
+ (1e+300,Infinity) | [(-10,2),(-10,3)]             | (-10,3)
+ (1e+300,Infinity) | [(0,-20),(30,-20)]            | (30,-20)
+ (NaN,NaN)         | [(1,2),(3,4)]                 | (NaN,NaN)
+ (NaN,NaN)         | [(0,0),(6,6)]                 | (NaN,NaN)
+ (NaN,NaN)         | [(10,-10),(-3,-4)]            | (NaN,NaN)
+ (NaN,NaN)         | [(-1000000,200),(300000,-40)] | (NaN,NaN)
+ (NaN,NaN)         | [(11,22),(33,44)]             | (NaN,NaN)
+ (NaN,NaN)         | [(-10,2),(-10,3)]             | (-10,NaN)
+ (NaN,NaN)         | [(0,-20),(30,-20)]            | (NaN,-20)
+ (10,10)           | [(1,2),(3,4)]                 | (3,4)
+ (10,10)           | [(0,0),(6,6)]                 | (6,6)
+ (10,10)           | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
+ (10,10)           | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
+ (10,10)           | [(11,22),(33,44)]             | (11,22)
+ (10,10)           | [(-10,2),(-10,3)]             | (-10,3)
+ (10,10)           | [(0,-20),(30,-20)]            | (10,-20)
+(63 rows)
+
+-- Closest point to box
+SELECT p.f1, b.f1, p.f1 ## b.f1
+FROM POINT_TBL p, BOX_TBL b;
+        f1         |         f1          |   ?column?   
+-------------------+---------------------+--------------
+ (0,0)             | (2,2),(0,0)         | (0,0)
+ (0,0)             | (3,3),(1,1)         | (1,1)
+ (0,0)             | (-2,2),(-8,-10)     | (-2,0)
+ (0,0)             | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (0,0)             | (3,3),(3,3)         | (3,3)
+ (-10,0)           | (2,2),(0,0)         | (0,0)
+ (-10,0)           | (3,3),(1,1)         | (1,1)
+ (-10,0)           | (-2,2),(-8,-10)     | (-8,0)
+ (-10,0)           | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (-10,0)           | (3,3),(3,3)         | (3,3)
+ (-3,4)            | (2,2),(0,0)         | (0,2)
+ (-3,4)            | (3,3),(1,1)         | (1,3)
+ (-3,4)            | (-2,2),(-8,-10)     | (-3,2)
+ (-3,4)            | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (-3,4)            | (3,3),(3,3)         | (3,3)
+ (5.1,34.5)        | (2,2),(0,0)         | (2,2)
+ (5.1,34.5)        | (3,3),(1,1)         | (3,3)
+ (5.1,34.5)        | (-2,2),(-8,-10)     | (-2,2)
+ (5.1,34.5)        | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (5.1,34.5)        | (3,3),(3,3)         | (3,3)
+ (-5,-12)          | (2,2),(0,0)         | (0,0)
+ (-5,-12)          | (3,3),(1,1)         | (1,1)
+ (-5,-12)          | (-2,2),(-8,-10)     | (-5,-10)
+ (-5,-12)          | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (-5,-12)          | (3,3),(3,3)         | (3,3)
+ (1e-300,-1e-300)  | (2,2),(0,0)         | (0,0)
+ (1e-300,-1e-300)  | (3,3),(1,1)         | (1,1)
+ (1e-300,-1e-300)  | (-2,2),(-8,-10)     | (-2,-1e-300)
+ (1e-300,-1e-300)  | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (1e-300,-1e-300)  | (3,3),(3,3)         | (3,3)
+ (1e+300,Infinity) | (2,2),(0,0)         | (0,2)
+ (1e+300,Infinity) | (3,3),(1,1)         | (1,3)
+ (1e+300,Infinity) | (-2,2),(-8,-10)     | (-8,2)
+ (1e+300,Infinity) | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (1e+300,Infinity) | (3,3),(3,3)         | (3,3)
+ (NaN,NaN)         | (2,2),(0,0)         | (0,NaN)
+ (NaN,NaN)         | (3,3),(1,1)         | (1,NaN)
+ (NaN,NaN)         | (-2,2),(-8,-10)     | (-8,NaN)
+ (NaN,NaN)         | (2.5,3.5),(2.5,2.5) | (2.5,NaN)
+ (NaN,NaN)         | (3,3),(3,3)         | (3,NaN)
+ (10,10)           | (2,2),(0,0)         | (2,2)
+ (10,10)           | (3,3),(1,1)         | (3,3)
+ (10,10)           | (-2,2),(-8,-10)     | (-2,2)
+ (10,10)           | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (10,10)           | (3,3),(3,3)         | (3,3)
+(45 rows)
+
+-- On line
+SELECT p.f1, l.s
+FROM POINT_TBL p, LINE_TBL l
+WHERE p.f1 <@ l.s;
+        f1        |    s     
+------------------+----------
+ (0,0)            | {0,3,0}
+ (0,0)            | {1,-1,0}
+ (-10,0)          | {0,3,0}
+ (-5,-12)         | {1,0,5}
+ (1e-300,-1e-300) | {0,3,0}
+ (1e-300,-1e-300) | {1,-1,0}
+ (10,10)          | {1,-1,0}
+(7 rows)
+
+-- On line segment
+SELECT p.f1, l.s
+FROM POINT_TBL p, LSEG_TBL l
+WHERE p.f1 <@ l.s;
+        f1        |       s       
+------------------+---------------
+ (0,0)            | [(0,0),(6,6)]
+ (1e-300,-1e-300) | [(0,0),(6,6)]
+(2 rows)
+
+-- On path
+SELECT p.f1, p1.f1
+FROM POINT_TBL p, PATH_TBL p1
+WHERE p.f1 <@ p1.f1;
+        f1        |            f1             
+------------------+---------------------------
+ (0,0)            | [(0,0),(3,0),(4,5),(1,6)]
+ (1e-300,-1e-300) | [(0,0),(3,0),(4,5),(1,6)]
+(2 rows)
+
+--
+-- Lines
+--
+-- Vertical
+SELECT s
+FROM LINE_TBL
+WHERE ?| s;
+    s     
+----------
+ {1,0,5}
+ {-1,0,1}
+ {-1,0,3}
+(3 rows)
+
+-- Horizontal
+SELECT s
+FROM LINE_TBL
+WHERE ?- s;
+    s     
+----------
+ {0,-1,5}
+ {0,3,0}
+ {0,-1,3}
+(3 rows)
+
+-- Same as line
+SELECT l1.s, l2.s
+FROM LINE_TBL l1, LINE_TBL l2
+WHERE l1.s = l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {0,-1,5}
+ {1,0,5}                               | {1,0,5}
+ {0,3,0}                               | {0,3,0}
+ {1,-1,0}                              | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846}
+ {-1,0,1}                              | {-1,0,1}
+ {0,-1,3}                              | {0,-1,3}
+ {-1,0,3}                              | {-1,0,3}
+(9 rows)
+
+-- Parallel to line
+SELECT l1.s, l2.s
+FROM LINE_TBL l1, LINE_TBL l2
+WHERE l1.s ?|| l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {0,-1,5}
+ {0,-1,5}                              | {0,3,0}
+ {0,-1,5}                              | {0,-1,3}
+ {1,0,5}                               | {1,0,5}
+ {1,0,5}                               | {-1,0,1}
+ {1,0,5}                               | {-1,0,3}
+ {0,3,0}                               | {0,-1,5}
+ {0,3,0}                               | {0,3,0}
+ {0,3,0}                               | {0,-1,3}
+ {1,-1,0}                              | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846}
+ {-1,0,1}                              | {1,0,5}
+ {-1,0,1}                              | {-1,0,1}
+ {-1,0,1}                              | {-1,0,3}
+ {0,-1,3}                              | {0,-1,5}
+ {0,-1,3}                              | {0,3,0}
+ {0,-1,3}                              | {0,-1,3}
+ {-1,0,3}                              | {1,0,5}
+ {-1,0,3}                              | {-1,0,1}
+ {-1,0,3}                              | {-1,0,3}
+(21 rows)
+
+-- Perpendicular to line
+SELECT l1.s, l2.s
+FROM LINE_TBL l1, LINE_TBL l2
+WHERE l1.s ?-| l2.s;
+    s     |    s     
+----------+----------
+ {0,-1,5} | {1,0,5}
+ {0,-1,5} | {-1,0,1}
+ {0,-1,5} | {-1,0,3}
+ {1,0,5}  | {0,-1,5}
+ {1,0,5}  | {0,3,0}
+ {1,0,5}  | {0,-1,3}
+ {0,3,0}  | {1,0,5}
+ {0,3,0}  | {-1,0,1}
+ {0,3,0}  | {-1,0,3}
+ {-1,0,1} | {0,-1,5}
+ {-1,0,1} | {0,3,0}
+ {-1,0,1} | {0,-1,3}
+ {0,-1,3} | {1,0,5}
+ {0,-1,3} | {-1,0,1}
+ {0,-1,3} | {-1,0,3}
+ {-1,0,3} | {0,-1,5}
+ {-1,0,3} | {0,3,0}
+ {-1,0,3} | {0,-1,3}
+(18 rows)
+
+-- Distance to line
+SELECT l1.s, l2.s, l1.s <-> l2.s
+FROM LINE_TBL l1, LINE_TBL l2;
+                   s                   |                   s                   | ?column? 
+---------------------------------------+---------------------------------------+----------
+ {0,-1,5}                              | {0,-1,5}                              |        0
+ {0,-1,5}                              | {1,0,5}                               |        0
+ {0,-1,5}                              | {0,3,0}                               |        5
+ {0,-1,5}                              | {1,-1,0}                              |        0
+ {0,-1,5}                              | {-0.4,-1,-6}                          |        0
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,-1,5}                              | {-1,0,1}                              |        0
+ {0,-1,5}                              | {3,NaN,5}                             |        0
+ {0,-1,5}                              | {0,-1,3}                              |        2
+ {0,-1,5}                              | {-1,0,3}                              |        0
+ {1,0,5}                               | {0,-1,5}                              |        0
+ {1,0,5}                               | {1,0,5}                               |        0
+ {1,0,5}                               | {0,3,0}                               |        0
+ {1,0,5}                               | {1,-1,0}                              |        0
+ {1,0,5}                               | {-0.4,-1,-6}                          |        0
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846} |        0
+ {1,0,5}                               | {-1,0,1}                              |        6
+ {1,0,5}                               | {3,NaN,5}                             |        0
+ {1,0,5}                               | {0,-1,3}                              |        0
+ {1,0,5}                               | {-1,0,3}                              |        8
+ {0,3,0}                               | {0,-1,5}                              |        5
+ {0,3,0}                               | {1,0,5}                               |        0
+ {0,3,0}                               | {0,3,0}                               |        0
+ {0,3,0}                               | {1,-1,0}                              |        0
+ {0,3,0}                               | {-0.4,-1,-6}                          |        0
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,3,0}                               | {-1,0,1}                              |        0
+ {0,3,0}                               | {3,NaN,5}                             |        0
+ {0,3,0}                               | {0,-1,3}                              |        3
+ {0,3,0}                               | {-1,0,3}                              |        0
+ {1,-1,0}                              | {0,-1,5}                              |        0
+ {1,-1,0}                              | {1,0,5}                               |        0
+ {1,-1,0}                              | {0,3,0}                               |        0
+ {1,-1,0}                              | {1,-1,0}                              |        0
+ {1,-1,0}                              | {-0.4,-1,-6}                          |        0
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {1,-1,0}                              | {-1,0,1}                              |        0
+ {1,-1,0}                              | {3,NaN,5}                             |        0
+ {1,-1,0}                              | {0,-1,3}                              |        0
+ {1,-1,0}                              | {-1,0,3}                              |        0
+ {-0.4,-1,-6}                          | {0,-1,5}                              |        0
+ {-0.4,-1,-6}                          | {1,0,5}                               |        0
+ {-0.4,-1,-6}                          | {0,3,0}                               |        0
+ {-0.4,-1,-6}                          | {1,-1,0}                              |        0
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}                          |        0
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846} |        0
+ {-0.4,-1,-6}                          | {-1,0,1}                              |        0
+ {-0.4,-1,-6}                          | {3,NaN,5}                             |        0
+ {-0.4,-1,-6}                          | {0,-1,3}                              |        0
+ {-0.4,-1,-6}                          | {-1,0,3}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}                               |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}                               |        0
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}                          |        0
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} |        0
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,1}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}                             |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}                              |        0
+ {-1,0,1}                              | {0,-1,5}                              |        0
+ {-1,0,1}                              | {1,0,5}                               |        6
+ {-1,0,1}                              | {0,3,0}                               |        0
+ {-1,0,1}                              | {1,-1,0}                              |        0
+ {-1,0,1}                              | {-0.4,-1,-6}                          |        0
+ {-1,0,1}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {-1,0,1}                              | {-1,0,1}                              |        0
+ {-1,0,1}                              | {3,NaN,5}                             |        0
+ {-1,0,1}                              | {0,-1,3}                              |        0
+ {-1,0,1}                              | {-1,0,3}                              |        2
+ {3,NaN,5}                             | {0,-1,5}                              |        0
+ {3,NaN,5}                             | {1,0,5}                               |        0
+ {3,NaN,5}                             | {0,3,0}                               |        0
+ {3,NaN,5}                             | {1,-1,0}                              |        0
+ {3,NaN,5}                             | {-0.4,-1,-6}                          |        0
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846} |        0
+ {3,NaN,5}                             | {-1,0,1}                              |        0
+ {3,NaN,5}                             | {3,NaN,5}                             |        0
+ {3,NaN,5}                             | {0,-1,3}                              |        0
+ {3,NaN,5}                             | {-1,0,3}                              |        0
+ {0,-1,3}                              | {0,-1,5}                              |        2
+ {0,-1,3}                              | {1,0,5}                               |        0
+ {0,-1,3}                              | {0,3,0}                               |        3
+ {0,-1,3}                              | {1,-1,0}                              |        0
+ {0,-1,3}                              | {-0.4,-1,-6}                          |        0
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,-1,3}                              | {-1,0,1}                              |        0
+ {0,-1,3}                              | {3,NaN,5}                             |        0
+ {0,-1,3}                              | {0,-1,3}                              |        0
+ {0,-1,3}                              | {-1,0,3}                              |        0
+ {-1,0,3}                              | {0,-1,5}                              |        0
+ {-1,0,3}                              | {1,0,5}                               |        8
+ {-1,0,3}                              | {0,3,0}                               |        0
+ {-1,0,3}                              | {1,-1,0}                              |        0
+ {-1,0,3}                              | {-0.4,-1,-6}                          |        0
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {-1,0,3}                              | {-1,0,1}                              |        2
+ {-1,0,3}                              | {3,NaN,5}                             |        0
+ {-1,0,3}                              | {0,-1,3}                              |        0
+ {-1,0,3}                              | {-1,0,3}                              |        0
+(100 rows)
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1
+FROM LINE_TBL l, BOX_TBL b;
+ERROR:  function "dist_lb" not implemented
+-- Intersect with line
+SELECT l1.s, l2.s
+FROM LINE_TBL l1, LINE_TBL l2
+WHERE l1.s ?# l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {1,0,5}
+ {0,-1,5}                              | {1,-1,0}
+ {0,-1,5}                              | {-0.4,-1,-6}
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,5}                              | {-1,0,1}
+ {0,-1,5}                              | {3,NaN,5}
+ {0,-1,5}                              | {-1,0,3}
+ {1,0,5}                               | {0,-1,5}
+ {1,0,5}                               | {0,3,0}
+ {1,0,5}                               | {1,-1,0}
+ {1,0,5}                               | {-0.4,-1,-6}
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846}
+ {1,0,5}                               | {3,NaN,5}
+ {1,0,5}                               | {0,-1,3}
+ {0,3,0}                               | {1,0,5}
+ {0,3,0}                               | {1,-1,0}
+ {0,3,0}                               | {-0.4,-1,-6}
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846}
+ {0,3,0}                               | {-1,0,1}
+ {0,3,0}                               | {3,NaN,5}
+ {0,3,0}                               | {-1,0,3}
+ {1,-1,0}                              | {0,-1,5}
+ {1,-1,0}                              | {1,0,5}
+ {1,-1,0}                              | {0,3,0}
+ {1,-1,0}                              | {-0.4,-1,-6}
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846}
+ {1,-1,0}                              | {-1,0,1}
+ {1,-1,0}                              | {3,NaN,5}
+ {1,-1,0}                              | {0,-1,3}
+ {1,-1,0}                              | {-1,0,3}
+ {-0.4,-1,-6}                          | {0,-1,5}
+ {-0.4,-1,-6}                          | {1,0,5}
+ {-0.4,-1,-6}                          | {0,3,0}
+ {-0.4,-1,-6}                          | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846}
+ {-0.4,-1,-6}                          | {-1,0,1}
+ {-0.4,-1,-6}                          | {3,NaN,5}
+ {-0.4,-1,-6}                          | {0,-1,3}
+ {-0.4,-1,-6}                          | {-1,0,3}
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,1}
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}
+ {-1,0,1}                              | {0,-1,5}
+ {-1,0,1}                              | {0,3,0}
+ {-1,0,1}                              | {1,-1,0}
+ {-1,0,1}                              | {-0.4,-1,-6}
+ {-1,0,1}                              | {-0.000184615384615,-1,15.3846153846}
+ {-1,0,1}                              | {3,NaN,5}
+ {-1,0,1}                              | {0,-1,3}
+ {3,NaN,5}                             | {0,-1,5}
+ {3,NaN,5}                             | {1,0,5}
+ {3,NaN,5}                             | {0,3,0}
+ {3,NaN,5}                             | {1,-1,0}
+ {3,NaN,5}                             | {-0.4,-1,-6}
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846}
+ {3,NaN,5}                             | {-1,0,1}
+ {3,NaN,5}                             | {3,NaN,5}
+ {3,NaN,5}                             | {0,-1,3}
+ {3,NaN,5}                             | {-1,0,3}
+ {0,-1,3}                              | {1,0,5}
+ {0,-1,3}                              | {1,-1,0}
+ {0,-1,3}                              | {-0.4,-1,-6}
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,3}                              | {-1,0,1}
+ {0,-1,3}                              | {3,NaN,5}
+ {0,-1,3}                              | {-1,0,3}
+ {-1,0,3}                              | {0,-1,5}
+ {-1,0,3}                              | {0,3,0}
+ {-1,0,3}                              | {1,-1,0}
+ {-1,0,3}                              | {-0.4,-1,-6}
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846}
+ {-1,0,3}                              | {3,NaN,5}
+ {-1,0,3}                              | {0,-1,3}
+(79 rows)
+
+-- Intersect with box
+SELECT l.s, b.f1
+FROM LINE_TBL l, BOX_TBL b
+WHERE l.s ?# b.f1;
+      s       |         f1          
+--------------+---------------------
+ {1,0,5}      | (-2,2),(-8,-10)
+ {0,3,0}      | (2,2),(0,0)
+ {0,3,0}      | (-2,2),(-8,-10)
+ {1,-1,0}     | (2,2),(0,0)
+ {1,-1,0}     | (3,3),(1,1)
+ {1,-1,0}     | (-2,2),(-8,-10)
+ {1,-1,0}     | (2.5,3.5),(2.5,2.5)
+ {1,-1,0}     | (3,3),(3,3)
+ {-0.4,-1,-6} | (-2,2),(-8,-10)
+ {-1,0,1}     | (2,2),(0,0)
+ {-1,0,1}     | (3,3),(1,1)
+ {0,-1,3}     | (3,3),(1,1)
+ {0,-1,3}     | (2.5,3.5),(2.5,2.5)
+ {0,-1,3}     | (3,3),(3,3)
+ {-1,0,3}     | (3,3),(1,1)
+(15 rows)
+
+-- Intersection point with line
+SELECT l1.s, l2.s, l1.s # l2.s
+FROM LINE_TBL l1, LINE_TBL l2;
+                   s                   |                   s                   |            ?column?             
+---------------------------------------+---------------------------------------+---------------------------------
+ {0,-1,5}                              | {0,-1,5}                              | 
+ {0,-1,5}                              | {1,0,5}                               | (-5,5)
+ {0,-1,5}                              | {0,3,0}                               | 
+ {0,-1,5}                              | {1,-1,0}                              | (5,5)
+ {0,-1,5}                              | {-0.4,-1,-6}                          | (-27.5,5)
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846} | (56250,5)
+ {0,-1,5}                              | {-1,0,1}                              | (1,5)
+ {0,-1,5}                              | {3,NaN,5}                             | (NaN,5)
+ {0,-1,5}                              | {0,-1,3}                              | 
+ {0,-1,5}                              | {-1,0,3}                              | (3,5)
+ {1,0,5}                               | {0,-1,5}                              | (-5,5)
+ {1,0,5}                               | {1,0,5}                               | 
+ {1,0,5}                               | {0,3,0}                               | (-5,0)
+ {1,0,5}                               | {1,-1,0}                              | (-5,-5)
+ {1,0,5}                               | {-0.4,-1,-6}                          | (-5,-4)
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846} | (-5,15.3855384615)
+ {1,0,5}                               | {-1,0,1}                              | 
+ {1,0,5}                               | {3,NaN,5}                             | (-5,NaN)
+ {1,0,5}                               | {0,-1,3}                              | (-5,3)
+ {1,0,5}                               | {-1,0,3}                              | 
+ {0,3,0}                               | {0,-1,5}                              | 
+ {0,3,0}                               | {1,0,5}                               | (-5,0)
+ {0,3,0}                               | {0,3,0}                               | 
+ {0,3,0}                               | {1,-1,0}                              | (0,0)
+ {0,3,0}                               | {-0.4,-1,-6}                          | (-15,0)
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846} | (83333.3333333,0)
+ {0,3,0}                               | {-1,0,1}                              | (1,0)
+ {0,3,0}                               | {3,NaN,5}                             | (NaN,0)
+ {0,3,0}                               | {0,-1,3}                              | 
+ {0,3,0}                               | {-1,0,3}                              | (3,0)
+ {1,-1,0}                              | {0,-1,5}                              | (5,5)
+ {1,-1,0}                              | {1,0,5}                               | (-5,-5)
+ {1,-1,0}                              | {0,3,0}                               | (0,0)
+ {1,-1,0}                              | {1,-1,0}                              | 
+ {1,-1,0}                              | {-0.4,-1,-6}                          | (-4.28571428571,-4.28571428571)
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846} | (15.3817756722,15.3817756722)
+ {1,-1,0}                              | {-1,0,1}                              | (1,1)
+ {1,-1,0}                              | {3,NaN,5}                             | (NaN,NaN)
+ {1,-1,0}                              | {0,-1,3}                              | (3,3)
+ {1,-1,0}                              | {-1,0,3}                              | (3,3)
+ {-0.4,-1,-6}                          | {0,-1,5}                              | (-27.5,5)
+ {-0.4,-1,-6}                          | {1,0,5}                               | (-5,-4)
+ {-0.4,-1,-6}                          | {0,3,0}                               | (-15,0)
+ {-0.4,-1,-6}                          | {1,-1,0}                              | (-4.28571428571,-4.28571428571)
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}                          | 
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846} | (-53.4862244113,15.3944897645)
+ {-0.4,-1,-6}                          | {-1,0,1}                              | (1,-6.4)
+ {-0.4,-1,-6}                          | {3,NaN,5}                             | (NaN,NaN)
+ {-0.4,-1,-6}                          | {0,-1,3}                              | (-22.5,3)
+ {-0.4,-1,-6}                          | {-1,0,3}                              | (3,-7.2)
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}                              | (56250,5)
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}                               | (-5,15.3855384615)
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}                               | (83333.3333333,0)
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}                              | (15.3817756722,15.3817756722)
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}                          | (-53.4862244113,15.3944897645)
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} | 
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,1}                              | (1,15.3844307692)
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}                             | (NaN,NaN)
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}                              | (67083.3333333,3)
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}                              | (3,15.3840615385)
+ {-1,0,1}                              | {0,-1,5}                              | (1,5)
+ {-1,0,1}                              | {1,0,5}                               | 
+ {-1,0,1}                              | {0,3,0}                               | (1,0)
+ {-1,0,1}                              | {1,-1,0}                              | (1,1)
+ {-1,0,1}                              | {-0.4,-1,-6}                          | (1,-6.4)
+ {-1,0,1}                              | {-0.000184615384615,-1,15.3846153846} | (1,15.3844307692)
+ {-1,0,1}                              | {-1,0,1}                              | 
+ {-1,0,1}                              | {3,NaN,5}                             | (1,NaN)
+ {-1,0,1}                              | {0,-1,3}                              | (1,3)
+ {-1,0,1}                              | {-1,0,3}                              | 
+ {3,NaN,5}                             | {0,-1,5}                              | (NaN,5)
+ {3,NaN,5}                             | {1,0,5}                               | (-5,NaN)
+ {3,NaN,5}                             | {0,3,0}                               | (NaN,0)
+ {3,NaN,5}                             | {1,-1,0}                              | (NaN,NaN)
+ {3,NaN,5}                             | {-0.4,-1,-6}                          | (NaN,NaN)
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ {3,NaN,5}                             | {-1,0,1}                              | (1,NaN)
+ {3,NaN,5}                             | {3,NaN,5}                             | (NaN,NaN)
+ {3,NaN,5}                             | {0,-1,3}                              | (NaN,3)
+ {3,NaN,5}                             | {-1,0,3}                              | (3,NaN)
+ {0,-1,3}                              | {0,-1,5}                              | 
+ {0,-1,3}                              | {1,0,5}                               | (-5,3)
+ {0,-1,3}                              | {0,3,0}                               | 
+ {0,-1,3}                              | {1,-1,0}                              | (3,3)
+ {0,-1,3}                              | {-0.4,-1,-6}                          | (-22.5,3)
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846} | (67083.3333333,3)
+ {0,-1,3}                              | {-1,0,1}                              | (1,3)
+ {0,-1,3}                              | {3,NaN,5}                             | (NaN,3)
+ {0,-1,3}                              | {0,-1,3}                              | 
+ {0,-1,3}                              | {-1,0,3}                              | (3,3)
+ {-1,0,3}                              | {0,-1,5}                              | (3,5)
+ {-1,0,3}                              | {1,0,5}                               | 
+ {-1,0,3}                              | {0,3,0}                               | (3,0)
+ {-1,0,3}                              | {1,-1,0}                              | (3,3)
+ {-1,0,3}                              | {-0.4,-1,-6}                          | (3,-7.2)
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846} | (3,15.3840615385)
+ {-1,0,3}                              | {-1,0,1}                              | 
+ {-1,0,3}                              | {3,NaN,5}                             | (3,NaN)
+ {-1,0,3}                              | {0,-1,3}                              | (3,3)
+ {-1,0,3}                              | {-1,0,3}                              | 
+(100 rows)
+
+-- Closest point to line segment
+SELECT l.s, l1.s, l.s ## l1.s
+FROM LINE_TBL l, LSEG_TBL l1;
+                   s                   |               s               |            ?column?            
+---------------------------------------+-------------------------------+--------------------------------
+ {0,-1,5}                              | [(1,2),(3,4)]                 | (3,4)
+ {0,-1,5}                              | [(0,0),(6,6)]                 | (5,5)
+ {0,-1,5}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,-1,5}                              | [(-1000000,200),(300000,-40)] | (56250,5)
+ {0,-1,5}                              | [(11,22),(33,44)]             | (11,22)
+ {0,-1,5}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {0,-1,5}                              | [(0,-20),(30,-20)]            | (30,-20)
+ {1,0,5}                               | [(1,2),(3,4)]                 | (1,2)
+ {1,0,5}                               | [(0,0),(6,6)]                 | (0,0)
+ {1,0,5}                               | [(10,-10),(-3,-4)]            | (-3,-4)
+ {1,0,5}                               | [(-1000000,200),(300000,-40)] | (-5,15.3855384615)
+ {1,0,5}                               | [(11,22),(33,44)]             | (11,22)
+ {1,0,5}                               | [(-10,2),(-10,3)]             | (-10,3)
+ {1,0,5}                               | [(0,-20),(30,-20)]            | (0,-20)
+ {0,3,0}                               | [(1,2),(3,4)]                 | (1,2)
+ {0,3,0}                               | [(0,0),(6,6)]                 | (0,0)
+ {0,3,0}                               | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,3,0}                               | [(-1000000,200),(300000,-40)] | (83333.3333333,0)
+ {0,3,0}                               | [(11,22),(33,44)]             | (11,22)
+ {0,3,0}                               | [(-10,2),(-10,3)]             | (-10,2)
+ {0,3,0}                               | [(0,-20),(30,-20)]            | (30,-20)
+ {1,-1,0}                              | [(1,2),(3,4)]                 | (3,4)
+ {1,-1,0}                              | [(0,0),(6,6)]                 | (6,6)
+ {1,-1,0}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {1,-1,0}                              | [(-1000000,200),(300000,-40)] | (15.3817756722,15.3817756722)
+ {1,-1,0}                              | [(11,22),(33,44)]             | (33,44)
+ {1,-1,0}                              | [(-10,2),(-10,3)]             | (-10,2)
+ {1,-1,0}                              | [(0,-20),(30,-20)]            | (0,-20)
+ {-0.4,-1,-6}                          | [(1,2),(3,4)]                 | (1,2)
+ {-0.4,-1,-6}                          | [(0,0),(6,6)]                 | (0,0)
+ {-0.4,-1,-6}                          | [(10,-10),(-3,-4)]            | (10,-10)
+ {-0.4,-1,-6}                          | [(-1000000,200),(300000,-40)] | (-53.4862244113,15.3944897645)
+ {-0.4,-1,-6}                          | [(11,22),(33,44)]             | (11,22)
+ {-0.4,-1,-6}                          | [(-10,2),(-10,3)]             | (-10,2)
+ {-0.4,-1,-6}                          | [(0,-20),(30,-20)]            | (30,-20)
+ {-0.000184615384615,-1,15.3846153846} | [(1,2),(3,4)]                 | (3,4)
+ {-0.000184615384615,-1,15.3846153846} | [(0,0),(6,6)]                 | (6,6)
+ {-0.000184615384615,-1,15.3846153846} | [(10,-10),(-3,-4)]            | (-3,-4)
+ {-0.000184615384615,-1,15.3846153846} | [(-1000000,200),(300000,-40)] | (-1000000,200)
+ {-0.000184615384615,-1,15.3846153846} | [(11,22),(33,44)]             | (11,22)
+ {-0.000184615384615,-1,15.3846153846} | [(-10,2),(-10,3)]             | (-10,3)
+ {-0.000184615384615,-1,15.3846153846} | [(0,-20),(30,-20)]            | (30,-20)
+ {-1,0,1}                              | [(1,2),(3,4)]                 | (1,2)
+ {-1,0,1}                              | [(0,0),(6,6)]                 | (1,1)
+ {-1,0,1}                              | [(10,-10),(-3,-4)]            | (1,-5.84615384615)
+ {-1,0,1}                              | [(-1000000,200),(300000,-40)] | (1,15.3844307692)
+ {-1,0,1}                              | [(11,22),(33,44)]             | (11,22)
+ {-1,0,1}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {-1,0,1}                              | [(0,-20),(30,-20)]            | (1,-20)
+ {3,NaN,5}                             | [(1,2),(3,4)]                 | (3,4)
+ {3,NaN,5}                             | [(0,0),(6,6)]                 | (6,6)
+ {3,NaN,5}                             | [(10,-10),(-3,-4)]            | (-3,-4)
+ {3,NaN,5}                             | [(-1000000,200),(300000,-40)] | (300000,-40)
+ {3,NaN,5}                             | [(11,22),(33,44)]             | (33,44)
+ {3,NaN,5}                             | [(-10,2),(-10,3)]             | (-10,3)
+ {3,NaN,5}                             | [(0,-20),(30,-20)]            | (30,-20)
+ {0,-1,3}                              | [(1,2),(3,4)]                 | (2,3)
+ {0,-1,3}                              | [(0,0),(6,6)]                 | (3,3)
+ {0,-1,3}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,-1,3}                              | [(-1000000,200),(300000,-40)] | (67083.3333333,3)
+ {0,-1,3}                              | [(11,22),(33,44)]             | (11,22)
+ {0,-1,3}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {0,-1,3}                              | [(0,-20),(30,-20)]            | (30,-20)
+ {-1,0,3}                              | [(1,2),(3,4)]                 | (3,4)
+ {-1,0,3}                              | [(0,0),(6,6)]                 | (3,3)
+ {-1,0,3}                              | [(10,-10),(-3,-4)]            | (3,-6.76923076923)
+ {-1,0,3}                              | [(-1000000,200),(300000,-40)] | (3,15.3840615385)
+ {-1,0,3}                              | [(11,22),(33,44)]             | (11,22)
+ {-1,0,3}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {-1,0,3}                              | [(0,-20),(30,-20)]            | (3,-20)
+(70 rows)
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1
+FROM LINE_TBL l, BOX_TBL b;
+ERROR:  function "close_lb" not implemented
 --
 -- Line segments
 --
 -- intersection
 SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
    FROM LSEG_TBL l, POINT_TBL p;
 ERROR:  operator does not exist: lseg # point
 LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
                                            ^
 HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (-0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
+-- Length
+SELECT s, @-@ s
+FROM LSEG_TBL;
+               s               |   ?column?    
+-------------------------------+---------------
+ [(1,2),(3,4)]                 | 2.82842712475
+ [(0,0),(6,6)]                 | 8.48528137424
+ [(10,-10),(-3,-4)]            | 14.3178210633
+ [(-1000000,200),(300000,-40)] | 1300000.02215
+ [(11,22),(33,44)]             | 31.1126983722
+ [(-10,2),(-10,3)]             |             1
+ [(0,-20),(30,-20)]            |            30
+(7 rows)
+
+-- Vertical
+SELECT s
+FROM LSEG_TBL
+WHERE ?| s;
+         s         
+-------------------
+ [(-10,2),(-10,3)]
+(1 row)
+
+-- Horizontal
+SELECT s
+FROM LSEG_TBL
+WHERE ?- s;
+         s          
+--------------------
+ [(0,-20),(30,-20)]
+(1 row)
+
+-- Center
+SELECT s, @@ s
+FROM LSEG_TBL;
+               s               |   ?column?   
+-------------------------------+--------------
+ [(1,2),(3,4)]                 | (2,3)
+ [(0,0),(6,6)]                 | (3,3)
+ [(10,-10),(-3,-4)]            | (3.5,-7)
+ [(-1000000,200),(300000,-40)] | (-350000,80)
+ [(11,22),(33,44)]             | (22,33)
+ [(-10,2),(-10,3)]             | (-10,2.5)
+ [(0,-20),(30,-20)]            | (15,-20)
+(7 rows)
+
+-- To point
+SELECT s, s::point
+FROM LSEG_TBL;
+               s               |      s       
+-------------------------------+--------------
+ [(1,2),(3,4)]                 | (2,3)
+ [(0,0),(6,6)]                 | (3,3)
+ [(10,-10),(-3,-4)]            | (3.5,-7)
+ [(-1000000,200),(300000,-40)] | (-350000,80)
+ [(11,22),(33,44)]             | (22,33)
+ [(-10,2),(-10,3)]             | (-10,2.5)
+ [(0,-20),(30,-20)]            | (15,-20)
+(7 rows)
+
+-- Has points less than line segment
+SELECT l1.s, l2.s
+FROM LSEG_TBL l1, LSEG_TBL l2
+WHERE l1.s < l2.s;
+         s          |               s               
+--------------------+-------------------------------
+ [(1,2),(3,4)]      | [(0,0),(6,6)]
+ [(1,2),(3,4)]      | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]      | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]      | [(11,22),(33,44)]
+ [(1,2),(3,4)]      | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]      | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]      | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]      | [(11,22),(33,44)]
+ [(0,0),(6,6)]      | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)] | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)] | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]  | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]  | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]  | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]  | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]  | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]  | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]  | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)] | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)] | [(11,22),(33,44)]
+(21 rows)
+
+-- Has points less than or equal to line segment
+SELECT l1.s, l2.s
+FROM LSEG_TBL l1, LSEG_TBL l2
+WHERE l1.s <= l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(28 rows)
+
+-- Has points equal to line segment
+SELECT l1.s, l2.s
+FROM LSEG_TBL l1, LSEG_TBL l2
+WHERE l1.s = l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(7 rows)
+
+-- Has points greater than or equal to line segment
+SELECT l1.s, l2.s
+FROM LSEG_TBL l1, LSEG_TBL l2
+WHERE l1.s >= l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(28 rows)
+
+-- Has points greater than line segment
+SELECT l1.s, l2.s
+FROM LSEG_TBL l1, LSEG_TBL l2
+WHERE l1.s > l2.s;
+               s               |         s          
+-------------------------------+--------------------
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+(21 rows)
+
+-- Has points not equal to line segment
+SELECT l1.s, l2.s
+FROM LSEG_TBL l1, LSEG_TBL l2
+WHERE l1.s != l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+(42 rows)
+
+-- Parallel with line segment
+SELECT l1.s, l2.s
+FROM LSEG_TBL l1, LSEG_TBL l2
+WHERE l1.s ?|| l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(13 rows)
+
+-- Perpendicular with line segment
+SELECT l1.s, l2.s
+FROM LSEG_TBL l1, LSEG_TBL l2
+WHERE l1.s ?-| l2.s;
+         s          |         s          
+--------------------+--------------------
+ [(-10,2),(-10,3)]  | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)] | [(-10,2),(-10,3)]
+(2 rows)
+
+-- Distance to line
+SELECT l.s, l1.s, l.s <-> l1.s
+FROM LSEG_TBL l, LINE_TBL l1;
+               s               |                   s                   |     ?column?      
+-------------------------------+---------------------------------------+-------------------
+ [(1,2),(3,4)]                 | {0,-1,5}                              |                 3
+ [(0,0),(6,6)]                 | {0,-1,5}                              |                 0
+ [(10,-10),(-3,-4)]            | {0,-1,5}                              |                15
+ [(-1000000,200),(300000,-40)] | {0,-1,5}                              |                 0
+ [(11,22),(33,44)]             | {0,-1,5}                              |                39
+ [(-10,2),(-10,3)]             | {0,-1,5}                              |                 3
+ [(0,-20),(30,-20)]            | {0,-1,5}                              |                25
+ [(1,2),(3,4)]                 | {1,0,5}                               |                 8
+ [(0,0),(6,6)]                 | {1,0,5}                               |                11
+ [(10,-10),(-3,-4)]            | {1,0,5}                               |                15
+ [(-1000000,200),(300000,-40)] | {1,0,5}                               |                 0
+ [(11,22),(33,44)]             | {1,0,5}                               |                38
+ [(-10,2),(-10,3)]             | {1,0,5}                               |                 5
+ [(0,-20),(30,-20)]            | {1,0,5}                               |                35
+ [(1,2),(3,4)]                 | {0,3,0}                               |                 4
+ [(0,0),(6,6)]                 | {0,3,0}                               |                 0
+ [(10,-10),(-3,-4)]            | {0,3,0}                               |                10
+ [(-1000000,200),(300000,-40)] | {0,3,0}                               |                 0
+ [(11,22),(33,44)]             | {0,3,0}                               |                44
+ [(-10,2),(-10,3)]             | {0,3,0}                               |                 3
+ [(0,-20),(30,-20)]            | {0,3,0}                               |                20
+ [(1,2),(3,4)]                 | {1,-1,0}                              |    0.707106781187
+ [(0,0),(6,6)]                 | {1,-1,0}                              |                 0
+ [(10,-10),(-3,-4)]            | {1,-1,0}                              |     14.1421356237
+ [(-1000000,200),(300000,-40)] | {1,-1,0}                              |                 0
+ [(11,22),(33,44)]             | {1,-1,0}                              |     7.77817459305
+ [(-10,2),(-10,3)]             | {1,-1,0}                              |     9.19238815543
+ [(0,-20),(30,-20)]            | {1,-1,0}                              |     35.3553390593
+ [(1,2),(3,4)]                 | {-0.4,-1,-6}                          |     10.3989389379
+ [(0,0),(6,6)]                 | {-0.4,-1,-6}                          |     13.3700643487
+ [(10,-10),(-3,-4)]            | {-0.4,-1,-6}                          |                 0
+ [(-1000000,200),(300000,-40)] | {-0.4,-1,-6}                          |                 0
+ [(11,22),(33,44)]             | {-0.4,-1,-6}                          |     58.6797268639
+ [(-10,2),(-10,3)]             | {-0.4,-1,-6}                          |     4.64238345443
+ [(0,-20),(30,-20)]            | {-0.4,-1,-6}                          |     12.9986736724
+ [(1,2),(3,4)]                 | {-0.000184615384615,-1,15.3846153846} |     13.3844305411
+ [(0,0),(6,6)]                 | {-0.000184615384615,-1,15.3846153846} |     15.3846151224
+ [(10,-10),(-3,-4)]            | {-0.000184615384615,-1,15.3846153846} |     25.3827687982
+ [(-1000000,200),(300000,-40)] | {-0.000184615384615,-1,15.3846153846} | 7.10542723651e-15
+ [(11,22),(33,44)]             | {-0.000184615384615,-1,15.3846153846} |     28.6214764353
+ [(-10,2),(-10,3)]             | {-0.000184615384615,-1,15.3846153846} |     13.3864613103
+ [(0,-20),(30,-20)]            | {-0.000184615384615,-1,15.3846153846} |     35.3846147816
+ [(1,2),(3,4)]                 | {-1,0,1}                              |                 0
+ [(0,0),(6,6)]                 | {-1,0,1}                              |                 0
+ [(10,-10),(-3,-4)]            | {-1,0,1}                              |                 0
+ [(-1000000,200),(300000,-40)] | {-1,0,1}                              |                 0
+ [(11,22),(33,44)]             | {-1,0,1}                              |                32
+ [(-10,2),(-10,3)]             | {-1,0,1}                              |                11
+ [(0,-20),(30,-20)]            | {-1,0,1}                              |                 0
+ [(1,2),(3,4)]                 | {3,NaN,5}                             |               NaN
+ [(0,0),(6,6)]                 | {3,NaN,5}                             |               NaN
+ [(10,-10),(-3,-4)]            | {3,NaN,5}                             |               NaN
+ [(-1000000,200),(300000,-40)] | {3,NaN,5}                             |               NaN
+ [(11,22),(33,44)]             | {3,NaN,5}                             |               NaN
+ [(-10,2),(-10,3)]             | {3,NaN,5}                             |               NaN
+ [(0,-20),(30,-20)]            | {3,NaN,5}                             |               NaN
+ [(1,2),(3,4)]                 | {0,-1,3}                              |                 0
+ [(0,0),(6,6)]                 | {0,-1,3}                              |                 0
+ [(10,-10),(-3,-4)]            | {0,-1,3}                              |                13
+ [(-1000000,200),(300000,-40)] | {0,-1,3}                              |                 0
+ [(11,22),(33,44)]             | {0,-1,3}                              |                41
+ [(-10,2),(-10,3)]             | {0,-1,3}                              |                 0
+ [(0,-20),(30,-20)]            | {0,-1,3}                              |                23
+ [(1,2),(3,4)]                 | {-1,0,3}                              |                 0
+ [(0,0),(6,6)]                 | {-1,0,3}                              |                 0
+ [(10,-10),(-3,-4)]            | {-1,0,3}                              |                 0
+ [(-1000000,200),(300000,-40)] | {-1,0,3}                              |                 0
+ [(11,22),(33,44)]             | {-1,0,3}                              |                30
+ [(-10,2),(-10,3)]             | {-1,0,3}                              |                13
+ [(0,-20),(30,-20)]            | {-1,0,3}                              |                 0
+(70 rows)
+
+-- Distance to line segment
+SELECT l1.s, l2.s, l1.s <-> l2.s
+FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               |     ?column?     
+-------------------------------+-------------------------------+------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 |                0
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 |   0.707106781187
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            |    7.12398901685
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] |    11.3840613445
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             |    19.6977156036
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             |               11
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            |               22
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 |   0.707106781187
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 |                0
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            |    4.88901207039
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] |     9.3835075324
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             |    16.7630546142
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             |    10.1980390272
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            |               20
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 |    7.12398901685
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 |    4.88901207039
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            |                0
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] |    19.3851689004
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             |    29.4737584815
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             |    9.21954445729
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            |               10
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 |    11.3840613445
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 |     9.3835075324
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            |    19.3851689004
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] | 7.1054273576e-15
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             |    6.61741527185
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             |    12.3864613274
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            |    35.3790763202
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 |    19.6977156036
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 |    16.7630546142
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            |    29.4737584815
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] |    6.61741527185
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             |                0
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             |     28.319604517
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            |               42
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 |               11
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 |    10.1980390272
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            |    9.21954445729
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] |    12.3864613274
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             |     28.319604517
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             |                0
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            |    24.1660919472
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 |               22
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 |               20
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            |               10
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] |    35.3790763202
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             |               42
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             |    24.1660919472
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            |                0
+(49 rows)
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1
+FROM LSEG_TBL l, BOX_TBL b;
+               s               |         f1          | ?column? 
+-------------------------------+---------------------+----------
+ [(1,2),(3,4)]                 | (2,2),(0,0)         |        0
+ [(1,2),(3,4)]                 | (3,3),(1,1)         |        0
+ [(1,2),(3,4)]                 | (-2,2),(-8,-10)     |        0
+ [(1,2),(3,4)]                 | (2.5,3.5),(2.5,2.5) |     0.25
+ [(1,2),(3,4)]                 | (3,3),(3,3)         |        0
+ [(0,0),(6,6)]                 | (2,2),(0,0)         |        0
+ [(0,0),(6,6)]                 | (3,3),(1,1)         |        0
+ [(0,0),(6,6)]                 | (-2,2),(-8,-10)     |        0
+ [(0,0),(6,6)]                 | (2.5,3.5),(2.5,2.5) |     0.25
+ [(0,0),(6,6)]                 | (3,3),(3,3)         |        0
+ [(10,-10),(-3,-4)]            | (2,2),(0,0)         |        0
+ [(10,-10),(-3,-4)]            | (3,3),(1,1)         |        0
+ [(10,-10),(-3,-4)]            | (-2,2),(-8,-10)     |        0
+ [(10,-10),(-3,-4)]            | (2.5,3.5),(2.5,2.5) |        0
+ [(10,-10),(-3,-4)]            | (3,3),(3,3)         |        0
+ [(-1000000,200),(300000,-40)] | (2,2),(0,0)         |        0
+ [(-1000000,200),(300000,-40)] | (3,3),(1,1)         |        0
+ [(-1000000,200),(300000,-40)] | (-2,2),(-8,-10)     |        0
+ [(-1000000,200),(300000,-40)] | (2.5,3.5),(2.5,2.5) |        0
+ [(-1000000,200),(300000,-40)] | (3,3),(3,3)         |        0
+ [(11,22),(33,44)]             | (2,2),(0,0)         |        0
+ [(11,22),(33,44)]             | (3,3),(1,1)         |        0
+ [(11,22),(33,44)]             | (-2,2),(-8,-10)     |        0
+ [(11,22),(33,44)]             | (2.5,3.5),(2.5,2.5) |        0
+ [(11,22),(33,44)]             | (3,3),(3,3)         |        0
+ [(-10,2),(-10,3)]             | (2,2),(0,0)         |        0
+ [(-10,2),(-10,3)]             | (3,3),(1,1)         |        0
+ [(-10,2),(-10,3)]             | (-2,2),(-8,-10)     |        0
+ [(-10,2),(-10,3)]             | (2.5,3.5),(2.5,2.5) |        0
+ [(-10,2),(-10,3)]             | (3,3),(3,3)         |        0
+ [(0,-20),(30,-20)]            | (2,2),(0,0)         |        0
+ [(0,-20),(30,-20)]            | (3,3),(1,1)         |        0
+ [(0,-20),(30,-20)]            | (-2,2),(-8,-10)     |        0
+ [(0,-20),(30,-20)]            | (2.5,3.5),(2.5,2.5) |        0
+ [(0,-20),(30,-20)]            | (3,3),(3,3)         |        0
+(35 rows)
+
+-- Intersect with line segment
+SELECT l.s, l1.s
+FROM LSEG_TBL l, LINE_TBL l1
+WHERE l.s ?# l1.s;
+               s               |      s       
+-------------------------------+--------------
+ [(0,0),(6,6)]                 | {0,-1,5}
+ [(-1000000,200),(300000,-40)] | {0,-1,5}
+ [(-1000000,200),(300000,-40)] | {1,0,5}
+ [(0,0),(6,6)]                 | {0,3,0}
+ [(-1000000,200),(300000,-40)] | {0,3,0}
+ [(-1000000,200),(300000,-40)] | {1,-1,0}
+ [(10,-10),(-3,-4)]            | {-0.4,-1,-6}
+ [(-1000000,200),(300000,-40)] | {-0.4,-1,-6}
+ [(1,2),(3,4)]                 | {-1,0,1}
+ [(0,0),(6,6)]                 | {-1,0,1}
+ [(10,-10),(-3,-4)]            | {-1,0,1}
+ [(-1000000,200),(300000,-40)] | {-1,0,1}
+ [(0,-20),(30,-20)]            | {-1,0,1}
+ [(1,2),(3,4)]                 | {0,-1,3}
+ [(0,0),(6,6)]                 | {0,-1,3}
+ [(-1000000,200),(300000,-40)] | {0,-1,3}
+ [(-10,2),(-10,3)]             | {0,-1,3}
+ [(1,2),(3,4)]                 | {-1,0,3}
+ [(0,0),(6,6)]                 | {-1,0,3}
+ [(10,-10),(-3,-4)]            | {-1,0,3}
+ [(-1000000,200),(300000,-40)] | {-1,0,3}
+ [(0,-20),(30,-20)]            | {-1,0,3}
+(22 rows)
+
+-- Intersect with box
+SELECT l.s, b.f1
+FROM LSEG_TBL l, BOX_TBL b
+WHERE l.s ?# b.f1;
+         s          |         f1          
+--------------------+---------------------
+ [(1,2),(3,4)]      | (2,2),(0,0)
+ [(1,2),(3,4)]      | (3,3),(1,1)
+ [(1,2),(3,4)]      | (2.5,3.5),(2.5,2.5)
+ [(0,0),(6,6)]      | (2,2),(0,0)
+ [(0,0),(6,6)]      | (3,3),(1,1)
+ [(0,0),(6,6)]      | (2.5,3.5),(2.5,2.5)
+ [(0,0),(6,6)]      | (3,3),(3,3)
+ [(10,-10),(-3,-4)] | (-2,2),(-8,-10)
+(8 rows)
+
+-- Intersection point with line segment
+SELECT l1.s, l2.s, l1.s # l2.s
+FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               | ?column? 
+-------------------------------+-------------------------------+----------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 | 
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            | 
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] | 
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             | 
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             | 
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            | 
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 | 
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            | 
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] | 
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             | 
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             | 
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            | 
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 | 
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 | 
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            | 
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] | 
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             | 
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             | 
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            | 
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 | 
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 | 
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            | 
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] | 
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             | 
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             | 
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            | 
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 | 
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 | 
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            | 
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] | 
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             | 
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             | 
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            | 
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 | 
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 | 
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            | 
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] | 
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             | 
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             | 
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            | 
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 | 
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 | 
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            | 
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] | 
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             | 
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             | 
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            | 
+(49 rows)
+
+-- Closest point to line
+SELECT l.s, l1.s, l.s ## l1.s
+FROM LSEG_TBL l, LINE_TBL l1;
+ERROR:  function "close_sl" not implemented
+-- Closest point to line segment
+SELECT l1.s, l2.s, l1.s ## l2.s
+FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               |            ?column?             
+-------------------------------+-------------------------------+---------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 | (1,2)
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | (1.5,1.5)
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            | (-1.98536585366,-4.46829268293)
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] | (3.00210167283,15.3840611505)
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             | (11,22)
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             | (-10,2)
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            | (1,-20)
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | (1,2)
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 | (0,0)
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] | (6.00173233982,15.3835073725)
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             | (11,22)
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             | (-10,2)
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            | (0,-20)
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 | (1,2)
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 | (0,0)
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            | (10,-10)
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] | (-2.99642119965,15.3851685701)
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             | (11,22)
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             | (-10,2)
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            | (10,-20)
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 | (3,4)
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 | (6,6)
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            | (-3,-4)
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] | (300000,-40)
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             | (11,22)
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             | (-10,3)
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            | (30,-20)
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 | (3,4)
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 | (6,6)
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            | (-1.3512195122,-4.76097560976)
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] | (10.9987783234,15.3825848409)
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             | (11,22)
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             | (-10,3)
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            | (11,-20)
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 | (1,2)
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 | (0,0)
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            | (-3,-4)
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] | (-9.99771326872,15.3864611163)
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             | (11,22)
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             | (-10,2)
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            | (0,-20)
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 | (1,2)
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 | (0,0)
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            | (10,-10)
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] | (30.0065315217,15.3790757173)
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             | (11,22)
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             | (-10,2)
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            | (0,-20)
+(49 rows)
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1
+FROM LSEG_TBL l, BOX_TBL b;
+               s               |         f1          |  ?column?   
+-------------------------------+---------------------+-------------
+ [(1,2),(3,4)]                 | (2,2),(0,0)         | (1,2)
+ [(1,2),(3,4)]                 | (3,3),(1,1)         | (1.5,2.5)
+ [(1,2),(3,4)]                 | (-2,2),(-8,-10)     | (-2,2)
+ [(1,2),(3,4)]                 | (2.5,3.5),(2.5,2.5) | (2.25,3.25)
+ [(1,2),(3,4)]                 | (3,3),(3,3)         | (3,3)
+ [(0,0),(6,6)]                 | (2,2),(0,0)         | (1,1)
+ [(0,0),(6,6)]                 | (3,3),(1,1)         | (2,2)
+ [(0,0),(6,6)]                 | (-2,2),(-8,-10)     | (-2,0)
+ [(0,0),(6,6)]                 | (2.5,3.5),(2.5,2.5) | (2.75,2.75)
+ [(0,0),(6,6)]                 | (3,3),(3,3)         | (3,3)
+ [(10,-10),(-3,-4)]            | (2,2),(0,0)         | (0,0)
+ [(10,-10),(-3,-4)]            | (3,3),(1,1)         | (1,1)
+ [(10,-10),(-3,-4)]            | (-2,2),(-8,-10)     | (-3,-4)
+ [(10,-10),(-3,-4)]            | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ [(10,-10),(-3,-4)]            | (3,3),(3,3)         | (3,3)
+ [(-1000000,200),(300000,-40)] | (2,2),(0,0)         | (2,2)
+ [(-1000000,200),(300000,-40)] | (3,3),(1,1)         | (3,3)
+ [(-1000000,200),(300000,-40)] | (-2,2),(-8,-10)     | (-2,2)
+ [(-1000000,200),(300000,-40)] | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ [(-1000000,200),(300000,-40)] | (3,3),(3,3)         | (3,3)
+ [(11,22),(33,44)]             | (2,2),(0,0)         | (2,2)
+ [(11,22),(33,44)]             | (3,3),(1,1)         | (3,3)
+ [(11,22),(33,44)]             | (-2,2),(-8,-10)     | (-2,2)
+ [(11,22),(33,44)]             | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ [(11,22),(33,44)]             | (3,3),(3,3)         | (3,3)
+ [(-10,2),(-10,3)]             | (2,2),(0,0)         | (0,2)
+ [(-10,2),(-10,3)]             | (3,3),(1,1)         | (1,2)
+ [(-10,2),(-10,3)]             | (-2,2),(-8,-10)     | (-8,2)
+ [(-10,2),(-10,3)]             | (2.5,3.5),(2.5,2.5) | (2.5,3)
+ [(-10,2),(-10,3)]             | (3,3),(3,3)         | (3,3)
+ [(0,-20),(30,-20)]            | (2,2),(0,0)         | (0,0)
+ [(0,-20),(30,-20)]            | (3,3),(1,1)         | (1,1)
+ [(0,-20),(30,-20)]            | (-2,2),(-8,-10)     | (-2,-10)
+ [(0,-20),(30,-20)]            | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ [(0,-20),(30,-20)]            | (3,3),(3,3)         | (3,3)
+(35 rows)
+
+-- On line
+SELECT l.s, l1.s
+FROM LSEG_TBL l, LINE_TBL l1
+WHERE l.s <@ l1.s;
+               s               |                   s                   
+-------------------------------+---------------------------------------
+ [(0,0),(6,6)]                 | {1,-1,0}
+ [(-1000000,200),(300000,-40)] | {-0.000184615384615,-1,15.3846153846}
+(2 rows)
+
+-- On box
+SELECT l.s, b.f1
+FROM LSEG_TBL l, BOX_TBL b
+WHERE l.s <@ b.f1;
+ s | f1 
+---+----
+(0 rows)
 
 --
 -- Boxes
 --
 SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
  six |                              box                               
 -----+----------------------------------------------------------------
      | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
      | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
      | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
      | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
      | (107.071067812,207.071067812),(92.9289321881,192.928932188)
      | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
+     | (3,5),(3,5)
+(7 rows)
 
 -- translation
 SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
+ twentyfour |             translation             
+------------+-------------------------------------
             | (2,2),(0,0)
             | (3,3),(1,1)
+            | (-2,2),(-8,-10)
             | (2.5,3.5),(2.5,2.5)
             | (3,3),(3,3)
             | (-8,2),(-10,0)
             | (-7,3),(-9,1)
+            | (-12,2),(-18,-10)
             | (-7.5,3.5),(-7.5,2.5)
             | (-7,3),(-7,3)
             | (-1,6),(-3,4)
             | (0,7),(-2,5)
+            | (-5,6),(-11,-6)
             | (-0.5,7.5),(-0.5,6.5)
             | (0,7),(0,7)
             | (7.1,36.5),(5.1,34.5)
             | (8.1,37.5),(6.1,35.5)
+            | (3.1,36.5),(-2.9,24.5)
             | (7.6,38),(7.6,37)
             | (8.1,37.5),(8.1,37.5)
             | (-3,-10),(-5,-12)
             | (-2,-9),(-4,-11)
+            | (-7,-10),(-13,-22)
             | (-2.5,-8.5),(-2.5,-9.5)
             | (-2,-9),(-2,-9)
+            | (2,2),(1e-300,-1e-300)
+            | (3,3),(1,1)
+            | (-2,2),(-8,-10)
+            | (2.5,3.5),(2.5,2.5)
+            | (3,3),(3,3)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
             | (12,12),(10,10)
             | (13,13),(11,11)
+            | (8,12),(2,0)
             | (12.5,13.5),(12.5,12.5)
             | (13,13),(13,13)
-(24 rows)
+(45 rows)
 
 SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
+ twentyfour |               translation               
+------------+-----------------------------------------
             | (2,2),(0,0)
             | (3,3),(1,1)
+            | (-2,2),(-8,-10)
             | (2.5,3.5),(2.5,2.5)
             | (3,3),(3,3)
             | (12,2),(10,0)
             | (13,3),(11,1)
+            | (8,2),(2,-10)
             | (12.5,3.5),(12.5,2.5)
             | (13,3),(13,3)
             | (5,-2),(3,-4)
             | (6,-1),(4,-3)
+            | (1,-2),(-5,-14)
             | (5.5,-0.5),(5.5,-1.5)
             | (6,-1),(6,-1)
             | (-3.1,-32.5),(-5.1,-34.5)
             | (-2.1,-31.5),(-4.1,-33.5)
+            | (-7.1,-32.5),(-13.1,-44.5)
             | (-2.6,-31),(-2.6,-32)
             | (-2.1,-31.5),(-2.1,-31.5)
             | (7,14),(5,12)
             | (8,15),(6,13)
+            | (3,14),(-3,2)
             | (7.5,15.5),(7.5,14.5)
             | (8,15),(8,15)
+            | (2,2),(-1e-300,1e-300)
+            | (3,3),(1,1)
+            | (-2,2),(-8,-10)
+            | (2.5,3.5),(2.5,2.5)
+            | (3,3),(3,3)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
             | (-8,-8),(-10,-10)
             | (-7,-7),(-9,-9)
+            | (-12,-8),(-18,-20)
             | (-7.5,-6.5),(-7.5,-7.5)
             | (-7,-7),(-7,-7)
-(24 rows)
+(45 rows)
 
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (-0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (-0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,-0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
+-- Multiply with point
+SELECT b.f1, p.f1, b.f1 * p.f1
+FROM BOX_TBL b, POINT_TBL p
+WHERE p.f1[0] BETWEEN 1 AND 1000;
+         f1          |     f1     |          ?column?           
+---------------------+------------+-----------------------------
+ (2,2),(0,0)         | (5.1,34.5) | (0,79.2),(-58.8,0)
+ (2,2),(0,0)         | (10,10)    | (0,40),(0,0)
+ (3,3),(1,1)         | (5.1,34.5) | (-29.4,118.8),(-88.2,39.6)
+ (3,3),(1,1)         | (10,10)    | (0,60),(0,20)
+ (-2,2),(-8,-10)     | (5.1,34.5) | (304.2,-58.8),(-79.2,-327)
+ (-2,2),(-8,-10)     | (10,10)    | (20,0),(-40,-180)
+ (2.5,3.5),(2.5,2.5) | (5.1,34.5) | (-73.5,104.1),(-108,99)
+ (2.5,3.5),(2.5,2.5) | (10,10)    | (0,60),(-10,50)
+ (3,3),(3,3)         | (5.1,34.5) | (-88.2,118.8),(-88.2,118.8)
+ (3,3),(3,3)         | (10,10)    | (0,60),(0,60)
+(10 rows)
 
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,-0),(-0.2,-0.2)
-        | (0.08,-0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (-0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
+-- Overflow error
+SELECT b.f1, p.f1, b.f1 * p.f1
+FROM BOX_TBL b, POINT_TBL p
+WHERE p.f1[0] > 1000;
+         f1          |        f1         |                  ?column?                  
+---------------------+-------------------+--------------------------------------------
+ (2,2),(0,0)         | (1e+300,Infinity) | (NaN,NaN),(-Infinity,Infinity)
+ (2,2),(0,0)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (3,3),(1,1)         | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (3,3),(1,1)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (-2,2),(-8,-10)     | (1e+300,Infinity) | (Infinity,-Infinity),(-Infinity,-Infinity)
+ (-2,2),(-8,-10)     | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (2.5,3.5),(2.5,2.5) | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (2.5,3.5),(2.5,2.5) | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (3,3),(3,3)         | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (3,3),(3,3)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+(10 rows)
 
+-- Divide by point
+SELECT b.f1, p.f1, b.f1 / p.f1
+FROM BOX_TBL b, POINT_TBL p
+WHERE p.f1[0] BETWEEN 1 AND 1000;
+         f1          |     f1     |                               ?column?                               
+---------------------+------------+----------------------------------------------------------------------
+ (2,2),(0,0)         | (5.1,34.5) | (0.0651176557644,0),(0,-0.0483449262493)
+ (2,2),(0,0)         | (10,10)    | (0.2,0),(0,0)
+ (3,3),(1,1)         | (5.1,34.5) | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
+ (3,3),(1,1)         | (10,10)    | (0.3,0),(0.1,0)
+ (-2,2),(-8,-10)     | (5.1,34.5) | (0.0483449262493,0.18499334024),(-0.317201914064,0.0651176557644)
+ (-2,2),(-8,-10)     | (10,10)    | (0,0.2),(-0.9,-0.1)
+ (2.5,3.5),(2.5,2.5) | (5.1,34.5) | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
+ (2.5,3.5),(2.5,2.5) | (10,10)    | (0.3,0.05),(0.25,0)
+ (3,3),(3,3)         | (5.1,34.5) | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
+ (3,3),(3,3)         | (10,10)    | (0.3,0),(0.3,0)
+(10 rows)
+
+-- To box
 SELECT f1::box
 	FROM POINT_TBL;
-          f1           
------------------------
+                 f1                  
+-------------------------------------
  (0,0),(0,0)
  (-10,0),(-10,0)
  (-3,4),(-3,4)
  (5.1,34.5),(5.1,34.5)
  (-5,-12),(-5,-12)
+ (1e-300,-1e-300),(1e-300,-1e-300)
+ (1e+300,Infinity),(1e+300,Infinity)
+ (NaN,NaN),(NaN,NaN)
  (10,10),(10,10)
-(6 rows)
+(9 rows)
 
 SELECT bound_box(a.f1, b.f1)
 	FROM BOX_TBL a, BOX_TBL b;
       bound_box      
 ---------------------
  (2,2),(0,0)
  (3,3),(0,0)
+ (2,2),(-8,-10)
  (2.5,3.5),(0,0)
  (3,3),(0,0)
  (3,3),(0,0)
  (3,3),(1,1)
+ (3,3),(-8,-10)
  (3,3.5),(1,1)
  (3,3),(1,1)
+ (2,2),(-8,-10)
+ (3,3),(-8,-10)
+ (-2,2),(-8,-10)
+ (2.5,3.5),(-8,-10)
+ (3,3),(-8,-10)
  (2.5,3.5),(0,0)
  (3,3.5),(1,1)
+ (2.5,3.5),(-8,-10)
  (2.5,3.5),(2.5,2.5)
  (3,3.5),(2.5,2.5)
  (3,3),(0,0)
  (3,3),(1,1)
+ (3,3),(-8,-10)
  (3,3.5),(2.5,2.5)
  (3,3),(3,3)
-(16 rows)
+(25 rows)
+
+-- Below box
+SELECT b1.f1, b2.f1, b1.f1 <^ b2.f1
+FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          | ?column? 
+---------------------+---------------------+----------
+ (2,2),(0,0)         | (2,2),(0,0)         | f
+ (2,2),(0,0)         | (3,3),(1,1)         | f
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | f
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | t
+ (2,2),(0,0)         | (3,3),(3,3)         | t
+ (3,3),(1,1)         | (2,2),(0,0)         | f
+ (3,3),(1,1)         | (3,3),(1,1)         | f
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | f
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(1,1)         | (3,3),(3,3)         | t
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | f
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | f
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | f
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | t
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | t
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | f
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | f
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | f
+ (3,3),(3,3)         | (2,2),(0,0)         | f
+ (3,3),(3,3)         | (3,3),(1,1)         | f
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | f
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(3,3)         | (3,3),(3,3)         | t
+(25 rows)
+
+-- Above box
+SELECT b1.f1, b2.f1, b1.f1 >^ b2.f1
+FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          | ?column? 
+---------------------+---------------------+----------
+ (2,2),(0,0)         | (2,2),(0,0)         | f
+ (2,2),(0,0)         | (3,3),(1,1)         | f
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | f
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | f
+ (2,2),(0,0)         | (3,3),(3,3)         | f
+ (3,3),(1,1)         | (2,2),(0,0)         | f
+ (3,3),(1,1)         | (3,3),(1,1)         | f
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | f
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(1,1)         | (3,3),(3,3)         | f
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | f
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | f
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | f
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | f
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | f
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | t
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | f
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | t
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | f
+ (3,3),(3,3)         | (2,2),(0,0)         | t
+ (3,3),(3,3)         | (3,3),(1,1)         | t
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | t
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(3,3)         | (3,3),(3,3)         | t
+(25 rows)
+
+-- Intersection point with box
+SELECT b1.f1, b2.f1, b1.f1 # b2.f1
+FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          |      ?column?       
+---------------------+---------------------+---------------------
+ (2,2),(0,0)         | (2,2),(0,0)         | (2,2),(0,0)
+ (2,2),(0,0)         | (3,3),(1,1)         | (2,2),(1,1)
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | 
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | 
+ (2,2),(0,0)         | (3,3),(3,3)         | 
+ (3,3),(1,1)         | (2,2),(0,0)         | (2,2),(1,1)
+ (3,3),(1,1)         | (3,3),(1,1)         | (3,3),(1,1)
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | 
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | (2.5,3),(2.5,2.5)
+ (3,3),(1,1)         | (3,3),(3,3)         | (3,3),(3,3)
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | 
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | 
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | (-2,2),(-8,-10)
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | 
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | 
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | 
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | (2.5,3),(2.5,2.5)
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | 
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5)
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | 
+ (3,3),(3,3)         | (2,2),(0,0)         | 
+ (3,3),(3,3)         | (3,3),(1,1)         | (3,3),(3,3)
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | 
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | 
+ (3,3),(3,3)         | (3,3),(3,3)         | (3,3),(3,3)
+(25 rows)
+
+-- Diagonal
+SELECT f1, diagonal(f1)
+FROM BOX_TBL;
+         f1          |       diagonal        
+---------------------+-----------------------
+ (2,2),(0,0)         | [(2,2),(0,0)]
+ (3,3),(1,1)         | [(3,3),(1,1)]
+ (-2,2),(-8,-10)     | [(-2,2),(-8,-10)]
+ (2.5,3.5),(2.5,2.5) | [(2.5,3.5),(2.5,2.5)]
+ (3,3),(3,3)         | [(3,3),(3,3)]
+(5 rows)
+
+-- Distance to box
+SELECT b1.f1, b2.f1, b1.f1 <-> b2.f1
+FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          |   ?column?    
+---------------------+---------------------+---------------
+ (2,2),(0,0)         | (2,2),(0,0)         |             0
+ (2,2),(0,0)         | (3,3),(1,1)         | 1.41421356237
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | 7.81024967591
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) |           2.5
+ (2,2),(0,0)         | (3,3),(3,3)         | 2.82842712475
+ (3,3),(1,1)         | (2,2),(0,0)         | 1.41421356237
+ (3,3),(1,1)         | (3,3),(1,1)         |             0
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | 9.21954445729
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | 1.11803398875
+ (3,3),(1,1)         | (3,3),(3,3)         | 1.41421356237
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | 7.81024967591
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | 9.21954445729
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     |             0
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | 10.2591422643
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | 10.6301458127
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         |           2.5
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | 1.11803398875
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | 10.2591422643
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) |             0
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         |           0.5
+ (3,3),(3,3)         | (2,2),(0,0)         | 2.82842712475
+ (3,3),(3,3)         | (3,3),(1,1)         | 1.41421356237
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | 10.6301458127
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) |           0.5
+ (3,3),(3,3)         | (3,3),(3,3)         |             0
+(25 rows)
 
 --
 -- Paths
 --
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
+-- Points
+SELECT f1, npoints(f1)
+FROM PATH_TBL;
+            f1             | npoints 
+---------------------------+---------
+ [(1,2),(3,4)]             |       2
+ ((1,2),(3,4))             |       2
+ [(0,0),(3,0),(4,5),(1,6)] |       4
+ ((1,2),(3,4))             |       2
+ ((1,2),(3,4))             |       2
+ [(1,2),(3,4)]             |       2
+ ((10,20))                 |       1
+ [(11,12),(13,14)]         |       2
+ ((11,12),(13,14))         |       2
+(9 rows)
 
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
+-- Area
+SELECT f1, area(f1)
+FROM PATH_TBL;
+            f1             | area 
+---------------------------+------
+ [(1,2),(3,4)]             |     
+ ((1,2),(3,4))             |    0
+ [(0,0),(3,0),(4,5),(1,6)] |     
+ ((1,2),(3,4))             |    0
+ ((1,2),(3,4))             |    0
+ [(1,2),(3,4)]             |     
+ ((10,20))                 |    0
+ [(11,12),(13,14)]         |     
+ ((11,12),(13,14))         |    0
+(9 rows)
 
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
+-- Length
+SELECT f1, @-@ f1
+FROM PATH_TBL;
+            f1             |   ?column?    
+---------------------------+---------------
+ [(1,2),(3,4)]             | 2.82842712475
+ ((1,2),(3,4))             | 5.65685424949
+ [(0,0),(3,0),(4,5),(1,6)] | 11.2612971738
+ ((1,2),(3,4))             | 5.65685424949
+ ((1,2),(3,4))             | 5.65685424949
+ [(1,2),(3,4)]             | 2.82842712475
+ ((10,20))                 |             0
+ [(11,12),(13,14)]         | 2.82842712475
+ ((11,12),(13,14))         | 5.65685424949
+(9 rows)
 
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
+-- Center
+SELECT f1, @@ f1
+FROM PATH_TBL;
+ERROR:  function "path_center" not implemented
+-- To polygon
+SELECT f1, f1::polygon
+FROM PATH_TBL
+WHERE isclosed(f1);
+        f1         |        f1         
+-------------------+-------------------
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((10,20))         | ((10,20))
+ ((11,12),(13,14)) | ((11,12),(13,14))
+(5 rows)
+
+-- Open path cannot be converted to polygon error
+SELECT f1, f1::polygon
+FROM PATH_TBL
+WHERE isopen(f1);
+ERROR:  open path cannot be converted to polygon
+-- Has points less than path
+SELECT p1.f1, p2.f1
+FROM PATH_TBL p1, PATH_TBL p2
+WHERE p1.f1 < p2.f1;
+        f1         |            f1             
+-------------------+---------------------------
+ [(1,2),(3,4)]     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]     | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))         | [(1,2),(3,4)]
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | [(1,2),(3,4)]
+ ((10,20))         | [(11,12),(13,14)]
+ ((10,20))         | ((11,12),(13,14))
+ [(11,12),(13,14)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((11,12),(13,14)) | [(0,0),(3,0),(4,5),(1,6)]
+(15 rows)
+
+-- Has points less than or equal to path
+SELECT p1.f1, p2.f1
+FROM PATH_TBL p1, PATH_TBL p2
+WHERE p1.f1 <= p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | [(1,2),(3,4)]
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | [(1,2),(3,4)]
+ ((10,20))                 | ((10,20))
+ ((10,20))                 | [(11,12),(13,14)]
+ ((10,20))                 | ((11,12),(13,14))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(66 rows)
+
+-- Has points equal to path
+SELECT p1.f1, p2.f1
+FROM PATH_TBL p1, PATH_TBL p2
+WHERE p1.f1 = p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | ((10,20))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(51 rows)
+
+-- Has points greater than or equal to path
+SELECT p1.f1, p2.f1
+FROM PATH_TBL p1, PATH_TBL p2
+WHERE p1.f1 >= p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | ((10,20))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((10,20))
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((10,20))
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(66 rows)
+
+-- Has points greater than path
+SELECT p1.f1, p2.f1
+FROM PATH_TBL p1, PATH_TBL p2
+WHERE p1.f1 > p2.f1;
+            f1             |        f1         
+---------------------------+-------------------
+ [(1,2),(3,4)]             | ((10,20))
+ ((1,2),(3,4))             | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | ((10,20))
+ [(1,2),(3,4)]             | ((10,20))
+ [(11,12),(13,14)]         | ((10,20))
+ ((11,12),(13,14))         | ((10,20))
+(15 rows)
+
+-- Add path
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1
+FROM PATH_TBL p1, PATH_TBL p2;
+            f1             |            f1             |                     ?column?                      
+---------------------------+---------------------------+---------------------------------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4),(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))                 | 
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         | [(1,2),(3,4),(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6),(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6),(0,0),(3,0),(4,5),(1,6)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6),(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))                 | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6),(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4),(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))                 | 
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         | [(1,2),(3,4),(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))         | 
+ ((10,20))                 | [(1,2),(3,4)]             | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | [(1,2),(3,4)]             | 
+ ((10,20))                 | ((10,20))                 | 
+ ((10,20))                 | [(11,12),(13,14)]         | 
+ ((10,20))                 | ((11,12),(13,14))         | 
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             | [(11,12),(13,14),(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14),(0,0),(3,0),(4,5),(1,6)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             | [(11,12),(13,14),(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((10,20))                 | 
+ [(11,12),(13,14)]         | [(11,12),(13,14)]         | [(11,12),(13,14),(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))         | 
+ ((11,12),(13,14))         | [(1,2),(3,4)]             | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | [(1,2),(3,4)]             | 
+ ((11,12),(13,14))         | ((10,20))                 | 
+ ((11,12),(13,14))         | [(11,12),(13,14)]         | 
+ ((11,12),(13,14))         | ((11,12),(13,14))         | 
+(81 rows)
+
+-- Add point
+SELECT p.f1, p1.f1, p.f1 + p1.f1
+FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                                 ?column?                                  
+---------------------------+-------------------+---------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((10,20))                 | (0,0)             | ((10,20))
+ [(11,12),(13,14)]         | (0,0)             | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (0,0)             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (-10,0)           | [(-9,2),(-7,4)]
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(-10,0),(-7,0),(-6,5),(-9,6)]
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ [(1,2),(3,4)]             | (-10,0)           | [(-9,2),(-7,4)]
+ ((10,20))                 | (-10,0)           | ((0,20))
+ [(11,12),(13,14)]         | (-10,0)           | [(1,12),(3,14)]
+ ((11,12),(13,14))         | (-10,0)           | ((1,12),(3,14))
+ [(1,2),(3,4)]             | (-3,4)            | [(-2,6),(0,8)]
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(-3,4),(0,4),(1,9),(-2,10)]
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ [(1,2),(3,4)]             | (-3,4)            | [(-2,6),(0,8)]
+ ((10,20))                 | (-3,4)            | ((7,24))
+ [(11,12),(13,14)]         | (-3,4)            | [(8,16),(10,18)]
+ ((11,12),(13,14))         | (-3,4)            | ((8,16),(10,18))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(6.1,36.5),(8.1,38.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(5.1,34.5),(8.1,34.5),(9.1,39.5),(6.1,40.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(6.1,36.5),(8.1,38.5)]
+ ((10,20))                 | (5.1,34.5)        | ((15.1,54.5))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(16.1,46.5),(18.1,48.5)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((16.1,46.5),(18.1,48.5))
+ [(1,2),(3,4)]             | (-5,-12)          | [(-4,-10),(-2,-8)]
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(-5,-12),(-2,-12),(-1,-7),(-4,-6)]
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ [(1,2),(3,4)]             | (-5,-12)          | [(-4,-10),(-2,-8)]
+ ((10,20))                 | (-5,-12)          | ((5,8))
+ [(11,12),(13,14)]         | (-5,-12)          | [(6,0),(8,2)]
+ ((11,12),(13,14))         | (-5,-12)          | ((6,0),(8,2))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(1e-300,-1e-300),(3,-1e-300),(4,5),(1,6)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((10,20))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity),(1e+300,Infinity),(1e+300,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((1e+300,Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(11,12),(13,14)]
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(10,10),(13,10),(14,15),(11,16)]
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (10,10)           | [(11,12),(13,14)]
+ ((10,20))                 | (10,10)           | ((20,30))
+ [(11,12),(13,14)]         | (10,10)           | [(21,22),(23,24)]
+ ((11,12),(13,14))         | (10,10)           | ((21,22),(23,24))
+(81 rows)
+
+-- Subtract point
+SELECT p.f1, p1.f1, p.f1 - p1.f1
+FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                                     ?column?                                      
+---------------------------+-------------------+-----------------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((10,20))                 | (0,0)             | ((10,20))
+ [(11,12),(13,14)]         | (0,0)             | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (0,0)             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (-10,0)           | [(11,2),(13,4)]
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(10,0),(13,0),(14,5),(11,6)]
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ [(1,2),(3,4)]             | (-10,0)           | [(11,2),(13,4)]
+ ((10,20))                 | (-10,0)           | ((20,20))
+ [(11,12),(13,14)]         | (-10,0)           | [(21,12),(23,14)]
+ ((11,12),(13,14))         | (-10,0)           | ((21,12),(23,14))
+ [(1,2),(3,4)]             | (-3,4)            | [(4,-2),(6,0)]
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(3,-4),(6,-4),(7,1),(4,2)]
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ [(1,2),(3,4)]             | (-3,4)            | [(4,-2),(6,0)]
+ ((10,20))                 | (-3,4)            | ((13,16))
+ [(11,12),(13,14)]         | (-3,4)            | [(14,8),(16,10)]
+ ((11,12),(13,14))         | (-3,4)            | ((14,8),(16,10))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-4.1,-32.5),(-2.1,-30.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(-5.1,-34.5),(-2.1,-34.5),(-1.1,-29.5),(-4.1,-28.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-4.1,-32.5),(-2.1,-30.5)]
+ ((10,20))                 | (5.1,34.5)        | ((4.9,-14.5))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(5.9,-22.5),(7.9,-20.5)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((5.9,-22.5),(7.9,-20.5))
+ [(1,2),(3,4)]             | (-5,-12)          | [(6,14),(8,16)]
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(5,12),(8,12),(9,17),(6,18)]
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ [(1,2),(3,4)]             | (-5,-12)          | [(6,14),(8,16)]
+ ((10,20))                 | (-5,-12)          | ((15,32))
+ [(11,12),(13,14)]         | (-5,-12)          | [(16,24),(18,26)]
+ ((11,12),(13,14))         | (-5,-12)          | ((16,24),(18,26))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(-1e-300,1e-300),(3,1e-300),(4,5),(1,6)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((10,20))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity),(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((-1e+300,-Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(-9,-8),(-7,-6)]
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(-10,-10),(-7,-10),(-6,-5),(-9,-4)]
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ [(1,2),(3,4)]             | (10,10)           | [(-9,-8),(-7,-6)]
+ ((10,20))                 | (10,10)           | ((0,10))
+ [(11,12),(13,14)]         | (10,10)           | [(1,2),(3,4)]
+ ((11,12),(13,14))         | (10,10)           | ((1,2),(3,4))
+(81 rows)
+
+-- Multiply with point
+SELECT p.f1, p1.f1, p.f1 * p1.f1
+FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                               ?column?                               
+---------------------------+-------------------+----------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(0,0),(0,0)]
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(0,0),(0,0),(0,0)]
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ [(1,2),(3,4)]             | (0,0)             | [(0,0),(0,0)]
+ ((10,20))                 | (0,0)             | ((0,0))
+ [(11,12),(13,14)]         | (0,0)             | [(0,0),(0,0)]
+ ((11,12),(13,14))         | (0,0)             | ((0,0),(0,0))
+ [(1,2),(3,4)]             | (-10,0)           | [(-10,-20),(-30,-40)]
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(0,0),(-30,0),(-40,-50),(-10,-60)]
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ [(1,2),(3,4)]             | (-10,0)           | [(-10,-20),(-30,-40)]
+ ((10,20))                 | (-10,0)           | ((-100,-200))
+ [(11,12),(13,14)]         | (-10,0)           | [(-110,-120),(-130,-140)]
+ ((11,12),(13,14))         | (-10,0)           | ((-110,-120),(-130,-140))
+ [(1,2),(3,4)]             | (-3,4)            | [(-11,-2),(-25,0)]
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(0,0),(-9,12),(-32,1),(-27,-14)]
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ [(1,2),(3,4)]             | (-3,4)            | [(-11,-2),(-25,0)]
+ ((10,20))                 | (-3,4)            | ((-110,-20))
+ [(11,12),(13,14)]         | (-3,4)            | [(-81,8),(-95,10)]
+ ((11,12),(13,14))         | (-3,4)            | ((-81,8),(-95,10))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-63.9,44.7),(-122.7,123.9)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(0,0),(15.3,103.5),(-152.1,163.5),(-201.9,65.1)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-63.9,44.7),(-122.7,123.9)]
+ ((10,20))                 | (5.1,34.5)        | ((-639,447))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(-357.9,440.7),(-416.7,519.9)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((-357.9,440.7),(-416.7,519.9))
+ [(1,2),(3,4)]             | (-5,-12)          | [(19,-22),(33,-56)]
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(0,0),(-15,-36),(40,-73),(67,-42)]
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ [(1,2),(3,4)]             | (-5,-12)          | [(19,-22),(33,-56)]
+ ((10,20))                 | (-5,-12)          | ((190,-220))
+ [(11,12),(13,14)]         | (-5,-12)          | [(89,-192),(103,-226)]
+ ((11,12),(13,14))         | (-5,-12)          | ((89,-192),(103,-226))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(3e-300,1e-300),(7e-300,1e-300)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(0,0),(3e-300,-3e-300),(9e-300,1e-300),(7e-300,5e-300)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(3e-300,1e-300),(7e-300,1e-300)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((3e-299,1e-299))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(2.3e-299,1e-300),(2.7e-299,1e-300)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((2.3e-299,1e-300),(2.7e-299,1e-300))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(NaN,NaN),(NaN,Infinity),(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((-Infinity,Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(-10,30),(-10,70)]
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(0,0),(30,30),(-10,90),(-50,70)]
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ [(1,2),(3,4)]             | (10,10)           | [(-10,30),(-10,70)]
+ ((10,20))                 | (10,10)           | ((-100,300))
+ [(11,12),(13,14)]         | (10,10)           | [(-10,230),(-10,270)]
+ ((11,12),(13,14))         | (10,10)           | ((-10,230),(-10,270))
+(81 rows)
+
+-- Divide by point
+SELECT p.f1, p1.f1, p.f1 / p1.f1
+FROM PATH_TBL p, POINT_TBL p1
+WHERE p1.f1[0] BETWEEN 1 AND 1000;
+            f1             |     f1     |                                                    ?column?                                                     
+---------------------------+------------+-----------------------------------------------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (5.1,34.5) | [(0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952)]
+ [(1,2),(3,4)]             | (10,10)    | [(0.15,0.05),(0.35,0.05)]
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5) | [(0,0),(0.0125795471363,-0.0850969365103),(0.158600957032,-0.0924966701199),(0.174387055399,-0.00320655123082)]
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)    | [(0,0),(0.15,-0.15),(0.45,0.05),(0.35,0.25)]
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ [(1,2),(3,4)]             | (5.1,34.5) | [(0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952)]
+ [(1,2),(3,4)]             | (10,10)    | [(0.15,0.05),(0.35,0.05)]
+ ((10,20))                 | (5.1,34.5) | ((0.609244733856,-0.199792807459))
+ ((10,20))                 | (10,10)    | ((1.5,0.5))
+ [(11,12),(13,14)]         | (5.1,34.5) | [(0.386512752208,-0.261703911993),(0.451630407972,-0.310048838242)]
+ [(11,12),(13,14)]         | (10,10)    | [(1.15,0.05),(1.35,0.05)]
+ ((11,12),(13,14))         | (5.1,34.5) | ((0.386512752208,-0.261703911993),(0.451630407972,-0.310048838242))
+ ((11,12),(13,14))         | (10,10)    | ((1.15,0.05),(1.35,0.05))
+(18 rows)
+
+-- Division by 0 error
+SELECT p.f1, p1.f1, p.f1 / p1.f1
+FROM PATH_TBL p, POINT_TBL p1
+WHERE p1.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to path
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1
+FROM PATH_TBL p1, PATH_TBL p2;
+            f1             |            f1             |    ?column?    
+---------------------------+---------------------------+----------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((10,20))                 |  17.4642491966
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         |   11.313708499
+ [(1,2),(3,4)]             | ((11,12),(13,14))         |   11.313708499
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)] |              0
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))                 |  16.1554944214
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]         |  9.89949493661
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))         |  9.89949493661
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((10,20))                 |  17.4642491966
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         |   11.313708499
+ [(1,2),(3,4)]             | ((11,12),(13,14))         |   11.313708499
+ ((10,20))                 | [(1,2),(3,4)]             |  17.4642491966
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)] |  16.1554944214
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | [(1,2),(3,4)]             |  17.4642491966
+ ((10,20))                 | ((10,20))                 |              0
+ ((10,20))                 | [(11,12),(13,14)]         |   6.7082039325
+ ((10,20))                 | ((11,12),(13,14))         |   6.7082039325
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             |   11.313708499
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)] |  9.89949493661
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             |   11.313708499
+ [(11,12),(13,14)]         | ((10,20))                 |   6.7082039325
+ [(11,12),(13,14)]         | [(11,12),(13,14)]         |              0
+ [(11,12),(13,14)]         | ((11,12),(13,14))         |              0
+ ((11,12),(13,14))         | [(1,2),(3,4)]             |   11.313708499
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)] |  9.89949493661
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | [(1,2),(3,4)]             |   11.313708499
+ ((11,12),(13,14))         | ((10,20))                 |   6.7082039325
+ ((11,12),(13,14))         | [(11,12),(13,14)]         |              0
+ ((11,12),(13,14))         | ((11,12),(13,14))         |              0
+(81 rows)
 
 --
 -- Polygons
 --
 -- containment
 SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
    FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
+ twentyfour |        f1         |             f1             | contains 
+------------+-------------------+----------------------------+----------
+            | (0,0)             | ((2,0),(2,4),(0,0))        | t
+            | (0,0)             | ((3,1),(3,3),(1,0))        | f
+            | (0,0)             | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (0,0)             | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (0,0)             | ((0,0))                    | t
+            | (0,0)             | ((0,1),(0,1))              | f
+            | (-10,0)           | ((2,0),(2,4),(0,0))        | f
+            | (-10,0)           | ((3,1),(3,3),(1,0))        | f
+            | (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-10,0)           | ((0,0))                    | f
+            | (-10,0)           | ((0,1),(0,1))              | f
+            | (-3,4)            | ((2,0),(2,4),(0,0))        | f
+            | (-3,4)            | ((3,1),(3,3),(1,0))        | f
+            | (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-3,4)            | ((0,0))                    | f
+            | (-3,4)            | ((0,1),(0,1))              | f
+            | (5.1,34.5)        | ((2,0),(2,4),(0,0))        | f
+            | (5.1,34.5)        | ((3,1),(3,3),(1,0))        | f
+            | (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (5.1,34.5)        | ((0,0))                    | f
+            | (5.1,34.5)        | ((0,1),(0,1))              | f
+            | (-5,-12)          | ((2,0),(2,4),(0,0))        | f
+            | (-5,-12)          | ((3,1),(3,3),(1,0))        | f
+            | (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-5,-12)          | ((0,0))                    | f
+            | (-5,-12)          | ((0,1),(0,1))              | f
+            | (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        | t
+            | (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        | f
+            | (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e-300,-1e-300)  | ((0,0))                    | t
+            | (1e-300,-1e-300)  | ((0,1),(0,1))              | f
+            | (1e+300,Infinity) | ((2,0),(2,4),(0,0))        | f
+            | (1e+300,Infinity) | ((3,1),(3,3),(1,0))        | f
+            | (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e+300,Infinity) | ((0,0))                    | f
+            | (1e+300,Infinity) | ((0,1),(0,1))              | f
+            | (NaN,NaN)         | ((2,0),(2,4),(0,0))        | f
+            | (NaN,NaN)         | ((3,1),(3,3),(1,0))        | f
+            | (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (NaN,NaN)         | ((0,0))                    | f
+            | (NaN,NaN)         | ((0,1),(0,1))              | f
+            | (10,10)           | ((2,0),(2,4),(0,0))        | f
+            | (10,10)           | ((3,1),(3,3),(1,0))        | f
+            | (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (10,10)           | ((0,0))                    | f
+            | (10,10)           | ((0,1),(0,1))              | f
+(63 rows)
 
 SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
    FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
+ twentyfour |        f1         |             f1             | contained 
+------------+-------------------+----------------------------+-----------
+            | (0,0)             | ((2,0),(2,4),(0,0))        | t
+            | (0,0)             | ((3,1),(3,3),(1,0))        | f
+            | (0,0)             | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (0,0)             | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (0,0)             | ((0,0))                    | t
+            | (0,0)             | ((0,1),(0,1))              | f
+            | (-10,0)           | ((2,0),(2,4),(0,0))        | f
+            | (-10,0)           | ((3,1),(3,3),(1,0))        | f
+            | (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-10,0)           | ((0,0))                    | f
+            | (-10,0)           | ((0,1),(0,1))              | f
+            | (-3,4)            | ((2,0),(2,4),(0,0))        | f
+            | (-3,4)            | ((3,1),(3,3),(1,0))        | f
+            | (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-3,4)            | ((0,0))                    | f
+            | (-3,4)            | ((0,1),(0,1))              | f
+            | (5.1,34.5)        | ((2,0),(2,4),(0,0))        | f
+            | (5.1,34.5)        | ((3,1),(3,3),(1,0))        | f
+            | (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (5.1,34.5)        | ((0,0))                    | f
+            | (5.1,34.5)        | ((0,1),(0,1))              | f
+            | (-5,-12)          | ((2,0),(2,4),(0,0))        | f
+            | (-5,-12)          | ((3,1),(3,3),(1,0))        | f
+            | (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-5,-12)          | ((0,0))                    | f
+            | (-5,-12)          | ((0,1),(0,1))              | f
+            | (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        | t
+            | (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        | f
+            | (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e-300,-1e-300)  | ((0,0))                    | t
+            | (1e-300,-1e-300)  | ((0,1),(0,1))              | f
+            | (1e+300,Infinity) | ((2,0),(2,4),(0,0))        | f
+            | (1e+300,Infinity) | ((3,1),(3,3),(1,0))        | f
+            | (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e+300,Infinity) | ((0,0))                    | f
+            | (1e+300,Infinity) | ((0,1),(0,1))              | f
+            | (NaN,NaN)         | ((2,0),(2,4),(0,0))        | f
+            | (NaN,NaN)         | ((3,1),(3,3),(1,0))        | f
+            | (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (NaN,NaN)         | ((0,0))                    | f
+            | (NaN,NaN)         | ((0,1),(0,1))              | f
+            | (10,10)           | ((2,0),(2,4),(0,0))        | f
+            | (10,10)           | ((3,1),(3,3),(1,0))        | f
+            | (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (10,10)           | ((0,0))                    | f
+            | (10,10)           | ((0,1),(0,1))              | f
+(63 rows)
 
 SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
    FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
+ four | npoints |          polygon           
+------+---------+----------------------------
       |       3 | ((2,0),(2,4),(0,0))
       |       3 | ((3,1),(3,3),(1,0))
+      |       4 | ((1,2),(3,4),(5,6),(7,8))
+      |       4 | ((7,8),(5,6),(3,4),(1,2))
+      |       4 | ((1,2),(7,8),(5,6),(3,-4))
       |       1 | ((0,0))
       |       2 | ((0,1),(0,1))
-(4 rows)
+(7 rows)
 
 SELECT '' AS four, polygon(f1)
    FROM BOX_TBL;
  four |                  polygon                  
 ------+-------------------------------------------
       | ((0,0),(0,2),(2,2),(2,0))
       | ((1,1),(1,3),(3,3),(3,1))
+      | ((-8,-10),(-8,2),(-2,2),(-2,-10))
       | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
       | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, polygon(f1)
    FROM PATH_TBL WHERE isclosed(f1);
  four |      polygon      
 ------+-------------------
       | ((1,2),(3,4))
       | ((1,2),(3,4))
       | ((1,2),(3,4))
+      | ((10,20))
       | ((11,12),(13,14))
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
    FROM PATH_TBL
    WHERE isopen(f1);
  four |         open_path         |          polygon          
 ------+---------------------------+---------------------------
       | [(1,2),(3,4)]             | ((1,2),(3,4))
       | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
       | [(1,2),(3,4)]             | ((1,2),(3,4))
       | [(11,12),(13,14)]         | ((11,12),(13,14))
 (4 rows)
 
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
+-- To box
+SELECT f1, f1::box
+FROM POLYGON_TBL;
+             f1             |      f1      
+----------------------------+--------------
+ ((2,0),(2,4),(0,0))        | (2,4),(0,0)
+ ((3,1),(3,3),(1,0))        | (3,3),(1,0)
+ ((1,2),(3,4),(5,6),(7,8))  | (7,8),(1,2)
+ ((7,8),(5,6),(3,4),(1,2))  | (7,8),(1,2)
+ ((1,2),(7,8),(5,6),(3,-4)) | (7,8),(1,-4)
+ ((0,0))                    | (0,0),(0,0)
+ ((0,1),(0,1))              | (0,1),(0,1)
+(7 rows)
 
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
+-- To path
+SELECT f1, f1::path
+FROM POLYGON_TBL;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(7 rows)
 
+-- Same as polygon
+SELECT p1.f1, p2.f1
+FROM POLYGON_TBL p1, POLYGON_TBL p2
+WHERE p1.f1 ~= p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(9 rows)
+
+-- Contained by polygon
+SELECT p1.f1, p2.f1
+FROM POLYGON_TBL p1, POLYGON_TBL p2
+WHERE p1.f1 <@ p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(12 rows)
+
+-- Contains polygon
+SELECT p1.f1, p2.f1
+FROM POLYGON_TBL p1, POLYGON_TBL p2
+WHERE p1.f1 @> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(12 rows)
+
+-- Overlap with polygon
+SELECT p1.f1, p2.f1
+FROM POLYGON_TBL p1, POLYGON_TBL p2
+WHERE p1.f1 && p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(25 rows)
+
+-- Left of polygon
+SELECT p1.f1, p2.f1
+FROM POLYGON_TBL p1, POLYGON_TBL p2
+WHERE p1.f1 << p2.f1;
+      f1       |             f1             
+---------------+----------------------------
+ ((0,0))       | ((3,1),(3,3),(1,0))
+ ((0,0))       | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))       | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))       | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1)) | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1)) | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1)) | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1)) | ((1,2),(7,8),(5,6),(3,-4))
+(8 rows)
+
+-- Overlap of left of polygon
+SELECT p1.f1, p2.f1
+FROM POLYGON_TBL p1, POLYGON_TBL p2
+WHERE p1.f1 &< p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))                    | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1))              | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(32 rows)
+
+-- Right of polygon
+SELECT p1.f1, p2.f1
+FROM POLYGON_TBL p1, POLYGON_TBL p2
+WHERE p1.f1 >> p2.f1;
+             f1             |      f1       
+----------------------------+---------------
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((0,1),(0,1))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1))
+(8 rows)
+
+-- Overlap of right of polygon
+SELECT p1.f1, p2.f1
+FROM POLYGON_TBL p1, POLYGON_TBL p2
+WHERE p1.f1 &> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((2,0),(2,4),(0,0))        | ((0,1),(0,1))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((0,1),(0,1))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((3,1),(3,3),(1,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(37 rows)
+
+-- Below polygon
+SELECT p1.f1, p2.f1
+FROM POLYGON_TBL p1, POLYGON_TBL p2
+WHERE p1.f1 <<| p2.f1;
+      f1       |            f1             
+---------------+---------------------------
+ ((0,0))       | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))       | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))       | ((0,1),(0,1))
+ ((0,1),(0,1)) | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1)) | ((7,8),(5,6),(3,4),(1,2))
+(5 rows)
+
+-- Overlap or below polygon
+SELECT p1.f1, p2.f1
+FROM POLYGON_TBL p1, POLYGON_TBL p2
+WHERE p1.f1 &<| p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))                    | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1))              | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(31 rows)
+
+-- Above polygon
+SELECT p1.f1, p2.f1
+FROM POLYGON_TBL p1, POLYGON_TBL p2
+WHERE p1.f1 |>> p2.f1;
+            f1             |      f1       
+---------------------------+---------------
+ ((1,2),(3,4),(5,6),(7,8)) | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8)) | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2)) | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2)) | ((0,1),(0,1))
+ ((0,1),(0,1))             | ((0,0))
+(5 rows)
+
+-- Overlap or above polygon
+SELECT p1.f1, p2.f1
+FROM POLYGON_TBL p1, POLYGON_TBL p2
+WHERE p1.f1 |&> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((3,1),(3,3),(1,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(32 rows)
+
+-- Distance to polygon
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1
+FROM POLYGON_TBL p1, POLYGON_TBL p2;
+ERROR:  function "poly_distance" not implemented
 --
 -- Circles
 --
 SELECT '' AS six, circle(f1, 50.0)
    FROM POINT_TBL;
- six |     circle      
------+-----------------
+ six |         circle         
+-----+------------------------
      | <(0,0),50>
      | <(-10,0),50>
      | <(-3,4),50>
      | <(5.1,34.5),50>
      | <(-5,-12),50>
+     | <(1e-300,-1e-300),50>
+     | <(1e+300,Infinity),50>
+     | <(NaN,NaN),50>
      | <(10,10),50>
-(6 rows)
+(9 rows)
 
 SELECT '' AS four, circle(f1)
    FROM BOX_TBL;
- four |        circle         
-------+-----------------------
+ four |         circle         
+------+------------------------
       | <(1,1),1.41421356237>
       | <(2,2),1.41421356237>
+      | <(-5,-4),6.7082039325>
       | <(2.5,3),0.5>
       | <(3,3),0>
-(4 rows)
+(5 rows)
 
 SELECT '' AS two, circle(f1)
    FROM POLYGON_TBL
    WHERE (# f1) >= 3;
  two |                    circle                     
 -----+-----------------------------------------------
      | <(1.33333333333,1.33333333333),2.04168905064>
      | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
+     | <(4,5),2.82842712475>
+     | <(4,5),2.82842712475>
+     | <(4,3),4.80664375676>
+(5 rows)
 
 SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
    FROM CIRCLE_TBL c1, POINT_TBL p1
    WHERE (p1.f1 <-> c1.f1) > 0
    ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
+ twentyfour |     circle     |       point       |   distance    
+------------+----------------+-------------------+---------------
+            | <(1,2),3>      | (-3,4)            |   1.472135955
+            | <(5,1),3>      | (0,0)             | 2.09901951359
+            | <(5,1),3>      | (1e-300,-1e-300)  | 2.09901951359
+            | <(5,1),3>      | (-3,4)            | 5.54400374532
+            | <(3,5),0>      | (0,0)             | 5.83095189485
+            | <(3,5),0>      | (1e-300,-1e-300)  | 5.83095189485
+            | <(3,5),0>      | (-3,4)            |  6.0827625303
+            | <(1,3),5>      | (-10,0)           | 6.40175425099
+            | <(1,3),5>      | (10,10)           | 6.40175425099
+            | <(5,1),3>      | (10,10)           | 7.29563014099
+            | <(1,2),3>      | (-10,0)           |  8.1803398875
+            | <(3,5),0>      | (10,10)           | 8.60232526704
+            | <(1,2),3>      | (10,10)           | 9.04159457879
+            | <(1,3),5>      | (-5,-12)          | 11.1554944214
+            | <(5,1),3>      | (-10,0)           | 12.0332963784
+            | <(1,2),3>      | (-5,-12)          | 12.2315462117
+            | <(5,1),3>      | (-5,-12)          | 13.4012194669
+            | <(3,5),0>      | (-10,0)           | 13.9283882772
+            | <(3,5),0>      | (-5,-12)          | 18.7882942281
+            | <(1,3),5>      | (5.1,34.5)        | 26.7657047773
+            | <(3,5),0>      | (5.1,34.5)        | 29.5746513082
+            | <(1,2),3>      | (5.1,34.5)        | 29.7575945393
+            | <(5,1),3>      | (5.1,34.5)        | 30.5001492534
+            | <(100,200),10> | (5.1,34.5)        | 180.778038568
+            | <(100,200),10> | (10,10)           | 200.237960416
+            | <(100,200),10> | (-3,4)            | 211.415898255
+            | <(100,200),10> | (0,0)             |  213.60679775
+            | <(100,200),10> | (1e-300,-1e-300)  |  213.60679775
+            | <(100,200),10> | (-10,0)           |  218.25424421
+            | <(100,200),10> | (-5,-12)          | 226.577682802
+            | <(3,5),0>      | (1e+300,Infinity) |      Infinity
+            | <(5,1),3>      | (1e+300,Infinity) |      Infinity
+            | <(1,2),3>      | (1e+300,Infinity) |      Infinity
+            | <(1,3),5>      | (1e+300,Infinity) |      Infinity
+            | <(100,200),10> | (1e+300,Infinity) |      Infinity
+            | <(1,2),100>    | (1e+300,Infinity) |      Infinity
+            | <(100,1),115>  | (1e+300,Infinity) |      Infinity
+            | <(3,5),0>      | (NaN,NaN)         |           NaN
+            | <(5,1),3>      | (NaN,NaN)         |           NaN
+            | <(1,2),3>      | (NaN,NaN)         |           NaN
+            | <(1,3),5>      | (NaN,NaN)         |           NaN
+            | <(100,200),10> | (NaN,NaN)         |           NaN
+            | <(1,2),100>    | (NaN,NaN)         |           NaN
+            | <(100,1),115>  | (NaN,NaN)         |           NaN
+(44 rows)
+
+-- To polygon
+SELECT f1, f1::polygon
+FROM CIRCLE_TBL
+WHERE f1 >= '<(0,0),1>';
+       f1       |                                                                                                          f1                                                                                                          
+----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ <(5,1),3>      | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
+ <(1,2),100>    | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
+ <(1,3),5>      | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
+ <(1,2),3>      | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
+ <(100,200),10> | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
+ <(100,1),115>  | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
+(6 rows)
+
+-- To polygon with less points
+SELECT f1, polygon(8, f1)
+FROM CIRCLE_TBL
+WHERE f1 >= '<(0,0),1>';
+       f1       |                                                                             polygon                                                                              
+----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ <(5,1),3>      | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
+ <(1,2),100>    | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
+ <(1,3),5>      | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
+ <(1,2),3>      | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
+ <(100,200),10> | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
+ <(100,1),115>  | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
+(6 rows)
+
+-- Too less points error
+SELECT f1, polygon(1, f1)
+FROM CIRCLE_TBL
+WHERE f1 >= '<(0,0),1>';
+ERROR:  must request at least 2 points
+-- Zero radius error
+SELECT f1, polygon(10, f1)
+FROM CIRCLE_TBL
+WHERE f1 < '<(0,0),1>';
+ERROR:  cannot convert circle with radius zero to polygon
+-- Same as circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 ~= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(7 rows)
+
+-- Overlap with circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 && c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,1),115>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(100,1),115>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(33 rows)
+
+-- Overlap or left of circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 &< c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(28 rows)
+
+-- Left of circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 << c2.f1;
+    f1     |       f1       
+-----------+----------------
+ <(5,1),3> | <(100,200),10>
+ <(1,3),5> | <(100,200),10>
+ <(1,2),3> | <(100,200),10>
+ <(3,5),0> | <(100,200),10>
+(4 rows)
+
+-- Right of circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 >> c2.f1;
+       f1       |    f1     
+----------------+-----------
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(3,5),0>
+(4 rows)
+
+-- Overlap or right of circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 &> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(28 rows)
+
+-- Contained by circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 <@ c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(17 rows)
+
+-- Contain by circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 @> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(3,5),0>
+(17 rows)
+
+-- Below circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 <<| c2.f1;
+      f1       |       f1       
+---------------+----------------
+ <(5,1),3>     | <(100,200),10>
+ <(5,1),3>     | <(3,5),0>
+ <(1,2),100>   | <(100,200),10>
+ <(1,3),5>     | <(100,200),10>
+ <(1,2),3>     | <(100,200),10>
+ <(100,1),115> | <(100,200),10>
+ <(3,5),0>     | <(100,200),10>
+(7 rows)
+
+-- Above circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 |>> c2.f1;
+       f1       |      f1       
+----------------+---------------
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(3,5),0>      | <(5,1),3>
+(7 rows)
+
+-- Overlap or below circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 &<| c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Overlap or above circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 |&> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area equal with circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 = c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(9 rows)
+
+-- Area not equal with circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 != c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(40 rows)
+
+-- Area less than circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 > c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(3,5),0>
+(20 rows)
+
+-- Area less than or equal circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 <= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area greater than or equal circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 >= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area less than circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Add point
+SELECT c.f1, p.f1, c.f1 + p.f1
+FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |        ?column?         
+----------------+-------------------+-------------------------
+ <(5,1),3>      | (0,0)             | <(5,1),3>
+ <(1,2),100>    | (0,0)             | <(1,2),100>
+ <(1,3),5>      | (0,0)             | <(1,3),5>
+ <(1,2),3>      | (0,0)             | <(1,2),3>
+ <(100,200),10> | (0,0)             | <(100,200),10>
+ <(100,1),115>  | (0,0)             | <(100,1),115>
+ <(3,5),0>      | (0,0)             | <(3,5),0>
+ <(5,1),3>      | (-10,0)           | <(-5,1),3>
+ <(1,2),100>    | (-10,0)           | <(-9,2),100>
+ <(1,3),5>      | (-10,0)           | <(-9,3),5>
+ <(1,2),3>      | (-10,0)           | <(-9,2),3>
+ <(100,200),10> | (-10,0)           | <(90,200),10>
+ <(100,1),115>  | (-10,0)           | <(90,1),115>
+ <(3,5),0>      | (-10,0)           | <(-7,5),0>
+ <(5,1),3>      | (-3,4)            | <(2,5),3>
+ <(1,2),100>    | (-3,4)            | <(-2,6),100>
+ <(1,3),5>      | (-3,4)            | <(-2,7),5>
+ <(1,2),3>      | (-3,4)            | <(-2,6),3>
+ <(100,200),10> | (-3,4)            | <(97,204),10>
+ <(100,1),115>  | (-3,4)            | <(97,5),115>
+ <(3,5),0>      | (-3,4)            | <(0,9),0>
+ <(5,1),3>      | (5.1,34.5)        | <(10.1,35.5),3>
+ <(1,2),100>    | (5.1,34.5)        | <(6.1,36.5),100>
+ <(1,3),5>      | (5.1,34.5)        | <(6.1,37.5),5>
+ <(1,2),3>      | (5.1,34.5)        | <(6.1,36.5),3>
+ <(100,200),10> | (5.1,34.5)        | <(105.1,234.5),10>
+ <(100,1),115>  | (5.1,34.5)        | <(105.1,35.5),115>
+ <(3,5),0>      | (5.1,34.5)        | <(8.1,39.5),0>
+ <(5,1),3>      | (-5,-12)          | <(0,-11),3>
+ <(1,2),100>    | (-5,-12)          | <(-4,-10),100>
+ <(1,3),5>      | (-5,-12)          | <(-4,-9),5>
+ <(1,2),3>      | (-5,-12)          | <(-4,-10),3>
+ <(100,200),10> | (-5,-12)          | <(95,188),10>
+ <(100,1),115>  | (-5,-12)          | <(95,-11),115>
+ <(3,5),0>      | (-5,-12)          | <(-2,-7),0>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(5,1),3>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(1,2),100>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(1,3),5>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(1,2),3>
+ <(100,200),10> | (1e-300,-1e-300)  | <(100,200),10>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(100,1),115>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(3,5),0>
+ <(5,1),3>      | (1e+300,Infinity) | <(1e+300,Infinity),3>
+ <(1,2),100>    | (1e+300,Infinity) | <(1e+300,Infinity),100>
+ <(1,3),5>      | (1e+300,Infinity) | <(1e+300,Infinity),5>
+ <(1,2),3>      | (1e+300,Infinity) | <(1e+300,Infinity),3>
+ <(100,200),10> | (1e+300,Infinity) | <(1e+300,Infinity),10>
+ <(100,1),115>  | (1e+300,Infinity) | <(1e+300,Infinity),115>
+ <(3,5),0>      | (1e+300,Infinity) | <(1e+300,Infinity),0>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),100>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),5>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),10>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),115>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),0>
+ <(5,1),3>      | (10,10)           | <(15,11),3>
+ <(1,2),100>    | (10,10)           | <(11,12),100>
+ <(1,3),5>      | (10,10)           | <(11,13),5>
+ <(1,2),3>      | (10,10)           | <(11,12),3>
+ <(100,200),10> | (10,10)           | <(110,210),10>
+ <(100,1),115>  | (10,10)           | <(110,11),115>
+ <(3,5),0>      | (10,10)           | <(13,15),0>
+(63 rows)
+
+-- Subtract point
+SELECT c.f1, p.f1, c.f1 - p.f1
+FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |         ?column?          
+----------------+-------------------+---------------------------
+ <(5,1),3>      | (0,0)             | <(5,1),3>
+ <(1,2),100>    | (0,0)             | <(1,2),100>
+ <(1,3),5>      | (0,0)             | <(1,3),5>
+ <(1,2),3>      | (0,0)             | <(1,2),3>
+ <(100,200),10> | (0,0)             | <(100,200),10>
+ <(100,1),115>  | (0,0)             | <(100,1),115>
+ <(3,5),0>      | (0,0)             | <(3,5),0>
+ <(5,1),3>      | (-10,0)           | <(15,1),3>
+ <(1,2),100>    | (-10,0)           | <(11,2),100>
+ <(1,3),5>      | (-10,0)           | <(11,3),5>
+ <(1,2),3>      | (-10,0)           | <(11,2),3>
+ <(100,200),10> | (-10,0)           | <(110,200),10>
+ <(100,1),115>  | (-10,0)           | <(110,1),115>
+ <(3,5),0>      | (-10,0)           | <(13,5),0>
+ <(5,1),3>      | (-3,4)            | <(8,-3),3>
+ <(1,2),100>    | (-3,4)            | <(4,-2),100>
+ <(1,3),5>      | (-3,4)            | <(4,-1),5>
+ <(1,2),3>      | (-3,4)            | <(4,-2),3>
+ <(100,200),10> | (-3,4)            | <(103,196),10>
+ <(100,1),115>  | (-3,4)            | <(103,-3),115>
+ <(3,5),0>      | (-3,4)            | <(6,1),0>
+ <(5,1),3>      | (5.1,34.5)        | <(-0.1,-33.5),3>
+ <(1,2),100>    | (5.1,34.5)        | <(-4.1,-32.5),100>
+ <(1,3),5>      | (5.1,34.5)        | <(-4.1,-31.5),5>
+ <(1,2),3>      | (5.1,34.5)        | <(-4.1,-32.5),3>
+ <(100,200),10> | (5.1,34.5)        | <(94.9,165.5),10>
+ <(100,1),115>  | (5.1,34.5)        | <(94.9,-33.5),115>
+ <(3,5),0>      | (5.1,34.5)        | <(-2.1,-29.5),0>
+ <(5,1),3>      | (-5,-12)          | <(10,13),3>
+ <(1,2),100>    | (-5,-12)          | <(6,14),100>
+ <(1,3),5>      | (-5,-12)          | <(6,15),5>
+ <(1,2),3>      | (-5,-12)          | <(6,14),3>
+ <(100,200),10> | (-5,-12)          | <(105,212),10>
+ <(100,1),115>  | (-5,-12)          | <(105,13),115>
+ <(3,5),0>      | (-5,-12)          | <(8,17),0>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(5,1),3>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(1,2),100>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(1,3),5>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(1,2),3>
+ <(100,200),10> | (1e-300,-1e-300)  | <(100,200),10>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(100,1),115>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(3,5),0>
+ <(5,1),3>      | (1e+300,Infinity) | <(-1e+300,-Infinity),3>
+ <(1,2),100>    | (1e+300,Infinity) | <(-1e+300,-Infinity),100>
+ <(1,3),5>      | (1e+300,Infinity) | <(-1e+300,-Infinity),5>
+ <(1,2),3>      | (1e+300,Infinity) | <(-1e+300,-Infinity),3>
+ <(100,200),10> | (1e+300,Infinity) | <(-1e+300,-Infinity),10>
+ <(100,1),115>  | (1e+300,Infinity) | <(-1e+300,-Infinity),115>
+ <(3,5),0>      | (1e+300,Infinity) | <(-1e+300,-Infinity),0>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),100>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),5>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),10>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),115>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),0>
+ <(5,1),3>      | (10,10)           | <(-5,-9),3>
+ <(1,2),100>    | (10,10)           | <(-9,-8),100>
+ <(1,3),5>      | (10,10)           | <(-9,-7),5>
+ <(1,2),3>      | (10,10)           | <(-9,-8),3>
+ <(100,200),10> | (10,10)           | <(90,190),10>
+ <(100,1),115>  | (10,10)           | <(90,-9),115>
+ <(3,5),0>      | (10,10)           | <(-7,-5),0>
+(63 rows)
+
+-- Multiply with point
+SELECT c.f1, p.f1, c.f1 * p.f1
+FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |                  ?column?                  
+----------------+-------------------+--------------------------------------------
+ <(5,1),3>      | (0,0)             | <(0,0),0>
+ <(1,2),100>    | (0,0)             | <(0,0),0>
+ <(1,3),5>      | (0,0)             | <(0,0),0>
+ <(1,2),3>      | (0,0)             | <(0,0),0>
+ <(100,200),10> | (0,0)             | <(0,0),0>
+ <(100,1),115>  | (0,0)             | <(0,0),0>
+ <(3,5),0>      | (0,0)             | <(0,0),0>
+ <(5,1),3>      | (-10,0)           | <(-50,-10),30>
+ <(1,2),100>    | (-10,0)           | <(-10,-20),1000>
+ <(1,3),5>      | (-10,0)           | <(-10,-30),50>
+ <(1,2),3>      | (-10,0)           | <(-10,-20),30>
+ <(100,200),10> | (-10,0)           | <(-1000,-2000),100>
+ <(100,1),115>  | (-10,0)           | <(-1000,-10),1150>
+ <(3,5),0>      | (-10,0)           | <(-30,-50),0>
+ <(5,1),3>      | (-3,4)            | <(-19,17),15>
+ <(1,2),100>    | (-3,4)            | <(-11,-2),500>
+ <(1,3),5>      | (-3,4)            | <(-15,-5),25>
+ <(1,2),3>      | (-3,4)            | <(-11,-2),15>
+ <(100,200),10> | (-3,4)            | <(-1100,-200),50>
+ <(100,1),115>  | (-3,4)            | <(-304,397),575>
+ <(3,5),0>      | (-3,4)            | <(-29,-3),0>
+ <(5,1),3>      | (5.1,34.5)        | <(-9,177.6),104.624758064>
+ <(1,2),100>    | (5.1,34.5)        | <(-63.9,44.7),3487.49193547>
+ <(1,3),5>      | (5.1,34.5)        | <(-98.4,49.8),174.374596774>
+ <(1,2),3>      | (5.1,34.5)        | <(-63.9,44.7),104.624758064>
+ <(100,200),10> | (5.1,34.5)        | <(-6390,4470),348.749193547>
+ <(100,1),115>  | (5.1,34.5)        | <(475.5,3455.1),4010.6157258>
+ <(3,5),0>      | (5.1,34.5)        | <(-157.2,129),0>
+ <(5,1),3>      | (-5,-12)          | <(-13,-65),39>
+ <(1,2),100>    | (-5,-12)          | <(19,-22),1300>
+ <(1,3),5>      | (-5,-12)          | <(31,-27),65>
+ <(1,2),3>      | (-5,-12)          | <(19,-22),39>
+ <(100,200),10> | (-5,-12)          | <(1900,-2200),130>
+ <(100,1),115>  | (-5,-12)          | <(-488,-1205),1495>
+ <(3,5),0>      | (-5,-12)          | <(45,-61),0>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(6e-300,-4e-300),4.24264068712e-300>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(3e-300,1e-300),1.41421356237e-298>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(4e-300,2e-300),7.07106781187e-300>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(3e-300,1e-300),4.24264068712e-300>
+ <(100,200),10> | (1e-300,-1e-300)  | <(3e-298,1e-298),1.41421356237e-299>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(1.01e-298,-9.9e-299),1.62634559673e-298>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(8e-300,2e-300),0>
+ <(5,1),3>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,2),100>    | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,3),5>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,2),3>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(100,200),10> | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(100,1),115>  | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(3,5),0>      | (1e+300,Infinity) | <(-Infinity,Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(40,60),42.4264068712>
+ <(1,2),100>    | (10,10)           | <(-10,30),1414.21356237>
+ <(1,3),5>      | (10,10)           | <(-20,40),70.7106781187>
+ <(1,2),3>      | (10,10)           | <(-10,30),42.4264068712>
+ <(100,200),10> | (10,10)           | <(-1000,3000),141.421356237>
+ <(100,1),115>  | (10,10)           | <(990,1010),1626.34559673>
+ <(3,5),0>      | (10,10)           | <(-20,80),0>
+(63 rows)
+
+-- Divide by point
+SELECT c.f1, p.f1, c.f1 / p.f1
+FROM CIRCLE_TBL c, POINT_TBL p
+WHERE p.f1[0] BETWEEN 1 AND 1000;
+       f1       |     f1     |                       ?column?                       
+----------------+------------+------------------------------------------------------
+ <(5,1),3>      | (5.1,34.5) | <(0.0493315573973,-0.137635045138),0.0860217042937>
+ <(5,1),3>      | (10,10)    | <(0.3,-0.2),0.212132034356>
+ <(1,2),100>    | (5.1,34.5) | <(0.0609244733856,-0.0199792807459),2.86739014312>
+ <(1,2),100>    | (10,10)    | <(0.15,0.05),7.07106781187>
+ <(1,3),5>      | (5.1,34.5) | <(0.0892901188891,-0.0157860983671),0.143369507156>
+ <(1,3),5>      | (10,10)    | <(0.2,0.1),0.353553390593>
+ <(1,2),3>      | (5.1,34.5) | <(0.0609244733856,-0.0199792807459),0.0860217042937>
+ <(1,2),3>      | (10,10)    | <(0.15,0.05),0.212132034356>
+ <(100,200),10> | (5.1,34.5) | <(6.09244733856,-1.99792807459),0.286739014312>
+ <(100,200),10> | (10,10)    | <(15,5),0.707106781187>
+ <(100,1),115>  | (5.1,34.5) | <(0.44768388338,-2.83237136796),3.29749866459>
+ <(100,1),115>  | (10,10)    | <(5.05,-4.95),8.13172798365>
+ <(3,5),0>      | (5.1,34.5) | <(0.154407774653,-0.0641310246164),0>
+ <(3,5),0>      | (10,10)    | <(0.4,0.1),0>
+(14 rows)
+
+-- Overflow error
+SELECT c.f1, p.f1, c.f1 / p.f1
+FROM CIRCLE_TBL c, POINT_TBL p
+WHERE p.f1[0] > 1000;
+ERROR:  value out of range: overflow
+-- Division by 0 error
+SELECT c.f1, p.f1, c.f1 / p.f1
+FROM CIRCLE_TBL c, POINT_TBL p
+WHERE p.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to polygon
+SELECT c.f1, p.f1, c.f1 <-> p.f1
+FROM CIRCLE_TBL c, POLYGON_TBL p;
+       f1       |             f1             |    ?column?    
+----------------+----------------------------+----------------
+ <(5,1),3>      | ((2,0),(2,4),(0,0))        |              0
+ <(5,1),3>      | ((3,1),(3,3),(1,0))        |             -1
+ <(5,1),3>      | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(5,1),3>      | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(5,1),3>      | ((1,2),(7,8),(5,6),(3,-4)) | -2.01941932431
+ <(5,1),3>      | ((0,0))                    |              0
+ <(5,1),3>      | ((0,1),(0,1))              |              0
+ <(1,2),100>    | ((2,0),(2,4),(0,0))        |           -100
+ <(1,2),100>    | ((3,1),(3,3),(1,0))        | -98.8905996075
+ <(1,2),100>    | ((1,2),(3,4),(5,6),(7,8))  |           -100
+ <(1,2),100>    | ((7,8),(5,6),(3,4),(1,2))  |           -100
+ <(1,2),100>    | ((1,2),(7,8),(5,6),(3,-4)) |           -100
+ <(1,2),100>    | ((0,0))                    | -97.7639320225
+ <(1,2),100>    | ((0,1),(0,1))              | -98.5857864376
+ <(1,3),5>      | ((2,0),(2,4),(0,0))        |  -4.5527864045
+ <(1,3),5>      | ((3,1),(3,3),(1,0))        | -3.33589941132
+ <(1,3),5>      | ((1,2),(3,4),(5,6),(7,8))  | -4.29289321881
+ <(1,3),5>      | ((7,8),(5,6),(3,4),(1,2))  | -4.29289321881
+ <(1,3),5>      | ((1,2),(7,8),(5,6),(3,-4)) | -4.29289321881
+ <(1,3),5>      | ((0,0))                    | -1.83772233983
+ <(1,3),5>      | ((0,1),(0,1))              |  -2.7639320225
+ <(1,2),3>      | ((2,0),(2,4),(0,0))        |             -3
+ <(1,2),3>      | ((3,1),(3,3),(1,0))        | -1.89059960755
+ <(1,2),3>      | ((1,2),(3,4),(5,6),(7,8))  |             -3
+ <(1,2),3>      | ((7,8),(5,6),(3,4),(1,2))  |             -3
+ <(1,2),3>      | ((1,2),(7,8),(5,6),(3,-4)) |             -3
+ <(1,2),3>      | ((0,0))                    |  -0.7639320225
+ <(1,2),3>      | ((0,1),(0,1))              | -1.58578643763
+ <(100,200),10> | ((2,0),(2,4),(0,0))        |              0
+ <(100,200),10> | ((3,1),(3,3),(1,0))        |              0
+ <(100,200),10> | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(100,200),10> | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(100,200),10> | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(100,200),10> | ((0,0))                    |              0
+ <(100,200),10> | ((0,1),(0,1))              |              0
+ <(100,1),115>  | ((2,0),(2,4),(0,0))        |            -17
+ <(100,1),115>  | ((3,1),(3,3),(1,0))        |            -18
+ <(100,1),115>  | ((1,2),(3,4),(5,6),(7,8))  | -21.7369312107
+ <(100,1),115>  | ((7,8),(5,6),(3,4),(1,2))  | -21.7369312107
+ <(100,1),115>  | ((1,2),(7,8),(5,6),(3,-4)) | -21.7369312107
+ <(100,1),115>  | ((0,0))                    |  -14.995000125
+ <(100,1),115>  | ((0,1),(0,1))              |            -15
+ <(3,5),0>      | ((2,0),(2,4),(0,0))        |              0
+ <(3,5),0>      | ((3,1),(3,3),(1,0))        |              0
+ <(3,5),0>      | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(3,5),0>      | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(3,5),0>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(3,5),0>      | ((0,0))                    |              0
+ <(3,5),0>      | ((0,1),(0,1))              |              0
+(49 rows)
 
diff --git a/src/test/regress/expected/geometry_1.out b/src/test/regress/expected/geometry_1.out
deleted file mode 100644
index 3b92e23059..0000000000
--- a/src/test/regress/expected/geometry_1.out
+++ /dev/null
@@ -1,563 +0,0 @@
---
--- GEOMETRY
---
--- Back off displayed precision a little bit to reduce platform-to-platform
--- variation in results.
-SET extra_float_digits TO -3;
---
--- Points
---
-SELECT '' AS four, center(f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS four, (@@ f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS six, point(f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS six, (@@ f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS two, (@@ f1) AS center
-   FROM POLYGON_TBL
-   WHERE (# f1) > 2;
- two |            center             
------+-------------------------------
-     | (1.33333333333,1.33333333333)
-     | (2.33333333333,1.33333333333)
-(2 rows)
-
--- "is horizontal" function
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is horizontal" operator
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is vertical" function
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE isvertical(p1.f1, point '(5.1,34.5)');
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
--- "is vertical" operator
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?| point '(5.1,34.5)';
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
---
--- Line segments
---
--- intersection
-SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-   FROM LSEG_TBL l, POINT_TBL p;
-ERROR:  operator does not exist: lseg # point
-LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-                                           ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
-
---
--- Boxes
---
-SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
- six |                              box                               
------+----------------------------------------------------------------
-     | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
-     | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
-     | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
-     | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
-     | (107.071067812,207.071067812),(92.9289321881,192.928932188)
-     | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
-
--- translation
-SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (-8,2),(-10,0)
-            | (-7,3),(-9,1)
-            | (-7.5,3.5),(-7.5,2.5)
-            | (-7,3),(-7,3)
-            | (-1,6),(-3,4)
-            | (0,7),(-2,5)
-            | (-0.5,7.5),(-0.5,6.5)
-            | (0,7),(0,7)
-            | (7.1,36.5),(5.1,34.5)
-            | (8.1,37.5),(6.1,35.5)
-            | (7.6,38),(7.6,37)
-            | (8.1,37.5),(8.1,37.5)
-            | (-3,-10),(-5,-12)
-            | (-2,-9),(-4,-11)
-            | (-2.5,-8.5),(-2.5,-9.5)
-            | (-2,-9),(-2,-9)
-            | (12,12),(10,10)
-            | (13,13),(11,11)
-            | (12.5,13.5),(12.5,12.5)
-            | (13,13),(13,13)
-(24 rows)
-
-SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (12,2),(10,0)
-            | (13,3),(11,1)
-            | (12.5,3.5),(12.5,2.5)
-            | (13,3),(13,3)
-            | (5,-2),(3,-4)
-            | (6,-1),(4,-3)
-            | (5.5,-0.5),(5.5,-1.5)
-            | (6,-1),(6,-1)
-            | (-3.1,-32.5),(-5.1,-34.5)
-            | (-2.1,-31.5),(-4.1,-33.5)
-            | (-2.6,-31),(-2.6,-32)
-            | (-2.1,-31.5),(-2.1,-31.5)
-            | (7,14),(5,12)
-            | (8,15),(6,13)
-            | (7.5,15.5),(7.5,14.5)
-            | (8,15),(8,15)
-            | (-8,-8),(-10,-10)
-            | (-7,-7),(-9,-9)
-            | (-7.5,-6.5),(-7.5,-7.5)
-            | (-7,-7),(-7,-7)
-(24 rows)
-
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
-
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,0),(-0.2,-0.2)
-        | (0.08,0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
-
-SELECT f1::box
-	FROM POINT_TBL;
-          f1           
------------------------
- (0,0),(0,0)
- (-10,0),(-10,0)
- (-3,4),(-3,4)
- (5.1,34.5),(5.1,34.5)
- (-5,-12),(-5,-12)
- (10,10),(10,10)
-(6 rows)
-
-SELECT bound_box(a.f1, b.f1)
-	FROM BOX_TBL a, BOX_TBL b;
-      bound_box      
----------------------
- (2,2),(0,0)
- (3,3),(0,0)
- (2.5,3.5),(0,0)
- (3,3),(0,0)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(1,1)
- (3,3),(1,1)
- (2.5,3.5),(0,0)
- (3,3.5),(1,1)
- (2.5,3.5),(2.5,2.5)
- (3,3.5),(2.5,2.5)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(2.5,2.5)
- (3,3),(3,3)
-(16 rows)
-
---
--- Paths
---
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
-
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
-
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
-
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
-
---
--- Polygons
---
--- containment
-SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
-   FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
-      |       3 | ((2,0),(2,4),(0,0))
-      |       3 | ((3,1),(3,3),(1,0))
-      |       1 | ((0,0))
-      |       2 | ((0,1),(0,1))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM BOX_TBL;
- four |                  polygon                  
-------+-------------------------------------------
-      | ((0,0),(0,2),(2,2),(2,0))
-      | ((1,1),(1,3),(3,3),(3,1))
-      | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
-      | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM PATH_TBL WHERE isclosed(f1);
- four |      polygon      
-------+-------------------
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((11,12),(13,14))
-(4 rows)
-
-SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
-   FROM PATH_TBL
-   WHERE isopen(f1);
- four |         open_path         |          polygon          
-------+---------------------------+---------------------------
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(11,12),(13,14)]         | ((11,12),(13,14))
-(4 rows)
-
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
-
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
-
---
--- Circles
---
-SELECT '' AS six, circle(f1, 50.0)
-   FROM POINT_TBL;
- six |     circle      
------+-----------------
-     | <(0,0),50>
-     | <(-10,0),50>
-     | <(-3,4),50>
-     | <(5.1,34.5),50>
-     | <(-5,-12),50>
-     | <(10,10),50>
-(6 rows)
-
-SELECT '' AS four, circle(f1)
-   FROM BOX_TBL;
- four |        circle         
-------+-----------------------
-      | <(1,1),1.41421356237>
-      | <(2,2),1.41421356237>
-      | <(2.5,3),0.5>
-      | <(3,3),0>
-(4 rows)
-
-SELECT '' AS two, circle(f1)
-   FROM POLYGON_TBL
-   WHERE (# f1) >= 3;
- two |                    circle                     
------+-----------------------------------------------
-     | <(1.33333333333,1.33333333333),2.04168905064>
-     | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
-
-SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
-   FROM CIRCLE_TBL c1, POINT_TBL p1
-   WHERE (p1.f1 <-> c1.f1) > 0
-   ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
-
diff --git a/src/test/regress/expected/geometry_2.out b/src/test/regress/expected/geometry_2.out
deleted file mode 100644
index 5a922bcd3f..0000000000
--- a/src/test/regress/expected/geometry_2.out
+++ /dev/null
@@ -1,563 +0,0 @@
---
--- GEOMETRY
---
--- Back off displayed precision a little bit to reduce platform-to-platform
--- variation in results.
-SET extra_float_digits TO -3;
---
--- Points
---
-SELECT '' AS four, center(f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS four, (@@ f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS six, point(f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS six, (@@ f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS two, (@@ f1) AS center
-   FROM POLYGON_TBL
-   WHERE (# f1) > 2;
- two |            center             
------+-------------------------------
-     | (1.33333333333,1.33333333333)
-     | (2.33333333333,1.33333333333)
-(2 rows)
-
--- "is horizontal" function
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is horizontal" operator
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is vertical" function
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE isvertical(p1.f1, point '(5.1,34.5)');
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
--- "is vertical" operator
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?| point '(5.1,34.5)';
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
---
--- Line segments
---
--- intersection
-SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-   FROM LSEG_TBL l, POINT_TBL p;
-ERROR:  operator does not exist: lseg # point
-LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-                                           ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
-
---
--- Boxes
---
-SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
- six |                              box                               
------+----------------------------------------------------------------
-     | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
-     | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
-     | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
-     | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
-     | (107.071067812,207.071067812),(92.9289321881,192.928932188)
-     | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
-
--- translation
-SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (-8,2),(-10,0)
-            | (-7,3),(-9,1)
-            | (-7.5,3.5),(-7.5,2.5)
-            | (-7,3),(-7,3)
-            | (-1,6),(-3,4)
-            | (0,7),(-2,5)
-            | (-0.5,7.5),(-0.5,6.5)
-            | (0,7),(0,7)
-            | (7.1,36.5),(5.1,34.5)
-            | (8.1,37.5),(6.1,35.5)
-            | (7.6,38),(7.6,37)
-            | (8.1,37.5),(8.1,37.5)
-            | (-3,-10),(-5,-12)
-            | (-2,-9),(-4,-11)
-            | (-2.5,-8.5),(-2.5,-9.5)
-            | (-2,-9),(-2,-9)
-            | (12,12),(10,10)
-            | (13,13),(11,11)
-            | (12.5,13.5),(12.5,12.5)
-            | (13,13),(13,13)
-(24 rows)
-
-SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (12,2),(10,0)
-            | (13,3),(11,1)
-            | (12.5,3.5),(12.5,2.5)
-            | (13,3),(13,3)
-            | (5,-2),(3,-4)
-            | (6,-1),(4,-3)
-            | (5.5,-0.5),(5.5,-1.5)
-            | (6,-1),(6,-1)
-            | (-3.1,-32.5),(-5.1,-34.5)
-            | (-2.1,-31.5),(-4.1,-33.5)
-            | (-2.6,-31),(-2.6,-32)
-            | (-2.1,-31.5),(-2.1,-31.5)
-            | (7,14),(5,12)
-            | (8,15),(6,13)
-            | (7.5,15.5),(7.5,14.5)
-            | (8,15),(8,15)
-            | (-8,-8),(-10,-10)
-            | (-7,-7),(-9,-9)
-            | (-7.5,-6.5),(-7.5,-7.5)
-            | (-7,-7),(-7,-7)
-(24 rows)
-
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (-0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (-0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,-0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
-
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,-0),(-0.2,-0.2)
-        | (0.08,-0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (-0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
-
-SELECT f1::box
-	FROM POINT_TBL;
-          f1           
------------------------
- (0,0),(0,0)
- (-10,0),(-10,0)
- (-3,4),(-3,4)
- (5.1,34.5),(5.1,34.5)
- (-5,-12),(-5,-12)
- (10,10),(10,10)
-(6 rows)
-
-SELECT bound_box(a.f1, b.f1)
-	FROM BOX_TBL a, BOX_TBL b;
-      bound_box      
----------------------
- (2,2),(0,0)
- (3,3),(0,0)
- (2.5,3.5),(0,0)
- (3,3),(0,0)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(1,1)
- (3,3),(1,1)
- (2.5,3.5),(0,0)
- (3,3.5),(1,1)
- (2.5,3.5),(2.5,2.5)
- (3,3.5),(2.5,2.5)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(2.5,2.5)
- (3,3),(3,3)
-(16 rows)
-
---
--- Paths
---
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
-
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
-
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
-
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
-
---
--- Polygons
---
--- containment
-SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
-   FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
-      |       3 | ((2,0),(2,4),(0,0))
-      |       3 | ((3,1),(3,3),(1,0))
-      |       1 | ((0,0))
-      |       2 | ((0,1),(0,1))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM BOX_TBL;
- four |                  polygon                  
-------+-------------------------------------------
-      | ((0,0),(0,2),(2,2),(2,0))
-      | ((1,1),(1,3),(3,3),(3,1))
-      | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
-      | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM PATH_TBL WHERE isclosed(f1);
- four |      polygon      
-------+-------------------
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((11,12),(13,14))
-(4 rows)
-
-SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
-   FROM PATH_TBL
-   WHERE isopen(f1);
- four |         open_path         |          polygon          
-------+---------------------------+---------------------------
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(11,12),(13,14)]         | ((11,12),(13,14))
-(4 rows)
-
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
-
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
-
---
--- Circles
---
-SELECT '' AS six, circle(f1, 50.0)
-   FROM POINT_TBL;
- six |     circle      
------+-----------------
-     | <(0,0),50>
-     | <(-10,0),50>
-     | <(-3,4),50>
-     | <(5.1,34.5),50>
-     | <(-5,-12),50>
-     | <(10,10),50>
-(6 rows)
-
-SELECT '' AS four, circle(f1)
-   FROM BOX_TBL;
- four |        circle         
-------+-----------------------
-      | <(1,1),1.41421356237>
-      | <(2,2),1.41421356237>
-      | <(2.5,3),0.5>
-      | <(3,3),0>
-(4 rows)
-
-SELECT '' AS two, circle(f1)
-   FROM POLYGON_TBL
-   WHERE (# f1) >= 3;
- two |                    circle                     
------+-----------------------------------------------
-     | <(1.33333333333,1.33333333333),2.04168905064>
-     | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
-
-SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
-   FROM CIRCLE_TBL c1, POINT_TBL p1
-   WHERE (p1.f1 <-> c1.f1) > 0
-   ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
-
diff --git a/src/test/regress/expected/line.out b/src/test/regress/expected/line.out
index f20abdc430..03b86884b4 100644
--- a/src/test/regress/expected/line.out
+++ b/src/test/regress/expected/line.out
@@ -1,271 +1,78 @@
 --
 -- LINE
 -- Infinite lines
 --
 --DROP TABLE LINE_TBL;
 CREATE TABLE LINE_TBL (s line);
-INSERT INTO LINE_TBL VALUES ('{1,-1,1}');
-INSERT INTO LINE_TBL VALUES ('(0,0),(6,6)');
+INSERT INTO LINE_TBL VALUES ('{0,-1,5}');	-- A == 0
+INSERT INTO LINE_TBL VALUES ('{1,0,5}');	-- B == 0
+INSERT INTO LINE_TBL VALUES ('{0,3,0}');	-- A == C == 0
+INSERT INTO LINE_TBL VALUES (' (0,0), (6,6)');
 INSERT INTO LINE_TBL VALUES ('10,-10 ,-5,-4');
 INSERT INTO LINE_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LINE_TBL VALUES ('(11,22,33,44)');
-INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
-ERROR:  invalid line specification: must be two distinct points
-LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
-                                     ^
+INSERT INTO LINE_TBL VALUES (line(point '(1,0)', point '(1,0)'));
+INSERT INTO LINE_TBL VALUES ('{3,NaN,5}');
 -- horizontal
 INSERT INTO LINE_TBL VALUES ('[(1,3),(2,3)]');
 -- vertical
 INSERT INTO LINE_TBL VALUES ('[(3,1),(3,2)]');
 -- bad values for parser testing
+INSERT INTO LINE_TBL VALUES ('{}');
+ERROR:  invalid input syntax for type line: "{}"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{}');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0');
+ERROR:  invalid input syntax for type line: "{0"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0,0}');
+ERROR:  invalid input syntax for type line: "{0,0}"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0}');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0,0,1');
+ERROR:  invalid input syntax for type line: "{0,0,1"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1');
+                                     ^
 INSERT INTO LINE_TBL VALUES ('{0,0,1}');
 ERROR:  invalid line specification: A and B cannot both be zero
 LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1}');
                                      ^
+INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
+ERROR:  invalid input syntax for type line: "{0,0,1} x"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
+                                     ^
 INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
 ERROR:  invalid input syntax for type line: "(3asdf,2 ,3,4r2)"
 LINE 1: INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
                                      ^
 INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
 ERROR:  invalid input syntax for type line: "[1,2,3, 4"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
                                      ^
 INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
 ERROR:  invalid input syntax for type line: "[(,2),(3,4)]"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
                                      ^
 INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
 ERROR:  invalid input syntax for type line: "[(1,2),(3,4)"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
                                      ^
+INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
+ERROR:  invalid line specification: must be two distinct points
+LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
+                                     ^
 select * from LINE_TBL;
                       s                      
 ---------------------------------------------
- {1,-1,1}
+ {0,-1,5}
+ {1,0,5}
+ {0,3,0}
  {1,-1,0}
  {-0.4,-1,-6}
  {-0.000184615384615385,-1,15.3846153846154}
- {1,-1,11}
+ {-1,0,1}
+ {3,NaN,5}
  {0,-1,3}
  {-1,0,3}
-(7 rows)
-
--- functions and operators
-SELECT * FROM LINE_TBL WHERE (s <-> line '[(1,2),(3,4)]') < 10;
-                      s                      
----------------------------------------------
- {1,-1,1}
- {1,-1,0}
- {-0.4,-1,-6}
- {-0.000184615384615385,-1,15.3846153846154}
- {1,-1,11}
- {0,-1,3}
- {-1,0,3}
-(7 rows)
-
-SELECT * FROM LINE_TBL WHERE (point '(0.1,0.1)' <-> s) < 1;
-    s     
-----------
- {1,-1,1}
- {1,-1,0}
-(2 rows)
-
-SELECT * FROM LINE_TBL WHERE (lseg '[(0.1,0.1),(0.2,0.2)]' <-> s) < 1;
-    s     
-----------
- {1,-1,1}
- {1,-1,0}
-(2 rows)
-
-SELECT line '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
- ?column? 
-----------
-        2
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
- ?column? 
-----------
-        2
-(1 row)
-
-SELECT point '(-1,1)' <-> line '[(-3,0),(-4,0)]';
- ?column? 
-----------
-        1
-(1 row)
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(2,0),(0,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# box '(0,0,2,2)';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(3,0),(4,1)]' ?# box '(0,0,2,2)';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(1,1)' <@ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT point '(1,1)' <@ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(1,1)' @ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT point '(1,1)' @ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT lseg '[(1,1),(2,2)]' <@ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' <@ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT lseg '[(1,1),(2,2)]' @ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' @ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(0,1)' ## line '[(0,0),(1,1)]';
- ?column?  
------------
- (0.5,0.5)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ## lseg '[(1,0),(2,0)]';
- ?column? 
-----------
- (1,0)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(2,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(1,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(2,1)]';
- ?column? 
-----------
- 
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(1,1)]';
- ?column? 
-----------
- (1,1)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(2,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,0)]' ?-| line '[(0,0),(0,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?-| line '[(1,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT ?- line '[(0,0),(1,0)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT ?- line '[(0,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT ?| line '[(0,0),(0,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT ?| line '[(0,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line(point '(1,2)', point '(3,4)');
-   line   
-----------
- {1,-1,1}
-(1 row)
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,5)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,4)]';  -- false
- ?column? 
-----------
- f
-(1 row)
+(10 rows)
 
diff --git a/src/test/regress/expected/lseg.out b/src/test/regress/expected/lseg.out
index bba1f3ee80..0f6339e914 100644
--- a/src/test/regress/expected/lseg.out
+++ b/src/test/regress/expected/lseg.out
@@ -1,21 +1,23 @@
 --
 -- LSEG
 -- Line segments
 --
 --DROP TABLE LSEG_TBL;
 CREATE TABLE LSEG_TBL (s lseg);
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('(0,0),(6,6)');
 INSERT INTO LSEG_TBL VALUES ('10,-10 ,-3,-4');
 INSERT INTO LSEG_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LSEG_TBL VALUES ('(11,22,33,44)');
+INSERT INTO LSEG_TBL VALUES (lseg(point(11, 22), point(33,44)));
+INSERT INTO LSEG_TBL VALUES ('[(-10,2),(-10,3)]');	-- vertical
+INSERT INTO LSEG_TBL VALUES ('[(0,-20),(30,-20)]');	-- horizontal
 -- bad values for parser testing
 INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
 ERROR:  invalid input syntax for type lseg: "(3asdf,2 ,3,4r2)"
 LINE 1: INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
                                      ^
 INSERT INTO LSEG_TBL VALUES ('[1,2,3, 4');
 ERROR:  invalid input syntax for type lseg: "[1,2,3, 4"
 LINE 1: INSERT INTO LSEG_TBL VALUES ('[1,2,3, 4');
                                      ^
 INSERT INTO LSEG_TBL VALUES ('[(,2),(3,4)]');
@@ -27,26 +29,14 @@ ERROR:  invalid input syntax for type lseg: "[(1,2),(3,4)"
 LINE 1: INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)');
                                      ^
 select * from LSEG_TBL;
                s               
 -------------------------------
  [(1,2),(3,4)]
  [(0,0),(6,6)]
  [(10,-10),(-3,-4)]
  [(-1000000,200),(300000,-40)]
  [(11,22),(33,44)]
-(5 rows)
-
-SELECT * FROM LSEG_TBL WHERE s <= lseg '[(1,2),(3,4)]';
-       s       
----------------
- [(1,2),(3,4)]
-(1 row)
-
-SELECT * FROM LSEG_TBL WHERE (s <-> lseg '[(1,2),(3,4)]') < 10;
-         s          
---------------------
- [(1,2),(3,4)]
- [(0,0),(6,6)]
- [(10,-10),(-3,-4)]
-(3 rows)
+ [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]
+(7 rows)
 
diff --git a/src/test/regress/expected/path.out b/src/test/regress/expected/path.out
index 08d6d61dda..bd6e467752 100644
--- a/src/test/regress/expected/path.out
+++ b/src/test/regress/expected/path.out
@@ -1,79 +1,82 @@
 --
 -- PATH
 --
 --DROP TABLE PATH_TBL;
 CREATE TABLE PATH_TBL (f1 path);
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)]');
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
-INSERT INTO PATH_TBL VALUES ('[(0,0),(3,0),(4,5),(1,6)]');
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
-INSERT INTO PATH_TBL VALUES ('1,2 ,3,4');
-INSERT INTO PATH_TBL VALUES ('[1,2,3, 4]');
-INSERT INTO PATH_TBL VALUES ('[11,12,13,14]');
-INSERT INTO PATH_TBL VALUES ('(11,12,13,14)');
+INSERT INTO PATH_TBL VALUES (' ( ( 1 , 2 ) , ( 3 , 4 ) ) ');
+INSERT INTO PATH_TBL VALUES ('[ (0,0),(3,0),(4,5),(1,6) ]');
+INSERT INTO PATH_TBL VALUES ('((1,2) ,(3,4 ))');
+INSERT INTO PATH_TBL VALUES ('1,2 ,3,4 ');
+INSERT INTO PATH_TBL VALUES (' [1,2,3, 4] ');
+INSERT INTO PATH_TBL VALUES ('((10,20))');	-- Only one point
+INSERT INTO PATH_TBL VALUES ('[ 11,12,13,14 ]');
+INSERT INTO PATH_TBL VALUES ('( 11,12,13,14) ');
 -- bad values for parser testing
+INSERT INTO PATH_TBL VALUES ('[]');
+ERROR:  invalid input syntax for type path: "[]"
+LINE 1: INSERT INTO PATH_TBL VALUES ('[]');
+                                     ^
 INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
 ERROR:  invalid input syntax for type path: "[(,2),(3,4)]"
 LINE 1: INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
                                      ^
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
 ERROR:  invalid input syntax for type path: "[(1,2),(3,4)"
 LINE 1: INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
                                      ^
-SELECT f1 FROM PATH_TBL;
-            f1             
----------------------------
- [(1,2),(3,4)]
- ((1,2),(3,4))
- [(0,0),(3,0),(4,5),(1,6)]
- ((1,2),(3,4))
- ((1,2),(3,4))
- [(1,2),(3,4)]
- [(11,12),(13,14)]
- ((11,12),(13,14))
-(8 rows)
-
+INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+ERROR:  invalid input syntax for type path: "(1,2,3,4"
+LINE 1: INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+                                     ^
+INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
+ERROR:  invalid input syntax for type path: "(1,2),(3,4)]"
+LINE 1: INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
+                                     ^
 SELECT '' AS count, f1 AS open_path FROM PATH_TBL WHERE isopen(f1);
  count |         open_path         
 -------+---------------------------
        | [(1,2),(3,4)]
        | [(0,0),(3,0),(4,5),(1,6)]
        | [(1,2),(3,4)]
        | [(11,12),(13,14)]
 (4 rows)
 
 SELECT '' AS count, f1 AS closed_path FROM PATH_TBL WHERE isclosed(f1);
  count |    closed_path    
 -------+-------------------
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
+       | ((10,20))
        | ((11,12),(13,14))
-(4 rows)
+(5 rows)
 
 SELECT '' AS count, pclose(f1) AS closed_path FROM PATH_TBL;
  count |        closed_path        
 -------+---------------------------
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((0,0),(3,0),(4,5),(1,6))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
+       | ((10,20))
        | ((11,12),(13,14))
        | ((11,12),(13,14))
-(8 rows)
+(9 rows)
 
 SELECT '' AS count, popen(f1) AS open_path FROM PATH_TBL;
  count |         open_path         
 -------+---------------------------
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
        | [(0,0),(3,0),(4,5),(1,6)]
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
+       | [(10,20)]
        | [(11,12),(13,14)]
        | [(11,12),(13,14)]
-(8 rows)
+(9 rows)
 
diff --git a/src/test/regress/expected/point.out b/src/test/regress/expected/point.out
index bfc0962749..88575647fa 100644
--- a/src/test/regress/expected/point.out
+++ b/src/test/regress/expected/point.out
@@ -1,75 +1,93 @@
 --
 -- POINT
 --
 CREATE TABLE POINT_TBL(f1 point);
 INSERT INTO POINT_TBL(f1) VALUES ('(0.0,0.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-10.0,0.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-3.0,4.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(5.1, 34.5)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-5.0,-12.0)');
+INSERT INTO POINT_TBL(f1) VALUES ('(1e-300,-1e-300)');	-- To underflow
+INSERT INTO POINT_TBL(f1) VALUES ('(1e+300,Inf)');		-- To overflow
+INSERT INTO POINT_TBL(f1) VALUES (' ( Nan , NaN ) ');
 -- bad format points
 INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
 ERROR:  invalid input syntax for type point: "asdfasdf"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
                                           ^
 INSERT INTO POINT_TBL(f1) VALUES ('10.0,10.0');
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
 ERROR:  invalid input syntax for type point: "(10.0 10.0)"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
                                           ^
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+ERROR:  invalid input syntax for type point: "(10.0, 10.0) x"
+LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+                                          ^
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
 ERROR:  invalid input syntax for type point: "(10.0,10.0"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
                                           ^
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');	-- Out of range
+ERROR:  "1e+500" is out of range for type double precision
+LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');
+                                          ^
 SELECT '' AS six, * FROM POINT_TBL;
- six |     f1     
------+------------
+ six |        f1         
+-----+-------------------
      | (0,0)
      | (-10,0)
      | (-3,4)
      | (5.1,34.5)
      | (-5,-12)
+     | (1e-300,-1e-300)
+     | (1e+300,Infinity)
+     | (NaN,NaN)
      | (10,10)
-(6 rows)
+(9 rows)
 
 -- left of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE p.f1 << '(0.0, 0.0)';
- three |    f1    
--------+----------
+ three |    f1     
+-------+-----------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
-(3 rows)
+       | (NaN,NaN)
+(4 rows)
 
 -- right of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE '(0.0,0.0)' >> p.f1;
- three |    f1    
--------+----------
+ three |    f1     
+-------+-----------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
-(3 rows)
+       | (NaN,NaN)
+(4 rows)
 
 -- above
 SELECT '' AS one, p.* FROM POINT_TBL p WHERE '(0.0,0.0)' >^ p.f1;
- one |    f1    
------+----------
+ one |    f1     
+-----+-----------
      | (-5,-12)
-(1 row)
+     | (NaN,NaN)
+(2 rows)
 
 -- below
 SELECT '' AS one, p.* FROM POINT_TBL p WHERE p.f1 <^ '(0.0, 0.0)';
- one |    f1    
------+----------
+ one |    f1     
+-----+-----------
      | (-5,-12)
-(1 row)
+     | (NaN,NaN)
+(2 rows)
 
 -- equal
 SELECT '' AS one, p.* FROM POINT_TBL p WHERE p.f1 ~= '(5.1, 34.5)';
  one |     f1     
 -----+------------
      | (5.1,34.5)
 (1 row)
 
 -- point in box
 SELECT '' AS three, p.* FROM POINT_TBL p
@@ -85,172 +103,316 @@ 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    
--------+----------
+ three |        f1         
+-------+-------------------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
-(3 rows)
+       | (1e-300,-1e-300)
+       | (1e+300,Infinity)
+       | (NaN,NaN)
+(6 rows)
 
 SELECT '' AS two, p.* FROM POINT_TBL p
    WHERE p.f1 <@ path '[(0,0),(-10,0),(-10,10)]';
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 SELECT '' AS three, p.* FROM POINT_TBL p
    WHERE not box '(0,0,100,100)' @> p.f1;
- three |    f1    
--------+----------
+ three |        f1         
+-------+-------------------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
-(3 rows)
+       | (1e-300,-1e-300)
+       | (1e+300,Infinity)
+       | (NaN,NaN)
+(6 rows)
 
 SELECT '' AS six, p.f1, p.f1 <-> point '(0,0)' AS dist
    FROM POINT_TBL p
    ORDER BY dist;
- six |     f1     |       dist       
------+------------+------------------
-     | (0,0)      |                0
-     | (-3,4)     |                5
-     | (-10,0)    |               10
-     | (-5,-12)   |               13
-     | (10,10)    |  14.142135623731
-     | (5.1,34.5) | 34.8749193547455
-(6 rows)
+ six |        f1         |         dist         
+-----+-------------------+----------------------
+     | (0,0)             |                    0
+     | (1e-300,-1e-300)  | 1.4142135623731e-300
+     | (-3,4)            |                    5
+     | (-10,0)           |                   10
+     | (-5,-12)          |                   13
+     | (10,10)           |      14.142135623731
+     | (5.1,34.5)        |     34.8749193547455
+     | (1e+300,Infinity) |             Infinity
+     | (NaN,NaN)         |                  NaN
+(9 rows)
 
 SELECT '' AS thirtysix, p1.f1 AS point1, p2.f1 AS point2, p1.f1 <-> p2.f1 AS dist
    FROM POINT_TBL p1, POINT_TBL p2
    ORDER BY dist, p1.f1[0], p2.f1[0];
- thirtysix |   point1   |   point2   |       dist       
------------+------------+------------+------------------
-           | (-10,0)    | (-10,0)    |                0
-           | (-5,-12)   | (-5,-12)   |                0
-           | (-3,4)     | (-3,4)     |                0
-           | (0,0)      | (0,0)      |                0
-           | (5.1,34.5) | (5.1,34.5) |                0
-           | (10,10)    | (10,10)    |                0
-           | (-3,4)     | (0,0)      |                5
-           | (0,0)      | (-3,4)     |                5
-           | (-10,0)    | (-3,4)     | 8.06225774829855
-           | (-3,4)     | (-10,0)    | 8.06225774829855
-           | (-10,0)    | (0,0)      |               10
-           | (0,0)      | (-10,0)    |               10
-           | (-10,0)    | (-5,-12)   |               13
-           | (-5,-12)   | (-10,0)    |               13
-           | (-5,-12)   | (0,0)      |               13
-           | (0,0)      | (-5,-12)   |               13
-           | (0,0)      | (10,10)    |  14.142135623731
-           | (10,10)    | (0,0)      |  14.142135623731
-           | (-3,4)     | (10,10)    | 14.3178210632764
-           | (10,10)    | (-3,4)     | 14.3178210632764
-           | (-5,-12)   | (-3,4)     | 16.1245154965971
-           | (-3,4)     | (-5,-12)   | 16.1245154965971
-           | (-10,0)    | (10,10)    | 22.3606797749979
-           | (10,10)    | (-10,0)    | 22.3606797749979
-           | (5.1,34.5) | (10,10)    | 24.9851956166046
-           | (10,10)    | (5.1,34.5) | 24.9851956166046
-           | (-5,-12)   | (10,10)    | 26.6270539113887
-           | (10,10)    | (-5,-12)   | 26.6270539113887
-           | (-3,4)     | (5.1,34.5) | 31.5572495632937
-           | (5.1,34.5) | (-3,4)     | 31.5572495632937
-           | (0,0)      | (5.1,34.5) | 34.8749193547455
-           | (5.1,34.5) | (0,0)      | 34.8749193547455
-           | (-10,0)    | (5.1,34.5) | 37.6597928831267
-           | (5.1,34.5) | (-10,0)    | 37.6597928831267
-           | (-5,-12)   | (5.1,34.5) | 47.5842410888311
-           | (5.1,34.5) | (-5,-12)   | 47.5842410888311
-(36 rows)
+ thirtysix |      point1       |      point2       |         dist         
+-----------+-------------------+-------------------+----------------------
+           | (-10,0)           | (-10,0)           |                    0
+           | (-5,-12)          | (-5,-12)          |                    0
+           | (-3,4)            | (-3,4)            |                    0
+           | (0,0)             | (0,0)             |                    0
+           | (1e-300,-1e-300)  | (1e-300,-1e-300)  |                    0
+           | (5.1,34.5)        | (5.1,34.5)        |                    0
+           | (10,10)           | (10,10)           |                    0
+           | (0,0)             | (1e-300,-1e-300)  | 1.4142135623731e-300
+           | (1e-300,-1e-300)  | (0,0)             | 1.4142135623731e-300
+           | (-3,4)            | (0,0)             |                    5
+           | (-3,4)            | (1e-300,-1e-300)  |                    5
+           | (0,0)             | (-3,4)            |                    5
+           | (1e-300,-1e-300)  | (-3,4)            |                    5
+           | (-10,0)           | (-3,4)            |     8.06225774829855
+           | (-3,4)            | (-10,0)           |     8.06225774829855
+           | (-10,0)           | (0,0)             |                   10
+           | (-10,0)           | (1e-300,-1e-300)  |                   10
+           | (0,0)             | (-10,0)           |                   10
+           | (1e-300,-1e-300)  | (-10,0)           |                   10
+           | (-10,0)           | (-5,-12)          |                   13
+           | (-5,-12)          | (-10,0)           |                   13
+           | (-5,-12)          | (0,0)             |                   13
+           | (-5,-12)          | (1e-300,-1e-300)  |                   13
+           | (0,0)             | (-5,-12)          |                   13
+           | (1e-300,-1e-300)  | (-5,-12)          |                   13
+           | (0,0)             | (10,10)           |      14.142135623731
+           | (1e-300,-1e-300)  | (10,10)           |      14.142135623731
+           | (10,10)           | (0,0)             |      14.142135623731
+           | (10,10)           | (1e-300,-1e-300)  |      14.142135623731
+           | (-3,4)            | (10,10)           |     14.3178210632764
+           | (10,10)           | (-3,4)            |     14.3178210632764
+           | (-5,-12)          | (-3,4)            |     16.1245154965971
+           | (-3,4)            | (-5,-12)          |     16.1245154965971
+           | (-10,0)           | (10,10)           |     22.3606797749979
+           | (10,10)           | (-10,0)           |     22.3606797749979
+           | (5.1,34.5)        | (10,10)           |     24.9851956166046
+           | (10,10)           | (5.1,34.5)        |     24.9851956166046
+           | (-5,-12)          | (10,10)           |     26.6270539113887
+           | (10,10)           | (-5,-12)          |     26.6270539113887
+           | (-3,4)            | (5.1,34.5)        |     31.5572495632937
+           | (5.1,34.5)        | (-3,4)            |     31.5572495632937
+           | (0,0)             | (5.1,34.5)        |     34.8749193547455
+           | (1e-300,-1e-300)  | (5.1,34.5)        |     34.8749193547455
+           | (5.1,34.5)        | (0,0)             |     34.8749193547455
+           | (5.1,34.5)        | (1e-300,-1e-300)  |     34.8749193547455
+           | (-10,0)           | (5.1,34.5)        |     37.6597928831267
+           | (5.1,34.5)        | (-10,0)           |     37.6597928831267
+           | (-5,-12)          | (5.1,34.5)        |     47.5842410888311
+           | (5.1,34.5)        | (-5,-12)          |     47.5842410888311
+           | (-10,0)           | (1e+300,Infinity) |             Infinity
+           | (-5,-12)          | (1e+300,Infinity) |             Infinity
+           | (-3,4)            | (1e+300,Infinity) |             Infinity
+           | (0,0)             | (1e+300,Infinity) |             Infinity
+           | (1e-300,-1e-300)  | (1e+300,Infinity) |             Infinity
+           | (5.1,34.5)        | (1e+300,Infinity) |             Infinity
+           | (10,10)           | (1e+300,Infinity) |             Infinity
+           | (1e+300,Infinity) | (-10,0)           |             Infinity
+           | (1e+300,Infinity) | (-5,-12)          |             Infinity
+           | (1e+300,Infinity) | (-3,4)            |             Infinity
+           | (1e+300,Infinity) | (0,0)             |             Infinity
+           | (1e+300,Infinity) | (1e-300,-1e-300)  |             Infinity
+           | (1e+300,Infinity) | (5.1,34.5)        |             Infinity
+           | (1e+300,Infinity) | (10,10)           |             Infinity
+           | (-10,0)           | (NaN,NaN)         |                  NaN
+           | (-5,-12)          | (NaN,NaN)         |                  NaN
+           | (-3,4)            | (NaN,NaN)         |                  NaN
+           | (0,0)             | (NaN,NaN)         |                  NaN
+           | (1e-300,-1e-300)  | (NaN,NaN)         |                  NaN
+           | (5.1,34.5)        | (NaN,NaN)         |                  NaN
+           | (10,10)           | (NaN,NaN)         |                  NaN
+           | (1e+300,Infinity) | (1e+300,Infinity) |                  NaN
+           | (1e+300,Infinity) | (NaN,NaN)         |                  NaN
+           | (NaN,NaN)         | (-10,0)           |                  NaN
+           | (NaN,NaN)         | (-5,-12)          |                  NaN
+           | (NaN,NaN)         | (-3,4)            |                  NaN
+           | (NaN,NaN)         | (0,0)             |                  NaN
+           | (NaN,NaN)         | (1e-300,-1e-300)  |                  NaN
+           | (NaN,NaN)         | (5.1,34.5)        |                  NaN
+           | (NaN,NaN)         | (10,10)           |                  NaN
+           | (NaN,NaN)         | (1e+300,Infinity) |                  NaN
+           | (NaN,NaN)         | (NaN,NaN)         |                  NaN
+(81 rows)
 
 SELECT '' AS thirty, p1.f1 AS point1, p2.f1 AS point2
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3;
- thirty |   point1   |   point2   
---------+------------+------------
-        | (0,0)      | (-10,0)
-        | (0,0)      | (-3,4)
-        | (0,0)      | (5.1,34.5)
-        | (0,0)      | (-5,-12)
-        | (0,0)      | (10,10)
-        | (-10,0)    | (0,0)
-        | (-10,0)    | (-3,4)
-        | (-10,0)    | (5.1,34.5)
-        | (-10,0)    | (-5,-12)
-        | (-10,0)    | (10,10)
-        | (-3,4)     | (0,0)
-        | (-3,4)     | (-10,0)
-        | (-3,4)     | (5.1,34.5)
-        | (-3,4)     | (-5,-12)
-        | (-3,4)     | (10,10)
-        | (5.1,34.5) | (0,0)
-        | (5.1,34.5) | (-10,0)
-        | (5.1,34.5) | (-3,4)
-        | (5.1,34.5) | (-5,-12)
-        | (5.1,34.5) | (10,10)
-        | (-5,-12)   | (0,0)
-        | (-5,-12)   | (-10,0)
-        | (-5,-12)   | (-3,4)
-        | (-5,-12)   | (5.1,34.5)
-        | (-5,-12)   | (10,10)
-        | (10,10)    | (0,0)
-        | (10,10)    | (-10,0)
-        | (10,10)    | (-3,4)
-        | (10,10)    | (5.1,34.5)
-        | (10,10)    | (-5,-12)
-(30 rows)
+ thirty |      point1       |      point2       
+--------+-------------------+-------------------
+        | (0,0)             | (-10,0)
+        | (0,0)             | (-3,4)
+        | (0,0)             | (5.1,34.5)
+        | (0,0)             | (-5,-12)
+        | (0,0)             | (1e+300,Infinity)
+        | (0,0)             | (NaN,NaN)
+        | (0,0)             | (10,10)
+        | (-10,0)           | (0,0)
+        | (-10,0)           | (-3,4)
+        | (-10,0)           | (5.1,34.5)
+        | (-10,0)           | (-5,-12)
+        | (-10,0)           | (1e-300,-1e-300)
+        | (-10,0)           | (1e+300,Infinity)
+        | (-10,0)           | (NaN,NaN)
+        | (-10,0)           | (10,10)
+        | (-3,4)            | (0,0)
+        | (-3,4)            | (-10,0)
+        | (-3,4)            | (5.1,34.5)
+        | (-3,4)            | (-5,-12)
+        | (-3,4)            | (1e-300,-1e-300)
+        | (-3,4)            | (1e+300,Infinity)
+        | (-3,4)            | (NaN,NaN)
+        | (-3,4)            | (10,10)
+        | (5.1,34.5)        | (0,0)
+        | (5.1,34.5)        | (-10,0)
+        | (5.1,34.5)        | (-3,4)
+        | (5.1,34.5)        | (-5,-12)
+        | (5.1,34.5)        | (1e-300,-1e-300)
+        | (5.1,34.5)        | (1e+300,Infinity)
+        | (5.1,34.5)        | (NaN,NaN)
+        | (5.1,34.5)        | (10,10)
+        | (-5,-12)          | (0,0)
+        | (-5,-12)          | (-10,0)
+        | (-5,-12)          | (-3,4)
+        | (-5,-12)          | (5.1,34.5)
+        | (-5,-12)          | (1e-300,-1e-300)
+        | (-5,-12)          | (1e+300,Infinity)
+        | (-5,-12)          | (NaN,NaN)
+        | (-5,-12)          | (10,10)
+        | (1e-300,-1e-300)  | (-10,0)
+        | (1e-300,-1e-300)  | (-3,4)
+        | (1e-300,-1e-300)  | (5.1,34.5)
+        | (1e-300,-1e-300)  | (-5,-12)
+        | (1e-300,-1e-300)  | (1e+300,Infinity)
+        | (1e-300,-1e-300)  | (NaN,NaN)
+        | (1e-300,-1e-300)  | (10,10)
+        | (1e+300,Infinity) | (0,0)
+        | (1e+300,Infinity) | (-10,0)
+        | (1e+300,Infinity) | (-3,4)
+        | (1e+300,Infinity) | (5.1,34.5)
+        | (1e+300,Infinity) | (-5,-12)
+        | (1e+300,Infinity) | (1e-300,-1e-300)
+        | (1e+300,Infinity) | (1e+300,Infinity)
+        | (1e+300,Infinity) | (NaN,NaN)
+        | (1e+300,Infinity) | (10,10)
+        | (NaN,NaN)         | (0,0)
+        | (NaN,NaN)         | (-10,0)
+        | (NaN,NaN)         | (-3,4)
+        | (NaN,NaN)         | (5.1,34.5)
+        | (NaN,NaN)         | (-5,-12)
+        | (NaN,NaN)         | (1e-300,-1e-300)
+        | (NaN,NaN)         | (1e+300,Infinity)
+        | (NaN,NaN)         | (NaN,NaN)
+        | (NaN,NaN)         | (10,10)
+        | (10,10)           | (0,0)
+        | (10,10)           | (-10,0)
+        | (10,10)           | (-3,4)
+        | (10,10)           | (5.1,34.5)
+        | (10,10)           | (-5,-12)
+        | (10,10)           | (1e-300,-1e-300)
+        | (10,10)           | (1e+300,Infinity)
+        | (10,10)           | (NaN,NaN)
+(72 rows)
 
 -- put distance result into output to allow sorting with GEQ optimizer - tgl 97/05/10
 SELECT '' AS fifteen, p1.f1 AS point1, p2.f1 AS point2, (p1.f1 <-> p2.f1) AS distance
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3 and p1.f1 << p2.f1
    ORDER BY distance, p1.f1[0], p2.f1[0];
- fifteen |   point1   |   point2   |     distance     
----------+------------+------------+------------------
-         | (-3,4)     | (0,0)      |                5
-         | (-10,0)    | (-3,4)     | 8.06225774829855
-         | (-10,0)    | (0,0)      |               10
-         | (-10,0)    | (-5,-12)   |               13
-         | (-5,-12)   | (0,0)      |               13
-         | (0,0)      | (10,10)    |  14.142135623731
-         | (-3,4)     | (10,10)    | 14.3178210632764
-         | (-5,-12)   | (-3,4)     | 16.1245154965971
-         | (-10,0)    | (10,10)    | 22.3606797749979
-         | (5.1,34.5) | (10,10)    | 24.9851956166046
-         | (-5,-12)   | (10,10)    | 26.6270539113887
-         | (-3,4)     | (5.1,34.5) | 31.5572495632937
-         | (0,0)      | (5.1,34.5) | 34.8749193547455
-         | (-10,0)    | (5.1,34.5) | 37.6597928831267
-         | (-5,-12)   | (5.1,34.5) | 47.5842410888311
-(15 rows)
+ fifteen |      point1       |      point2       |     distance     
+---------+-------------------+-------------------+------------------
+         | (-3,4)            | (0,0)             |                5
+         | (-3,4)            | (1e-300,-1e-300)  |                5
+         | (-10,0)           | (-3,4)            | 8.06225774829855
+         | (-10,0)           | (0,0)             |               10
+         | (-10,0)           | (1e-300,-1e-300)  |               10
+         | (-10,0)           | (-5,-12)          |               13
+         | (-5,-12)          | (0,0)             |               13
+         | (-5,-12)          | (1e-300,-1e-300)  |               13
+         | (0,0)             | (10,10)           |  14.142135623731
+         | (1e-300,-1e-300)  | (10,10)           |  14.142135623731
+         | (-3,4)            | (10,10)           | 14.3178210632764
+         | (-5,-12)          | (-3,4)            | 16.1245154965971
+         | (-10,0)           | (10,10)           | 22.3606797749979
+         | (5.1,34.5)        | (10,10)           | 24.9851956166046
+         | (-5,-12)          | (10,10)           | 26.6270539113887
+         | (-3,4)            | (5.1,34.5)        | 31.5572495632937
+         | (0,0)             | (5.1,34.5)        | 34.8749193547455
+         | (1e-300,-1e-300)  | (5.1,34.5)        | 34.8749193547455
+         | (-10,0)           | (5.1,34.5)        | 37.6597928831267
+         | (-5,-12)          | (5.1,34.5)        | 47.5842410888311
+         | (-10,0)           | (1e+300,Infinity) |         Infinity
+         | (-5,-12)          | (1e+300,Infinity) |         Infinity
+         | (-3,4)            | (1e+300,Infinity) |         Infinity
+         | (0,0)             | (1e+300,Infinity) |         Infinity
+         | (1e-300,-1e-300)  | (1e+300,Infinity) |         Infinity
+         | (5.1,34.5)        | (1e+300,Infinity) |         Infinity
+         | (10,10)           | (1e+300,Infinity) |         Infinity
+         | (-10,0)           | (NaN,NaN)         |              NaN
+         | (-5,-12)          | (NaN,NaN)         |              NaN
+         | (-3,4)            | (NaN,NaN)         |              NaN
+         | (0,0)             | (NaN,NaN)         |              NaN
+         | (1e-300,-1e-300)  | (NaN,NaN)         |              NaN
+         | (5.1,34.5)        | (NaN,NaN)         |              NaN
+         | (10,10)           | (NaN,NaN)         |              NaN
+         | (1e+300,Infinity) | (NaN,NaN)         |              NaN
+         | (NaN,NaN)         | (-10,0)           |              NaN
+         | (NaN,NaN)         | (-5,-12)          |              NaN
+         | (NaN,NaN)         | (-3,4)            |              NaN
+         | (NaN,NaN)         | (0,0)             |              NaN
+         | (NaN,NaN)         | (1e-300,-1e-300)  |              NaN
+         | (NaN,NaN)         | (5.1,34.5)        |              NaN
+         | (NaN,NaN)         | (10,10)           |              NaN
+         | (NaN,NaN)         | (1e+300,Infinity) |              NaN
+         | (NaN,NaN)         | (NaN,NaN)         |              NaN
+(44 rows)
 
 -- put distance result into output to allow sorting with GEQ optimizer - tgl 97/05/10
 SELECT '' AS three, p1.f1 AS point1, p2.f1 AS point2, (p1.f1 <-> p2.f1) AS distance
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3 and p1.f1 << p2.f1 and p1.f1 >^ p2.f1
    ORDER BY distance;
- three |   point1   |  point2  |     distance     
--------+------------+----------+------------------
-       | (-3,4)     | (0,0)    |                5
-       | (-10,0)    | (-5,-12) |               13
-       | (5.1,34.5) | (10,10)  | 24.9851956166046
-(3 rows)
+ three |      point1       |      point2       |     distance     
+-------+-------------------+-------------------+------------------
+       | (-3,4)            | (0,0)             |                5
+       | (-3,4)            | (1e-300,-1e-300)  |                5
+       | (-10,0)           | (-5,-12)          |               13
+       | (5.1,34.5)        | (10,10)           | 24.9851956166046
+       | (-5,-12)          | (NaN,NaN)         |              NaN
+       | (1e-300,-1e-300)  | (NaN,NaN)         |              NaN
+       | (1e+300,Infinity) | (NaN,NaN)         |              NaN
+       | (NaN,NaN)         | (0,0)             |              NaN
+       | (NaN,NaN)         | (-10,0)           |              NaN
+       | (NaN,NaN)         | (-3,4)            |              NaN
+       | (NaN,NaN)         | (5.1,34.5)        |              NaN
+       | (NaN,NaN)         | (-5,-12)          |              NaN
+       | (NaN,NaN)         | (1e-300,-1e-300)  |              NaN
+       | (NaN,NaN)         | (1e+300,Infinity) |              NaN
+       | (NaN,NaN)         | (NaN,NaN)         |              NaN
+       | (NaN,NaN)         | (10,10)           |              NaN
+       | (0,0)             | (NaN,NaN)         |              NaN
+       | (10,10)           | (NaN,NaN)         |              NaN
+       | (-10,0)           | (NaN,NaN)         |              NaN
+       | (-3,4)            | (NaN,NaN)         |              NaN
+       | (5.1,34.5)        | (NaN,NaN)         |              NaN
+(21 rows)
 
 -- Test that GiST indexes provide same behavior as sequential scan
 CREATE TEMP TABLE point_gist_tbl(f1 point);
 INSERT INTO point_gist_tbl SELECT '(0,0)' FROM generate_series(0,1000);
 CREATE INDEX point_gist_tbl_index ON point_gist_tbl USING gist (f1);
 INSERT INTO point_gist_tbl VALUES ('(0.0000009,0.0000009)');
 SET enable_seqscan TO true;
 SET enable_indexscan TO false;
 SET enable_bitmapscan TO false;
 SELECT COUNT(*) FROM point_gist_tbl WHERE f1 ~= '(0.0000009,0.0000009)'::point;
diff --git a/src/test/regress/expected/polygon.out b/src/test/regress/expected/polygon.out
index 2361274f9e..ba78604d76 100644
--- a/src/test/regress/expected/polygon.out
+++ b/src/test/regress/expected/polygon.out
@@ -1,18 +1,21 @@
 --
 -- POLYGON
 --
 -- polygon logic
 --
 CREATE TABLE POLYGON_TBL(f1 polygon);
 INSERT INTO POLYGON_TBL(f1) VALUES ('(2.0,0.0),(2.0,4.0),(0.0,0.0)');
 INSERT INTO POLYGON_TBL(f1) VALUES ('(3.0,1.0),(3.0,3.0),(1.0,0.0)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(3,4),(5,6),(7,8)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(7,8),(5,6),(3,4),(1,2)'); -- Reverse
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(7,8),(5,6),(3,-4)');
 -- degenerate polygons
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,0.0)');
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,1.0),(0.0,1.0)');
 -- bad polygon input strings
 INSERT INTO POLYGON_TBL(f1) VALUES ('0.0');
 ERROR:  invalid input syntax for type polygon: "0.0"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('0.0');
                                             ^
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0 0.0');
 ERROR:  invalid input syntax for type polygon: "(0.0 0.0"
@@ -24,206 +27,21 @@ LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2)');
                                             ^
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2,3');
 ERROR:  invalid input syntax for type polygon: "(0,1,2,3"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2,3');
                                             ^
 INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
 ERROR:  invalid input syntax for type polygon: "asdf"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
                                             ^
 SELECT '' AS four, * FROM POLYGON_TBL;
- four |         f1          
-------+---------------------
+ four |             f1             
+------+----------------------------
       | ((2,0),(2,4),(0,0))
       | ((3,1),(3,3),(1,0))
+      | ((1,2),(3,4),(5,6),(7,8))
+      | ((7,8),(5,6),(3,4),(1,2))
+      | ((1,2),(7,8),(5,6),(3,-4))
       | ((0,0))
       | ((0,1),(0,1))
-(4 rows)
-
--- overlap
-SELECT '' AS three, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 && '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- three |         f1          
--------+---------------------
-       | ((2,0),(2,4),(0,0))
-       | ((3,1),(3,3),(1,0))
-(2 rows)
-
--- left overlap
-SELECT '' AS four, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &< '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- four |         f1          
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
-
--- right overlap
-SELECT '' AS two, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- two |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- left of
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 << '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |      f1       
------+---------------
-     | ((0,0))
-     | ((0,1),(0,1))
-(2 rows)
-
--- right of
-SELECT '' AS zero, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 >> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- zero | f1 
-------+----
-(0 rows)
-
--- contained
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- same
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- contains
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
---
--- polygon logic
---
--- left of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- left overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
- true 
-------
- f
-(1 row)
-
--- right overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' &> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- right of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' >> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- contained in
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- contains
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((0,4),(6,4),(3,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
-SELECT '((1,1),(1,4),(5,4),(5,3),(2,3),(2,2),(5,2),(5,1))'::polygon @> '((3,2),(3,3),(4,3),(4,2))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((0,0),(0,3),(3,3),(3,0))'::polygon @> '((2,1),(2,2),(3,2),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
--- same
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' && polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
- true 
-------
- t
-(1 row)
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon && '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
-SELECT '((1,4),(1,1),(4,1),(4,2),(2,2),(2,4),(1,4))'::polygon && '((3,3),(4,3),(4,4),(3,4),(3,3))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((200,800),(800,800),(800,200),(200,200))' &&  '(1000,1000,0,0)'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
--- distance from a point
-SELECT	'(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
-	'(1,1)'::point <-> '((0,0),(2,2),(1,3))'::polygon as on_segment,
-	'(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;
- on_corner | on_segment | inside |   near_corner   | near_segment 
------------+------------+--------+-----------------+--------------
-         0 |          0 |      0 | 1.4142135623731 |          3.2
-(1 row)
+(7 rows)
 
diff --git a/src/test/regress/sql/box.sql b/src/test/regress/sql/box.sql
index 135ac108eb..6710fc90f5 100644
--- a/src/test/regress/sql/box.sql
+++ b/src/test/regress/sql/box.sql
@@ -18,29 +18,38 @@
 
 -- boxes are specified by two points, given by four floats x1,y1,x2,y2
 
 
 CREATE TABLE BOX_TBL (f1 box);
 
 INSERT INTO BOX_TBL (f1) VALUES ('(2.0,2.0,0.0,0.0)');
 
 INSERT INTO BOX_TBL (f1) VALUES ('(1.0,1.0,3.0,3.0)');
 
+INSERT INTO BOX_TBL (f1) VALUES ('((-8, 2), (-2, -10))');
+
+
 -- degenerate cases where the box is a line or a point
 -- note that lines and points boxes all have zero area
 INSERT INTO BOX_TBL (f1) VALUES ('(2.5, 2.5, 2.5,3.5)');
 
 INSERT INTO BOX_TBL (f1) VALUES ('(3.0, 3.0,3.0,3.0)');
 
 -- badly formatted box inputs
 INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
 
+INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+
 INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
 
 
 SELECT '' AS four, * FROM BOX_TBL;
 
 SELECT '' AS four, b.*, area(b.f1) as barea
    FROM BOX_TBL b;
 
 -- overlap
 SELECT '' AS three, b.f1
diff --git a/src/test/regress/sql/circle.sql b/src/test/regress/sql/circle.sql
index c0284b2b59..1a3ae6c84e 100644
--- a/src/test/regress/sql/circle.sql
+++ b/src/test/regress/sql/circle.sql
@@ -7,26 +7,32 @@ CREATE TABLE CIRCLE_TBL (f1 circle);
 INSERT INTO CIRCLE_TBL VALUES ('<(5,1),3>');
 
 INSERT INTO CIRCLE_TBL VALUES ('<(1,2),100>');
 
 INSERT INTO CIRCLE_TBL VALUES ('1,3,5');
 
 INSERT INTO CIRCLE_TBL VALUES ('((1,2),3)');
 
 INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10>');
 
-INSERT INTO CIRCLE_TBL VALUES ('<(100,1),115>');
+INSERT INTO CIRCLE_TBL VALUES (' < ( 100 , 1 ) , 115 > ');
+
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),0>');	-- Zero radius
 
 -- bad values
 
 INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
 
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+
 INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
 
 INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
 
 SELECT * FROM CIRCLE_TBL;
 
 SELECT '' AS six, center(f1) AS center
   FROM CIRCLE_TBL;
 
 SELECT '' AS six, radius(f1) AS radius
diff --git a/src/test/regress/sql/geometry.sql b/src/test/regress/sql/geometry.sql
index 1429ee772a..0c6d278f68 100644
--- a/src/test/regress/sql/geometry.sql
+++ b/src/test/regress/sql/geometry.sql
@@ -39,74 +39,420 @@ SELECT '' AS two, p1.f1
 -- "is vertical" function
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE isvertical(p1.f1, point '(5.1,34.5)');
 
 -- "is vertical" operator
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?| point '(5.1,34.5)';
 
+-- Slope
+SELECT p1.f1, p2.f1, slope(p1.f1, p2.f1)
+FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Add point
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1
+FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Subtract point
+SELECT p1.f1, p2.f1, p1.f1 - p2.f1
+FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Multiply with point
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1
+FROM POINT_TBL p1, POINT_TBL p2
+WHERE p1.f1[0] BETWEEN 1 AND 1000;
+
+-- Underflow error
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1
+FROM POINT_TBL p1, POINT_TBL p2
+WHERE p1.f1[0] < 1;
+
+-- Divide by point
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1
+FROM POINT_TBL p1, POINT_TBL p2
+WHERE p2.f1[0] BETWEEN 1 AND 1000;
+
+-- Overflow error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1
+FROM POINT_TBL p1, POINT_TBL p2
+WHERE p2.f1[0] > 1000;
+
+-- Division by 0 error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1
+FROM POINT_TBL p1, POINT_TBL p2
+WHERE p2.f1 ~= '(0,0)'::point;
+
+-- Distance to line
+SELECT p.f1, l.s, p.f1 <-> l.s
+FROM POINT_TBL p, LINE_TBL l;
+
+-- Distance to line segment
+SELECT p.f1, l.s, p.f1 <-> l.s
+FROM POINT_TBL p, LSEG_TBL l;
+
+-- Distance to box
+SELECT p.f1, b.f1, p.f1 <-> b.f1
+FROM POINT_TBL p, BOX_TBL b;
+
+-- Distance to path
+SELECT p.f1, p.f1, p.f1 <-> p1.f1
+FROM POINT_TBL p, PATH_TBL p1;
+
+-- Distance to polygon
+SELECT p.f1, p.f1, p.f1 <-> p1.f1
+FROM POINT_TBL p, POLYGON_TBL p1;
+
+-- Closest point to line
+SELECT p.f1, l.s, p.f1 ## l.s
+FROM POINT_TBL p, LINE_TBL l;
+
+-- Closest point to line segment
+SELECT p.f1, l.s, p.f1 ## l.s
+FROM POINT_TBL p, LSEG_TBL l;
+
+-- Closest point to box
+SELECT p.f1, b.f1, p.f1 ## b.f1
+FROM POINT_TBL p, BOX_TBL b;
+
+-- On line
+SELECT p.f1, l.s
+FROM POINT_TBL p, LINE_TBL l
+WHERE p.f1 <@ l.s;
+
+-- On line segment
+SELECT p.f1, l.s
+FROM POINT_TBL p, LSEG_TBL l
+WHERE p.f1 <@ l.s;
+
+-- On path
+SELECT p.f1, p1.f1
+FROM POINT_TBL p, PATH_TBL p1
+WHERE p.f1 <@ p1.f1;
+
+--
+-- Lines
+--
+
+-- Vertical
+SELECT s
+FROM LINE_TBL
+WHERE ?| s;
+
+-- Horizontal
+SELECT s
+FROM LINE_TBL
+WHERE ?- s;
+
+-- Same as line
+SELECT l1.s, l2.s
+FROM LINE_TBL l1, LINE_TBL l2
+WHERE l1.s = l2.s;
+
+-- Parallel to line
+SELECT l1.s, l2.s
+FROM LINE_TBL l1, LINE_TBL l2
+WHERE l1.s ?|| l2.s;
+
+-- Perpendicular to line
+SELECT l1.s, l2.s
+FROM LINE_TBL l1, LINE_TBL l2
+WHERE l1.s ?-| l2.s;
+
+-- Distance to line
+SELECT l1.s, l2.s, l1.s <-> l2.s
+FROM LINE_TBL l1, LINE_TBL l2;
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1
+FROM LINE_TBL l, BOX_TBL b;
+
+-- Intersect with line
+SELECT l1.s, l2.s
+FROM LINE_TBL l1, LINE_TBL l2
+WHERE l1.s ?# l2.s;
+
+-- Intersect with box
+SELECT l.s, b.f1
+FROM LINE_TBL l, BOX_TBL b
+WHERE l.s ?# b.f1;
+
+-- Intersection point with line
+SELECT l1.s, l2.s, l1.s # l2.s
+FROM LINE_TBL l1, LINE_TBL l2;
+
+-- Closest point to line segment
+SELECT l.s, l1.s, l.s ## l1.s
+FROM LINE_TBL l, LSEG_TBL l1;
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1
+FROM LINE_TBL l, BOX_TBL b;
+
 --
 -- Line segments
 --
 
 -- intersection
 SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
    FROM LSEG_TBL l, POINT_TBL p;
 
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
+-- Length
+SELECT s, @-@ s
+FROM LSEG_TBL;
+
+-- Vertical
+SELECT s
+FROM LSEG_TBL
+WHERE ?| s;
+
+-- Horizontal
+SELECT s
+FROM LSEG_TBL
+WHERE ?- s;
+
+-- Center
+SELECT s, @@ s
+FROM LSEG_TBL;
+
+-- To point
+SELECT s, s::point
+FROM LSEG_TBL;
+
+-- Has points less than line segment
+SELECT l1.s, l2.s
+FROM LSEG_TBL l1, LSEG_TBL l2
+WHERE l1.s < l2.s;
+
+-- Has points less than or equal to line segment
+SELECT l1.s, l2.s
+FROM LSEG_TBL l1, LSEG_TBL l2
+WHERE l1.s <= l2.s;
+
+-- Has points equal to line segment
+SELECT l1.s, l2.s
+FROM LSEG_TBL l1, LSEG_TBL l2
+WHERE l1.s = l2.s;
+
+-- Has points greater than or equal to line segment
+SELECT l1.s, l2.s
+FROM LSEG_TBL l1, LSEG_TBL l2
+WHERE l1.s >= l2.s;
+
+-- Has points greater than line segment
+SELECT l1.s, l2.s
+FROM LSEG_TBL l1, LSEG_TBL l2
+WHERE l1.s > l2.s;
+
+-- Has points not equal to line segment
+SELECT l1.s, l2.s
+FROM LSEG_TBL l1, LSEG_TBL l2
+WHERE l1.s != l2.s;
+
+-- Parallel with line segment
+SELECT l1.s, l2.s
+FROM LSEG_TBL l1, LSEG_TBL l2
+WHERE l1.s ?|| l2.s;
+
+-- Perpendicular with line segment
+SELECT l1.s, l2.s
+FROM LSEG_TBL l1, LSEG_TBL l2
+WHERE l1.s ?-| l2.s;
+
+-- Distance to line
+SELECT l.s, l1.s, l.s <-> l1.s
+FROM LSEG_TBL l, LINE_TBL l1;
+
+-- Distance to line segment
+SELECT l1.s, l2.s, l1.s <-> l2.s
+FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1
+FROM LSEG_TBL l, BOX_TBL b;
+
+-- Intersect with line segment
+SELECT l.s, l1.s
+FROM LSEG_TBL l, LINE_TBL l1
+WHERE l.s ?# l1.s;
+
+-- Intersect with box
+SELECT l.s, b.f1
+FROM LSEG_TBL l, BOX_TBL b
+WHERE l.s ?# b.f1;
+
+-- Intersection point with line segment
+SELECT l1.s, l2.s, l1.s # l2.s
+FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Closest point to line
+SELECT l.s, l1.s, l.s ## l1.s
+FROM LSEG_TBL l, LINE_TBL l1;
+
+-- Closest point to line segment
+SELECT l1.s, l2.s, l1.s ## l2.s
+FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1
+FROM LSEG_TBL l, BOX_TBL b;
+
+-- On line
+SELECT l.s, l1.s
+FROM LSEG_TBL l, LINE_TBL l1
+WHERE l.s <@ l1.s;
+
+-- On box
+SELECT l.s, b.f1
+FROM LSEG_TBL l, BOX_TBL b
+WHERE l.s <@ b.f1;
 
 --
 -- Boxes
 --
 
 SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
 
 -- translation
 SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
 
 SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
 
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
+-- Multiply with point
+SELECT b.f1, p.f1, b.f1 * p.f1
+FROM BOX_TBL b, POINT_TBL p
+WHERE p.f1[0] BETWEEN 1 AND 1000;
 
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
+-- Overflow error
+SELECT b.f1, p.f1, b.f1 * p.f1
+FROM BOX_TBL b, POINT_TBL p
+WHERE p.f1[0] > 1000;
 
+-- Divide by point
+SELECT b.f1, p.f1, b.f1 / p.f1
+FROM BOX_TBL b, POINT_TBL p
+WHERE p.f1[0] BETWEEN 1 AND 1000;
+
+-- To box
 SELECT f1::box
 	FROM POINT_TBL;
 
 SELECT bound_box(a.f1, b.f1)
 	FROM BOX_TBL a, BOX_TBL b;
 
+-- Below box
+SELECT b1.f1, b2.f1, b1.f1 <^ b2.f1
+FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Above box
+SELECT b1.f1, b2.f1, b1.f1 >^ b2.f1
+FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Intersection point with box
+SELECT b1.f1, b2.f1, b1.f1 # b2.f1
+FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Diagonal
+SELECT f1, diagonal(f1)
+FROM BOX_TBL;
+
+-- Distance to box
+SELECT b1.f1, b2.f1, b1.f1 <-> b2.f1
+FROM BOX_TBL b1, BOX_TBL b2;
+
 --
 -- Paths
 --
 
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
+-- Points
+SELECT f1, npoints(f1)
+FROM PATH_TBL;
 
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
+-- Area
+SELECT f1, area(f1)
+FROM PATH_TBL;
 
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
+-- Length
+SELECT f1, @-@ f1
+FROM PATH_TBL;
 
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
+-- Center
+SELECT f1, @@ f1
+FROM PATH_TBL;
+
+-- To polygon
+SELECT f1, f1::polygon
+FROM PATH_TBL
+WHERE isclosed(f1);
+
+-- Open path cannot be converted to polygon error
+SELECT f1, f1::polygon
+FROM PATH_TBL
+WHERE isopen(f1);
+
+-- Has points less than path
+SELECT p1.f1, p2.f1
+FROM PATH_TBL p1, PATH_TBL p2
+WHERE p1.f1 < p2.f1;
+
+-- Has points less than or equal to path
+SELECT p1.f1, p2.f1
+FROM PATH_TBL p1, PATH_TBL p2
+WHERE p1.f1 <= p2.f1;
+
+-- Has points equal to path
+SELECT p1.f1, p2.f1
+FROM PATH_TBL p1, PATH_TBL p2
+WHERE p1.f1 = p2.f1;
+
+-- Has points greater than or equal to path
+SELECT p1.f1, p2.f1
+FROM PATH_TBL p1, PATH_TBL p2
+WHERE p1.f1 >= p2.f1;
+
+-- Has points greater than path
+SELECT p1.f1, p2.f1
+FROM PATH_TBL p1, PATH_TBL p2
+WHERE p1.f1 > p2.f1;
+
+-- Add path
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1
+FROM PATH_TBL p1, PATH_TBL p2;
+
+-- Add point
+SELECT p.f1, p1.f1, p.f1 + p1.f1
+FROM PATH_TBL p, POINT_TBL p1;
+
+-- Subtract point
+SELECT p.f1, p1.f1, p.f1 - p1.f1
+FROM PATH_TBL p, POINT_TBL p1;
+
+-- Multiply with point
+SELECT p.f1, p1.f1, p.f1 * p1.f1
+FROM PATH_TBL p, POINT_TBL p1;
+
+-- Divide by point
+SELECT p.f1, p1.f1, p.f1 / p1.f1
+FROM PATH_TBL p, POINT_TBL p1
+WHERE p1.f1[0] BETWEEN 1 AND 1000;
+
+-- Division by 0 error
+SELECT p.f1, p1.f1, p.f1 / p1.f1
+FROM PATH_TBL p, POINT_TBL p1
+WHERE p1.f1 ~= '(0,0)'::point;
+
+-- Distance to path
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1
+FROM PATH_TBL p1, PATH_TBL p2;
 
 --
 -- Polygons
 --
 
 -- containment
 SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
    FROM POLYGON_TBL poly, POINT_TBL p;
 
 SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
@@ -118,36 +464,251 @@ SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
 SELECT '' AS four, polygon(f1)
    FROM BOX_TBL;
 
 SELECT '' AS four, polygon(f1)
    FROM PATH_TBL WHERE isclosed(f1);
 
 SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
    FROM PATH_TBL
    WHERE isopen(f1);
 
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
+-- To box
+SELECT f1, f1::box
+FROM POLYGON_TBL;
 
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
+-- To path
+SELECT f1, f1::path
+FROM POLYGON_TBL;
+
+-- Same as polygon
+SELECT p1.f1, p2.f1
+FROM POLYGON_TBL p1, POLYGON_TBL p2
+WHERE p1.f1 ~= p2.f1;
+
+-- Contained by polygon
+SELECT p1.f1, p2.f1
+FROM POLYGON_TBL p1, POLYGON_TBL p2
+WHERE p1.f1 <@ p2.f1;
+
+-- Contains polygon
+SELECT p1.f1, p2.f1
+FROM POLYGON_TBL p1, POLYGON_TBL p2
+WHERE p1.f1 @> p2.f1;
+
+-- Overlap with polygon
+SELECT p1.f1, p2.f1
+FROM POLYGON_TBL p1, POLYGON_TBL p2
+WHERE p1.f1 && p2.f1;
+
+-- Left of polygon
+SELECT p1.f1, p2.f1
+FROM POLYGON_TBL p1, POLYGON_TBL p2
+WHERE p1.f1 << p2.f1;
+
+-- Overlap of left of polygon
+SELECT p1.f1, p2.f1
+FROM POLYGON_TBL p1, POLYGON_TBL p2
+WHERE p1.f1 &< p2.f1;
+
+-- Right of polygon
+SELECT p1.f1, p2.f1
+FROM POLYGON_TBL p1, POLYGON_TBL p2
+WHERE p1.f1 >> p2.f1;
+
+-- Overlap of right of polygon
+SELECT p1.f1, p2.f1
+FROM POLYGON_TBL p1, POLYGON_TBL p2
+WHERE p1.f1 &> p2.f1;
+
+-- Below polygon
+SELECT p1.f1, p2.f1
+FROM POLYGON_TBL p1, POLYGON_TBL p2
+WHERE p1.f1 <<| p2.f1;
+
+-- Overlap or below polygon
+SELECT p1.f1, p2.f1
+FROM POLYGON_TBL p1, POLYGON_TBL p2
+WHERE p1.f1 &<| p2.f1;
+
+-- Above polygon
+SELECT p1.f1, p2.f1
+FROM POLYGON_TBL p1, POLYGON_TBL p2
+WHERE p1.f1 |>> p2.f1;
+
+-- Overlap or above polygon
+SELECT p1.f1, p2.f1
+FROM POLYGON_TBL p1, POLYGON_TBL p2
+WHERE p1.f1 |&> p2.f1;
+
+-- Distance to polygon
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1
+FROM POLYGON_TBL p1, POLYGON_TBL p2;
 
 --
 -- Circles
 --
 
 SELECT '' AS six, circle(f1, 50.0)
    FROM POINT_TBL;
 
 SELECT '' AS four, circle(f1)
    FROM BOX_TBL;
 
 SELECT '' AS two, circle(f1)
    FROM POLYGON_TBL
    WHERE (# f1) >= 3;
 
 SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
    FROM CIRCLE_TBL c1, POINT_TBL p1
    WHERE (p1.f1 <-> c1.f1) > 0
    ORDER BY distance, area(c1.f1), p1.f1[0];
+
+-- To polygon
+SELECT f1, f1::polygon
+FROM CIRCLE_TBL
+WHERE f1 >= '<(0,0),1>';
+
+-- To polygon with less points
+SELECT f1, polygon(8, f1)
+FROM CIRCLE_TBL
+WHERE f1 >= '<(0,0),1>';
+
+-- Too less points error
+SELECT f1, polygon(1, f1)
+FROM CIRCLE_TBL
+WHERE f1 >= '<(0,0),1>';
+
+-- Zero radius error
+SELECT f1, polygon(10, f1)
+FROM CIRCLE_TBL
+WHERE f1 < '<(0,0),1>';
+
+-- Same as circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 ~= c2.f1;
+
+-- Overlap with circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 && c2.f1;
+
+-- Overlap or left of circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 &< c2.f1;
+
+-- Left of circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 << c2.f1;
+
+-- Right of circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 >> c2.f1;
+
+-- Overlap or right of circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 &> c2.f1;
+
+-- Contained by circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 <@ c2.f1;
+
+-- Contain by circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 @> c2.f1;
+
+-- Below circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 <<| c2.f1;
+
+-- Above circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 |>> c2.f1;
+
+-- Overlap or below circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 &<| c2.f1;
+
+-- Overlap or above circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 |&> c2.f1;
+
+-- Area equal with circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 = c2.f1;
+
+-- Area not equal with circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 != c2.f1;
+
+-- Area less than circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 < c2.f1;
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 > c2.f1;
+
+-- Area less than or equal circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 <= c2.f1;
+
+-- Area greater than or equal circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 >= c2.f1;
+
+-- Area less than circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 < c2.f1;
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1
+FROM CIRCLE_TBL c1, CIRCLE_TBL c2
+WHERE c1.f1 < c2.f1;
+
+-- Add point
+SELECT c.f1, p.f1, c.f1 + p.f1
+FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Subtract point
+SELECT c.f1, p.f1, c.f1 - p.f1
+FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Multiply with point
+SELECT c.f1, p.f1, c.f1 * p.f1
+FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Divide by point
+SELECT c.f1, p.f1, c.f1 / p.f1
+FROM CIRCLE_TBL c, POINT_TBL p
+WHERE p.f1[0] BETWEEN 1 AND 1000;
+
+-- Overflow error
+SELECT c.f1, p.f1, c.f1 / p.f1
+FROM CIRCLE_TBL c, POINT_TBL p
+WHERE p.f1[0] > 1000;
+
+-- Division by 0 error
+SELECT c.f1, p.f1, c.f1 / p.f1
+FROM CIRCLE_TBL c, POINT_TBL p
+WHERE p.f1 ~= '(0,0)'::point;
+
+-- Distance to polygon
+SELECT c.f1, p.f1, c.f1 <-> p.f1
+FROM CIRCLE_TBL c, POLYGON_TBL p;
diff --git a/src/test/regress/sql/line.sql b/src/test/regress/sql/line.sql
index 94067b0cee..2b2b592ba0 100644
--- a/src/test/regress/sql/line.sql
+++ b/src/test/regress/sql/line.sql
@@ -1,87 +1,38 @@
 --
 -- LINE
 -- Infinite lines
 --
 
 --DROP TABLE LINE_TBL;
 CREATE TABLE LINE_TBL (s line);
 
-INSERT INTO LINE_TBL VALUES ('{1,-1,1}');
-INSERT INTO LINE_TBL VALUES ('(0,0),(6,6)');
+INSERT INTO LINE_TBL VALUES ('{0,-1,5}');	-- A == 0
+INSERT INTO LINE_TBL VALUES ('{1,0,5}');	-- B == 0
+INSERT INTO LINE_TBL VALUES ('{0,3,0}');	-- A == C == 0
+INSERT INTO LINE_TBL VALUES (' (0,0), (6,6)');
 INSERT INTO LINE_TBL VALUES ('10,-10 ,-5,-4');
 INSERT INTO LINE_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LINE_TBL VALUES ('(11,22,33,44)');
 
-INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
+INSERT INTO LINE_TBL VALUES (line(point '(1,0)', point '(1,0)'));
+
+INSERT INTO LINE_TBL VALUES ('{3,NaN,5}');
 
 -- horizontal
 INSERT INTO LINE_TBL VALUES ('[(1,3),(2,3)]');
 -- vertical
 INSERT INTO LINE_TBL VALUES ('[(3,1),(3,2)]');
 
 -- bad values for parser testing
+INSERT INTO LINE_TBL VALUES ('{}');
+INSERT INTO LINE_TBL VALUES ('{0');
+INSERT INTO LINE_TBL VALUES ('{0,0}');
+INSERT INTO LINE_TBL VALUES ('{0,0,1');
 INSERT INTO LINE_TBL VALUES ('{0,0,1}');
+INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
 INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
 INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
 INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
 INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
+INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
 
 select * from LINE_TBL;
-
-
--- functions and operators
-
-SELECT * FROM LINE_TBL WHERE (s <-> line '[(1,2),(3,4)]') < 10;
-
-SELECT * FROM LINE_TBL WHERE (point '(0.1,0.1)' <-> s) < 1;
-
-SELECT * FROM LINE_TBL WHERE (lseg '[(0.1,0.1),(0.2,0.2)]' <-> s) < 1;
-
-SELECT line '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
-SELECT lseg '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
-SELECT point '(-1,1)' <-> line '[(-3,0),(-4,0)]';
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(2,0),(0,2)]';  -- true
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(0,0),(1,0)]';  -- false
-
-SELECT line '[(0,0),(1,1)]' ?# box '(0,0,2,2)';  -- true
-SELECT line '[(3,0),(4,1)]' ?# box '(0,0,2,2)';  -- false
-
-SELECT point '(1,1)' <@ line '[(0,0),(2,2)]';  -- true
-SELECT point '(1,1)' <@ line '[(0,0),(1,0)]';  -- false
-
-SELECT point '(1,1)' @ line '[(0,0),(2,2)]';  -- true
-SELECT point '(1,1)' @ line '[(0,0),(1,0)]';  -- false
-
-SELECT lseg '[(1,1),(2,2)]' <@ line '[(0,0),(2,2)]';  -- true
-SELECT lseg '[(1,1),(2,1)]' <@ line '[(0,0),(1,0)]';  -- false
-
-SELECT lseg '[(1,1),(2,2)]' @ line '[(0,0),(2,2)]';  -- true
-SELECT lseg '[(1,1),(2,1)]' @ line '[(0,0),(1,0)]';  -- false
-
-SELECT point '(0,1)' ## line '[(0,0),(1,1)]';
-
-SELECT line '[(0,0),(1,1)]' ## lseg '[(1,0),(2,0)]';
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(2,1)]';  -- false
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(1,1)]';  -- true
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(2,1)]';
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(1,1)]';
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(2,1)]';  -- true
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(1,1)]';  -- false
-
-SELECT line '[(0,0),(1,0)]' ?-| line '[(0,0),(0,1)]';  -- true
-SELECT line '[(0,0),(1,1)]' ?-| line '[(1,0),(1,1)]';  -- false
-
-SELECT ?- line '[(0,0),(1,0)]';  -- true
-SELECT ?- line '[(0,0),(1,1)]';  -- false
-
-SELECT ?| line '[(0,0),(0,1)]';  -- true
-SELECT ?| line '[(0,0),(1,1)]';  -- false
-
-SELECT line(point '(1,2)', point '(3,4)');
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,5)]';  -- true
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,4)]';  -- false
diff --git a/src/test/regress/sql/lseg.sql b/src/test/regress/sql/lseg.sql
index 07c5a29e0a..4a152e2b6d 100644
--- a/src/test/regress/sql/lseg.sql
+++ b/src/test/regress/sql/lseg.sql
@@ -3,23 +3,21 @@
 -- Line segments
 --
 
 --DROP TABLE LSEG_TBL;
 CREATE TABLE LSEG_TBL (s lseg);
 
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('(0,0),(6,6)');
 INSERT INTO LSEG_TBL VALUES ('10,-10 ,-3,-4');
 INSERT INTO LSEG_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LSEG_TBL VALUES ('(11,22,33,44)');
+INSERT INTO LSEG_TBL VALUES (lseg(point(11, 22), point(33,44)));
+INSERT INTO LSEG_TBL VALUES ('[(-10,2),(-10,3)]');	-- vertical
+INSERT INTO LSEG_TBL VALUES ('[(0,-20),(30,-20)]');	-- horizontal
 
 -- bad values for parser testing
 INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
 INSERT INTO LSEG_TBL VALUES ('[1,2,3, 4');
 INSERT INTO LSEG_TBL VALUES ('[(,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)');
 
 select * from LSEG_TBL;
-
-SELECT * FROM LSEG_TBL WHERE s <= lseg '[(1,2),(3,4)]';
-
-SELECT * FROM LSEG_TBL WHERE (s <-> lseg '[(1,2),(3,4)]') < 10;
diff --git a/src/test/regress/sql/path.sql b/src/test/regress/sql/path.sql
index 7e69b539ad..318decf974 100644
--- a/src/test/regress/sql/path.sql
+++ b/src/test/regress/sql/path.sql
@@ -1,38 +1,44 @@
 --
 -- PATH
 --
 
 --DROP TABLE PATH_TBL;
 
 CREATE TABLE PATH_TBL (f1 path);
 
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)]');
 
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
+INSERT INTO PATH_TBL VALUES (' ( ( 1 , 2 ) , ( 3 , 4 ) ) ');
 
-INSERT INTO PATH_TBL VALUES ('[(0,0),(3,0),(4,5),(1,6)]');
+INSERT INTO PATH_TBL VALUES ('[ (0,0),(3,0),(4,5),(1,6) ]');
 
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
+INSERT INTO PATH_TBL VALUES ('((1,2) ,(3,4 ))');
 
-INSERT INTO PATH_TBL VALUES ('1,2 ,3,4');
+INSERT INTO PATH_TBL VALUES ('1,2 ,3,4 ');
 
-INSERT INTO PATH_TBL VALUES ('[1,2,3, 4]');
+INSERT INTO PATH_TBL VALUES (' [1,2,3, 4] ');
 
-INSERT INTO PATH_TBL VALUES ('[11,12,13,14]');
+INSERT INTO PATH_TBL VALUES ('((10,20))');	-- Only one point
 
-INSERT INTO PATH_TBL VALUES ('(11,12,13,14)');
+INSERT INTO PATH_TBL VALUES ('[ 11,12,13,14 ]');
+
+INSERT INTO PATH_TBL VALUES ('( 11,12,13,14) ');
 
 -- bad values for parser testing
+INSERT INTO PATH_TBL VALUES ('[]');
+
 INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
 
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
 
-SELECT f1 FROM PATH_TBL;
+INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+
+INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
 
 SELECT '' AS count, f1 AS open_path FROM PATH_TBL WHERE isopen(f1);
 
 SELECT '' AS count, f1 AS closed_path FROM PATH_TBL WHERE isclosed(f1);
 
 SELECT '' AS count, pclose(f1) AS closed_path FROM PATH_TBL;
 
 SELECT '' AS count, popen(f1) AS open_path FROM PATH_TBL;
diff --git a/src/test/regress/sql/point.sql b/src/test/regress/sql/point.sql
index 63a803a809..a209f3bfeb 100644
--- a/src/test/regress/sql/point.sql
+++ b/src/test/regress/sql/point.sql
@@ -7,29 +7,39 @@ CREATE TABLE POINT_TBL(f1 point);
 INSERT INTO POINT_TBL(f1) VALUES ('(0.0,0.0)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-10.0,0.0)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-3.0,4.0)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(5.1, 34.5)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-5.0,-12.0)');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(1e-300,-1e-300)');	-- To underflow
+
+INSERT INTO POINT_TBL(f1) VALUES ('(1e+300,Inf)');		-- To overflow
+
+INSERT INTO POINT_TBL(f1) VALUES (' ( Nan , NaN ) ');
+
 -- bad format points
 INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
 
 INSERT INTO POINT_TBL(f1) VALUES ('10.0,10.0');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');	-- Out of range
+
 
 SELECT '' AS six, * FROM POINT_TBL;
 
 -- left of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE p.f1 << '(0.0, 0.0)';
 
 -- right of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE '(0.0,0.0)' >> p.f1;
 
 -- above
diff --git a/src/test/regress/sql/polygon.sql b/src/test/regress/sql/polygon.sql
index 7ac8079465..93f222d6d6 100644
--- a/src/test/regress/sql/polygon.sql
+++ b/src/test/regress/sql/polygon.sql
@@ -4,115 +4,32 @@
 -- polygon logic
 --
 
 CREATE TABLE POLYGON_TBL(f1 polygon);
 
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(2.0,0.0),(2.0,4.0),(0.0,0.0)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(3.0,1.0),(3.0,3.0),(1.0,0.0)');
 
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(3,4),(5,6),(7,8)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(7,8),(5,6),(3,4),(1,2)'); -- Reverse
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(7,8),(5,6),(3,-4)');
+
 -- degenerate polygons
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,0.0)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,1.0),(0.0,1.0)');
 
 -- bad polygon input strings
 INSERT INTO POLYGON_TBL(f1) VALUES ('0.0');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0 0.0');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2,3');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
 
 
 SELECT '' AS four, * FROM POLYGON_TBL;
-
--- overlap
-SELECT '' AS three, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 && '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- left overlap
-SELECT '' AS four, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &< '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- right overlap
-SELECT '' AS two, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- left of
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 << '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- right of
-SELECT '' AS zero, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 >> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- contained
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- same
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- contains
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
---
--- polygon logic
---
--- left of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- left overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
-
--- right overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' &> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- right of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' >> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- contained in
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- contains
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "false";
-
-SELECT '((0,4),(6,4),(3,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
-
-SELECT '((1,1),(1,4),(5,4),(5,3),(2,3),(2,2),(5,2),(5,1))'::polygon @> '((3,2),(3,3),(4,3),(4,2))'::polygon AS "false";
-
-SELECT '((0,0),(0,3),(3,3),(3,0))'::polygon @> '((2,1),(2,2),(3,2),(3,1))'::polygon AS "true";
-
--- same
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' && polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon && '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
-
-SELECT '((1,4),(1,1),(4,1),(4,2),(2,2),(2,4),(1,4))'::polygon && '((3,3),(4,3),(4,4),(3,4),(3,3))'::polygon AS "false";
-SELECT '((200,800),(800,800),(800,200),(200,200))' &&  '(1000,1000,0,0)'::polygon AS "true";
-
--- distance from a point
-SELECT	'(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
-	'(1,1)'::point <-> '((0,0),(2,2),(1,3))'::polygon as on_segment,
-	'(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;
-- 
2.13.6 (Apple Git-96)

#29Kyotaro HORIGUCHI
horiguchi.kyotaro@lab.ntt.co.jp
In reply to: Emre Hasegeli (#28)
Re: [PATCH] Improve geometric types

Hello, thanks for the new patch.

0004 failed to be applied on the underneath patches.

At Sun, 5 Nov 2017 15:54:19 +0100, Emre Hasegeli <emre@hasegeli.com> wrote in <CAE2gYzzngpYgrQbJ-2TjzZ+MZBa0D0Xzj8tjjJLv6C3CPARMGw@mail.gmail.com>

I am not sure how useful NaNs are in geometric types context, but we
allow them, so inconsistent hypot() would be a problem. I will change
my patches to keep pg_hypot().

New versions of the patches are attached with 2 additional ones. The
new versions leave pg_hypot() in place. One of the new patches
improves the test coverage. The line coverage of geo_ops.c increases
from 55% to 81%. The other one fixes -0 values to 0 on float
operators. I am not sure about performance implication of this, so
kept it separate. It may be a better idea to check this only on the
platforms that has tendency to produce -0.

While working on the tests, I found some unreachable code and removed
it. I also found that lseg ## lseg operator returning wrong results.
It is defined as "closest point to first segment on the second
segment", but:

# select '[(1,2),(3,4)]'::lseg ## '[(0,0),(6,6)]'::lseg;
?column?
----------
(1,2)
(1 row)

I appended the fix to the patches. This is also effecting lseg ## box operator.

Mmm.. It returns (1.5, 1.5) with the 0004 patch. It is surely a
point on the second operand but I'm not sure it's right that the
operator returns a specific point for two parallel segments.

I also changed recently band-aided point ## lseg operator to return
the point instead of NULL when it cannot find the correct result to
avoid the operators depending on this one to crash.

I'd like to put comments on 0001 and 0004 only now:

- Adding [LR]DELIM_L looks good but they should be described in
the comment just above.

- Renaming float8_slope to slope seems no problem.

- I'm not sure the change of box_construct is good but currently
all callers fits the new interface (giving two points, not
four coordinates).

- close_lseg seems forgetting the case where the two given
segments are crossing (and parallel). For example,

select '(-8,-8),(1,1)'::lseg ## '(-10,0),(2,0)'::lseg;

is expected to return (0,0), which is the crossing point of
the two segments, but it returns (1,0) (and returned (1,1)
before the patch), which is the point on the l2 closest to the
closer end of l1 to l2.

As mentioned above, it is difficult to dicide what is the
proper result for parallel segments. I suppose that the
following operation should return an invalid value as a point.

select '(-1,0),(1,0)'::lseg ## '(-1,1),(1,1)'::lseg;

close_lseg does the following operations in the else case of
'if (float8_...)'. If i'm not missing something, the result of
the following operation is always the closer end of l2. In
other words it seems a waste of cycles.

| point = DirectFunctionCall2(close_ps,
| PointPGetDatum(&l2->p[closer_end2]),
| LsegPGetDatum(l1));
| return DirectFunctionCall2(close_ps, point, LsegPGetDatum(l2));

- make_bound_box operates directly on the poly->boundbox. I'm
afraid that such coding hinders compiers from using registers.

This is a bit apart from this patch, it would be better if we
could eliminate internal calls using DirectFunctionCall.

reagrds,

--
Kyotaro Horiguchi
NTT Open Source Software Center

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

#30Kyotaro HORIGUCHI
horiguchi.kyotaro@lab.ntt.co.jp
In reply to: Kyotaro HORIGUCHI (#29)
Re: [PATCH] Improve geometric types

Hello,

I'd like to put comments on 0001 and 0004 only now:

...

I don't have a comment on 0002.

About 0003:

@@ -4487,21 +4486,21 @@ circle_in(PG_FUNCTION_ARGS)
...
circle->radius = single_decode(s, &s, "circle", str);
- if (circle->radius < 0)
+ if (float8_lt(circle->radius, 0.0))
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),

flost8_lt and its family functions are provided to unify the
sorting order including NaN. NaN is not rejected by the usage of
float8_lt in the case but it is what the function is expected to
be used for. If we wanted to check if it is positive, it
unexpectedly throws an exception. (I suppose that NaNs should be
silently ignored rather than stopping a query by throwng an
exception.)

Addition to that I don't think it proper that applying EPSILON(!)
there. It should be strictly compared regardless whether EPSION
is considered or not.

Similary, circle_overlap for example, float8_le is used to
compare the distance and the summed radius.

NaN causes a problem in another place.

PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
float8_pl(circle1->radius, circle2->radius)));

If the distance was NaN and the summed radius is not, the
function returns true. I think that a reasonable behavior is that
an object containing NaN cannot make any meaningful relationship
with other objects as floating number itself behave so. (Any
comparison other than != with NaN returns always false)

Just using another series of comparison functions that return
false for NaN-containing comparison is not a solution since the
meaning of the returned false differs by context, just same as
the first problem above. For exameple, the fictious functions
below,

| bool circle_overlaps()
| ret = FPle(distance, radius_sum);

This gives correct results, but

| bool circle_not_overlaps()
| ret = FPgt(distance, radius_sum);

This gives a wrong result for NaN-containing objects.

Perhaps it is enough to explicitly define behaviors for NaN
before comparison.

circle_overlap()

distance = point_dt(....);
radius_sum = float8_pl(...);

/* NaN-containing objects doesn't overlap any other objects */
if (isnan(distance) || isnan(radius_sum))
PG_RETURN_BOOL(false);

/* NaN ordering of FPle() doesn't get into mischief here */
return PG_RETURN_BOOL(FPle(distance, radius_sum));

(End Of the Comment to 0003)

regards,

--
Kyotaro Horiguchi
NTT Open Source Software Center

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

#31Emre Hasegeli
emre@hasegeli.com
In reply to: Kyotaro HORIGUCHI (#29)
Re: [PATCH] Improve geometric types

This is also effecting lseg ## box operator.

Mmm.. It returns (1.5, 1.5) with the 0004 patch. It is surely a
point on the second operand but I'm not sure it's right that the
operator returns a specific point for two parallel segments.

I am changing it to return NULL, when they are parallel.

I'd like to put comments on 0001 and 0004 only now:

- Adding [LR]DELIM_L looks good but they should be described in
the comment just above.

I will mention it on the new version.

- I'm not sure the change of box_construct is good but currently
all callers fits the new interface (giving two points, not
four coordinates).

I tried to make things more consistent. The other constructors takes points.

- close_lseg seems forgetting the case where the two given
segments are crossing (and parallel).

I am re-implementing it covering those cases.

- make_bound_box operates directly on the poly->boundbox. I'm
afraid that such coding hinders compiers from using registers.

I am changing it back.

This is a bit apart from this patch, it would be better if we
could eliminate internal calls using DirectFunctionCall.

We don't seem to be able to fix all issues without doing that. I will
incorporate the change.

Thank you for your review. I will address your other email before
posting new versions.

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

#32Emre Hasegeli
emre@hasegeli.com
In reply to: Kyotaro HORIGUCHI (#18)
Re: [HACKERS] [PATCH] Improve geometric types

dist_pl is changed to take the smaller distance of both ends of
the segment. It seems absorbing error, so it might be better
taking the mean of the two distances. If you have a firm reason
for the change, it is better to be written there, or it might be
better left alone.

I am sorry for not paying enough attention to this before. The
distance functions are meant to return the minimum distance. Getting
the maximum is just wrong in here. Can you think of any particular
error it would absorb? Otherwise I will put this change back to the
patch for fixes.

#33Emre Hasegeli
emre@hasegeli.com
In reply to: Kyotaro HORIGUCHI (#30)
6 attachment(s)
Re: [HACKERS] [PATCH] Improve geometric types

flost8_lt and its family functions are provided to unify the
sorting order including NaN. NaN is not rejected by the usage of
float8_lt in the case but it is what the function is expected to
be used for. If we wanted to check if it is positive, it
unexpectedly throws an exception. (I suppose that NaNs should be
silently ignored rather than stopping a query by throwng an
exception.)

It would at least be dump-and-restore hazard if we don't let them in.
The new version allows NaNs.

This gives a wrong result for NaN-containing objects.

I removed the NaN aware comparisons from FP macros, and carefully
reviewed the places that needs to be NaN aware.

I am sorry that it took so long for me to post the new versions. The
more I get into this the more problems I find. The new versions
include non-trivial changes. I would be glad if you can look into
them.

Attachments:

0001-geo-funcs-v06.patchapplication/octet-stream; name=0001-geo-funcs-v06.patchDownload
From d7c459b2e841a390983d0c461fd50562b03fe184 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 27 May 2017 11:27:18 -0400
Subject: [PATCH 1/6] geo-funcs-v06

Refactor geometric functions and operators code

Most of the geometric types were not using functions of each other's.
I believe the reason behind this is simpler types line point and line
being developed after more complicated ones.  This patch reduces
duplicate code and makes functions of different datatypes more
compatible.  The changes can be summarised as:

* Eliminate SQL level function calls
* Re-use more functions to implement others
* Unify internal function names and signatures
* Remove private functions from geo_decls.h
* Replace not-possible checks with Assert()
* Add comments to describe some functions
* Remove some unreachable code
* Define delimiter symbols of line datatype like the other ones
* Remove debugging print()s from the refactored functions

This commits aims to not cause any user visible changes, but it is
almost impossible to stay completely bug-compatible with the old code.
---
 src/backend/utils/adt/geo_ops.c | 1836 ++++++++++++++++++---------------------
 src/include/utils/geo_decls.h   |    3 -
 src/test/regress/regress.c      |   11 +-
 3 files changed, 846 insertions(+), 1004 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 9dbe5db2b2..46ac24e740 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -31,76 +31,102 @@
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
+/* Routines for two-dimensional points */
+static inline void point_construct(Point *result, float8 x, float8 y);
+static inline void point_add_point(Point *result, Point *pt1, Point *pt2);
+static inline void point_sub_point(Point *result, Point *pt1, Point *pt2);
+static inline void point_mul_point(Point *result, Point *pt1, Point *pt2);
+static inline void point_div_point(Point *result, Point *pt1, Point *pt2);
+static inline bool point_eq_point(Point *pt1, Point *pt2);
+static float8 point_dt(Point *pt1, Point *pt2);
+static inline float8 slope(float8 x1, float8 x2, float8 y1, float8 y2);
 static int	point_inside(Point *p, int npts, Point *plist);
+
+/* Routines for two-dimensional lines */
+static inline void line_construct_pm(LINE *result, Point *pt, float8 m);
+static inline void line_construct_pts(LINE *result, Point *pt1, Point *pt2);
+static bool	line_interpt_line(Point *result, LINE *l1, LINE *l2);
+static bool line_contain_point(LINE *line, Point *point);
+static float8 line_closept_point(Point *result, LINE *line, Point *pt);
+
+/* Routines for two-dimensional line segments */
+static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
+static bool	lseg_interpt_line(Point *result, LSEG *lseg, LINE *line);
+static bool	lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2);
 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	lseg_contain_point(LSEG *lseg, Point *point);
+static float8 lseg_closept_point(Point *result, LSEG *lseg, Point *pt);
+static float8 lseg_closept_line(Point *result, LSEG *lseg, LINE *line);
+static float8 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2);
+
+/* Routines for two-dimensional boxes */
+static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
+static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
+static double box_ar(BOX *box);
 static double box_ht(BOX *box);
 static double box_wd(BOX *box);
+static bool box_contain_point(BOX *box, Point *point);
+static bool box_contain_box(BOX *box1, BOX *box2);
+static bool box_contain_lseg(BOX *box, LSEG *lseg);
+static bool box_interpt_lseg(Point *result, BOX *box, LSEG *lseg);
+static float8 box_closept_point(Point *result, BOX *box, Point *point);
+static float8 box_closept_lseg(Point *result, BOX *box, LSEG *lseg);
+
+/* Routines for two-dimensional circles */
 static double circle_ar(CIRCLE *circle);
-static CIRCLE *circle_copy(CIRCLE *circle);
-static LINE *line_construct_pm(Point *pt, double m);
-static void line_construct_pts(LINE *line, Point *pt1, Point *pt2);
-static bool lseg_intersect_internal(LSEG *l1, LSEG *l2);
-static double lseg_dt(LSEG *l1, LSEG *l2);
-static bool on_ps_internal(Point *pt, LSEG *lseg);
+
+/* Routines for two-dimensional polygons */
 static void make_bound_box(POLYGON *poly);
+static void poly_to_circle(CIRCLE *result, POLYGON *poly);
+static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
+static bool poly_contain_poly(POLYGON *polya, POLYGON *polyb);
 static bool plist_same(int npts, Point *p1, Point *p2);
-static Point *point_construct(double x, double y);
-static Point *point_copy(Point *pt);
+static float8 dist_ppoly_internal(Point *pt, POLYGON *poly);
+
+/* Routines for encoding and decoding */
 static double single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
 static void pair_decode(char *str, double *x, double *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
 static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
-static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
-static double box_ar(BOX *box);
-static void box_cn(Point *center, BOX *box);
-static Point *interpt_sl(LSEG *lseg, LINE *line);
-static bool has_interpt_sl(LSEG *lseg, LINE *line);
-static double dist_pl_internal(Point *pt, LINE *line);
-static double dist_ps_internal(Point *pt, LSEG *lseg);
-static Point *line_interpt_internal(LINE *l1, LINE *l2);
-static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
-static Point *lseg_interpt_internal(LSEG *l1, LSEG *l2);
-static double dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 
 /*
  * Delimiters for input and output strings.
  * LDELIM, RDELIM, and DELIM are left, right, and separator delimiters, respectively.
  * LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints.
  */
 
 #define LDELIM			'('
 #define RDELIM			')'
 #define DELIM			','
 #define LDELIM_EP		'['
 #define RDELIM_EP		']'
 #define LDELIM_C		'<'
 #define RDELIM_C		'>'
+#define LDELIM_L		'{'
+#define RDELIM_L		'}'
 
 
 /*
  * Geometric data types are composed of points.
  * This code tries to support a common format throughout the data types,
  *	to allow for more predictable usage and data type conversion.
  * The fundamental unit is the point. Other units are line segments,
  *	open paths, boxes, closed paths, and polygons (which should be considered
  *	non-intersecting closed paths).
  *
@@ -230,26 +256,23 @@ path_decode(char *str, bool opentype, int npts, Point *p,
 	}
 
 	for (i = 0; i < npts; i++)
 	{
 		pair_decode(str, &(p->x), &(p->y), &str, type_name, orig_string);
 		if (*str == DELIM)
 			str++;
 		p++;
 	}
 
-	while (isspace((unsigned char) *str))
-		str++;
 	while (depth > 0)
 	{
-		if ((*str == RDELIM)
-			|| ((*str == RDELIM_EP) && (*isopen) && (depth == 1)))
+		if (*str == RDELIM || (*str == RDELIM_EP && *isopen && depth == 1))
 		{
 			depth--;
 			str++;
 			while (isspace((unsigned char) *str))
 				str++;
 		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
@@ -434,89 +457,61 @@ box_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, box->high.x);
 	pq_sendfloat8(&buf, box->high.y);
 	pq_sendfloat8(&buf, box->low.x);
 	pq_sendfloat8(&buf, box->low.y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*		box_construct	-		fill in a new box.
  */
-static BOX *
-box_construct(double x1, double x2, double y1, double y2)
+static inline void
+box_construct(BOX *result, Point *pt1, Point *pt2)
 {
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	return box_fill(result, x1, x2, y1, y2);
-}
-
-
-/*		box_fill		-		fill in a given box struct
- */
-static BOX *
-box_fill(BOX *result, double x1, double x2, double y1, double y2)
-{
-	if (x1 > x2)
+	if (pt1->x > pt2->x)
 	{
-		result->high.x = x1;
-		result->low.x = x2;
+		result->high.x = pt1->x;
+		result->low.x = pt2->x;
 	}
 	else
 	{
-		result->high.x = x2;
-		result->low.x = x1;
+		result->high.x = pt2->x;
+		result->low.x = pt1->x;
 	}
-	if (y1 > y2)
+	if (pt1->y > pt2->y)
 	{
-		result->high.y = y1;
-		result->low.y = y2;
+		result->high.y = pt1->y;
+		result->low.y = pt2->y;
 	}
 	else
 	{
-		result->high.y = y2;
-		result->low.y = y1;
+		result->high.y = pt2->y;
+		result->low.y = pt1->y;
 	}
-
-	return result;
-}
-
-
-/*		box_copy		-		copy a box
- */
-static BOX *
-box_copy(BOX *box)
-{
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	memcpy((char *) result, (char *) box, sizeof(BOX));
-
-	return result;
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for BOXes.
  *		<, >, <=, >=, and == are based on box area.
  *---------------------------------------------------------*/
 
 /*		box_same		-		are two boxes identical?
  */
 Datum
 box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPeq(box1->high.x, box2->high.x) &&
-				   FPeq(box1->low.x, box2->low.x) &&
-				   FPeq(box1->high.y, box2->high.y) &&
-				   FPeq(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(point_eq_point(&box1->high, &box2->high) &&
+				   point_eq_point(&box1->low, &box2->low));
 }
 
 /*		box_overlap		-		does box1 overlap box2?
  */
 Datum
 box_overlap(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
@@ -631,38 +626,44 @@ box_overabove(PG_FUNCTION_ARGS)
 }
 
 /*		box_contained	-		is box1 contained by box2?
  */
 Datum
 box_contained(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPle(box1->high.x, box2->high.x) &&
-				   FPge(box1->low.x, box2->low.x) &&
-				   FPle(box1->high.y, box2->high.y) &&
-				   FPge(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(box_contain_box(box2, box1));
 }
 
 /*		box_contain		-		does box1 contain box2?
  */
 Datum
 box_contain(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPge(box1->high.x, box2->high.x) &&
-				   FPle(box1->low.x, box2->low.x) &&
-				   FPge(box1->high.y, box2->high.y) &&
-				   FPle(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(box_contain_box(box1, box2));
+}
+
+/*
+ * Check whether the box is in the box or on its border
+ */
+static bool
+box_contain_box(BOX *box1, BOX *box2)
+{
+	return FPge(box1->high.x, box2->high.x) &&
+		   FPle(box1->low.x, box2->low.x) &&
+		   FPge(box1->high.y, box2->high.y) &&
+		   FPle(box1->low.y, box2->low.y);
 }
 
 
 /*		box_positionop	-
  *				is box1 entirely {above,below} box2?
  *
  * box_below_eq and box_above_eq are obsolete versions that (probably
  * erroneously) accept the equal-boundaries case.  Since these are not
  * in sync with the box_left and box_right code, they are deprecated and
  * not supported in the PG 8.1 rtree operator class extension.
@@ -751,51 +752,51 @@ box_area(PG_FUNCTION_ARGS)
 
 
 /*		box_width		-		returns the width of the box
  *								  (horizontal magnitude).
  */
 Datum
 box_width(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.x - box->low.x);
+	PG_RETURN_FLOAT8(box_wd(box));
 }
 
 
 /*		box_height		-		returns the height of the box
  *								  (vertical magnitude).
  */
 Datum
 box_height(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.y - box->low.y);
+	PG_RETURN_FLOAT8(box_ht(box));
 }
 
 
 /*		box_distance	-		returns the distance between the
  *								  center points of two boxes.
  */
 Datum
 box_distance(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 	Point		a,
 				b;
 
 	box_cn(&a, box1);
 	box_cn(&b, box2);
 
-	PG_RETURN_FLOAT8(HYPOT(a.x - b.x, a.y - b.y));
+	PG_RETURN_FLOAT8(point_dt(&a, &b));
 }
 
 
 /*		box_center		-		returns the center point of the box.
  */
 Datum
 box_center(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *result = (Point *) palloc(sizeof(Point));
@@ -899,76 +900,77 @@ static bool
 line_decode(char *s, const char *str, LINE *line)
 {
 	/* s was already advanced over leading '{' */
 	line->A = single_decode(s, &s, "line", str);
 	if (*s++ != DELIM)
 		return false;
 	line->B = single_decode(s, &s, "line", str);
 	if (*s++ != DELIM)
 		return false;
 	line->C = single_decode(s, &s, "line", str);
-	if (*s++ != '}')
+	if (*s++ != RDELIM_L)
 		return false;
 	while (isspace((unsigned char) *s))
 		s++;
 	if (*s != '\0')
 		return false;
 	return true;
 }
 
 Datum
 line_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	LINE	   *line = (LINE *) palloc(sizeof(LINE));
 	LSEG		lseg;
 	bool		isopen;
 	char	   *s;
 
 	s = str;
 	while (isspace((unsigned char) *s))
 		s++;
-	if (*s == '{')
+	if (*s == LDELIM_L)
 	{
 		if (!line_decode(s + 1, str, line))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
 							"line", str)));
 		if (FPzero(line->A) && FPzero(line->B))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: A and B cannot both be zero")));
 	}
 	else
 	{
-		path_decode(s, true, 2, &(lseg.p[0]), &isopen, NULL, "line", str);
-		if (FPeq(lseg.p[0].x, lseg.p[1].x) && FPeq(lseg.p[0].y, lseg.p[1].y))
+		path_decode(s, true, 2, &lseg.p[0], &isopen, NULL, "line", str);
+		if (point_eq_point(&lseg.p[0], &lseg.p[1]))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: must be two distinct points")));
 		line_construct_pts(line, &lseg.p[0], &lseg.p[1]);
 	}
 
 	PG_RETURN_LINE_P(line);
 }
 
 
 Datum
 line_out(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	char	   *astr = float8out_internal(line->A);
 	char	   *bstr = float8out_internal(line->B);
 	char	   *cstr = float8out_internal(line->C);
 
-	PG_RETURN_CSTRING(psprintf("{%s,%s,%s}", astr, bstr, cstr));
+	PG_RETURN_CSTRING(psprintf("%c%s%c%s%c%s%c", LDELIM_L, astr, DELIM, bstr,
+							   DELIM, cstr, RDELIM_L));
 }
 
 /*
  *		line_recv			- converts external binary format to line
  */
 Datum
 line_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LINE	   *line;
@@ -997,86 +999,59 @@ line_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, line->C);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*----------------------------------------------------------
  *	Conversion routines from one line formula to internal.
  *		Internal form:	Ax+By+C=0
  *---------------------------------------------------------*/
 
-/* line_construct_pm()
- * point-slope
+/*
+ * Fill already-allocated LINE struct from the point and the slope
  */
-static LINE *
-line_construct_pm(Point *pt, double m)
+static inline void
+line_construct_pm(LINE *result, Point *pt, float8 m)
 {
-	LINE	   *result = (LINE *) palloc(sizeof(LINE));
-
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
 		result->A = -1;
 		result->B = 0;
 		result->C = pt->x;
 	}
+	else if (m == 0.0)
+	{
+		/* horizontal - use "y = C" */
+		result->A = 0.0;
+		result->B = -1.0;
+		result->C = pt->y;
+	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
 		result->C = pt->y - m * pt->x;
 	}
-
-	return result;
 }
 
 /*
  * Fill already-allocated LINE struct from two points on the line
  */
-static void
-line_construct_pts(LINE *line, Point *pt1, Point *pt2)
+static inline void
+line_construct_pts(LINE *result, Point *pt1, Point *pt2)
 {
-	if (FPeq(pt1->x, pt2->x))
-	{							/* vertical */
-		/* use "x = C" */
-		line->A = -1;
-		line->B = 0;
-		line->C = pt1->x;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is vertical\n");
-#endif
-	}
-	else if (FPeq(pt1->y, pt2->y))
-	{							/* horizontal */
-		/* use "y = C" */
-		line->A = 0;
-		line->B = -1;
-		line->C = pt1->y;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is horizontal\n");
-#endif
-	}
-	else
-	{
-		/* use "mx - y + yinter = 0" */
-		line->A = (pt2->y - pt1->y) / (pt2->x - pt1->x);
-		line->B = -1.0;
-		line->C = pt1->y - line->A * pt1->x;
-		/* on some platforms, the preceding expression tends to produce -0 */
-		if (line->C == 0.0)
-			line->C = 0.0;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is neither vertical nor horizontal (diffs x=%.*g, y=%.*g\n",
-			   DBL_DIG, (pt2->x - pt1->x), DBL_DIG, (pt2->y - pt1->y));
-#endif
-	}
+	float8		m;
+
+	m = slope(pt1->x, pt2->x, pt1->y, pt2->y);
+	line_construct_pm(result, pt1, m);
 }
 
 /* line_construct_pp()
  * two points
  */
 Datum
 line_construct_pp(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
@@ -1090,23 +1065,21 @@ line_construct_pp(PG_FUNCTION_ARGS)
 /*----------------------------------------------------------
  *	Relative position routines.
  *---------------------------------------------------------*/
 
 Datum
 line_intersect(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(!DatumGetBool(DirectFunctionCall2(line_parallel,
-													 LinePGetDatum(l1),
-													 LinePGetDatum(l2))));
+	PG_RETURN_BOOL(line_interpt_line(NULL, l1, l2));
 }
 
 Datum
 line_parallel(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->B));
@@ -1172,96 +1145,90 @@ line_eq(PG_FUNCTION_ARGS)
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
-	Point	   *tmp;
+	Point		tmp;
 
-	if (!DatumGetBool(DirectFunctionCall2(line_parallel,
-										  LinePGetDatum(l1),
-										  LinePGetDatum(l2))))
+	if (line_interpt_line(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
 		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
-	tmp = point_construct(0.0, l1->C);
-	result = dist_pl_internal(tmp, l2);
+	point_construct(&tmp, 0.0, l1->C);
+	result = line_closept_point(NULL, l2, &tmp);
 	PG_RETURN_FLOAT8(result);
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
-	result = line_interpt_internal(l1, l2);
+	result = (Point *) palloc(sizeof(Point));
 
-	if (result == NULL)
+	if (!line_interpt_line(result, l1, l2))
 		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
 
 /*
  * Internal version of line_interpt
  *
- * returns a NULL pointer if no intersection point
+ * This returns true if two lines intersect (they do, if they are not
+ * parallel), false if they do not.  This also sets the intersection point
+ * to *result, if it is not NULL.
+ *
+ * NOTE If the lines are identical then we will find they are parallel
+ * and report "no intersection".  This is a little weird, but since
+ * there's no *unique* intersection, maybe it's appropriate behavior.
  */
-static Point *
-line_interpt_internal(LINE *l1, LINE *l2)
+static bool
+line_interpt_line(Point *result, LINE *l1, LINE *l2)
 {
-	Point	   *result;
 	double		x,
 				y;
 
-	/*
-	 * NOTE: if the lines are identical then we will find they are parallel
-	 * and report "no intersection".  This is a little weird, but since
-	 * there's no *unique* intersection, maybe it's appropriate behavior.
-	 */
-	if (DatumGetBool(DirectFunctionCall2(line_parallel,
-										 LinePGetDatum(l1),
-										 LinePGetDatum(l2))))
-		return NULL;
-
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
+		if (FPzero(l2->B))		/* l2 vertical? */
+			return false;
+
 		x = l1->C;
 		y = (l2->A * x + l2->C);
 	}
 	else if (FPzero(l2->B))		/* l2 vertical? */
 	{
 		x = l2->C;
 		y = (l1->A * x + l1->C);
 	}
 	else
 	{
+		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+			return false;
+
 		x = (l1->C - l2->C) / (l2->A - l1->A);
 		y = (l1->A * x + l1->C);
 	}
-	result = point_construct(x, y);
+	if (result != NULL)
+		point_construct(result, x, y);
 
-#ifdef GEODEBUG
-	printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
-		   DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
-	printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
-#endif
-
-	return result;
+	return true;
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D paths (sequences of line segments, also
  **				called `polylines').
  **
  **				This is not a general package for geometric paths,
  **				which of course include polygons; the emphasis here
@@ -1556,22 +1523,21 @@ path_inter(PG_FUNCTION_ARGS)
 {
 	PATH	   *p1 = PG_GETARG_PATH_P(0);
 	PATH	   *p2 = PG_GETARG_PATH_P(1);
 	BOX			b1,
 				b2;
 	int			i,
 				j;
 	LSEG		seg1,
 				seg2;
 
-	if (p1->npts <= 0 || p2->npts <= 0)
-		PG_RETURN_BOOL(false);
+	Assert(p1->npts > 0 && p2->npts > 0);
 
 	b1.high.x = b1.low.x = p1->p[0].x;
 	b1.high.y = b1.low.y = p1->p[0].y;
 	for (i = 1; i < p1->npts; i++)
 	{
 		b1.high.x = Max(p1->p[i].x, b1.high.x);
 		b1.high.y = Max(p1->p[i].y, b1.high.y);
 		b1.low.x = Min(p1->p[i].x, b1.low.x);
 		b1.low.y = Min(p1->p[i].y, b1.low.y);
 	}
@@ -1609,21 +1575,21 @@ path_inter(PG_FUNCTION_ARGS)
 				jprev = j - 1;
 			else
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
-			if (lseg_intersect_internal(&seg1, &seg2))
+			if (lseg_interpt_lseg(NULL, &seg1, &seg2))
 				PG_RETURN_BOOL(true);
 		}
 	}
 
 	/* if we dropped through, no two segs intersected */
 	PG_RETURN_BOOL(false);
 }
 
 /* path_distance()
  * This essentially does a cartesian product of the lsegs in the
@@ -1664,23 +1630,21 @@ path_distance(PG_FUNCTION_ARGS)
 			else
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
-			tmp = DatumGetFloat8(DirectFunctionCall2(lseg_distance,
-													 LsegPGetDatum(&seg1),
-													 LsegPGetDatum(&seg2)));
+			tmp = lseg_closept_lseg(NULL, &seg1, &seg2);
 			if (!have_min || tmp < min)
 			{
 				min = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	if (!have_min)
 		PG_RETURN_NULL();
@@ -1774,44 +1738,31 @@ point_send(PG_FUNCTION_ARGS)
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	StringInfoData buf;
 
 	pq_begintypsend(&buf);
 	pq_sendfloat8(&buf, pt->x);
 	pq_sendfloat8(&buf, pt->y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
-static Point *
-point_construct(double x, double y)
+/*
+ * Initialize a point
+ *
+ * This function is over-simple, but it is, at least, useful when the new
+ * point is calculated using the existing one.
+ */
+static inline void
+point_construct(Point *result, float8 x, float8 y)
 {
-	Point	   *result = (Point *) palloc(sizeof(Point));
-
 	result->x = x;
 	result->y = y;
-	return result;
-}
-
-
-static Point *
-point_copy(Point *pt)
-{
-	Point	   *result;
-
-	if (!PointerIsValid(pt))
-		return NULL;
-
-	result = (Point *) palloc(sizeof(Point));
-
-	result->x = pt->x;
-	result->y = pt->y;
-	return result;
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for Points.
  *		Since we do have a sense of coordinates being
  *		"equal" to a given accuracy (point_vert, point_horiz),
  *		the other ops must preserve that sense.  This means
  *		that results may, strictly speaking, be a lie (unless
  *		EPSILON = 0.0).
@@ -1870,71 +1821,85 @@ point_horiz(PG_FUNCTION_ARGS)
 
 	PG_RETURN_BOOL(FPeq(pt1->y, pt2->y));
 }
 
 Datum
 point_eq(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y));
+	PG_RETURN_BOOL(point_eq_point(pt1, pt2));
 }
 
 Datum
 point_ne(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPne(pt1->x, pt2->x) || FPne(pt1->y, pt2->y));
+	PG_RETURN_BOOL(!point_eq_point(pt1, pt2));
 }
 
+static inline bool
+point_eq_point(Point *pt1, Point *pt2)
+{
+	return FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y);
+}
+
+
 /*----------------------------------------------------------
  *	"Arithmetic" operators on points.
  *---------------------------------------------------------*/
 
 Datum
 point_distance(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_FLOAT8(HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
+	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
-double
+static float8
 point_dt(Point *pt1, Point *pt2)
 {
-#ifdef GEODEBUG
-	printf("point_dt- segment (%f,%f),(%f,%f) length is %f\n",
-		   pt1->x, pt1->y, pt2->x, pt2->y, HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
-#endif
 	return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
 }
 
 Datum
 point_slope(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_FLOAT8(point_sl(pt1, pt2));
+	PG_RETURN_FLOAT8(slope(pt1->x, pt2->x, pt1->y, pt2->y));
 }
 
 
-double
-point_sl(Point *pt1, Point *pt2)
+/*
+ * Return slope of two points
+ *
+ * This function accepts x and y coordinates separately to let it be used
+ * to calculate inverse slope.  To achieve that, pass the values in
+ * (y1, y2, x2, x1) order.
+ */
+static inline float8
+slope(float8 x1, float8 x2, float8 y1, float8 y2)
 {
-	return (FPeq(pt1->x, pt2->x)
-			? (double) DBL_MAX
-			: (pt1->y - pt2->y) / (pt1->x - pt2->x));
+	/*
+	 * XXX This should be exact checking.  The callers are using the macros
+	 * when necessary.
+	 */
+	if (FPeq(x1, x2))
+		return DBL_MAX;
+	return (y1 - y2) / (x1 - x2);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D line segments.
  **
  ***********************************************************************/
 
 /*----------------------------------------------------------
@@ -1946,31 +1911,31 @@ point_sl(Point *pt1, Point *pt2)
  *		(old form)		"(x1, y1, x2, y2)"
  *---------------------------------------------------------*/
 
 Datum
 lseg_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	LSEG	   *lseg = (LSEG *) palloc(sizeof(LSEG));
 	bool		isopen;
 
-	path_decode(str, true, 2, &(lseg->p[0]), &isopen, NULL, "lseg", str);
+	path_decode(str, true, 2, &lseg->p[0], &isopen, NULL, "lseg", str);
 	PG_RETURN_LSEG_P(lseg);
 }
 
 
 Datum
 lseg_out(PG_FUNCTION_ARGS)
 {
 	LSEG	   *ls = PG_GETARG_LSEG_P(0);
 
-	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, (Point *) &(ls->p[0])));
+	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, &ls->p[0]));
 }
 
 /*
  *		lseg_recv			- converts external binary format to lseg
  */
 Datum
 lseg_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LSEG	   *lseg;
@@ -2015,21 +1980,21 @@ lseg_construct(PG_FUNCTION_ARGS)
 
 	result->p[0].x = pt1->x;
 	result->p[0].y = pt1->y;
 	result->p[1].x = pt2->x;
 	result->p[1].y = pt2->y;
 
 	PG_RETURN_LSEG_P(result);
 }
 
 /* like lseg_construct, but assume space already allocated */
-static void
+static inline void
 statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2)
 {
 	lseg->p[0].x = pt1->x;
 	lseg->p[0].y = pt1->y;
 	lseg->p[1].x = pt2->x;
 	lseg->p[1].y = pt2->y;
 }
 
 Datum
 lseg_length(PG_FUNCTION_ARGS)
@@ -2046,69 +2011,53 @@ lseg_length(PG_FUNCTION_ARGS)
 /*
  **  find intersection of the two lines, and see if it falls on
  **  both segments.
  */
 Datum
 lseg_intersect(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(lseg_intersect_internal(l1, l2));
+	PG_RETURN_BOOL(lseg_interpt_lseg(NULL, l1, l2));
 }
 
-static bool
-lseg_intersect_internal(LSEG *l1, LSEG *l2)
-{
-	LINE		ln;
-	Point	   *interpt;
-	bool		retval;
-
-	line_construct_pts(&ln, &l2->p[0], &l2->p[1]);
-	interpt = interpt_sl(l1, &ln);
-
-	if (interpt != NULL && on_ps_internal(interpt, l2))
-		retval = true;			/* interpt on l1 and l2 */
-	else
-		retval = false;
-	return retval;
-}
 
 Datum
 lseg_parallel(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPeq(point_sl(&l1->p[0], &l1->p[1]),
-						point_sl(&l2->p[0], &l2->p[1])));
+	PG_RETURN_BOOL(FPeq(slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y),
+						slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y)));
 }
 
 /* lseg_perp()
  * Determine if two line segments are perpendicular.
  *
  * This code did not get the correct answer for
  *	'((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg
  * So, modified it to check explicitly for slope of vertical line
- *	returned by point_sl() and the results seem better.
+ *	returned by slope() and the results seem better.
  * - thomas 1998-01-31
  */
 Datum
 lseg_perp(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	double		m1,
 				m2;
 
-	m1 = point_sl(&(l1->p[0]), &(l1->p[1]));
-	m2 = point_sl(&(l2->p[0]), &(l2->p[1]));
+	m1 = slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y);
+	m2 = slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y);
 
 #ifdef GEODEBUG
 	printf("lseg_perp- slopes are %g and %g\n", m1, m2);
 #endif
 	if (FPzero(m1))
 		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
 	else if (FPzero(m2))
 		PG_RETURN_BOOL(FPeq(m1, DBL_MAX));
 
 	PG_RETURN_BOOL(FPeq(m1 / m2, -1.0));
@@ -2130,36 +2079,32 @@ lseg_horizontal(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(FPeq(lseg->p[0].y, lseg->p[1].y));
 }
 
 
 Datum
 lseg_eq(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPeq(l1->p[0].x, l2->p[0].x) &&
-				   FPeq(l1->p[0].y, l2->p[0].y) &&
-				   FPeq(l1->p[1].x, l2->p[1].x) &&
-				   FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(point_eq_point(&l1->p[0], &l2->p[0]) &&
+				   point_eq_point(&l1->p[1], &l2->p[1]));
 }
 
 Datum
 lseg_ne(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(!FPeq(l1->p[0].x, l2->p[0].x) ||
-				   !FPeq(l1->p[0].y, l2->p[0].y) ||
-				   !FPeq(l1->p[1].x, l2->p[1].x) ||
-				   !FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(!point_eq_point(&l1->p[0], &l2->p[0]) ||
+				   !point_eq_point(&l1->p[1], &l2->p[1]));
 }
 
 Datum
 lseg_lt(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_BOOL(FPlt(point_dt(&l1->p[0], &l1->p[1]),
 						point_dt(&l2->p[0], &l2->p[1])));
@@ -2204,126 +2149,81 @@ lseg_ge(PG_FUNCTION_ARGS)
  *		If two segments don't intersect, then the closest
  *		point will be from one of the endpoints to the other
  *		segment.
  */
 Datum
 lseg_distance(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_FLOAT8(lseg_dt(l1, l2));
-}
-
-/* lseg_dt()
- * Distance between two line segments.
- * Must check both sets of endpoints to ensure minimum distance is found.
- * - thomas 1998-02-01
- */
-static double
-lseg_dt(LSEG *l1, LSEG *l2)
-{
-	double		result,
-				d;
-
-	if (lseg_intersect_internal(l1, l2))
-		return 0.0;
-
-	d = dist_ps_internal(&l1->p[0], l2);
-	result = d;
-	d = dist_ps_internal(&l1->p[1], l2);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[0], l1);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[1], l1);
-	result = Min(result, d);
-
-	return result;
+	PG_RETURN_FLOAT8(lseg_closept_lseg(NULL, l1, l2));
 }
 
 
 Datum
 lseg_center(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
 	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
 
 	PG_RETURN_POINT_P(result);
 }
 
-static Point *
-lseg_interpt_internal(LSEG *l1, LSEG *l2)
+
+/*
+ *		Find the intersection point of two segments (if any).
+ *
+ * This returns true if two line segments intersect, false if they do not.
+ * This also sets the intersection point to *result, if it is not NULL.
+ * This function is almost perfectly symmetric, even though it doesn't look
+ * like it.  See lseg_interpt_line() for the other half of it.
+ */
+static bool
+lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2)
 {
-	Point	   *result;
-	LINE		tmp1,
-				tmp2;
+	Point		interpt;
+	LINE		tmp;
+
+	line_construct_pts(&tmp, &l2->p[0], &l2->p[1]);
+	if (!lseg_interpt_line(&interpt, l1, &tmp))
+		return false;
 
 	/*
-	 * Find the intersection of the appropriate lines, if any.
+	 * If the line intersection point isn't within l2, there is no valid
+	 * segment intersection point at all.
 	 */
-	line_construct_pts(&tmp1, &l1->p[0], &l1->p[1]);
-	line_construct_pts(&tmp2, &l2->p[0], &l2->p[1]);
-	result = line_interpt_internal(&tmp1, &tmp2);
-	if (!PointerIsValid(result))
-		return NULL;
+	if (!lseg_contain_point(l2, &interpt))
+		return false;
 
-	/*
-	 * If the line intersection point isn't within l1 (or equivalently l2),
-	 * there is no valid segment intersection point at all.
-	 */
-	if (!on_ps_internal(result, l1) ||
-		!on_ps_internal(result, l2))
-	{
-		pfree(result);
-		return NULL;
-	}
+	if (result != NULL)
+		*result = interpt;
 
-	/*
-	 * If there is an intersection, then check explicitly for matching
-	 * endpoints since there may be rounding effects with annoying lsb
-	 * residue. - tgl 1997-07-09
-	 */
-	if ((FPeq(l1->p[0].x, l2->p[0].x) && FPeq(l1->p[0].y, l2->p[0].y)) ||
-		(FPeq(l1->p[0].x, l2->p[1].x) && FPeq(l1->p[0].y, l2->p[1].y)))
-	{
-		result->x = l1->p[0].x;
-		result->y = l1->p[0].y;
-	}
-	else if ((FPeq(l1->p[1].x, l2->p[0].x) && FPeq(l1->p[1].y, l2->p[0].y)) ||
-			 (FPeq(l1->p[1].x, l2->p[1].x) && FPeq(l1->p[1].y, l2->p[1].y)))
-	{
-		result->x = l1->p[1].x;
-		result->y = l1->p[1].y;
-	}
-
-	return result;
+	return true;
 }
 
-/* lseg_interpt -
- *		Find the intersection point of two segments (if any).
- */
 Datum
 lseg_interpt(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
-	result = lseg_interpt_internal(l1, l2);
-	if (!PointerIsValid(result))
-		PG_RETURN_NULL();
+	result = (Point *) palloc(sizeof(Point));
 
+	if (!lseg_interpt_lseg(result, l1, l2))
+		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
 
 /***********************************************************************
  **
  **		Routines for position comparisons of differently-typed
  **				2D objects.
  **
  ***********************************************************************/
 
@@ -2334,215 +2234,128 @@ lseg_interpt(PG_FUNCTION_ARGS)
 
 /*
  * Distance from a point to a line
  */
 Datum
 dist_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_FLOAT8(dist_pl_internal(pt, line));
+	PG_RETURN_FLOAT8(line_closept_point(NULL, line, pt));
 }
 
-static double
-dist_pl_internal(Point *pt, LINE *line)
-{
-	return fabs((line->A * pt->x + line->B * pt->y + line->C) /
-				HYPOT(line->A, line->B));
-}
 
 /*
  * Distance from a point to a lseg
  */
 Datum
 dist_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_FLOAT8(dist_ps_internal(pt, lseg));
-}
-
-static double
-dist_ps_internal(Point *pt, LSEG *lseg)
-{
-	double		m;				/* slope of perp. */
-	LINE	   *ln;
-	double		result,
-				tmpdist;
-	Point	   *ip;
-
-	/*
-	 * Construct a line perpendicular to the input segment and through the
-	 * input point
-	 */
-	if (lseg->p[1].x == lseg->p[0].x)
-		m = 0;
-	else if (lseg->p[1].y == lseg->p[0].y)
-		m = (double) DBL_MAX;	/* slope is infinite */
-	else
-		m = (lseg->p[0].x - lseg->p[1].x) / (lseg->p[1].y - lseg->p[0].y);
-	ln = line_construct_pm(pt, m);
-
-#ifdef GEODEBUG
-	printf("dist_ps- line is A=%g B=%g C=%g from (point) slope (%f,%f) %g\n",
-		   ln->A, ln->B, ln->C, pt->x, pt->y, m);
-#endif
-
-	/*
-	 * Calculate distance to the line segment or to the nearest endpoint of
-	 * the segment.
-	 */
-
-	/* intersection is on the line segment? */
-	if ((ip = interpt_sl(lseg, ln)) != NULL)
-	{
-		/* yes, so use distance to the intersection point */
-		result = point_dt(pt, ip);
-#ifdef GEODEBUG
-		printf("dist_ps- distance is %f to intersection point is (%f,%f)\n",
-			   result, ip->x, ip->y);
-#endif
-	}
-	else
-	{
-		/* no, so use distance to the nearer endpoint */
-		result = point_dt(pt, &lseg->p[0]);
-		tmpdist = point_dt(pt, &lseg->p[1]);
-		if (tmpdist < result)
-			result = tmpdist;
-	}
-
-	return result;
+	PG_RETURN_FLOAT8(lseg_closept_point(NULL, lseg, pt));
 }
 
 /*
  * Distance from a point to a path
  */
 Datum
 dist_ppath(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	PATH	   *path = PG_GETARG_PATH_P(1);
 	float8		result = 0.0;	/* keep compiler quiet */
 	bool		have_min = false;
 	float8		tmp;
 	int			i;
 	LSEG		lseg;
 
-	switch (path->npts)
+	Assert(path->npts > 0);
+
+	/*
+	 * The distance from a point to a path is the smallest distance
+	 * from the point to any of its constituent segments.
+	 */
+	for (i = 0; i < path->npts; i++)
 	{
-		case 0:
-			/* no points in path? then result is undefined... */
-			PG_RETURN_NULL();
-		case 1:
-			/* one point in path? then get distance between two points... */
-			result = point_dt(pt, &path->p[0]);
-			break;
-		default:
-			/* make sure the path makes sense... */
-			Assert(path->npts > 1);
+		int			iprev;
 
-			/*
-			 * the distance from a point to a path is the smallest distance
-			 * from the point to any of its constituent segments.
-			 */
-			for (i = 0; i < path->npts; i++)
-			{
-				int			iprev;
+		if (i > 0)
+			iprev = i - 1;
+		else
+		{
+			if (!path->closed)
+				continue;
+			iprev = path->npts - 1; /* Include the closure segment */
+		}
 
-				if (i > 0)
-					iprev = i - 1;
-				else
-				{
-					if (!path->closed)
-						continue;
-					iprev = path->npts - 1; /* include the closure segment */
-				}
-
-				statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
-				tmp = dist_ps_internal(pt, &lseg);
-				if (!have_min || tmp < result)
-				{
-					result = tmp;
-					have_min = true;
-				}
-			}
-			break;
+		statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
+		tmp = lseg_closept_point(NULL, &lseg, pt);
+		if (!have_min || tmp < result)
+		{
+			result = tmp;
+			have_min = true;
+		}
 	}
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a point to a box
  */
 Datum
 dist_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
-	float8		result;
-	Point	   *near;
 
-	near = DatumGetPointP(DirectFunctionCall2(close_pb,
-											  PointPGetDatum(pt),
-											  BoxPGetDatum(box)));
-	result = point_dt(near, pt);
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(box_closept_point(NULL, box, pt));
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	float8		result,
 				d2;
 
-	if (has_interpt_sl(lseg, line))
+	if (lseg_interpt_line(NULL, lseg, line))
 		result = 0.0;
 	else
 	{
-		result = dist_pl_internal(&lseg->p[0], line);
-		d2 = dist_pl_internal(&lseg->p[1], line);
+		result = line_closept_point(NULL, line, &lseg->p[0]);
+		d2 = line_closept_point(NULL, line, &lseg->p[1]);
 		/* XXX shouldn't we take the min not max? */
 		if (d2 > result)
 			result = d2;
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
-	Point	   *tmp;
-	Datum		result;
 
-	tmp = DatumGetPointP(DirectFunctionCall2(close_sb,
-											 LsegPGetDatum(lseg),
-											 BoxPGetDatum(box)));
-	result = DirectFunctionCall2(dist_pb,
-								 PointPGetDatum(tmp),
-								 BoxPGetDatum(box));
-
-	PG_RETURN_DATUM(result);
+	PG_RETURN_FLOAT8(box_closept_lseg(NULL, box, lseg));
 }
 
 /*
  * Distance from a line to a box
  */
 Datum
 dist_lb(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -2578,612 +2391,604 @@ dist_cpoly(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a point to a polygon
  */
 Datum
 dist_ppoly(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	POLYGON    *poly = PG_GETARG_POLYGON_P(1);
-	float8		result;
 
-	result = dist_ppoly_internal(point, poly);
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(dist_ppoly_internal(point, poly));
 }
 
 Datum
 dist_polyp(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	float8		result;
 
-	result = dist_ppoly_internal(point, poly);
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(dist_ppoly_internal(point, poly));
 }
 
-static double
+static float8
 dist_ppoly_internal(Point *pt, POLYGON *poly)
 {
 	float8		result;
 	float8		d;
 	int			i;
 	LSEG		seg;
 
 	if (point_inside(pt, poly->npts, poly->p) != 0)
 	{
 #ifdef GEODEBUG
 		printf("dist_ppoly_internal- point inside of polygon\n");
 #endif
 		return 0.0;
 	}
 
 	/* initialize distance with segment between first and last points */
 	seg.p[0].x = poly->p[0].x;
 	seg.p[0].y = poly->p[0].y;
 	seg.p[1].x = poly->p[poly->npts - 1].x;
 	seg.p[1].y = poly->p[poly->npts - 1].y;
-	result = dist_ps_internal(pt, &seg);
+	result = lseg_closept_point(NULL, &seg, pt);
 #ifdef GEODEBUG
-	printf("dist_ppoly_internal- segment 0/n distance is %f\n", result);
+	printf("dist_ppoly_internal- segment 0/n distance is %f\n", *result);
 #endif
 
 	/* check distances for other segments */
-	for (i = 0; (i < poly->npts - 1); i++)
+	for (i = 0; i < poly->npts - 1; i++)
 	{
 		seg.p[0].x = poly->p[i].x;
 		seg.p[0].y = poly->p[i].y;
 		seg.p[1].x = poly->p[i + 1].x;
 		seg.p[1].y = poly->p[i + 1].y;
-		d = dist_ps_internal(pt, &seg);
+		d = lseg_closept_point(NULL, &seg, pt);
 #ifdef GEODEBUG
 		printf("dist_ppoly_internal- segment %d distance is %f\n", (i + 1), d);
 #endif
 		if (d < result)
 			result = d;
 	}
 
 	return result;
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
  *				Intersection point of objects.
  *				We choose to ignore the "point" of intersection between
  *				  lines and boxes, since there are typically two.
  *-------------------------------------------------------------------*/
 
-/* Get intersection point of lseg and line; returns NULL if no intersection */
-static Point *
-interpt_sl(LSEG *lseg, LINE *line)
+/*
+ * Check if the line segment intersects with the line
+ *
+ * This returns true if line segment intersects with line, false if they
+ * do not.  This also sets the intersection point to *result, if it is not
+ * NULL.
+ */
+static bool
+lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
 {
+	Point		interpt;
 	LINE		tmp;
-	Point	   *p;
 
 	line_construct_pts(&tmp, &lseg->p[0], &lseg->p[1]);
-	p = line_interpt_internal(&tmp, line);
-#ifdef GEODEBUG
-	printf("interpt_sl- segment is (%.*g %.*g) (%.*g %.*g)\n",
-		   DBL_DIG, lseg->p[0].x, DBL_DIG, lseg->p[0].y, DBL_DIG, lseg->p[1].x, DBL_DIG, lseg->p[1].y);
-	printf("interpt_sl- segment becomes line A=%.*g B=%.*g C=%.*g\n",
-		   DBL_DIG, tmp.A, DBL_DIG, tmp.B, DBL_DIG, tmp.C);
-#endif
-	if (PointerIsValid(p))
-	{
-#ifdef GEODEBUG
-		printf("interpt_sl- intersection point is (%.*g %.*g)\n", DBL_DIG, p->x, DBL_DIG, p->y);
-#endif
-		if (on_ps_internal(p, lseg))
-		{
-#ifdef GEODEBUG
-			printf("interpt_sl- intersection point is on segment\n");
-#endif
-		}
-		else
-			p = NULL;
-	}
+	if (!line_interpt_line(&interpt, &tmp, line))
+		return false;
 
-	return p;
-}
+	if (!lseg_contain_point(lseg, &interpt))
+		return false;
 
-/* variant: just indicate if intersection point exists */
-static bool
-has_interpt_sl(LSEG *lseg, LINE *line)
-{
-	Point	   *tmp;
-
-	tmp = interpt_sl(lseg, line);
-	if (tmp)
+	if (result == NULL)
 		return true;
-	return false;
+
+	/*
+	 * If there is an intersection, then check explicitly for matching
+	 * endpoints since there may be rounding effects with annoying LSB
+	 * residue.
+	 */
+	if (FPeq(lseg->p[0].x, interpt.x) && FPeq(lseg->p[0].y, interpt.y))
+		*result = lseg->p[0];
+	else if (FPeq(lseg->p[1].x, interpt.x) && FPeq(lseg->p[1].y, interpt.y))
+		*result = lseg->p[1];
+	else
+		*result = interpt;
+
+	return true;
 }
 
 /*---------------------------------------------------------------------
  *		close_
  *				Point of closest proximity between objects.
  *-------------------------------------------------------------------*/
 
-/* close_pl -
+/*
  *		The intersection point of a perpendicular of the line
  *		through the point.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
+static float8
+line_closept_point(Point *result, LINE *line, Point *point)
+{
+	bool		retval;
+	float8		m;
+	LINE		tmp;
+
+	/* Drop a perpendicular and find the intersection point */
+	m = slope(line->A, 0.0, line->B, 0.0);
+	line_construct_pm(&tmp, point, m);
+	retval = line_interpt_line(result, line, &tmp);
+	Assert(retval);		/* XXX We need something better. */
+
+	/*
+	 * XXX We could use the distance to the closest point, but
+	 * line_interpt_line() is currently giving wrong results.
+	 */
+	return fabs((line->A * point->x + line->B * point->y + line->C) /
+				HYPOT(line->A, line->B));
+}
+
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
-	LINE	   *tmp;
-	double		invm;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	if (FPzero(line->B))		/* vertical? */
-	{
-		result->x = line->C;
-		result->y = pt->y;
-		PG_RETURN_POINT_P(result);
-	}
-	if (FPzero(line->A))		/* horizontal? */
-	{
-		result->x = pt->x;
-		result->y = line->C;
-		PG_RETURN_POINT_P(result);
-	}
-	/* drop a perpendicular and find the intersection point */
+	line_closept_point(result, line, pt);
 
-	/* invert and flip the sign on the slope to get a perpendicular */
-	invm = line->B / line->A;
-	tmp = line_construct_pm(pt, invm);
-	result = line_interpt_internal(tmp, line);
-	Assert(result != NULL);
 	PG_RETURN_POINT_P(result);
 }
 
 
-/* close_ps()
+/*
  * Closest point on line segment to specified point.
- * Take the closest endpoint if the point is left, right,
- *	above, or below the segment, otherwise find the intersection
- *	point of the segment and its perpendicular through the point.
  *
- * Some tricky code here, relying on boolean expressions
- *	evaluating to only zero or one to use as an array index.
- *		bug fixes by gthaker@atl.lmco.com; May 1, 1998
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
+static float8
+lseg_closept_point(Point *result, LSEG *lseg, Point *pt)
+{
+	double		invm;
+	Point		closept;
+	LINE		tmp;
+
+	/*
+	 * To find the closest point, we draw a perpendicular line from the point
+	 * to the line segment.
+	 */
+	invm = slope(lseg->p[0].y, lseg->p[1].y, lseg->p[1].x, lseg->p[0].x);
+	line_construct_pm(&tmp, pt, invm);
+	lseg_closept_line(&closept, lseg, &tmp);
+
+	if (result != NULL)
+		*result = closept;
+
+	return point_dt(&closept, pt);
+}
+
 Datum
 close_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
-	LINE	   *tmp;
-	double		invm;
-	int			xh,
-				yh;
+	Point	   *result;
 
-#ifdef GEODEBUG
-	printf("close_sp:pt->x %f pt->y %f\nlseg(0).x %f lseg(0).y %f  lseg(1).x %f lseg(1).y %f\n",
-		   pt->x, pt->y, lseg->p[0].x, lseg->p[0].y,
-		   lseg->p[1].x, lseg->p[1].y);
-#endif
+	result = (Point *) palloc(sizeof(Point));
 
-	/* xh (or yh) is the index of upper x( or y) end point of lseg */
-	/* !xh (or !yh) is the index of lower x( or y) end point of lseg */
-	xh = lseg->p[0].x < lseg->p[1].x;
-	yh = lseg->p[0].y < lseg->p[1].y;
-
-	if (FPeq(lseg->p[0].x, lseg->p[1].x))	/* vertical? */
-	{
-#ifdef GEODEBUG
-		printf("close_ps- segment is vertical\n");
-#endif
-		/* first check if point is below or above the entire lseg. */
-		if (pt->y < lseg->p[!yh].y)
-			result = point_copy(&lseg->p[!yh]); /* below the lseg */
-		else if (pt->y > lseg->p[yh].y)
-			result = point_copy(&lseg->p[yh]);	/* above the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
-
-		/* point lines along (to left or right) of the vertical lseg. */
-
-		result = (Point *) palloc(sizeof(Point));
-		result->x = lseg->p[0].x;
-		result->y = pt->y;
-		PG_RETURN_POINT_P(result);
-	}
-	else if (FPeq(lseg->p[0].y, lseg->p[1].y))	/* horizontal? */
-	{
-#ifdef GEODEBUG
-		printf("close_ps- segment is horizontal\n");
-#endif
-		/* first check if point is left or right of the entire lseg. */
-		if (pt->x < lseg->p[!xh].x)
-			result = point_copy(&lseg->p[!xh]); /* left of the lseg */
-		else if (pt->x > lseg->p[xh].x)
-			result = point_copy(&lseg->p[xh]);	/* right of the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
-
-		/* point lines along (at top or below) the horiz. lseg. */
-		result = (Point *) palloc(sizeof(Point));
-		result->x = pt->x;
-		result->y = lseg->p[0].y;
-		PG_RETURN_POINT_P(result);
-	}
-
-	/*
-	 * vert. and horiz. cases are down, now check if the closest point is one
-	 * of the end points or someplace on the lseg.
-	 */
-
-	invm = -1.0 / point_sl(&(lseg->p[0]), &(lseg->p[1]));
-	tmp = line_construct_pm(&lseg->p[!yh], invm);	/* lower edge of the
-													 * "band" */
-	if (pt->y < (tmp->A * pt->x + tmp->C))
-	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[!yh]); /* below the lseg, take lower end
-											 * pt */
-#ifdef GEODEBUG
-		printf("close_ps below: tmp A %f  B %f   C %f\n",
-			   tmp->A, tmp->B, tmp->C);
-#endif
-		PG_RETURN_POINT_P(result);
-	}
-	tmp = line_construct_pm(&lseg->p[yh], invm);	/* upper edge of the
-													 * "band" */
-	if (pt->y > (tmp->A * pt->x + tmp->C))
-	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[yh]);	/* above the lseg, take higher end
-											 * pt */
-#ifdef GEODEBUG
-		printf("close_ps above: tmp A %f  B %f   C %f\n",
-			   tmp->A, tmp->B, tmp->C);
-#endif
-		PG_RETURN_POINT_P(result);
-	}
-
-	/*
-	 * at this point the "normal" from point will hit lseg. The closest point
-	 * will be somewhere on the lseg
-	 */
-	tmp = line_construct_pm(pt, invm);
-#ifdef GEODEBUG
-	printf("close_ps- tmp A %f  B %f   C %f\n",
-		   tmp->A, tmp->B, tmp->C);
-#endif
-	result = interpt_sl(lseg, tmp);
-
-	/*
-	 * ordinarily we should always find an intersection point, but that could
-	 * fail in the presence of NaN coordinates, and perhaps even from simple
-	 * roundoff issues.  Return a SQL NULL if so.
-	 */
-	if (result == NULL)
+	if (isnan(lseg_closept_point(result, lseg, pt)))
 		PG_RETURN_NULL();
 
-#ifdef GEODEBUG
-	printf("close_ps- result.x %f  result.y %f\n", result->x, result->y);
-#endif
 	PG_RETURN_POINT_P(result);
 }
 
 
-/* close_lseg()
+/*
  * Closest point to l1 on l2.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
+ *
+ * XXX This function is wrong.  If must never set the *result to a point on
+ * the second segment.
  */
+static float8
+lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
+{
+	Point		point;
+	double		dist;
+	double		d;
+
+	d = lseg_closept_point(NULL, l1, &l2->p[0]);
+	dist = d;
+	if (result != NULL)
+		*result = l2->p[0];
+
+	d = lseg_closept_point(NULL, l1, &l2->p[1]);
+	if (d < dist)
+	{
+		dist = d;
+		if (result != NULL)
+			*result = l2->p[1];
+	}
+
+	if (lseg_closept_point(&point, l2, &l1->p[0]) < dist)
+		d = lseg_closept_point(result, l1, &point);
+
+	if (lseg_closept_point(&point, l2, &l1->p[1]) < dist)
+		d = lseg_closept_point(result, l1, &point);
+
+	if (d < dist)
+		dist = d;
+
+	return dist;
+}
+
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
-	Point		point;
-	double		dist;
-	double		d;
+	Point	   *result;
 
-	d = dist_ps_internal(&l1->p[0], l2);
-	dist = d;
-	memcpy(&point, &l1->p[0], sizeof(Point));
+	result = (Point *) palloc(sizeof(Point));
 
-	if ((d = dist_ps_internal(&l1->p[1], l2)) < dist)
-	{
-		dist = d;
-		memcpy(&point, &l1->p[1], sizeof(Point));
-	}
-
-	if (dist_ps_internal(&l2->p[0], l1) < dist)
-	{
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&l2->p[0]),
-													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
-													LsegPGetDatum(l2)));
-	}
-
-	if (dist_ps_internal(&l2->p[1], l1) < dist)
-	{
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&l2->p[1]),
-													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
-													LsegPGetDatum(l2)));
-	}
-
-	if (result == NULL)
-		result = point_copy(&point);
+	lseg_closept_lseg(result, l2, l1);
 
 	PG_RETURN_POINT_P(result);
 }
 
-/* close_pb()
+
+/*
  * Closest point on or in box to specified point.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
-Datum
-close_pb(PG_FUNCTION_ARGS)
+static float8
+box_closept_point(Point *result, BOX *box, Point *pt)
 {
-	Point	   *pt = PG_GETARG_POINT_P(0);
-	BOX		   *box = PG_GETARG_BOX_P(1);
-	LSEG		lseg,
-				seg;
-	Point		point;
+	LSEG		lseg;
+	Point		point,
+				closept;
 	double		dist,
 				d;
 
-	if (DatumGetBool(DirectFunctionCall2(on_pb,
-										 PointPGetDatum(pt),
-										 BoxPGetDatum(box))))
-		PG_RETURN_POINT_P(pt);
+	if (box_contain_point(box, pt))
+	{
+		if (result != NULL)
+			*result = *pt;
+
+		return 0.0;
+	}
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&lseg, &box->low, &point);
-	dist = dist_ps_internal(pt, &lseg);
+	dist = lseg_closept_point(result, &lseg, pt);
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	statlseg_construct(&lseg, &box->high, &point);
+	d = lseg_closept_point(&closept, &lseg, pt);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&lseg, &seg, sizeof(lseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
-	statlseg_construct(&seg, &box->low, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	statlseg_construct(&lseg, &box->low, &point);
+	d = lseg_closept_point(&closept, &lseg, pt);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&lseg, &seg, sizeof(lseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	statlseg_construct(&lseg, &box->high, &point);
+	d = lseg_closept_point(&closept, &lseg, pt);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&lseg, &seg, sizeof(lseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
-										PointPGetDatum(pt),
-										LsegPGetDatum(&lseg)));
+	return dist;
 }
 
+Datum
+close_pb(PG_FUNCTION_ARGS)
+{
+	Point	   *pt = PG_GETARG_POINT_P(0);
+	BOX		   *box = PG_GETARG_BOX_P(1);
+	Point	   *result;
+
+	result = (Point *) palloc(sizeof(Point));
+
+	box_closept_point(result, box, pt);
+
+	PG_RETURN_POINT_P(result);
+}
+
+
 /* close_sl()
  * Closest point on line to line segment.
  *
  * XXX THIS CODE IS WRONG
  * The code is actually calculating the point on the line segment
  *	which is backwards from the routine naming convention.
  * Copied code to new routine close_ls() but haven't fixed this one yet.
  * - thomas 1998-01-31
  */
 Datum
 close_sl(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 	float8		d1,
 				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
+	result = (Point *) palloc(sizeof(Point));
+
+	if (lseg_interpt_line(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
-	d1 = dist_pl_internal(&lseg->p[0], line);
-	d2 = dist_pl_internal(&lseg->p[1], line);
+	d1 = line_closept_point(NULL, line, &lseg->p[0]);
+	d2 = line_closept_point(NULL, line, &lseg->p[1]);
 	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
+		*result = lseg->p[0];
 	else
-		result = point_copy(&lseg->p[1]);
+		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
 
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_sl\" not implemented")));
 
 	PG_RETURN_NULL();
 }
 
-/* close_ls()
+/*
  * Closest point on line segment to line.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
+ *
+ * NOTE When the lines are parallel, endpoints of one of the line segment
+ * are FPeq(), in presence of NaN or Infinitive coordinates, or perhaps =
+ * even because of simple roundoff issues, there may not be a single closest
+ * point.  We are likely to set the result to the second endpoint in these
+ * cases.
  */
+static float8
+lseg_closept_line(Point *result, LSEG *lseg, LINE *line)
+{
+	float8		dist1,
+				dist2;
+
+	if (lseg_interpt_line(result, lseg, line))
+		return 0.0;
+
+	dist1 = line_closept_point(NULL, line, &lseg->p[0]);
+	dist2 = line_closept_point(NULL, line, &lseg->p[1]);
+
+	if (dist1 < dist2)
+	{
+		if (result != NULL)
+			*result = lseg->p[0];
+
+		return dist1;
+	}
+	else
+	{
+		if (result != NULL)
+			*result = lseg->p[1];
+
+		return dist2;
+	}
+}
+
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
-	float8		d1,
-				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
-		PG_RETURN_POINT_P(result);
+	result = (Point *) palloc(sizeof(Point));
 
-	d1 = dist_pl_internal(&lseg->p[0], line);
-	d2 = dist_pl_internal(&lseg->p[1], line);
-	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
-	else
-		result = point_copy(&lseg->p[1]);
+	lseg_closept_line(result, lseg, line);
 
 	PG_RETURN_POINT_P(result);
 }
 
-/* close_sb()
+
+/*
  * Closest point on or in box to line segment.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
-Datum
-close_sb(PG_FUNCTION_ARGS)
+static float8
+box_closept_lseg(Point *result, BOX *box, LSEG *lseg)
 {
-	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
-	BOX		   *box = PG_GETARG_BOX_P(1);
-	Point		point;
-	LSEG		bseg,
-				seg;
+	Point		point,
+				closept;
+	LSEG		bseg;
 	double		dist,
 				d;
 
-	/* segment intersects box? then just return closest point to center */
-	if (DatumGetBool(DirectFunctionCall2(inter_sb,
-										 LsegPGetDatum(lseg),
-										 BoxPGetDatum(box))))
-	{
-		box_cn(&point, box);
-		PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
-											PointPGetDatum(&point),
-											LsegPGetDatum(lseg)));
-	}
+	if (box_interpt_lseg(result, box, lseg))
+		return 0.0;
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	dist = lseg_dt(lseg, &bseg);
+	dist = lseg_closept_lseg(result, &bseg, lseg);
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	statlseg_construct(&bseg, &box->high, &point);
+	d = lseg_closept_lseg(&closept, &bseg, lseg);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&bseg, &seg, sizeof(bseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
-	statlseg_construct(&seg, &box->low, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	statlseg_construct(&bseg, &box->low, &point);
+	d = lseg_closept_lseg(&closept, &bseg, lseg);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&bseg, &seg, sizeof(bseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	statlseg_construct(&bseg, &box->high, &point);
+	d = lseg_closept_lseg(&closept, &bseg, lseg);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&bseg, &seg, sizeof(bseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	/* OK, we now have the closest line segment on the box boundary */
-	PG_RETURN_DATUM(DirectFunctionCall2(close_lseg,
-										LsegPGetDatum(lseg),
-										LsegPGetDatum(&bseg)));
+	return dist;
 }
 
 Datum
+close_sb(PG_FUNCTION_ARGS)
+{
+	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
+	BOX		   *box = PG_GETARG_BOX_P(1);
+	Point	   *result;
+
+	result = (Point *) palloc(sizeof(Point));
+
+	box_closept_lseg(result, box, lseg);
+
+	PG_RETURN_POINT_P(result);
+}
+
+
+Datum
 close_lb(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 #endif
 
 	/* think about this one for a while */
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_lb\" not implemented")));
 
 	PG_RETURN_NULL();
 }
 
 /*---------------------------------------------------------------------
  *		on_
  *				Whether one object lies completely within another.
  *-------------------------------------------------------------------*/
 
-/* on_pl -
+/*
  *		Does the point satisfy the equation?
  */
+static bool
+line_contain_point(LINE *line, Point *point)
+{
+	return FPzero(line->A * point->x + line->B * point->y + line->C);
+}
+
 Datum
 on_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(FPzero(line->A * pt->x + line->B * pt->y + line->C));
+	PG_RETURN_BOOL(line_contain_point(line, pt));
 }
 
 
-/* on_ps -
+/*
  *		Determine colinearity by detecting a triangle inequality.
  * This algorithm seems to behave nicely even with lsb residues - tgl 1997-07-09
  */
+static bool
+lseg_contain_point(LSEG *lseg, Point *pt)
+{
+	return FPeq(point_dt(pt, &lseg->p[0]) +
+				point_dt(pt, &lseg->p[1]),
+				point_dt(&lseg->p[0], &lseg->p[1]));
+}
+
 Datum
 on_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(on_ps_internal(pt, lseg));
+	PG_RETURN_BOOL(lseg_contain_point(lseg, pt));
 }
 
+
+/*
+ * Check whether the point is in the box or on its border
+ */
 static bool
-on_ps_internal(Point *pt, LSEG *lseg)
+box_contain_point(BOX *box, Point *point)
 {
-	return FPeq(point_dt(pt, &lseg->p[0]) + point_dt(pt, &lseg->p[1]),
-				point_dt(&lseg->p[0], &lseg->p[1]));
+	return box->high.x >= point->x && box->low.x <= point->x &&
+		   box->high.y >= point->y && box->low.y <= point-> y;
 }
 
 Datum
 on_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_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);
+	PG_RETURN_BOOL(box_contain_point(box, pt));
 }
 
 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);
+	PG_RETURN_BOOL(box_contain_point(box, pt));
 }
 
+
 /* on_ppath -
  *		Whether a point lies within (on) a polyline.
  *		If open, we have to (groan) check each segment.
  * (uses same algorithm as for point intersecting segment - tgl 1997-07-09)
  *		If closed, we use the old O(n) ray method for point-in-polygon.
  *				The ray is horizontal, from pt out to the right.
  *				Each segment that crosses the ray counts as an
  *				intersection; note that an endpoint or edge may touch
  *				but not cross.
  *				(we can do p-in-p in lg(n), but it takes preprocessing)
@@ -3211,158 +3016,184 @@ on_ppath(PG_FUNCTION_ARGS)
 				PG_RETURN_BOOL(true);
 			a = b;
 		}
 		PG_RETURN_BOOL(false);
 	}
 
 	/*-- CLOSED --*/
 	PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
 }
 
+
+/*
+ * Check whether the line segment is on the line or close enough
+ *
+ * It is, if both of its points are on the line or close enough.
+ */
 Datum
 on_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(DatumGetBool(DirectFunctionCall2(on_pl,
-													PointPGetDatum(&lseg->p[0]),
-													LinePGetDatum(line))) &&
-				   DatumGetBool(DirectFunctionCall2(on_pl,
-													PointPGetDatum(&lseg->p[1]),
-													LinePGetDatum(line))));
+	PG_RETURN_BOOL(line_contain_point(line, &lseg->p[0]) &&
+				   line_contain_point(line, &lseg->p[1]));
+}
+
+
+/*
+ * Check whether the line segment is in the box or on its border
+ *
+ * It is, if both of its points are in the box or on its border.
+ */
+static bool
+box_contain_lseg(BOX *box, LSEG *lseg)
+{
+	return box_contain_point(box, &lseg->p[0]) &&
+		   box_contain_point(box, &lseg->p[1]);
 }
 
 Datum
 on_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(DatumGetBool(DirectFunctionCall2(on_pb,
-													PointPGetDatum(&lseg->p[0]),
-													BoxPGetDatum(box))) &&
-				   DatumGetBool(DirectFunctionCall2(on_pb,
-													PointPGetDatum(&lseg->p[1]),
-													BoxPGetDatum(box))));
+	PG_RETURN_BOOL(box_contain_lseg(box, lseg));
 }
 
 /*---------------------------------------------------------------------
  *		inter_
  *				Whether one object intersects another.
  *-------------------------------------------------------------------*/
 
 Datum
 inter_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(has_interpt_sl(lseg, line));
+	PG_RETURN_BOOL(lseg_interpt_line(NULL, lseg, line));
 }
 
-/* inter_sb()
+
+/*
  * Do line segment and box intersect?
  *
  * Segment completely inside box counts as intersection.
  * If you want only segments crossing box boundaries,
  *	try converting box to path first.
  *
+ * This function also sets the *result to the closest point on the line
+ * segment to the center of the box when they overlap and the result is
+ * not NULL.  It is somewhat arbitrary, but maybe the best we can do as
+ * there are typically two points they intersect.
+ *
  * Optimize for non-intersection by checking for box intersection first.
  * - thomas 1998-01-30
  */
-Datum
-inter_sb(PG_FUNCTION_ARGS)
+static bool
+box_interpt_lseg(Point *result, BOX *box, LSEG *lseg)
 {
-	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
-	BOX		   *box = PG_GETARG_BOX_P(1);
 	BOX			lbox;
 	LSEG		bseg;
 	Point		point;
 
 	lbox.low.x = Min(lseg->p[0].x, lseg->p[1].x);
 	lbox.low.y = Min(lseg->p[0].y, lseg->p[1].y);
 	lbox.high.x = Max(lseg->p[0].x, lseg->p[1].x);
 	lbox.high.y = Max(lseg->p[0].y, lseg->p[1].y);
 
 	/* nothing close to overlap? then not going to intersect */
 	if (!box_ov(&lbox, box))
-		PG_RETURN_BOOL(false);
+		return false;
+
+	if (result != NULL)
+	{
+		box_cn(&point, box);
+		lseg_closept_point(result, lseg, &point);
+	}
 
 	/* an endpoint of segment is inside box? then clearly intersects */
-	if (DatumGetBool(DirectFunctionCall2(on_pb,
-										 PointPGetDatum(&lseg->p[0]),
-										 BoxPGetDatum(box))) ||
-		DatumGetBool(DirectFunctionCall2(on_pb,
-										 PointPGetDatum(&lseg->p[1]),
-										 BoxPGetDatum(box))))
-		PG_RETURN_BOOL(true);
+	if (box_contain_point(box, &lseg->p[0]) ||
+		box_contain_point(box, &lseg->p[1]))
+		return true;
 
 	/* pairwise check lseg intersections */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	/* if we dropped through, no two segs intersected */
-	PG_RETURN_BOOL(false);
+	return false;
 }
 
+Datum
+inter_sb(PG_FUNCTION_ARGS)
+{
+	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
+	BOX		   *box = PG_GETARG_BOX_P(1);
+
+	PG_RETURN_BOOL(box_interpt_lseg(NULL, box, lseg));
+}
+
+
 /* inter_lb()
  * Do line and box intersect?
  */
 Datum
 inter_lb(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	LSEG		bseg;
 	Point		p1,
 				p2;
 
 	/* pairwise check lseg intersections */
 	p1.x = box->low.x;
 	p1.y = box->low.y;
 	p2.x = box->low.x;
 	p2.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->high.x;
 	p1.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p2.x = box->high.x;
 	p2.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->low.x;
 	p1.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 
 	/* if we dropped through, no intersection */
 	PG_RETURN_BOOL(false);
 }
 
 /*------------------------------------------------------------------
  * The following routines define a data type and operator class for
  * POLYGONS .... Part of which (the polygon's bounding box) is built on
  * top of the BOX data type.
@@ -3375,42 +3206,40 @@ inter_lb(PG_FUNCTION_ARGS)
  *---------------------------------------------------------------------*/
 static void
 make_bound_box(POLYGON *poly)
 {
 	int			i;
 	double		x1,
 				y1,
 				x2,
 				y2;
 
-	if (poly->npts > 0)
-	{
-		x2 = x1 = poly->p[0].x;
-		y2 = y1 = poly->p[0].y;
-		for (i = 1; i < poly->npts; i++)
-		{
-			if (poly->p[i].x < x1)
-				x1 = poly->p[i].x;
-			if (poly->p[i].x > x2)
-				x2 = poly->p[i].x;
-			if (poly->p[i].y < y1)
-				y1 = poly->p[i].y;
-			if (poly->p[i].y > y2)
-				y2 = poly->p[i].y;
-		}
+	Assert(poly->npts > 0);
 
-		box_fill(&(poly->boundbox), x1, x2, y1, y2);
+	x1 = x2 = poly->p[0].x;
+	y2 = y1 = poly->p[0].y;
+	for (i = 1; i < poly->npts; i++)
+	{
+		if (poly->p[i].x < x1)
+			x1 = poly->p[i].x;
+		if (poly->p[i].x > x2)
+			x2 = poly->p[i].x;
+		if (poly->p[i].y < y1)
+			y1 = poly->p[i].y;
+		if (poly->p[i].y > y2)
+			y2 = poly->p[i].y;
 	}
-	else
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot create bounding box for empty polygon")));
+
+	poly->boundbox.low.x = x1;
+	poly->boundbox.high.x = x2;
+	poly->boundbox.low.y = y1;
+	poly->boundbox.high.y = y2;
 }
 
 /*------------------------------------------------------------------
  * poly_in - read in the polygon from a string specification
  *
  *		External format:
  *				"((x0,y0),...,(xn,yn))"
  *				"x0,y0,...,xn,yn"
  *				also supports the older style "(x1,...,xn,y1,...yn)"
  *------------------------------------------------------------------*/
@@ -3742,63 +3571,62 @@ poly_same(PG_FUNCTION_ARGS)
  *-----------------------------------------------------------------*/
 Datum
 poly_overlap(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
 	/* Quick check by bounding box */
 	result = (polya->npts > 0 && polyb->npts > 0 &&
-			  box_ov(&polya->boundbox, &polyb->boundbox)) ? true : false;
+			  box_ov(&polya->boundbox, &polyb->boundbox));
 
 	/*
 	 * Brute-force algorithm - try to find intersected edges, if so then
 	 * polygons are overlapped else check is one polygon inside other or not
 	 * by testing single point of them.
 	 */
 	if (result)
 	{
 		int			ia,
 					ib;
 		LSEG		sa,
 					sb;
 
 		/* Init first of polya's edge with last point */
 		sa.p[0] = polya->p[polya->npts - 1];
 		result = false;
 
-		for (ia = 0; ia < polya->npts && result == false; ia++)
+		for (ia = 0; ia < polya->npts && !result; ia++)
 		{
 			/* Second point of polya's edge is a current one */
 			sa.p[1] = polya->p[ia];
 
 			/* Init first of polyb's edge with last point */
 			sb.p[0] = polyb->p[polyb->npts - 1];
 
-			for (ib = 0; ib < polyb->npts && result == false; ib++)
+			for (ib = 0; ib < polyb->npts && !result; ib++)
 			{
 				sb.p[1] = polyb->p[ib];
-				result = lseg_intersect_internal(&sa, &sb);
+				result = lseg_interpt_lseg(NULL, &sa, &sb);
 				sb.p[0] = sb.p[1];
 			}
 
 			/*
 			 * move current endpoint to the first point of next edge
 			 */
 			sa.p[0] = sa.p[1];
 		}
 
-		if (result == false)
+		if (!result)
 		{
-			result = (point_inside(polya->p, polyb->npts, polyb->p)
-					  ||
+			result = (point_inside(polya->p, polyb->npts, polyb->p) ||
 					  point_inside(polyb->p, polya->npts, polya->p));
 		}
 	}
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
@@ -3818,36 +3646,35 @@ poly_overlap(PG_FUNCTION_ARGS)
 
 static bool
 touched_lseg_inside_poly(Point *a, Point *b, LSEG *s, POLYGON *poly, int start)
 {
 	/* point a is on s, b is not */
 	LSEG		t;
 
 	t.p[0] = *a;
 	t.p[1] = *b;
 
-#define POINTEQ(pt1, pt2)	(FPeq((pt1)->x, (pt2)->x) && FPeq((pt1)->y, (pt2)->y))
-	if (POINTEQ(a, s->p))
+	if (point_eq_point(a, s->p))
 	{
-		if (on_ps_internal(s->p + 1, &t))
+		if (lseg_contain_point(&t, s->p + 1))
 			return lseg_inside_poly(b, s->p + 1, poly, start);
 	}
-	else if (POINTEQ(a, s->p + 1))
+	else if (point_eq_point(a, s->p + 1))
 	{
-		if (on_ps_internal(s->p, &t))
+		if (lseg_contain_point(&t, s->p))
 			return lseg_inside_poly(b, s->p, poly, start);
 	}
-	else if (on_ps_internal(s->p, &t))
+	else if (lseg_contain_point(&t, s->p))
 	{
 		return lseg_inside_poly(b, s->p, poly, start);
 	}
-	else if (on_ps_internal(s->p + 1, &t))
+	else if (lseg_contain_point(&t, s->p + 1))
 	{
 		return lseg_inside_poly(b, s->p + 1, poly, start);
 	}
 
 	return true;				/* may be not true, but that will check later */
 }
 
 /*
  * Returns true if segment (a,b) is in polygon, option
  * start is used for optimization - function checks
@@ -3861,50 +3688,49 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 	int			i;
 	bool		res = true,
 				intersection = false;
 
 	t.p[0] = *a;
 	t.p[1] = *b;
 	s.p[0] = poly->p[(start == 0) ? (poly->npts - 1) : (start - 1)];
 
 	for (i = start; i < poly->npts && res; i++)
 	{
-		Point	   *interpt;
+		Point		interpt;
 
 		CHECK_FOR_INTERRUPTS();
 
 		s.p[1] = poly->p[i];
 
-		if (on_ps_internal(t.p, &s))
+		if (lseg_contain_point(&s, t.p))
 		{
-			if (on_ps_internal(t.p + 1, &s))
+			if (lseg_contain_point(&s, t.p + 1))
 				return true;	/* t is contained by s */
 
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p, t.p + 1, &s, poly, i + 1);
 		}
-		else if (on_ps_internal(t.p + 1, &s))
+		else if (lseg_contain_point(&s, t.p + 1))
 		{
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p + 1, t.p, &s, poly, i + 1);
 		}
-		else if ((interpt = lseg_interpt_internal(&t, &s)) != NULL)
+		else if (lseg_interpt_lseg(&interpt, &t, &s))
 		{
 			/*
 			 * segments are X-crossing, go to check each subsegment
 			 */
 
 			intersection = true;
-			res = lseg_inside_poly(t.p, interpt, poly, i + 1);
+			res = lseg_inside_poly(t.p, &interpt, poly, i + 1);
 			if (res)
-				res = lseg_inside_poly(t.p + 1, interpt, poly, i + 1);
-			pfree(interpt);
+				res = lseg_inside_poly(t.p + 1, &interpt, poly, i + 1);
 		}
 
 		s.p[0] = s.p[1];
 	}
 
 	if (res && !intersection)
 	{
 		Point		p;
 
 		/*
@@ -3916,74 +3742,86 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 
 		res = point_inside(&p, poly->npts, poly->p);
 	}
 
 	return res;
 }
 
 /*-----------------------------------------------------------------
  * Determine if polygon A contains polygon B.
  *-----------------------------------------------------------------*/
+static bool
+poly_contain_poly(POLYGON *polya, POLYGON *polyb)
+{
+	int			i;
+	LSEG		s;
+
+	Assert(polya->npts > 0 && polyb->npts > 0);
+
+	/*
+	 * Quick check to see if bounding box is contained.
+	 */
+	if (!box_contain_box(&polya->boundbox, &polyb->boundbox))
+		return false;
+
+	s.p[0] = polyb->p[polyb->npts - 1];
+
+	for (i = 0; i < polyb->npts; i++)
+	{
+		s.p[1] = polyb->p[i];
+		if (!lseg_inside_poly(s.p, s.p + 1, polya, 0))
+			return false;
+		s.p[0] = s.p[1];
+	}
+
+	return true;
+}
+
 Datum
 poly_contain(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	/*
-	 * Quick check to see if bounding box is contained.
-	 */
-	if (polya->npts > 0 && polyb->npts > 0 &&
-		DatumGetBool(DirectFunctionCall2(box_contain,
-										 BoxPGetDatum(&polya->boundbox),
-										 BoxPGetDatum(&polyb->boundbox))))
-	{
-		int			i;
-		LSEG		s;
-
-		s.p[0] = polyb->p[polyb->npts - 1];
-		result = true;
-
-		for (i = 0; i < polyb->npts && result; i++)
-		{
-			s.p[1] = polyb->p[i];
-			result = lseg_inside_poly(s.p, s.p + 1, polya, 0);
-			s.p[0] = s.p[1];
-		}
-	}
-	else
-	{
-		result = false;
-	}
+	result = poly_contain_poly(polya, polyb);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
 
 /*-----------------------------------------------------------------
  * Determine if polygon A is contained by polygon B
  *-----------------------------------------------------------------*/
 Datum
 poly_contained(PG_FUNCTION_ARGS)
 {
-	Datum		polya = PG_GETARG_DATUM(0);
-	Datum		polyb = PG_GETARG_DATUM(1);
+	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
+	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
+	bool		result;
 
 	/* Just switch the arguments and pass it off to poly_contain */
-	PG_RETURN_DATUM(DirectFunctionCall2(poly_contain, polyb, polya));
+	result = poly_contain_poly(polyb, polya);
+
+	/*
+	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
+	 */
+	PG_FREE_IF_COPY(polya, 0);
+	PG_FREE_IF_COPY(polyb, 1);
+
+	PG_RETURN_BOOL(result);
 }
 
 
 Datum
 poly_contain_pt(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_BOOL(point_inside(p, poly->npts, poly->p) != 0);
@@ -4019,170 +3857,215 @@ poly_distance(PG_FUNCTION_ARGS)
  **
  **		Routines for 2D points.
  **
  ***********************************************************************/
 
 Datum
 construct_point(PG_FUNCTION_ARGS)
 {
 	float8		x = PG_GETARG_FLOAT8(0);
 	float8		y = PG_GETARG_FLOAT8(1);
+	Point	   *result;
 
-	PG_RETURN_POINT_P(point_construct(x, y));
+	result = (Point *) palloc(sizeof(Point));
+
+	point_construct(result, x, y);
+
+	PG_RETURN_POINT_P(result);
+}
+
+
+static inline void
+point_add_point(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x + pt2->x,
+					pt1->y + pt2->y);
 }
 
 Datum
 point_add(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x + p2->x);
-	result->y = (p1->y + p2->y);
+	point_add_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+
+static inline void
+point_sub_point(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x - pt2->x,
+					pt1->y - pt2->y);
+}
+
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x - p2->x);
-	result->y = (p1->y - p2->y);
+	point_sub_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+
+static inline void
+point_mul_point(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					(pt1->x * pt2->x) - (pt1->y * pt2->y),
+					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+}
+
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x * p2->x) - (p1->y * p2->y);
-	result->y = (p1->x * p2->y) + (p1->y * p2->x);
+	point_mul_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+
+static inline void
+point_div_point(Point *result, Point *pt1, Point *pt2)
+{
+	double		div;
+
+	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
+
+	if (div == 0.0)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	point_construct(result,
+					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
+					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+}
+
 Datum
 point_div(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
-	double		div;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	div = (p2->x * p2->x) + (p2->y * p2->y);
-
-	if (div == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result->x = ((p1->x * p2->x) + (p1->y * p2->y)) / div;
-	result->y = ((p2->x * p1->y) - (p2->y * p1->x)) / div;
+	point_div_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D boxes.
  **
  ***********************************************************************/
 
 Datum
 points_box(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct(p1->x, p2->x, p1->y, p2->y));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	box_construct(result, p1, p2);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_add(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct((box->high.x + p->x),
-								  (box->low.x + p->x),
-								  (box->high.y + p->y),
-								  (box->low.y + p->y)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_add_point(&result->high, &box->high, p);
+	point_add_point(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_sub(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct((box->high.x - p->x),
-								  (box->low.x - p->x),
-								  (box->high.y - p->y),
-								  (box->low.y - p->y)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_sub_point(&result->high, &box->high, p);
+	point_sub_point(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_mul(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
 
-	high = DatumGetPointP(DirectFunctionCall2(point_mul,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_mul,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	result = (BOX *) palloc(sizeof(BOX));
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	point_mul_point(&high, &box->high, p);
+	point_mul_point(&low, &box->low, p);
+
+	box_construct(result, &high, &low);
 
 	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_div(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
 
-	high = DatumGetPointP(DirectFunctionCall2(point_div,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_div,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	result = (BOX *) palloc(sizeof(BOX));
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	point_div_point(&high, &box->high, p);
+	point_div_point(&low, &box->low, p);
+
+	box_construct(result, &high, &low);
 
 	PG_RETURN_BOX_P(result);
 }
 
 /*
  * Convert point to empty box
  */
 Datum
 point_box(PG_FUNCTION_ARGS)
 {
@@ -4278,83 +4161,63 @@ path_add(PG_FUNCTION_ARGS)
  * Translation operators.
  */
 Datum
 path_add_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x += point->x;
-		path->p[i].y += point->y;
-	}
+		point_add_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_sub_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x -= point->x;
-		path->p[i].y -= point->y;
-	}
+		point_sub_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 /* path_mul_pt()
  * Rotation and scaling operators.
  */
 Datum
 path_mul_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_mul,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_mul_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_div_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_div,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_div_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 
 Datum
 path_center(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	PATH	   *path = PG_GETARG_PATH_P(0);
@@ -4415,42 +4278,42 @@ poly_npoints(PG_FUNCTION_ARGS)
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 
 	PG_RETURN_INT32(poly->npts);
 }
 
 
 Datum
 poly_center(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
-	Datum		result;
-	CIRCLE	   *circle;
+	Point	   *result;
+	CIRCLE		circle;
 
-	circle = DatumGetCircleP(DirectFunctionCall1(poly_circle,
-												 PolygonPGetDatum(poly)));
-	result = DirectFunctionCall1(circle_center,
-								 CirclePGetDatum(circle));
+	result = (Point *) palloc(sizeof(Point));
 
-	PG_RETURN_DATUM(result);
+	poly_to_circle(&circle, poly);
+	*result = circle.center;
+
+	PG_RETURN_POINT_P(result);
 }
 
 
 Datum
 poly_box(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	BOX		   *box;
 
-	if (poly->npts < 1)
-		PG_RETURN_NULL();
+	Assert(poly->npts > 0);
 
-	box = box_copy(&poly->boundbox);
+	box = (BOX *) palloc(sizeof(BOX));
+	*box = poly->boundbox;
 
 	PG_RETURN_BOX_P(box);
 }
 
 
 /* box_poly()
  * Convert a box to a polygon.
  */
 Datum
 box_poly(PG_FUNCTION_ARGS)
@@ -4468,22 +4331,21 @@ box_poly(PG_FUNCTION_ARGS)
 
 	poly->p[0].x = box->low.x;
 	poly->p[0].y = box->low.y;
 	poly->p[1].x = box->low.x;
 	poly->p[1].y = box->high.y;
 	poly->p[2].x = box->high.x;
 	poly->p[2].y = box->high.y;
 	poly->p[3].x = box->high.x;
 	poly->p[3].y = box->low.y;
 
-	box_fill(&poly->boundbox, box->high.x, box->low.x,
-			 box->high.y, box->low.y);
+	box_construct(&poly->boundbox, &box->high, &box->low);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
 
 Datum
 poly_path(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	PATH	   *path;
@@ -4558,22 +4420,21 @@ circle_in(PG_FUNCTION_ARGS)
 
 	circle->radius = single_decode(s, &s, "circle", str);
 	if (circle->radius < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
 
 	while (depth > 0)
 	{
-		if ((*s == RDELIM)
-			|| ((*s == RDELIM_C) && (depth == 1)))
+		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
 			s++;
 			while (isspace((unsigned char) *s))
 				s++;
 		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
@@ -4657,22 +4518,21 @@ circle_send(PG_FUNCTION_ARGS)
 
 /*		circles identical?
  */
 Datum
 circle_same(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPeq(circle1->radius, circle2->radius) &&
-				   FPeq(circle1->center.x, circle2->center.x) &&
-				   FPeq(circle1->center.y, circle2->center.y));
+				   point_eq_point(&circle1->center, &circle2->center));
 }
 
 /*		circle_overlap	-		does circle1 overlap circle2?
  */
 Datum
 circle_overlap(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
@@ -4731,32 +4591,34 @@ circle_overright(PG_FUNCTION_ARGS)
 }
 
 /*		circle_contained		-		is circle1 contained by circle2?
  */
 Datum
 circle_contained(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle1->radius), circle2->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						circle2->radius - circle1->radius));
 }
 
 /*		circle_contain	-		does circle1 contain circle2?
  */
 Datum
 circle_contain(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle2->radius), circle1->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						circle1->radius - circle2->radius));
 }
 
 
 /*		circle_below		-		is circle1 strictly below circle2?
  */
 Datum
 circle_below(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
@@ -4859,107 +4721,83 @@ circle_ge(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPge(circle_ar(circle1), circle_ar(circle2)));
 }
 
 
 /*----------------------------------------------------------
  *	"Arithmetic" operators on circles.
  *---------------------------------------------------------*/
 
-static CIRCLE *
-circle_copy(CIRCLE *circle)
-{
-	CIRCLE	   *result;
-
-	if (!PointerIsValid(circle))
-		return NULL;
-
-	result = (CIRCLE *) palloc(sizeof(CIRCLE));
-	memcpy((char *) result, (char *) circle, sizeof(CIRCLE));
-	return result;
-}
-
-
 /* circle_add_pt()
  * Translation operator.
  */
 Datum
 circle_add_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x += point->x;
-	result->center.y += point->y;
+	point_add_point(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_sub_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x -= point->x;
-	result->center.y -= point->y;
+	point_sub_point(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /* circle_mul_pt()
  * Rotation and scaling operators.
  */
 Datum
 circle_mul_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_mul,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
-	result->radius *= HYPOT(point->x, point->y);
+	point_mul_point(&result->center, &circle->center, point);
+	result->radius = circle->radius * HYPOT(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_div_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_div,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
-	result->radius /= HYPOT(point->x, point->y);
+	point_div_point(&result->center, &circle->center, point);
+	result->radius = circle->radius / HYPOT(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /*		circle_area		-		returns the area of the circle.
  */
 Datum
 circle_area(PG_FUNCTION_ARGS)
 {
@@ -4994,22 +4832,22 @@ circle_radius(PG_FUNCTION_ARGS)
 /*		circle_distance -		returns the distance between
  *								  two circles.
  */
 Datum
 circle_distance(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(&circle1->center, &circle2->center)
-		- (circle1->radius + circle2->radius);
+	result = point_dt(&circle1->center, &circle2->center) -
+		(circle1->radius + circle2->radius);
 	if (result < 0)
 		result = 0;
 	PG_RETURN_FLOAT8(result);
 }
 
 
 Datum
 circle_contain_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
@@ -5191,56 +5029,60 @@ circle_poly(PG_FUNCTION_ARGS)
 		angle = i * anglestep;
 		poly->p[i].x = circle->center.x - (circle->radius * cos(angle));
 		poly->p[i].y = circle->center.y + (circle->radius * sin(angle));
 	}
 
 	make_bound_box(poly);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
-/*		poly_circle		- convert polygon to circle
+/*
+ * Convert polygon to circle
+ *
+ * The result must be preallocated.
  *
  * XXX This algorithm should use weighted means of line segments
  *	rather than straight average values of points - tgl 97/01/21.
  */
+static void
+poly_to_circle(CIRCLE *result, POLYGON *poly)
+{
+	int			i;
+
+	Assert(poly->npts > 0);
+
+	result->center.x = 0;
+	result->center.y = 0;
+	result->radius = 0;
+
+	for (i = 0; i < poly->npts; i++)
+		point_add_point(&result->center, &result->center, &poly->p[i]);
+	result->center.x /= poly->npts;
+	result->center.y /= poly->npts;
+
+	for (i = 0; i < poly->npts; i++)
+		result->radius += point_dt(&poly->p[i], &result->center);
+	result->radius /= poly->npts;
+}
+
 Datum
 poly_circle(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
-	CIRCLE	   *circle;
-	int			i;
+	CIRCLE	   *result;
 
-	if (poly->npts < 1)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot convert empty polygon to circle")));
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
+	poly_to_circle(result, poly);
 
-	circle->center.x = 0;
-	circle->center.y = 0;
-	circle->radius = 0;
-
-	for (i = 0; i < poly->npts; i++)
-	{
-		circle->center.x += poly->p[i].x;
-		circle->center.y += poly->p[i].y;
-	}
-	circle->center.x /= poly->npts;
-	circle->center.y /= poly->npts;
-
-	for (i = 0; i < poly->npts; i++)
-		circle->radius += point_dt(&poly->p[i], &circle->center);
-	circle->radius /= poly->npts;
-
-	PG_RETURN_CIRCLE_P(circle);
+	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /***********************************************************************
  **
  **		Private routines for multiple types.
  **
  ***********************************************************************/
 
 /*
@@ -5262,22 +5104,21 @@ point_inside(Point *p, int npts, Point *plist)
 	double		x0,
 				y0;
 	double		prev_x,
 				prev_y;
 	int			i = 0;
 	double		x,
 				y;
 	int			cross,
 				total_cross = 0;
 
-	if (npts <= 0)
-		return 0;
+	Assert(npts > 0);
 
 	/* compute first polygon point relative to single point */
 	x0 = plist[0].x - p->x;
 	y0 = plist[0].y - p->y;
 
 	prev_x = x0;
 	prev_y = y0;
 	/* loop over polygon points and aggregate total_cross */
 	for (i = 1; i < npts; i++)
 	{
@@ -5372,51 +5213,48 @@ lseg_crossing(double x, double y, double prev_x, double prev_y)
 static bool
 plist_same(int npts, Point *p1, Point *p2)
 {
 	int			i,
 				ii,
 				j;
 
 	/* find match for first point */
 	for (i = 0; i < npts; i++)
 	{
-		if ((FPeq(p2[i].x, p1[0].x))
-			&& (FPeq(p2[i].y, p1[0].y)))
+		if (point_eq_point(&p2[i], &p1[0]))
 		{
 
 			/* match found? then look forward through remaining points */
 			for (ii = 1, j = i + 1; ii < npts; ii++, j++)
 			{
 				if (j >= npts)
 					j = 0;
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_point(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed forward match with %d\n", j, ii);
 #endif
 					break;
 				}
 			}
 #ifdef GEODEBUG
 			printf("plist_same- ii = %d/%d after forward match\n", ii, npts);
 #endif
 			if (ii == npts)
 				return true;
 
 			/* match not found forwards? then look backwards */
 			for (ii = 1, j = i - 1; ii < npts; ii++, j--)
 			{
 				if (j < 0)
 					j = (npts - 1);
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_point(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed reverse match with %d\n", j, ii);
 #endif
 					break;
 				}
 			}
 #ifdef GEODEBUG
 			printf("plist_same- ii = %d/%d after reverse match\n", ii, npts);
 #endif
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 44c6381b85..19ecf4e712 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -171,16 +171,13 @@ typedef struct
 #define DatumGetCircleP(X)	  ((CIRCLE *) DatumGetPointer(X))
 #define CirclePGetDatum(X)	  PointerGetDatum(X)
 #define PG_GETARG_CIRCLE_P(n) DatumGetCircleP(PG_GETARG_DATUM(n))
 #define PG_RETURN_CIRCLE_P(x) return CirclePGetDatum(x)
 
 
 /*
  * 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 */
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index 0e9e46e667..51dfd52a44 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -62,21 +62,23 @@ regress_dist_ptpath(PG_FUNCTION_ARGS)
 	float8		result = 0.0;	/* keep compiler quiet */
 	float8		tmp;
 	int			i;
 	LSEG		lseg;
 
 	switch (path->npts)
 	{
 		case 0:
 			PG_RETURN_NULL();
 		case 1:
-			result = point_dt(pt, &path->p[0]);
+			result = DatumGetFloat8(DirectFunctionCall2(point_distance,
+														PointPGetDatum(pt),
+												PointPGetDatum(&path->p[0])));
 			break;
 		default:
 
 			/*
 			 * the distance from a point to a path is the smallest distance
 			 * from the point to any of its constituent segments.
 			 */
 			Assert(path->npts > 1);
 			for (i = 0; i < path->npts - 1; ++i)
 			{
@@ -280,22 +282,27 @@ widget_out(PG_FUNCTION_ARGS)
 	PG_RETURN_CSTRING(str);
 }
 
 PG_FUNCTION_INFO_V1(pt_in_widget);
 
 Datum
 pt_in_widget(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	WIDGET	   *widget = (WIDGET *) PG_GETARG_POINTER(1);
+	float8		distance;
 
-	PG_RETURN_BOOL(point_dt(point, &widget->center) < widget->radius);
+	distance = DatumGetFloat8(DirectFunctionCall2(point_distance,
+												  PointPGetDatum(point),
+											PointPGetDatum(&widget->center)));
+
+	PG_RETURN_BOOL(distance < widget->radius);
 }
 
 PG_FUNCTION_INFO_V1(boxarea);
 
 Datum
 boxarea(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	double		width,
 				height;
-- 
2.13.6 (Apple Git-96)

0002-float-header-v10.patchapplication/octet-stream; name=0002-float-header-v10.patchDownload
From 8a98096915f65d97d22e7f027cb5ed96fd5a3061 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 28 May 2016 18:16:05 +0200
Subject: [PATCH 2/6] float-header-v10

Provide header file for built-in float datatypes

Even though, some datatypes under adt/ have separate header files,
most of the simple ones do not.  Their public functions were on
the builtins.h.  We would need to make more functions of floats public
to let the geometric types built on top of them.  This is a good
opportunity to make a separate header file for floats.

1acf7572554515b99ef6e783750aaea8777524ec made _cmp functions public
to solve NaN problem locally for GiST indexes.  This patch reworks it
in favour of a more extensive API.  Kevin Grittner suggested to design
the API using inline functions.  They are easier to use compared
to macros, and avoid double-evaluation hazards.
---
 contrib/btree_gin/btree_gin.c                 |   1 +
 contrib/btree_gist/btree_ts.c                 |   1 +
 contrib/cube/cube.c                           |   2 +-
 contrib/cube/cubeparse.y                      |   2 +-
 contrib/postgres_fdw/postgres_fdw.c           |   1 +
 src/backend/access/gist/gistget.c             |   2 +-
 src/backend/access/gist/gistproc.c            |  55 +--
 src/backend/access/gist/gistutil.c            |   2 +-
 src/backend/utils/adt/float.c                 | 589 ++++++--------------------
 src/backend/utils/adt/formatting.c            |   1 +
 src/backend/utils/adt/geo_ops.c               |   6 +-
 src/backend/utils/adt/geo_spgist.c            |   2 +-
 src/backend/utils/adt/numeric.c               |   1 +
 src/backend/utils/adt/rangetypes_gist.c       |   3 +-
 src/backend/utils/adt/rangetypes_selfuncs.c   |   3 +-
 src/backend/utils/adt/rangetypes_typanalyze.c |   3 +-
 src/backend/utils/adt/timestamp.c             |   1 +
 src/backend/utils/misc/guc.c                  |   1 +
 src/include/utils/builtins.h                  |  14 -
 src/include/utils/float.h                     | 376 ++++++++++++++++
 src/include/utils/geo_decls.h                 |   1 +
 21 files changed, 554 insertions(+), 513 deletions(-)
 create mode 100644 src/include/utils/float.h

diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index 2473f79ca1..301caefd47 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -3,20 +3,21 @@
  */
 #include "postgres.h"
 
 #include <limits.h>
 
 #include "access/stratnum.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/cash.h"
 #include "utils/date.h"
+#include "utils/float.h"
 #include "utils/inet.h"
 #include "utils/numeric.h"
 #include "utils/timestamp.h"
 #include "utils/varbit.h"
 
 PG_MODULE_MAGIC;
 
 typedef struct QueryInfo
 {
 	StrategyNumber strategy;
diff --git a/contrib/btree_gist/btree_ts.c b/contrib/btree_gist/btree_ts.c
index 18740cad38..49d1849d88 100644
--- a/contrib/btree_gist/btree_ts.c
+++ b/contrib/btree_gist/btree_ts.c
@@ -2,20 +2,21 @@
  * contrib/btree_gist/btree_ts.c
  */
 #include "postgres.h"
 
 #include <limits.h>
 
 #include "btree_gist.h"
 #include "btree_utils_num.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 typedef struct
 {
 	Timestamp	lower;
 	Timestamp	upper;
 } tsKEY;
 
 /*
 ** timestamp ops
 */
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c
index 3e3d83323c..ed41110a17 100644
--- a/contrib/cube/cube.c
+++ b/contrib/cube/cube.c
@@ -7,21 +7,21 @@
 ******************************************************************************/
 
 #include "postgres.h"
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 
 #include "cubedata.h"
 
 PG_MODULE_MAGIC;
 
 /*
  * Taken from the intarray contrib header
  */
 #define ARRPTR(x)  ( (double *) ARR_DATA_PTR(x) )
 #define ARRNELEMS(x)  ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x))
diff --git a/contrib/cube/cubeparse.y b/contrib/cube/cubeparse.y
index 1b65fa967c..deb2efdc0d 100644
--- a/contrib/cube/cubeparse.y
+++ b/contrib/cube/cubeparse.y
@@ -1,20 +1,20 @@
 %{
 /* contrib/cube/cubeparse.y */
 
 /* NdBox = [(lowerleft),(upperright)] */
 /* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */
 
 #include "postgres.h"
 
 #include "cubedata.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 
 /* All grammar constructs return strings */
 #define YYSTYPE char *
 
 /*
  * Bison doesn't allocate anything that needs to live across parser calls,
  * so we can easily have it use palloc instead of malloc.  This prevents
  * memory leaks if we error out during parsing.  Note this only works with
  * bison >= 2.0.  However, in bison 1.875 the default is to use alloca()
  * if possible, so there's not really much problem anyhow, at least if
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index fb65e2eb20..33bf0fe142 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -28,20 +28,21 @@
 #include "optimizer/cost.h"
 #include "optimizer/clauses.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
 #include "optimizer/planmain.h"
 #include "optimizer/restrictinfo.h"
 #include "optimizer/var.h"
 #include "optimizer/tlist.h"
 #include "parser/parsetree.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 #include "utils/sampling.h"
 #include "utils/selfuncs.h"
 
 PG_MODULE_MAGIC;
 
 /* Default CPU cost to start up a foreign query. */
diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c
index fb233a56d0..5a83dd4b76 100644
--- a/src/backend/access/gist/gistget.c
+++ b/src/backend/access/gist/gistget.c
@@ -13,21 +13,21 @@
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/gist_private.h"
 #include "access/relscan.h"
 #include "catalog/pg_type.h"
 #include "miscadmin.h"
 #include "pgstat.h"
 #include "lib/pairingheap.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 
 /*
  * gistkillitems() -- set LP_DEAD state for items an indexscan caller has
  * told us were killed.
  *
  * We re-read page here, so it's important to check page LSN. If the page
  * has been modified since the last read (as determined by LSN), we cannot
  * flag any entries because it is possible that the old entry was vacuumed
diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index 78f3107555..dc067d209d 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -27,62 +27,53 @@
 
 
 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
 						 StrategyNumber strategy);
 static bool rtree_internal_consistent(BOX *key, BOX *query,
 						  StrategyNumber strategy);
 
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
 
-/* Convenience macros for NaN-aware comparisons */
-#define FLOAT8_EQ(a,b)	(float8_cmp_internal(a, b) == 0)
-#define FLOAT8_LT(a,b)	(float8_cmp_internal(a, b) < 0)
-#define FLOAT8_LE(a,b)	(float8_cmp_internal(a, b) <= 0)
-#define FLOAT8_GT(a,b)	(float8_cmp_internal(a, b) > 0)
-#define FLOAT8_GE(a,b)	(float8_cmp_internal(a, b) >= 0)
-#define FLOAT8_MAX(a,b)  (FLOAT8_GT(a, b) ? (a) : (b))
-#define FLOAT8_MIN(a,b)  (FLOAT8_LT(a, b) ? (a) : (b))
-
 
 /**************************************************
  * Box ops
  **************************************************/
 
 /*
  * Calculates union of two boxes, a and b. The result is stored in *n.
  */
 static void
 rt_box_union(BOX *n, const BOX *a, const BOX *b)
 {
-	n->high.x = FLOAT8_MAX(a->high.x, b->high.x);
-	n->high.y = FLOAT8_MAX(a->high.y, b->high.y);
-	n->low.x = FLOAT8_MIN(a->low.x, b->low.x);
-	n->low.y = FLOAT8_MIN(a->low.y, b->low.y);
+	n->high.x = float8_max(a->high.x, b->high.x);
+	n->high.y = float8_max(a->high.y, b->high.y);
+	n->low.x = float8_min(a->low.x, b->low.x);
+	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
 static double
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
-	if (FLOAT8_LE(box->high.x, box->low.x) ||
-		FLOAT8_LE(box->high.y, box->low.y))
+	if (float8_le(box->high.x, box->low.x) ||
+		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
 	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
@@ -137,27 +128,27 @@ gist_box_consistent(PG_FUNCTION_ARGS)
 												 query,
 												 strategy));
 }
 
 /*
  * Increase BOX b to include addon.
  */
 static void
 adjustBox(BOX *b, const BOX *addon)
 {
-	if (FLOAT8_LT(b->high.x, addon->high.x))
+	if (float8_lt(b->high.x, addon->high.x))
 		b->high.x = addon->high.x;
-	if (FLOAT8_GT(b->low.x, addon->low.x))
+	if (float8_gt(b->low.x, addon->low.x))
 		b->low.x = addon->low.x;
-	if (FLOAT8_LT(b->high.y, addon->high.y))
+	if (float8_lt(b->high.y, addon->high.y))
 		b->high.y = addon->high.y;
-	if (FLOAT8_GT(b->low.y, addon->low.y))
+	if (float8_gt(b->low.y, addon->low.y))
 		b->low.y = addon->low.y;
 }
 
 /*
  * The GiST Union method for boxes
  *
  * returns the minimal bounding box that encloses all the entries in entryvec
  */
 Datum
 gist_box_union(PG_FUNCTION_ARGS)
@@ -609,36 +600,36 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		i1 = 0;
 		i2 = 0;
 		rightLower = intervalsLower[i1].lower;
 		leftUpper = intervalsUpper[i2].lower;
 		while (true)
 		{
 			/*
 			 * Find next lower bound of right group.
 			 */
 			while (i1 < nentries &&
-				   FLOAT8_EQ(rightLower, intervalsLower[i1].lower))
+				   float8_eq(rightLower, intervalsLower[i1].lower))
 			{
-				if (FLOAT8_LT(leftUpper, intervalsLower[i1].upper))
+				if (float8_lt(leftUpper, intervalsLower[i1].upper))
 					leftUpper = intervalsLower[i1].upper;
 				i1++;
 			}
 			if (i1 >= nentries)
 				break;
 			rightLower = intervalsLower[i1].lower;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * left group.
 			 */
 			while (i2 < nentries &&
-				   FLOAT8_LE(intervalsUpper[i2].upper, leftUpper))
+				   float8_le(intervalsUpper[i2].upper, leftUpper))
 				i2++;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim, rightLower, i1, leftUpper, i2);
 		}
 
 		/*
 		 * Iterate over upper bound of left group finding greatest possible
@@ -646,35 +637,35 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		 */
 		i1 = nentries - 1;
 		i2 = nentries - 1;
 		rightLower = intervalsLower[i1].upper;
 		leftUpper = intervalsUpper[i2].upper;
 		while (true)
 		{
 			/*
 			 * Find next upper bound of left group.
 			 */
-			while (i2 >= 0 && FLOAT8_EQ(leftUpper, intervalsUpper[i2].upper))
+			while (i2 >= 0 && float8_eq(leftUpper, intervalsUpper[i2].upper))
 			{
-				if (FLOAT8_GT(rightLower, intervalsUpper[i2].lower))
+				if (float8_gt(rightLower, intervalsUpper[i2].lower))
 					rightLower = intervalsUpper[i2].lower;
 				i2--;
 			}
 			if (i2 < 0)
 				break;
 			leftUpper = intervalsUpper[i2].upper;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * right group.
 			 */
-			while (i1 >= 0 && FLOAT8_GE(intervalsLower[i1].lower, rightLower))
+			while (i1 >= 0 && float8_ge(intervalsLower[i1].lower, rightLower))
 				i1--;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim,
 								 rightLower, i1 + 1, leftUpper, i2 + 1);
 		}
 	}
 
@@ -748,42 +739,42 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
 		}
 		else
 		{
 			lower = box->low.y;
 			upper = box->high.y;
 		}
 
-		if (FLOAT8_LE(upper, context.leftUpper))
+		if (float8_le(upper, context.leftUpper))
 		{
 			/* Fits to the left group */
-			if (FLOAT8_GE(lower, context.rightLower))
+			if (float8_ge(lower, context.rightLower))
 			{
 				/* Fits also to the right group, so "common entry" */
 				commonEntries[commonEntriesCount++].index = i;
 			}
 			else
 			{
 				/* Doesn't fit to the right group, so join to the left group */
 				PLACE_LEFT(box, i);
 			}
 		}
 		else
 		{
 			/*
 			 * Each entry should fit on either left or right group. Since this
 			 * entry didn't fit on the left group, it better fit in the right
 			 * group.
 			 */
-			Assert(FLOAT8_GE(lower, context.rightLower));
+			Assert(float8_ge(lower, context.rightLower));
 
 			/* Doesn't fit to the left group, so join to the right group */
 			PLACE_RIGHT(box, i);
 		}
 	}
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
@@ -853,24 +844,24 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
  * equivalent to box_same().
  */
 Datum
 gist_box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *b1 = PG_GETARG_BOX_P(0);
 	BOX		   *b2 = PG_GETARG_BOX_P(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
 	if (b1 && b2)
-		*result = (FLOAT8_EQ(b1->low.x, b2->low.x) &&
-				   FLOAT8_EQ(b1->low.y, b2->low.y) &&
-				   FLOAT8_EQ(b1->high.x, b2->high.x) &&
-				   FLOAT8_EQ(b1->high.y, b2->high.y));
+		*result = (float8_eq(b1->low.x, b2->low.x) &&
+				   float8_eq(b1->low.y, b2->low.y) &&
+				   float8_eq(b1->high.x, b2->high.x) &&
+				   float8_eq(b1->high.y, b2->high.y));
 	else
 		*result = (b1 == NULL && b2 == NULL);
 	PG_RETURN_POINTER(result);
 }
 
 /*
  * Leaf-level consistency for boxes: just apply the query operator
  */
 static bool
 gist_box_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy)
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index d8d1c0acfc..be7f8d066e 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -15,21 +15,21 @@
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist_private.h"
 #include "access/htup_details.h"
 #include "access/reloptions.h"
 #include "catalog/pg_opclass.h"
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/syscache.h"
 
 
 /*
  * Write itup vector to page, has no control of free space.
  */
 void
 gistfillbuffer(Page page, IndexTuple *itup, int len, OffsetNumber off)
 {
 	OffsetNumber l = InvalidOffsetNumber;
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index 18b3b949ac..dfd82bb80e 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -15,62 +15,29 @@
 #include "postgres.h"
 
 #include <ctype.h>
 #include <float.h>
 #include <math.h>
 #include <limits.h>
 
 #include "catalog/pg_type.h"
 #include "libpq/pqformat.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/sortsupport.h"
 
 
-#ifndef M_PI
-/* from my RH5.2 gcc math.h file - thomas 2000-04-03 */
-#define M_PI 3.14159265358979323846
-#endif
-
-/* Radians per degree, a.k.a. PI / 180 */
-#define RADIANS_PER_DEGREE 0.0174532925199432957692
-
-/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0.  NAN definition from
- * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfNotNumberNANItems.asp
- */
-#if defined(WIN32) && !defined(NAN)
-static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
-
-#define NAN (*(const double *) nan)
-#endif
-
 /* not sure what the following should be, but better to make it over-sufficient */
 #define MAXFLOATWIDTH	64
 #define MAXDOUBLEWIDTH	128
 
-/*
- * check to see if a float4/8 val has underflowed or overflowed
- */
-#define CHECKFLOATVAL(val, inf_is_valid, zero_is_valid)			\
-do {															\
-	if (isinf(val) && !(inf_is_valid))							\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		  errmsg("value out of range: overflow")));				\
-																\
-	if ((val) == 0.0 && !(zero_is_valid))						\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		 errmsg("value out of range: underflow")));				\
-} while(0)
-
-
 /* Configurable GUC parameter */
 int			extra_float_digits = 0; /* Added to DBL_DIG or FLT_DIG */
 
 /* Cached constants for degree-based trig functions */
 static bool degree_consts_set = false;
 static float8 sin_30 = 0;
 static float8 one_minus_cos_60 = 0;
 static float8 asin_0_5 = 0;
 static float8 acos_0_5 = 0;
 static float8 atan_1_0 = 0;
@@ -102,100 +69,20 @@ static void init_degree_constants(void);
  * their compilers spit up at the mismatch between extern declaration
  * and static definition.  We work around that here by the expedient
  * of a #define to make the actual name of the static function different.
  */
 #define cbrt my_cbrt
 static double cbrt(double x);
 #endif							/* HAVE_CBRT */
 
 
 /*
- * Routines to provide reasonably platform-independent handling of
- * infinity and NaN.  We assume that isinf() and isnan() are available
- * and work per spec.  (On some platforms, we have to supply our own;
- * see src/port.)  However, generating an Infinity or NaN in the first
- * place is less well standardized; pre-C99 systems tend not to have C99's
- * INFINITY and NAN macros.  We centralize our workarounds for this here.
- */
-
-double
-get_float8_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (double) INFINITY;
-#else
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (double) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-/*
-* The funny placements of the two #pragmas is necessary because of a
-* long lived bug in the Microsoft compilers.
-* See http://support.microsoft.com/kb/120968/en-us for details
-*/
-#if (_MSC_VER >= 1800)
-#pragma warning(disable:4756)
-#endif
-float
-get_float4_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (float) INFINITY;
-#else
-#if (_MSC_VER >= 1800)
-#pragma warning(default:4756)
-#endif
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (float) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-double
-get_float8_nan(void)
-{
-	/* (double) NAN doesn't work on some NetBSD/MIPS releases */
-#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
-	/* C99 standard way */
-	return (double) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (double) (0.0 / 0.0);
-#endif
-}
-
-float
-get_float4_nan(void)
-{
-#ifdef NAN
-	/* C99 standard way */
-	return (float) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (float) (0.0 / 0.0);
-#endif
-}
-
-
-/*
  * Returns -1 if 'val' represents negative infinity, 1 if 'val'
  * represents (positive) infinity, and 0 otherwise. On some platforms,
  * this is equivalent to the isinf() macro, but not everywhere: C99
  * does not specify that isinf() needs to distinguish between positive
  * and negative infinity.
  */
 int
 is_infinite(double val)
 {
 	int			inf = isinf(val);
@@ -339,21 +226,21 @@ float4in(PG_FUNCTION_ARGS)
 	if (*endptr != '\0')
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"real", orig_num)));
 
 	/*
 	 * if we get here, we have a legal double, still need to check to see if
 	 * it's a legal float4
 	 */
-	CHECKFLOATVAL((float4) val, isinf(val), val == 0);
+	check_float4_val((float4) val, isinf(val), val == 0);
 
 	PG_RETURN_FLOAT4((float4) val);
 }
 
 /*
  *		float4out		- converts a float4 number to a string
  *						  using a standard output format
  */
 Datum
 float4out(PG_FUNCTION_ARGS)
@@ -689,35 +576,35 @@ float4up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT4(arg);
 }
 
 Datum
 float4larger(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) > 0)
+	if (float4_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 Datum
 float4smaller(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) < 0)
+	if (float4_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 /*
  *		======================
  *		FLOAT8 BASE OPERATIONS
  *		======================
@@ -756,35 +643,35 @@ float8up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT8(arg);
 }
 
 Datum
 float8larger(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) > 0)
+	if (float8_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 Datum
 float8smaller(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) < 0)
+	if (float8_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		====================
  *		ARITHMETIC OPERATORS
@@ -795,234 +682,165 @@ float8smaller(PG_FUNCTION_ARGS)
  *		float4pl		- returns arg1 + arg2
  *		float4mi		- returns arg1 - arg2
  *		float4mul		- returns arg1 * arg2
  *		float4div		- returns arg1 / arg2
  */
 Datum
 float4pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 + arg2;
-
-	/*
-	 * There isn't any way to check for underflow of addition/subtraction
-	 * because numbers near the underflow value have already been rounded to
-	 * the point where we can't detect that the two values were originally
-	 * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
-	 * 1.4013e-45.
-	 */
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_pl(arg1, arg2));
 }
 
 Datum
 float4mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mi(arg1, arg2));
 }
 
 Datum
 float4mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mul(arg1, arg2));
 }
 
 Datum
 float4div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_div(arg1, arg2));
 }
 
 /*
  *		float8pl		- returns arg1 + arg2
  *		float8mi		- returns arg1 - arg2
  *		float8mul		- returns arg1 * arg2
  *		float8div		- returns arg1 / arg2
  */
 Datum
 float8pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 + arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, arg2));
 }
 
 Datum
 float8mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 - arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, arg2));
 }
 
 Datum
 float8mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 * arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, arg2));
 }
 
 Datum
 float8div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, arg2));
 }
 
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float4{eq,ne,lt,le,gt,ge}		- float4/float4 comparison operations
  */
 int
 float4_cmp_internal(float4 a, float4 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float4_gt(a, b))
+		return 1;
+	if (float4_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
 float4eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float4_eq(arg1, arg2));
 }
 
 Datum
 float4ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float4_ne(arg1, arg2));
 }
 
 Datum
 float4lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float4_lt(arg1, arg2));
 }
 
 Datum
 float4le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float4_le(arg1, arg2));
 }
 
 Datum
 float4gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float4_gt(arg1, arg2));
 }
 
 Datum
 float4ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float4_ge(arg1, arg2));
 }
 
 Datum
 btfloat4cmp(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
 	PG_RETURN_INT32(float4_cmp_internal(arg1, arg2));
 }
@@ -1044,99 +862,79 @@ btfloat4sortsupport(PG_FUNCTION_ARGS)
 	ssup->comparator = btfloat4fastcmp;
 	PG_RETURN_VOID();
 }
 
 /*
  *		float8{eq,ne,lt,le,gt,ge}		- float8/float8 comparison operations
  */
 int
 float8_cmp_internal(float8 a, float8 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float8_gt(a, b))
+		return 1;
+	if (float8_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
 float8eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, arg2));
 }
 
 Datum
 float8ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, arg2));
 }
 
 Datum
 float8lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, arg2));
 }
 
 Datum
 float8le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, arg2));
 }
 
 Datum
 float8gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, arg2));
 }
 
 Datum
 float8ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, arg2));
 }
 
 Datum
 btfloat8cmp(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
 	PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
 }
@@ -1199,21 +997,21 @@ ftod(PG_FUNCTION_ARGS)
 
 
 /*
  *		dtof			- converts a float8 number to a float4 number
  */
 Datum
 dtof(PG_FUNCTION_ARGS)
 {
 	float8		num = PG_GETARG_FLOAT8(0);
 
-	CHECKFLOATVAL((float4) num, isinf(num), num == 0);
+	check_float4_val((float4) num, isinf(num), num == 0);
 
 	PG_RETURN_FLOAT4((float4) num);
 }
 
 
 /*
  *		dtoi4			- converts a float8 number to an int4 number
  */
 Datum
 dtoi4(PG_FUNCTION_ARGS)
@@ -1424,36 +1222,36 @@ dsqrt(PG_FUNCTION_ARGS)
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
 				 errmsg("cannot take square root of a negative number")));
 
 	result = sqrt(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcbrt			- returns cube root of arg1
  */
 Datum
 dcbrt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	result = cbrt(arg1);
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dpow			- returns pow(arg1,arg2)
  */
 Datum
 dpow(PG_FUNCTION_ARGS)
 {
@@ -1492,40 +1290,40 @@ dpow(PG_FUNCTION_ARGS)
 			/* The sign of Inf is not significant in this case. */
 			result = get_float8_infinity();
 		else if (fabs(arg1) != 1)
 			result = 0;
 		else
 			result = 1;
 	}
 	else if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
+	check_float8_val(result, isinf(arg1) || isinf(arg2), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dexp			- returns the exponential function of arg1
  */
 Datum
 dexp(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	errno = 0;
 	result = exp(arg1);
 	if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1), false);
+	check_float8_val(result, isinf(arg1), false);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dlog1			- returns the natural logarithm of arg1
  */
 Datum
 dlog1(PG_FUNCTION_ARGS)
 {
@@ -1540,21 +1338,21 @@ dlog1(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of zero")));
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of a negative number")));
 
 	result = log(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dlog10			- returns the base 10 logarithm of arg1
  */
 Datum
 dlog10(PG_FUNCTION_ARGS)
 {
@@ -1570,21 +1368,21 @@ dlog10(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of zero")));
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of a negative number")));
 
 	result = log10(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dacos			- returns the arccos of arg1 (radians)
  */
 Datum
 dacos(PG_FUNCTION_ARGS)
 {
@@ -1600,21 +1398,21 @@ dacos(PG_FUNCTION_ARGS)
 	 * range [-1, 1] to values in the range [0, Pi], so we should reject any
 	 * inputs outside that range and the result will always be finite.
 	 */
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = acos(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dasin			- returns the arcsin of arg1 (radians)
  */
 Datum
 dasin(PG_FUNCTION_ARGS)
 {
@@ -1630,21 +1428,21 @@ dasin(PG_FUNCTION_ARGS)
 	 * range [-1, 1] to values in the range [-Pi/2, Pi/2], so we should reject
 	 * any inputs outside that range and the result will always be finite.
 	 */
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = asin(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		datan			- returns the arctan of arg1 (radians)
  */
 Datum
 datan(PG_FUNCTION_ARGS)
 {
@@ -1655,21 +1453,21 @@ datan(PG_FUNCTION_ARGS)
 	if (isnan(arg1))
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/*
 	 * The principal branch of the inverse tangent function maps all inputs to
 	 * values in the range [-Pi/2, Pi/2], so the result should always be
 	 * finite, even if the input is infinite.
 	 */
 	result = atan(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		atan2			- returns the arctan of arg1/arg2 (radians)
  */
 Datum
 datan2(PG_FUNCTION_ARGS)
 {
@@ -1680,21 +1478,21 @@ datan2(PG_FUNCTION_ARGS)
 	/* Per the POSIX spec, return NaN if either input is NaN */
 	if (isnan(arg1) || isnan(arg2))
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/*
 	 * atan2 maps all inputs to values in the range [-Pi, Pi], so the result
 	 * should always be finite, even if the inputs are infinite.
 	 */
 	result = atan2(arg1, arg2);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcos			- returns the cosine of arg1 (radians)
  */
 Datum
 dcos(PG_FUNCTION_ARGS)
 {
@@ -1720,21 +1518,21 @@ dcos(PG_FUNCTION_ARGS)
 	 * platform reports via errno, so also explicitly test for infinite
 	 * inputs.
 	 */
 	errno = 0;
 	result = cos(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcot			- returns the cotangent of arg1 (radians)
  */
 Datum
 dcot(PG_FUNCTION_ARGS)
 {
@@ -1747,21 +1545,21 @@ dcot(PG_FUNCTION_ARGS)
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = tan(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = 1.0 / result;
-	CHECKFLOATVAL(result, true /* cot(0) == Inf */ , true);
+	check_float8_val(result, true /* cot(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dsin			- returns the sine of arg1 (radians)
  */
 Datum
 dsin(PG_FUNCTION_ARGS)
 {
@@ -1773,21 +1571,21 @@ dsin(PG_FUNCTION_ARGS)
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = sin(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dtan			- returns the tangent of arg1 (radians)
  */
 Datum
 dtan(PG_FUNCTION_ARGS)
 {
@@ -1799,21 +1597,21 @@ dtan(PG_FUNCTION_ARGS)
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = tan(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, true /* tan(pi/2) == Inf */ , true);
+	check_float8_val(result, true /* tan(pi/2) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /* ========== DEGREE-BASED TRIGONOMETRIC FUNCTIONS ========== */
 
 
 /*
  * Initialize the cached constants declared at the head of this file
  * (sin_30 etc).  The fact that we need those at all, let alone need this
@@ -1951,21 +1749,21 @@ dacosd(PG_FUNCTION_ARGS)
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	if (arg1 >= 0.0)
 		result = acosd_q1(arg1);
 	else
 		result = 90.0 + asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dasind			- returns the arcsin of arg1 (degrees)
  */
 Datum
 dasind(PG_FUNCTION_ARGS)
 {
@@ -1986,21 +1784,21 @@ dasind(PG_FUNCTION_ARGS)
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	if (arg1 >= 0.0)
 		result = asind_q1(arg1);
 	else
 		result = -asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		datand			- returns the arctan of arg1 (degrees)
  */
 Datum
 datand(PG_FUNCTION_ARGS)
 {
@@ -2016,21 +1814,21 @@ datand(PG_FUNCTION_ARGS)
 
 	/*
 	 * The principal branch of the inverse tangent function maps all inputs to
 	 * values in the range [-90, 90], so the result should always be finite,
 	 * even if the input is infinite.  Additionally, we take care to ensure
 	 * than when arg1 is 1, the result is exactly 45.
 	 */
 	atan_arg1 = atan(arg1);
 	result = (atan_arg1 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		atan2d			- returns the arctan of arg1/arg2 (degrees)
  */
 Datum
 datan2d(PG_FUNCTION_ARGS)
 {
@@ -2050,21 +1848,21 @@ datan2d(PG_FUNCTION_ARGS)
 	 * result should always be finite, even if the inputs are infinite.
 	 *
 	 * Note: this coding assumes that atan(1.0) is a suitable scaling constant
 	 * to get an exact result from atan2().  This might well fail on us at
 	 * some point, requiring us to decide exactly what inputs we think we're
 	 * going to guarantee an exact result for.
 	 */
 	atan2_arg1_arg2 = atan2(arg1, arg2);
 	result = (atan2_arg1_arg2 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		sind_0_to_30	- returns the sine of an angle that lies between 0 and
  *						  30 degrees.  This will return exactly 0 when x is 0,
  *						  and exactly 0.5 when x is 30 degrees.
  */
 static double
@@ -2171,21 +1969,21 @@ dcosd(PG_FUNCTION_ARGS)
 
 	if (arg1 > 90.0)
 	{
 		/* cosd(180-x) = -cosd(x) */
 		arg1 = 180.0 - arg1;
 		sign = -sign;
 	}
 
 	result = sign * cosd_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcotd			- returns the cotangent of arg1 (degrees)
  */
 Datum
 dcotd(PG_FUNCTION_ARGS)
 {
@@ -2236,21 +2034,21 @@ dcotd(PG_FUNCTION_ARGS)
 	result = sign * (cot_arg1 / cot_45);
 
 	/*
 	 * On some machines we get cotd(270) = minus zero, but this isn't always
 	 * true.  For portability, and because the user constituency for this
 	 * function probably doesn't want minus zero, force it to plain zero.
 	 */
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* cotd(0) == Inf */ , true);
+	check_float8_val(result, true /* cotd(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dsind			- returns the sine of arg1 (degrees)
  */
 Datum
 dsind(PG_FUNCTION_ARGS)
 {
@@ -2290,21 +2088,21 @@ dsind(PG_FUNCTION_ARGS)
 	}
 
 	if (arg1 > 90.0)
 	{
 		/* sind(180-x) = sind(x) */
 		arg1 = 180.0 - arg1;
 	}
 
 	result = sign * sind_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dtand			- returns the tangent of arg1 (degrees)
  */
 Datum
 dtand(PG_FUNCTION_ARGS)
 {
@@ -2355,64 +2153,56 @@ dtand(PG_FUNCTION_ARGS)
 	result = sign * (tan_arg1 / tan_45);
 
 	/*
 	 * On some machines we get tand(180) = minus zero, but this isn't always
 	 * true.  For portability, and because the user constituency for this
 	 * function probably doesn't want minus zero, force it to plain zero.
 	 */
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* tand(90) == Inf */ , true);
+	check_float8_val(result, true /* tand(90) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		degrees		- returns degrees converted from radians
  */
 Datum
 degrees(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
 
-	result = arg1 / RADIANS_PER_DEGREE;
-
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, RADIANS_PER_DEGREE));
 }
 
 
 /*
  *		dpi				- returns the constant PI
  */
 Datum
 dpi(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_FLOAT8(M_PI);
 }
 
 
 /*
  *		radians		- returns radians converted from degrees
  */
 Datum
 radians(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
 
-	result = arg1 * RADIANS_PER_DEGREE;
-
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, RADIANS_PER_DEGREE));
 }
 
 
 /*
  *		drandom		- returns a random number
  */
 Datum
 drandom(PG_FUNCTION_ARGS)
 {
 	float8		result;
@@ -2490,144 +2280,105 @@ check_float8_array(ArrayType *transarray, const char *caller, int n)
  * This function is used only in two stage aggregation and
  * shouldn't be called outside aggregate context.
  */
 Datum
 float8_combine(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_combine", 3);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-
 	transvalues2 = check_float8_array(transarray2, "float8_combine", 3);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
 
 Datum
 float8_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8		newval = PG_GETARG_FLOAT8(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float8_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
 	else
 	{
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
 								 sizeof(float8), FLOAT8PASSBYVAL, 'd');
 
 		PG_RETURN_ARRAYTYPE_P(result);
 	}
 }
 
 Datum
 float4_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 
 	/* do computations as float8 */
 	float8		newval = PG_GETARG_FLOAT4(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float4_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
 	else
 	{
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
 								 sizeof(float8), FLOAT8PASSBYVAL, 'd');
 
 		PG_RETURN_ARRAYTYPE_P(result);
 	}
 }
 
 Datum
@@ -2663,21 +2414,21 @@ float8_var_pop(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_var_pop", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Population variance is undefined when N is 0, so return NULL */
 	if (N == 0.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / (N * N));
 }
 
 Datum
 float8_var_samp(PG_FUNCTION_ARGS)
@@ -2692,21 +2443,21 @@ float8_var_samp(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_var_samp", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Sample variance is undefined when N is 0 or 1, so return NULL */
 	if (N <= 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
 }
 
 Datum
 float8_stddev_pop(PG_FUNCTION_ARGS)
@@ -2721,21 +2472,21 @@ float8_stddev_pop(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_stddev_pop", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Population stddev is undefined when N is 0, so return NULL */
 	if (N == 0.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(sqrt(numerator / (N * N)));
 }
 
 Datum
 float8_stddev_samp(PG_FUNCTION_ARGS)
@@ -2750,21 +2501,21 @@ float8_stddev_samp(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_stddev_samp", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Sample stddev is undefined when N is 0 or 1, so return NULL */
 	if (N <= 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(sqrt(numerator / (N * (N - 1.0))));
 }
 
 /*
  *		=========================
@@ -2799,30 +2550,30 @@ float8_regr_accum(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_accum", 6);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	N += 1.0;
 	sumX += newvalX;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
+	check_float8_val(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
 	sumX2 += newvalX * newvalX;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
+	check_float8_val(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
 	sumY += newvalY;
-	CHECKFLOATVAL(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
+	check_float8_val(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
 	sumY2 += newvalY * newvalY;
-	CHECKFLOATVAL(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
+	check_float8_val(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
 	sumXY += newvalX * newvalY;
-	CHECKFLOATVAL(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
-				  isinf(newvalY), true);
+	check_float8_val(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
+					 isinf(newvalY), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
 		transvalues[0] = N;
 		transvalues[1] = sumX;
@@ -2861,63 +2612,33 @@ float8_regr_accum(PG_FUNCTION_ARGS)
  * This function is used only in two stage aggregation and
  * shouldn't be called outside aggregate context.
  */
 Datum
 float8_regr_combine(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2,
-				sumY,
-				sumY2,
-				sumXY;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_regr_combine", 6);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-	sumY = transvalues1[3];
-	sumY2 = transvalues1[4];
-	sumXY = transvalues1[5];
-
 	transvalues2 = check_float8_array(transarray2, "float8_regr_combine", 6);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-	sumY += transvalues2[3];
-	CHECKFLOATVAL(sumY, isinf(transvalues1[3]) || isinf(transvalues2[3]),
-				  true);
-	sumY2 += transvalues2[4];
-	CHECKFLOATVAL(sumY2, isinf(transvalues1[4]) || isinf(transvalues2[4]),
-				  true);
-	sumXY += transvalues2[5];
-	CHECKFLOATVAL(sumXY, isinf(transvalues1[5]) || isinf(transvalues2[5]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
-	transvalues1[3] = sumY;
-	transvalues1[4] = sumY2;
-	transvalues1[5] = sumXY;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
+	transvalues1[3] = float8_pl(transvalues1[3], transvalues2[3]);
+	transvalues1[4] = float8_pl(transvalues1[4], transvalues2[4]);
+	transvalues1[5] = float8_pl(transvalues1[5], transvalues2[5]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
 
 
 Datum
 float8_regr_sxx(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
@@ -2929,21 +2650,21 @@ float8_regr_sxx(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_sxx", 6);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_syy(PG_FUNCTION_ARGS)
@@ -2958,21 +2679,21 @@ float8_regr_syy(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_syy", 6);
 	N = transvalues[0];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumY2) || isinf(sumY), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_sxy(PG_FUNCTION_ARGS)
@@ -2989,22 +2710,22 @@ float8_regr_sxy(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	/* A negative result is valid here */
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_avgx(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3057,22 +2778,22 @@ float8_covar_pop(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * N));
 }
 
 Datum
 float8_covar_samp(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
 	float8		N,
@@ -3085,22 +2806,22 @@ float8_covar_samp(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is <= 1 we should return NULL */
 	if (N < 2.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
 }
 
 Datum
 float8_corr(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
 	float8		N,
@@ -3119,26 +2840,26 @@ float8_corr(PG_FUNCTION_ARGS)
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0 || numeratorY <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXY / sqrt(numeratorX * numeratorY));
 }
 
 Datum
 float8_regr_r2(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3159,26 +2880,26 @@ float8_regr_r2(PG_FUNCTION_ARGS)
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 	/* per spec, horizontal line produces 1.0 */
 	if (numeratorY <= 0)
 		PG_RETURN_FLOAT8(1.0);
 
 	PG_RETURN_FLOAT8((numeratorXY * numeratorXY) /
 					 (numeratorX * numeratorY));
 }
 
@@ -3200,24 +2921,24 @@ float8_regr_slope(PG_FUNCTION_ARGS)
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXY / numeratorX);
 }
 
 Datum
 float8_regr_intercept(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3235,24 +2956,24 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXXY = sumY * sumX2 - sumX * sumXY;
-	CHECKFLOATVAL(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
-				  isinf(sumX) || isinf(sumXY), true);
+	check_float8_val(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
+					 isinf(sumX) || isinf(sumXY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXXY / numeratorX);
 }
 
 
 /*
  *		====================================
  *		MIXED-PRECISION ARITHMETIC OPERATORS
@@ -3263,251 +2984,211 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
  *		float48pl		- returns arg1 + arg2
  *		float48mi		- returns arg1 - arg2
  *		float48mul		- returns arg1 * arg2
  *		float48div		- returns arg1 / arg2
  */
 Datum
 float48pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 + arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl((float8) arg1, arg2));
 }
 
 Datum
 float48mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi((float8) arg1, arg2));
 }
 
 Datum
 float48mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul((float8) arg1, arg2));
 }
 
 Datum
 float48div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div((float8) arg1, arg2));
 }
 
 /*
  *		float84pl		- returns arg1 + arg2
  *		float84mi		- returns arg1 - arg2
  *		float84mul		- returns arg1 * arg2
  *		float84div		- returns arg1 / arg2
  */
 Datum
 float84pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 + arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, (float8) arg2));
 }
 
 Datum
 float84mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 - arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, (float8) arg2));
 }
 
 Datum
 float84mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 * arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, (float8) arg2));
 }
 
 Datum
 float84div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, (float8) arg2));
 }
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float48{eq,ne,lt,le,gt,ge}		- float4/float8 comparison operations
  */
 Datum
 float48eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq((float8) arg1, arg2));
 }
 
 Datum
 float48ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne((float8) arg1, arg2));
 }
 
 Datum
 float48lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt((float8) arg1, arg2));
 }
 
 Datum
 float48le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le((float8) arg1, arg2));
 }
 
 Datum
 float48gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt((float8) arg1, arg2));
 }
 
 Datum
 float48ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge((float8) arg1, arg2));
 }
 
 /*
  *		float84{eq,ne,lt,le,gt,ge}		- float8/float4 comparison operations
  */
 Datum
 float84eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, (float8) arg2));
 }
 
 Datum
 float84ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, (float8) arg2));
 }
 
 Datum
 float84lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, (float8) arg2));
 }
 
 Datum
 float84le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, (float8) arg2));
 }
 
 Datum
 float84gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, (float8) arg2));
 }
 
 Datum
 float84ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, (float8) arg2));
 }
 
 /*
  * Implements the float8 version of the width_bucket() function
  * defined by SQL2003. See also width_bucket_numeric().
  *
  * 'bound1' and 'bound2' are the lower and upper bounds of the
  * histogram's range, respectively. 'count' is the number of buckets
  * in the histogram. width_bucket() returns an integer indicating the
  * bucket number that 'operand' belongs to in an equiwidth histogram
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c
index ec97de0ad2..b282839591 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -84,20 +84,21 @@
 
 #ifdef USE_ICU
 #include <unicode/ustring.h>
 #endif
 
 #include "catalog/pg_collation.h"
 #include "mb/pg_wchar.h"
 #include "utils/builtins.h"
 #include "utils/date.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 #include "utils/formatting.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/pg_locale.h"
 
 /* ----------
  * Routines type
  * ----------
  */
 #define DCH_TYPE		1		/* DATE-TIME version	*/
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 46ac24e740..a4fa4d6792 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -14,27 +14,23 @@
  */
 #include "postgres.h"
 
 #include <math.h>
 #include <limits.h>
 #include <float.h>
 #include <ctype.h>
 
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
-#include "utils/builtins.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index f6334bae14..c800bb1338 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -69,21 +69,21 @@
  *			src/backend/utils/adt/geo_spgist.c
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
 
 #include "access/spgist.h"
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
  * is going only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 82e6f4483b..534347558b 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -28,20 +28,21 @@
 
 #include "access/hash.h"
 #include "catalog/pg_type.h"
 #include "funcapi.h"
 #include "lib/hyperloglog.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/sortsupport.h"
 
 /* ----------
  * Uncomment the following to enable compilation of dump_numeric()
  * and dump_var() and to get a dump of any result produced by make_result().
  * ----------
 #define NUMERIC_DEBUG
diff --git a/src/backend/utils/adt/rangetypes_gist.c b/src/backend/utils/adt/rangetypes_gist.c
index 29fa1ae325..d8c1525acc 100644
--- a/src/backend/utils/adt/rangetypes_gist.c
+++ b/src/backend/utils/adt/rangetypes_gist.c
@@ -9,21 +9,22 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_gist.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/gist.h"
 #include "access/stratnum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/datum.h"
 #include "utils/rangetypes.h"
 
 
 /*
  * Range class properties used to segregate different classes of ranges in
  * GiST.  Each unique combination of properties is a class.  CLS_EMPTY cannot
  * be combined with anything else.
  */
 #define CLS_NORMAL			0	/* Ordinary finite range (no bits set) */
diff --git a/src/backend/utils/adt/rangetypes_selfuncs.c b/src/backend/utils/adt/rangetypes_selfuncs.c
index cba8974dbe..97308aea9a 100644
--- a/src/backend/utils/adt/rangetypes_selfuncs.c
+++ b/src/backend/utils/adt/rangetypes_selfuncs.c
@@ -14,21 +14,22 @@
  *	  src/backend/utils/adt/rangetypes_selfuncs.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/htup_details.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 #include "utils/selfuncs.h"
 #include "utils/typcache.h"
 
 static double calc_rangesel(TypeCacheEntry *typcache, VariableStatData *vardata,
 			  RangeType *constval, Oid operator);
 static double default_range_selectivity(Oid operator);
 static double calc_hist_selectivity(TypeCacheEntry *typcache,
 					  VariableStatData *vardata, RangeType *constval,
diff --git a/src/backend/utils/adt/rangetypes_typanalyze.c b/src/backend/utils/adt/rangetypes_typanalyze.c
index 3efd982d1b..8a7ad4f3f7 100644
--- a/src/backend/utils/adt/rangetypes_typanalyze.c
+++ b/src/backend/utils/adt/rangetypes_typanalyze.c
@@ -19,21 +19,22 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_typanalyze.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "catalog/pg_operator.h"
 #include "commands/vacuum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 
 static int	float8_qsort_cmp(const void *a1, const void *a2);
 static int	range_bound_qsort_cmp(const void *a1, const void *a2, void *arg);
 static void compute_range_stats(VacAttrStats *stats,
 					AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows);
 
 /*
  * range_typanalyze -- typanalyze function for range columns
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 5797aaad34..74a2ef55ec 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -27,20 +27,21 @@
 #include "common/int128.h"
 #include "funcapi.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
 #include "parser/scansup.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 /*
  * gcc's -ffast-math switch breaks routines that expect exact results from
  * expressions like timeval / SECS_PER_HOUR, where timeval is double.
  */
 #ifdef __FAST_MATH__
 #error -ffast-math is known to break this code
 #endif
 
 #define SAMESIGN(a,b)	(((a) < 0) == ((b) < 0))
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 6dcd738be6..0443e839ba 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -72,20 +72,21 @@
 #include "storage/fd.h"
 #include "storage/large_object.h"
 #include "storage/pg_shmem.h"
 #include "storage/proc.h"
 #include "storage/predicate.h"
 #include "tcop/tcopprot.h"
 #include "tsearch/ts_cache.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/guc_tables.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/pg_locale.h"
 #include "utils/plancache.h"
 #include "utils/portal.h"
 #include "utils/ps_status.h"
 #include "utils/rls.h"
 #include "utils/snapmgr.h"
 #include "utils/tzparser.h"
 #include "utils/varlena.h"
 #include "utils/xml.h"
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 762532f636..668e037737 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -43,34 +43,20 @@ extern int	namestrcmp(Name name, const char *str);
 
 /* numutils.c */
 extern int32 pg_atoi(const char *s, int size, int c);
 extern void pg_itoa(int16 i, char *a);
 extern void pg_ltoa(int32 l, char *a);
 extern void pg_lltoa(int64 ll, char *a);
 extern char *pg_ltostr_zeropad(char *str, int32 value, int32 minwidth);
 extern char *pg_ltostr(char *str, int32 value);
 extern uint64 pg_strtouint64(const char *str, char **endptr, int base);
 
-/* float.c */
-extern PGDLLIMPORT int extra_float_digits;
-
-extern double get_float8_infinity(void);
-extern float get_float4_infinity(void);
-extern double get_float8_nan(void);
-extern float get_float4_nan(void);
-extern int	is_infinite(double val);
-extern double float8in_internal(char *num, char **endptr_p,
-				  const char *type_name, const char *orig_string);
-extern char *float8out_internal(double num);
-extern int	float4_cmp_internal(float4 a, float4 b);
-extern int	float8_cmp_internal(float8 a, float8 b);
-
 /* oid.c */
 extern oidvector *buildoidvector(const Oid *oids, int n);
 extern Oid	oidparse(Node *node);
 extern int	oid_cmp(const void *p1, const void *p2);
 
 /* regexp.c */
 extern char *regexp_fixed_prefix(text *text_re, bool case_insensitive,
 					Oid collation, bool *exact);
 
 /* ruleutils.c */
diff --git a/src/include/utils/float.h b/src/include/utils/float.h
new file mode 100644
index 0000000000..c9f5fd30ca
--- /dev/null
+++ b/src/include/utils/float.h
@@ -0,0 +1,376 @@
+/*-------------------------------------------------------------------------
+ *
+ * float.h
+ *	  Definitions for the built-in floating-point types
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/include/utils/float.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef FLOAT_H
+#define FLOAT_H
+
+#include <math.h>
+
+#ifndef M_PI
+/* From my RH5.2 gcc math.h file - thomas 2000-04-03 */
+#define M_PI 3.14159265358979323846
+#endif
+
+/* Radians per degree, a.k.a. PI / 180 */
+#define RADIANS_PER_DEGREE 0.0174532925199432957692
+
+/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0.  NAN definition from
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfNotNumberNANItems.asp
+ */
+#if defined(WIN32) && !defined(NAN)
+static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
+
+#define NAN (*(const float8 *) nan)
+#endif
+
+extern PGDLLIMPORT int extra_float_digits;
+
+/*
+ * Utility functions in float.c
+ */
+extern int	is_infinite(float8 val);
+extern float8 float8in_internal(char *num, char **endptr_p,
+				  const char *type_name, const char *orig_string);
+extern char *float8out_internal(float8 num);
+extern int	float4_cmp_internal(float4 a, float4 b);
+extern int	float8_cmp_internal(float8 a, float8 b);
+
+/*
+ * Routines to provide reasonably platform-independent handling of
+ * infinity and NaN
+ *
+ * We assume that isinf() and isnan() are available and work per spec.
+ * (On some platforms, we have to supply our own; see src/port.)  However,
+ * generating an Infinity or NaN in the first place is less well standardized;
+ * pre-C99 systems tend not to have C99's INFINITY and NAN macros.  We
+ * centralize our workarounds for this here.
+ */
+
+/*
+ * The funny placements of the two #pragmas is necessary because of a
+ * long lived bug in the Microsoft compilers.
+ * See http://support.microsoft.com/kb/120968/en-us for details
+ */
+#if (_MSC_VER >= 1800)
+#pragma warning(disable:4756)
+#endif
+static inline float
+get_float4_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float) INFINITY;
+#else
+#if (_MSC_VER >= 1800)
+#pragma warning(default:4756)
+#endif
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float8
+get_float8_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float8) INFINITY;
+#else
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float8) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float4
+get_float4_nan(void)
+{
+#ifdef NAN
+	/* C99 standard way */
+	return (float) NAN;
+#else
+	/* Assume we can get a NAN via zero divide */
+	return (float) (0.0 / 0.0);
+#endif
+}
+
+static inline float8
+get_float8_nan(void)
+{
+	/* (float8) NAN doesn't work on some NetBSD/MIPS releases */
+#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
+	/* C99 standard way */
+	return (float8) NAN;
+#else
+	/* Assume we can get a NAN via zero divide */
+	return (float8) (0.0 / 0.0);
+#endif
+}
+
+/*
+ * Checks to see if a float4/8 val has underflowed or overflowed
+ */
+
+static inline void
+check_float4_val(float4 val, bool inf_is_valid, bool zero_is_valid)
+{
+	if (isinf(val) && !inf_is_valid)
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if (val == 0.0 && !zero_is_valid)
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+static inline void
+check_float8_val(float8 val, bool inf_is_valid, bool zero_is_valid)
+{
+	if (isinf(val) && !inf_is_valid)
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if (val == 0.0 && !zero_is_valid)
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+/*
+ * Routines for operations with the checks above
+ *
+ * There isn't any way to check for underflow of addition/subtraction
+ * because numbers near the underflow value have already been rounded to
+ * the point where we can't detect that the two values were originally
+ * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
+ * 1.4013e-45.
+ */
+
+static inline float4
+float4_pl(float4 val1, float4 val2)
+{
+	float4		result;
+
+	result = val1 + val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_pl(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = val1 + val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mi(float4 val1, float4 val2)
+{
+	float4		result;
+
+	result = val1 - val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_mi(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = val1 - val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mul(float4 val1, float4 val2)
+{
+	float4		result;
+
+	result = val1 * val2;
+	check_float4_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0f || val2 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_mul(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = val1 * val2;
+	check_float8_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0 || val2 == 0.0);
+
+	return result;
+}
+
+static inline float4
+float4_div(float4 val1, float4 val2)
+{
+	float4		result;
+
+	if (val2 == 0.0f)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), val1 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_div(float8 val1, float8 val2)
+{
+	float8		result;
+
+	if (val2 == 0.0)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
+
+	return result;
+}
+
+/*
+ * Routines for NaN-aware comparisons
+ *
+ * We consider all NANs to be equal and larger than any non-NAN. This is
+ * somewhat arbitrary; the important thing is to have a consistent sort
+ * order.
+ */
+
+static inline bool
+float4_eq(float4 val1, float4 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float8_eq(float8 val1, float8 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float4_ne(float4 val1, float4 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float8_ne(float8 val1, float8 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float4_lt(float4 val1, float4 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float8_lt(float8 val1, float8 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float4_le(float4 val1, float4 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float8_le(float8 val1, float8 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float4_gt(float4 val1, float4 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float8_gt(float8 val1, float8 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float4_ge(float4 val1, float4 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline bool
+float8_ge(float8 val1, float8 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline float4
+float4_min(float4 val1, float4 val2)
+{
+	return float4_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_min(float8 val1, float8 val2)
+{
+	return float8_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float4
+float4_max(float4 val1, float4 val2)
+{
+	return float4_gt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_max(float8 val1, float8 val2)
+{
+	return float8_gt(val1, val2) ? val1 : val2;
+}
+
+#endif							/* FLOAT_H */
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 19ecf4e712..ea2e3690ea 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -17,20 +17,21 @@
  *		and data types. There are still some more to do. - tgl 97/04/19
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEO_DECLS_H
 #define GEO_DECLS_H
 
 #include <math.h>
 
 #include "fmgr.h"
+#include "utils/float.h"
 
 /*--------------------------------------------------------------------
  * Useful floating point utilities and constants.
  *-------------------------------------------------------------------*/
 
 
 #define EPSILON					1.0E-06
 
 #ifdef EPSILON
 #define FPzero(A)				(fabs(A) <= EPSILON)
-- 
2.13.6 (Apple Git-96)

0003-geo-float-v07.patchapplication/octet-stream; name=0003-geo-float-v07.patchDownload
From 3c88809c3c13ad61d27765873dba941bdcf90f28 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 27 May 2017 16:17:42 -0400
Subject: [PATCH 3/6] geo-float-v07

Use the built-in float datatype to implement geometric types

The changes can be summarised as:

* Check for underflow and overflow
* Check for division by zero
* Let the objects with NaN values to be the same
* Return NULL when the distance is NaN for all closest point operators
* Don't round the slope to DBL_MAX
* Use NaN as the slope of two equal points
* Favour not-NaN over NaN where it makes sense

The patch also replaces all occurrences of "double" as "float8".  They
are the same, but were randomly spread on the same file.
---
 src/backend/access/gist/gistproc.c |  91 +++----
 src/backend/utils/adt/geo_ops.c    | 494 ++++++++++++++++++++-----------------
 src/backend/utils/adt/geo_spgist.c |  28 +--
 src/include/utils/geo_decls.h      |  17 +-
 4 files changed, 331 insertions(+), 299 deletions(-)

diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index dc067d209d..7fc50d4a79 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -16,20 +16,21 @@
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/geo_decls.h"
 
 
 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
 						 StrategyNumber strategy);
 static bool rtree_internal_consistent(BOX *key, BOX *query,
 						  StrategyNumber strategy);
 
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
@@ -48,55 +49,56 @@ rt_box_union(BOX *n, const BOX *a, const BOX *b)
 	n->high.x = float8_max(a->high.x, b->high.x);
 	n->high.y = float8_max(a->high.y, b->high.y);
 	n->low.x = float8_min(a->low.x, b->low.x);
 	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
 	if (float8_le(box->high.x, box->low.x) ||
 		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
-	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
+	return float8_mul(float8_mi(box->high.x, box->low.x),
+					  float8_mi(box->high.y, box->low.y));
 }
 
 /*
  * Return amount by which the union of the two boxes is larger than
  * the original BOX's area.  The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 box_penalty(const BOX *original, const BOX *new)
 {
 	BOX			unionbox;
 
 	rt_box_union(&unionbox, original, new);
-	return size_box(&unionbox) - size_box(original);
+	return float8_mi(size_box(&unionbox), size_box(original));
 }
 
 /*
  * The GiST Consistent method for boxes
  *
  * Should return false if for all data items x below entry,
  * the predicate x op query must be false, where op is the oper
  * corresponding to strategy in the pg_amop table.
  */
 Datum
@@ -256,74 +258,74 @@ fallbackSplit(GistEntryVector *entryvec, GIST_SPLITVEC *v)
 
 /*
  * Represents information about an entry that can be placed to either group
  * without affecting overlap over selected axis ("common entry").
  */
 typedef struct
 {
 	/* Index of entry in the initial array */
 	int			index;
 	/* Delta between penalties of entry insertion into different groups */
-	double		delta;
+	float8		delta;
 } CommonEntry;
 
 /*
  * Context for g_box_consider_split. Contains information about currently
  * selected split and some general information.
  */
 typedef struct
 {
 	int			entriesCount;	/* total number of entries being split */
 	BOX			boundingBox;	/* minimum bounding box across all entries */
 
 	/* Information about currently selected split follows */
 
 	bool		first;			/* true if no split was selected yet */
 
-	double		leftUpper;		/* upper bound of left interval */
-	double		rightLower;		/* lower bound of right interval */
+	float8		leftUpper;		/* upper bound of left interval */
+	float8		rightLower;		/* lower bound of right interval */
 
 	float4		ratio;
 	float4		overlap;
 	int			dim;			/* axis of this split */
-	double		range;			/* width of general MBR projection to the
+	float8		range;			/* width of general MBR projection to the
 								 * selected axis */
 } ConsiderSplitContext;
 
 /*
  * Interval represents projection of box to axis.
  */
 typedef struct
 {
-	double		lower,
+	float8		lower,
 				upper;
 } SplitInterval;
 
 /*
  * Interval comparison function by lower bound of the interval;
  */
 static int
 interval_cmp_lower(const void *i1, const void *i2)
 {
-	double		lower1 = ((const SplitInterval *) i1)->lower,
+	float8		lower1 = ((const SplitInterval *) i1)->lower,
 				lower2 = ((const SplitInterval *) i2)->lower;
 
 	return float8_cmp_internal(lower1, lower2);
 }
 
 /*
  * Interval comparison function by upper bound of the interval;
  */
 static int
 interval_cmp_upper(const void *i1, const void *i2)
 {
-	double		upper1 = ((const SplitInterval *) i1)->upper,
+	float8		upper1 = ((const SplitInterval *) i1)->upper,
 				upper2 = ((const SplitInterval *) i2)->upper;
 
 	return float8_cmp_internal(upper1, upper2);
 }
 
 /*
  * Replace negative (or NaN) value with zero.
  */
 static inline float
 non_negative(float val)
@@ -332,28 +334,28 @@ non_negative(float val)
 		return val;
 	else
 		return 0.0f;
 }
 
 /*
  * Consider replacement of currently selected split with the better one.
  */
 static inline void
 g_box_consider_split(ConsiderSplitContext *context, int dimNum,
-					 double rightLower, int minLeftCount,
-					 double leftUpper, int maxLeftCount)
+					 float8 rightLower, int minLeftCount,
+					 float8 leftUpper, int maxLeftCount)
 {
 	int			leftCount,
 				rightCount;
 	float4		ratio,
 				overlap;
-	double		range;
+	float8		range;
 
 	/*
 	 * Calculate entries distribution ratio assuming most uniform distribution
 	 * of common entries.
 	 */
 	if (minLeftCount >= (context->entriesCount + 1) / 2)
 	{
 		leftCount = minLeftCount;
 	}
 	else
@@ -362,40 +364,41 @@ g_box_consider_split(ConsiderSplitContext *context, int dimNum,
 			leftCount = maxLeftCount;
 		else
 			leftCount = context->entriesCount / 2;
 	}
 	rightCount = context->entriesCount - leftCount;
 
 	/*
 	 * Ratio of split - quotient between size of lesser group and total
 	 * entries count.
 	 */
-	ratio = ((float4) Min(leftCount, rightCount)) /
-		((float4) context->entriesCount);
+	ratio = float4_div(Min(leftCount, rightCount), context->entriesCount);
 
 	if (ratio > LIMIT_RATIO)
 	{
 		bool		selectthis = false;
 
 		/*
 		 * The ratio is acceptable, so compare current split with previously
 		 * selected one. Between splits of one dimension we search for minimal
 		 * overlap (allowing negative values) and minimal ration (between same
 		 * overlaps. We switch dimension if find less overlap (non-negative)
 		 * or less range with same overlap.
 		 */
 		if (dimNum == 0)
-			range = context->boundingBox.high.x - context->boundingBox.low.x;
+			range = float8_mi(context->boundingBox.high.x,
+							  context->boundingBox.low.x);
 		else
-			range = context->boundingBox.high.y - context->boundingBox.low.y;
+			range = float8_mi(context->boundingBox.high.y,
+							  context->boundingBox.low.y);
 
-		overlap = (leftUpper - rightLower) / range;
+		overlap = float8_div(float8_mi(leftUpper, rightLower), range);
 
 		/* If there is no previous selection, select this */
 		if (context->first)
 			selectthis = true;
 		else if (context->dim == dimNum)
 		{
 			/*
 			 * Within the same dimension, choose the new split if it has a
 			 * smaller overlap, or same overlap but better ratio.
 			 */
@@ -524,21 +527,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		else
 			adjustBox(&context.boundingBox, box);
 	}
 
 	/*
 	 * Iterate over axes for optimal split searching.
 	 */
 	context.first = true;		/* nothing selected yet */
 	for (dim = 0; dim < 2; dim++)
 	{
-		double		leftUpper,
+		float8		leftUpper,
 					rightLower;
 		int			i1,
 					i2;
 
 		/* Project each entry as an interval on the selected axis. */
 		for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 		{
 			box = DatumGetBoxP(entryvec->vector[i].key);
 			if (dim == 0)
 			{
@@ -721,21 +724,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 			*rightBox = *(box);					\
 		v->spl_right[v->spl_nright++] = off;	\
 	} while(0)
 
 	/*
 	 * Distribute entries which can be distributed unambiguously, and collect
 	 * common entries.
 	 */
 	for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 	{
-		double		lower,
+		float8		lower,
 					upper;
 
 		/*
 		 * Get upper and lower bounds along selected axis.
 		 */
 		box = DatumGetBoxP(entryvec->vector[i].key);
 		if (context.dim == 0)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
@@ -776,31 +779,31 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
 	{
 		/*
 		 * Calculate minimum number of entries that must be placed in both
 		 * groups, to reach LIMIT_RATIO.
 		 */
-		int			m = ceil(LIMIT_RATIO * (double) nentries);
+		int			m = ceil(LIMIT_RATIO * (float8) nentries);
 
 		/*
 		 * Calculate delta between penalties of join "common entries" to
 		 * different groups.
 		 */
 		for (i = 0; i < commonEntriesCount; i++)
 		{
 			box = DatumGetBoxP(entryvec->vector[commonEntries[i].index].key);
-			commonEntries[i].delta = Abs(box_penalty(leftBox, box) -
-										 box_penalty(rightBox, box));
+			commonEntries[i].delta = Abs(float8_mi(box_penalty(leftBox, box),
+												   box_penalty(rightBox, box)));
 		}
 
 		/*
 		 * Sort "common entries" by calculated deltas in order to distribute
 		 * the most ambiguous entries first.
 		 */
 		qsort(commonEntries, commonEntriesCount, sizeof(CommonEntry), common_entry_cmp);
 
 		/*
 		 * Distribute "common entries" between groups.
@@ -1100,24 +1103,24 @@ gist_circle_compress(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	GISTENTRY  *retval;
 
 	if (entry->leafkey)
 	{
 		CIRCLE	   *in = DatumGetCircleP(entry->key);
 		BOX		   *r;
 
 		r = (BOX *) palloc(sizeof(BOX));
-		r->high.x = in->center.x + in->radius;
-		r->low.x = in->center.x - in->radius;
-		r->high.y = in->center.y + in->radius;
-		r->low.y = in->center.y - in->radius;
+		r->high.x = float8_pl(in->center.x, in->radius);
+		r->low.x = float8_mi(in->center.x, in->radius);
+		r->high.y = float8_pl(in->center.y, in->radius);
+		r->low.y = float8_mi(in->center.y, in->radius);
 
 		retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
 		gistentryinit(*retval, PointerGetDatum(r),
 					  entry->rel, entry->page,
 					  entry->offset, false);
 	}
 	else
 		retval = entry;
 	PG_RETURN_POINTER(retval);
 }
@@ -1141,24 +1144,24 @@ gist_circle_consistent(PG_FUNCTION_ARGS)
 	*recheck = true;
 
 	if (DatumGetBoxP(entry->key) == NULL || query == NULL)
 		PG_RETURN_BOOL(false);
 
 	/*
 	 * Since the operators require recheck anyway, we can just use
 	 * rtree_internal_consistent even at leaf nodes.  (This works in part
 	 * because the index entries are bounding boxes not circles.)
 	 */
-	bbox.high.x = query->center.x + query->radius;
-	bbox.low.x = query->center.x - query->radius;
-	bbox.high.y = query->center.y + query->radius;
-	bbox.low.y = query->center.y - query->radius;
+	bbox.high.x = float8_pl(query->center.x, query->radius);
+	bbox.low.x = float8_mi(query->center.x, query->radius);
+	bbox.high.y = float8_pl(query->center.y, query->radius);
+	bbox.low.y = float8_mi(query->center.y, query->radius);
 
 	result = rtree_internal_consistent(DatumGetBoxP(entry->key),
 									   &bbox, strategy);
 
 	PG_RETURN_BOOL(result);
 }
 
 /**************************************************
  * Point ops
  **************************************************/
@@ -1209,63 +1212,63 @@ gist_point_fetch(PG_FUNCTION_ARGS)
 				  entry->offset, false);
 
 	PG_RETURN_POINTER(retval);
 }
 
 
 #define point_point_distance(p1,p2) \
 	DatumGetFloat8(DirectFunctionCall2(point_distance, \
 									   PointPGetDatum(p1), PointPGetDatum(p2)))
 
-static double
+static float8
 computeDistance(bool isLeaf, BOX *box, Point *point)
 {
-	double		result = 0.0;
+	float8		result = 0.0;
 
 	if (isLeaf)
 	{
 		/* simple point to point distance */
 		result = point_point_distance(point, &box->low);
 	}
 	else if (point->x <= box->high.x && point->x >= box->low.x &&
 			 point->y <= box->high.y && point->y >= box->low.y)
 	{
 		/* point inside the box */
 		result = 0.0;
 	}
 	else if (point->x <= box->high.x && point->x >= box->low.x)
 	{
 		/* point is over or below box */
 		Assert(box->low.y <= box->high.y);
 		if (point->y > box->high.y)
-			result = point->y - box->high.y;
+			result = float8_mi(point->y, box->high.y);
 		else if (point->y < box->low.y)
-			result = box->low.y - point->y;
+			result = float8_mi(box->low.y, point->y);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
 	else if (point->y <= box->high.y && point->y >= box->low.y)
 	{
 		/* point is to left or right of box */
 		Assert(box->low.x <= box->high.x);
 		if (point->x > box->high.x)
-			result = point->x - box->high.x;
+			result = float8_mi(point->x, box->high.x);
 		else if (point->x < box->low.x)
-			result = box->low.x - point->x;
+			result = float8_mi(box->low.x, point->x);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
 	else
 	{
 		/* closest point will be a vertex */
 		Point		p;
-		double		subresult;
+		float8		subresult;
 
 		result = point_point_distance(point, &box->low);
 
 		subresult = point_point_distance(point, &box->high);
 		if (result > subresult)
 			result = subresult;
 
 		p.x = box->low.x;
 		p.y = box->high.y;
 		subresult = point_point_distance(point, &p);
@@ -1442,21 +1445,21 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 	}
 
 	PG_RETURN_BOOL(result);
 }
 
 Datum
 gist_point_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(GIST_LEAF(entry),
 									   DatumGetBoxP(entry->key),
 									   PG_GETARG_POINT_P(1));
 			break;
 		default:
@@ -1471,25 +1474,25 @@ gist_point_distance(PG_FUNCTION_ARGS)
 /*
  * The inexact GiST distance method for geometric types that store bounding
  * boxes.
  *
  * Compute lossy distance from point to index entries.  The result is inexact
  * because index entries are bounding boxes, not the exact shapes of the
  * indexed geometric types.  We use distance from point to MBR of index entry.
  * This is a lower bound estimate of distance from point to indexed geometric
  * type.
  */
-static double
+static float8
 gist_bbox_distance(GISTENTRY *entry, Datum query,
 				   StrategyNumber strategy, bool *recheck)
 {
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	/* Bounding box distance is always inexact. */
 	*recheck = true;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(false,
 									   DatumGetBoxP(entry->key),
@@ -1505,32 +1508,32 @@ gist_bbox_distance(GISTENTRY *entry, Datum query,
 
 Datum
 gist_circle_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
 
 Datum
 gist_poly_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index a4fa4d6792..16f853ae9b 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -49,56 +49,56 @@ static int	point_inside(Point *p, int npts, Point *plist);
 static inline void line_construct_pm(LINE *result, Point *pt, float8 m);
 static inline void line_construct_pts(LINE *result, Point *pt1, Point *pt2);
 static bool	line_interpt_line(Point *result, LINE *l1, LINE *l2);
 static bool line_contain_point(LINE *line, Point *point);
 static float8 line_closept_point(Point *result, LINE *line, Point *pt);
 
 /* Routines for two-dimensional line segments */
 static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
 static bool	lseg_interpt_line(Point *result, LSEG *lseg, LINE *line);
 static bool	lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2);
-static int	lseg_crossing(double x, double y, double px, double py);
+static int	lseg_crossing(float8 x, float8 y, float8 px, float8 py);
 static bool	lseg_contain_point(LSEG *lseg, Point *point);
 static float8 lseg_closept_point(Point *result, LSEG *lseg, Point *pt);
 static float8 lseg_closept_line(Point *result, LSEG *lseg, LINE *line);
 static float8 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2);
 
 /* Routines for two-dimensional boxes */
 static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
 static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
-static double box_ar(BOX *box);
-static double box_ht(BOX *box);
-static double box_wd(BOX *box);
+static float8 box_ar(BOX *box);
+static float8 box_ht(BOX *box);
+static float8 box_wd(BOX *box);
 static bool box_contain_point(BOX *box, Point *point);
 static bool box_contain_box(BOX *box1, BOX *box2);
 static bool box_contain_lseg(BOX *box, LSEG *lseg);
 static bool box_interpt_lseg(Point *result, BOX *box, LSEG *lseg);
 static float8 box_closept_point(Point *result, BOX *box, Point *point);
 static float8 box_closept_lseg(Point *result, BOX *box, LSEG *lseg);
 
 /* Routines for two-dimensional circles */
-static double circle_ar(CIRCLE *circle);
+static float8 circle_ar(CIRCLE *circle);
 
 /* Routines for two-dimensional polygons */
 static void make_bound_box(POLYGON *poly);
 static void poly_to_circle(CIRCLE *result, POLYGON *poly);
 static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
 static bool poly_contain_poly(POLYGON *polya, POLYGON *polyb);
 static bool plist_same(int npts, Point *p1, Point *p2);
 static float8 dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 /* Routines for encoding and decoding */
-static double single_decode(char *num, char **endptr_p,
+static float8 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
-static void pair_decode(char *str, double *x, double *y, char **endptr_p,
+static void pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
 static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
 
 
 /*
@@ -136,38 +136,38 @@ static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
  *
  * For boxes, the points are opposite corners with the first point at the top right.
  * For closed paths and polygons, the points should be reordered to allow
  *	fast and correct equality comparisons.
  *
  * XXX perhaps points in complex shapes should be reordered internally
  *	to allow faster internal operations, but should keep track of input order
  *	and restore that order for text output - tgl 97/01/16
  */
 
-static double
+static float8
 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string)
 {
 	return float8in_internal(num, endptr_p, type_name, orig_string);
 }								/* single_decode() */
 
 static void
 single_encode(float8 x, StringInfo str)
 {
 	char	   *xstr = float8out_internal(x);
 
 	appendStringInfoString(str, xstr);
 	pfree(xstr);
 }								/* single_encode() */
 
 static void
-pair_decode(char *str, double *x, double *y, char **endptr_p,
+pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string)
 {
 	bool		has_delim;
 
 	while (isspace((unsigned char) *str))
 		str++;
 	if ((has_delim = (*str == LDELIM)))
 		str++;
 
 	*x = float8in_internal(str, &str, type_name, orig_string);
@@ -366,33 +366,33 @@ pair_count(char *s, char delim)
  *		External format: (two corners of box)
  *				"(f8, f8), (f8, f8)"
  *				also supports the older style "(f8, f8, f8, f8)"
  */
 Datum
 box_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	BOX		   *box = (BOX *) palloc(sizeof(BOX));
 	bool		isopen;
-	double		x,
+	float8		x,
 				y;
 
 	path_decode(str, false, 2, &(box->high), &isopen, NULL, "box", str);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*		box_out -		convert a box to external form.
@@ -406,38 +406,38 @@ box_out(PG_FUNCTION_ARGS)
 }
 
 /*
  *		box_recv			- converts external binary format to box
  */
 Datum
 box_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	BOX		   *box;
-	double		x,
+	float8		x,
 				y;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
 	box->high.x = pq_getmsgfloat8(buf);
 	box->high.y = pq_getmsgfloat8(buf);
 	box->low.x = pq_getmsgfloat8(buf);
 	box->low.y = pq_getmsgfloat8(buf);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*
@@ -456,31 +456,31 @@ box_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, box->low.y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*		box_construct	-		fill in a new box.
  */
 static inline void
 box_construct(BOX *result, Point *pt1, Point *pt2)
 {
-	if (pt1->x > pt2->x)
+	if (float8_gt(pt1->x, pt2->x))
 	{
 		result->high.x = pt1->x;
 		result->low.x = pt2->x;
 	}
 	else
 	{
 		result->high.x = pt2->x;
 		result->low.x = pt1->x;
 	}
-	if (pt1->y > pt2->y)
+	if (float8_gt(pt1->y, pt2->y))
 	{
 		result->high.y = pt1->y;
 		result->low.y = pt2->y;
 	}
 	else
 	{
 		result->high.y = pt2->y;
 		result->low.y = pt1->y;
 	}
 }
@@ -798,54 +798,54 @@ box_center(PG_FUNCTION_ARGS)
 	Point	   *result = (Point *) palloc(sizeof(Point));
 
 	box_cn(result, box);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		box_ar	-		returns the area of the box.
  */
-static double
+static float8
 box_ar(BOX *box)
 {
-	return box_wd(box) * box_ht(box);
+	return float8_mul(box_wd(box), box_ht(box));
 }
 
 
 /*		box_cn	-		stores the centerpoint of the box into *center.
  */
 static void
 box_cn(Point *center, BOX *box)
 {
-	center->x = (box->high.x + box->low.x) / 2.0;
-	center->y = (box->high.y + box->low.y) / 2.0;
+	center->x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	center->y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 }
 
 
 /*		box_wd	-		returns the width (length) of the box
  *								  (horizontal magnitude).
  */
-static double
+static float8
 box_wd(BOX *box)
 {
-	return box->high.x - box->low.x;
+	return float8_mi(box->high.x, box->low.x);
 }
 
 
 /*		box_ht	-		returns the height of the box
  *								  (vertical magnitude).
  */
-static double
+static float8
 box_ht(BOX *box)
 {
-	return box->high.y - box->low.y;
+	return float8_mi(box->high.y, box->low.y);
 }
 
 
 /*----------------------------------------------------------
  *	Funky operations.
  *---------------------------------------------------------*/
 
 /*		box_intersect	-
  *				returns the overlapping portion of two boxes,
  *				  or NULL if they do not intersect.
@@ -855,24 +855,24 @@ box_intersect(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 	BOX		   *result;
 
 	if (!box_ov(box1, box2))
 		PG_RETURN_NULL();
 
 	result = (BOX *) palloc(sizeof(BOX));
 
-	result->high.x = Min(box1->high.x, box2->high.x);
-	result->low.x = Max(box1->low.x, box2->low.x);
-	result->high.y = Min(box1->high.y, box2->high.y);
-	result->low.y = Max(box1->low.y, box2->low.y);
+	result->high.x = float8_min(box1->high.x, box2->high.x);
+	result->low.x = float8_max(box1->low.x, box2->low.x);
+	result->high.y = float8_min(box1->high.y, box2->high.y);
+	result->low.y = float8_max(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(result);
 }
 
 
 /*		box_diagonal	-
  *				returns a line segment which happens to be the
  *				  positive-slope diagonal of "box".
  */
 Datum
@@ -1004,37 +1004,37 @@ line_send(PG_FUNCTION_ARGS)
 
 /*
  * Fill already-allocated LINE struct from the point and the slope
  */
 static inline void
 line_construct_pm(LINE *result, Point *pt, float8 m)
 {
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
-		result->A = -1;
-		result->B = 0;
+		result->A = -1.0;
+		result->B = 0.0;
 		result->C = pt->x;
 	}
 	else if (m == 0.0)
 	{
 		/* horizontal - use "y = C" */
 		result->A = 0.0;
 		result->B = -1.0;
 		result->C = pt->y;
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
-		result->C = pt->y - m * pt->x;
+		result->C = float8_mi(pt->y, float8_mul(m, pt->x));
 	}
 }
 
 /*
  * Fill already-allocated LINE struct from two points on the line
  */
 static inline void
 line_construct_pts(LINE *result, Point *pt1, Point *pt2)
 {
 	float8		m;
@@ -1073,35 +1073,36 @@ line_intersect(PG_FUNCTION_ARGS)
 
 Datum
 line_parallel(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->B));
 
-	PG_RETURN_BOOL(FPeq(l2->A, l1->A * (l2->B / l1->B)));
+	PG_RETURN_BOOL(FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))));
 }
 
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
 	else if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
 
-	PG_RETURN_BOOL(FPeq(((l1->A * l2->B) / (l1->B * l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
+								   float8_mul(l1->B, l2->A)), -1.0));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
@@ -1111,34 +1112,37 @@ line_horizontal(PG_FUNCTION_ARGS)
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->A));
 }
 
 Datum
 line_eq(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	double		k;
+	float8		ratio;
 
-	if (!FPzero(l2->A))
-		k = l1->A / l2->A;
-	else if (!FPzero(l2->B))
-		k = l1->B / l2->B;
-	else if (!FPzero(l2->C))
-		k = l1->C / l2->C;
+	if (!FPzero(l2->A) && !isnan(l2->A))
+		ratio = float8_div(l1->A, l2->A);
+	else if (!FPzero(l2->B) && !isnan(l2->B))
+		ratio = float8_div(l1->B, l2->B);
+	else if (!FPzero(l2->C) && !isnan(l2->C))
+		ratio = float8_div(l1->C, l2->C);
 	else
-		k = 1.0;
+		ratio = 1.0;
 
-	PG_RETURN_BOOL(FPeq(l1->A, k * l2->A) &&
-				   FPeq(l1->B, k * l2->B) &&
-				   FPeq(l1->C, k * l2->C));
+	PG_RETURN_BOOL(((isnan(l1->A) && isnan(l2->A)) ||
+					FPeq(l1->A, float8_mul(ratio, l2->A))) &&
+				   ((isnan(l1->B) && isnan(l2->B)) ||
+					FPeq(l1->B, float8_mul(ratio, l2->B))) &&
+				   ((isnan(l1->C) && isnan(l2->C)) ||
+					FPeq(l1->C, float8_mul(ratio, l2->C))));
 }
 
 
 /*----------------------------------------------------------
  *	Line arithmetic routines.
  *---------------------------------------------------------*/
 
 /* line_distance()
  * Distance between two lines.
  */
@@ -1146,21 +1150,21 @@ Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
 	Point		tmp;
 
 	if (line_interpt_line(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
+		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
 	point_construct(&tmp, 0.0, l1->C);
 	result = line_closept_point(NULL, l2, &tmp);
 	PG_RETURN_FLOAT8(result);
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
@@ -1179,47 +1183,51 @@ line_interpt(PG_FUNCTION_ARGS)
 /*
  * Internal version of line_interpt
  *
  * This returns true if two lines intersect (they do, if they are not
  * parallel), false if they do not.  This also sets the intersection point
  * to *result, if it is not NULL.
  *
  * NOTE If the lines are identical then we will find they are parallel
  * and report "no intersection".  This is a little weird, but since
  * there's no *unique* intersection, maybe it's appropriate behavior.
+ *
+ * If the lines have NaN constants, we will return true, and the intersection
+ * point would have NaN coordinates.  We shouldn't return false in this case
+ * because that would mean the lines are parallel.
  */
 static bool
 line_interpt_line(Point *result, LINE *l1, LINE *l2)
 {
-	double		x,
+	float8		x,
 				y;
 
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
 		if (FPzero(l2->B))		/* l2 vertical? */
 			return false;
 
 		x = l1->C;
-		y = (l2->A * x + l2->C);
+		y = float8_pl(float8_mul(l2->A, x), l2->C);
 	}
 	else if (FPzero(l2->B))		/* l2 vertical? */
 	{
 		x = l2->C;
-		y = (l1->A * x + l1->C);
+		y = float8_pl(float8_mul(l1->A, x), l1->C);
 	}
 	else
 	{
-		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
 			return false;
 
-		x = (l1->C - l2->C) / (l2->A - l1->A);
-		y = (l1->A * x + l1->C);
+		x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
+		y = float8_pl(float8_mul(l1->A, x), l1->C);
 	}
 	if (result != NULL)
 		point_construct(result, x, y);
 
 	return true;
 }
 
 
 /***********************************************************************
  **
@@ -1240,36 +1248,35 @@ line_interpt_line(Point *result, LINE *l1, LINE *l2)
  *				"(xcoord, ycoord),... "
  *				"[xcoord, ycoord,... ]"
  *		Also support older format:
  *				"(closed, npts, xcoord, ycoord,... )"
  *---------------------------------------------------------*/
 
 Datum
 path_area(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P(0);
-	double		area = 0.0;
+	float8		area = 0.0;
 	int			i,
 				j;
 
 	if (!path->closed)
 		PG_RETURN_NULL();
 
 	for (i = 0; i < path->npts; i++)
 	{
 		j = (i + 1) % path->npts;
-		area += path->p[i].x * path->p[j].y;
-		area -= path->p[i].y * path->p[j].x;
+		area = float8_pl(area, float8_mul(path->p[i].x, path->p[j].y));
+		area = float8_mi(area, float8_mul(path->p[i].y, path->p[j].x));
 	}
 
-	area *= 0.5;
-	PG_RETURN_FLOAT8(area < 0.0 ? -area : area);
+	PG_RETURN_FLOAT8(float8_div(fabs(area), 2.0));
 }
 
 
 Datum
 path_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	PATH	   *path;
 	bool		isopen;
 	char	   *s;
@@ -1525,33 +1532,33 @@ path_inter(PG_FUNCTION_ARGS)
 				j;
 	LSEG		seg1,
 				seg2;
 
 	Assert(p1->npts > 0 && p2->npts > 0);
 
 	b1.high.x = b1.low.x = p1->p[0].x;
 	b1.high.y = b1.low.y = p1->p[0].y;
 	for (i = 1; i < p1->npts; i++)
 	{
-		b1.high.x = Max(p1->p[i].x, b1.high.x);
-		b1.high.y = Max(p1->p[i].y, b1.high.y);
-		b1.low.x = Min(p1->p[i].x, b1.low.x);
-		b1.low.y = Min(p1->p[i].y, b1.low.y);
+		b1.high.x = float8_max(p1->p[i].x, b1.high.x);
+		b1.high.y = float8_max(p1->p[i].y, b1.high.y);
+		b1.low.x = float8_min(p1->p[i].x, b1.low.x);
+		b1.low.y = float8_min(p1->p[i].y, b1.low.y);
 	}
 	b2.high.x = b2.low.x = p2->p[0].x;
 	b2.high.y = b2.low.y = p2->p[0].y;
 	for (i = 1; i < p2->npts; i++)
 	{
-		b2.high.x = Max(p2->p[i].x, b2.high.x);
-		b2.high.y = Max(p2->p[i].y, b2.high.y);
-		b2.low.x = Min(p2->p[i].x, b2.low.x);
-		b2.low.y = Min(p2->p[i].y, b2.low.y);
+		b2.high.x = float8_max(p2->p[i].x, b2.high.x);
+		b2.high.y = float8_max(p2->p[i].y, b2.high.y);
+		b2.low.x = float8_min(p2->p[i].x, b2.low.x);
+		b2.low.y = float8_min(p2->p[i].y, b2.low.y);
 	}
 	if (!box_ov(&b1, &b2))
 		PG_RETURN_BOOL(false);
 
 	/* pairwise check lseg intersections */
 	for (i = 0; i < p1->npts; i++)
 	{
 		int			iprev;
 
 		if (i > 0)
@@ -1627,21 +1634,21 @@ path_distance(PG_FUNCTION_ARGS)
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
 			tmp = lseg_closept_lseg(NULL, &seg1, &seg2);
-			if (!have_min || tmp < min)
+			if (!have_min || float8_lt(tmp, min))
 			{
 				min = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	if (!have_min)
 		PG_RETURN_NULL();
 
@@ -1666,21 +1673,21 @@ path_length(PG_FUNCTION_ARGS)
 
 		if (i > 0)
 			iprev = i - 1;
 		else
 		{
 			if (!path->closed)
 				continue;
 			iprev = path->npts - 1; /* include the closure segment */
 		}
 
-		result += point_dt(&path->p[iprev], &path->p[i]);
+		result = float8_pl(result, point_dt(&path->p[iprev], &path->p[i]));
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /***********************************************************************
  **
  **		Routines for 2D points.
  **
  ***********************************************************************/
@@ -1832,41 +1839,42 @@ point_ne(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_BOOL(!point_eq_point(pt1, pt2));
 }
 
 static inline bool
 point_eq_point(Point *pt1, Point *pt2)
 {
-	return FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y);
+	return ((isnan(pt1->x) && isnan(pt2->x)) || FPeq(pt1->x, pt2->x)) &&
+		   ((isnan(pt1->y) && isnan(pt2->y)) || FPeq(pt1->y, pt2->y));
 }
 
 
 /*----------------------------------------------------------
  *	"Arithmetic" operators on points.
  *---------------------------------------------------------*/
 
 Datum
 point_distance(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
 static float8
 point_dt(Point *pt1, Point *pt2)
 {
-	return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
+	return HYPOT(float8_mi(pt1->x, pt2->x), float8_mi(pt1->y, pt2->y));
 }
 
 Datum
 point_slope(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(slope(pt1->x, pt2->x, pt1->y, pt2->y));
 }
@@ -1875,27 +1883,29 @@ point_slope(PG_FUNCTION_ARGS)
 /*
  * Return slope of two points
  *
  * This function accepts x and y coordinates separately to let it be used
  * to calculate inverse slope.  To achieve that, pass the values in
  * (y1, y2, x2, x1) order.
  */
 static inline float8
 slope(float8 x1, float8 x2, float8 y1, float8 y2)
 {
-	/*
-	 * XXX This should be exact checking.  The callers are using the macros
-	 * when necessary.
-	 */
-	if (FPeq(x1, x2))
+	if (x1 == x2)
+	{
+		if (y1 == y2)
+			return NAN;
+
 		return DBL_MAX;
-	return (y1 - y2) / (x1 - x2);
+	}
+
+	return float8_div(float8_mi(y1, y2), float8_mi(x1, x2));
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D line segments.
  **
  ***********************************************************************/
 
 /*----------------------------------------------------------
@@ -2035,21 +2045,21 @@ lseg_parallel(PG_FUNCTION_ARGS)
  *	'((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg
  * So, modified it to check explicitly for slope of vertical line
  *	returned by slope() and the results seem better.
  * - thomas 1998-01-31
  */
 Datum
 lseg_perp(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	double		m1,
+	float8		m1,
 				m2;
 
 	m1 = slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y);
 	m2 = slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y);
 
 #ifdef GEODEBUG
 	printf("lseg_perp- slopes are %g and %g\n", m1, m2);
 #endif
 	if (FPzero(m1))
 		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
@@ -2157,22 +2167,22 @@ lseg_distance(PG_FUNCTION_ARGS)
 
 
 Datum
 lseg_center(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
-	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
+	result->x = float8_div(float8_pl(lseg->p[0].x, lseg->p[1].x), 2.0);
+	result->y = float8_div(float8_pl(lseg->p[0].y, lseg->p[1].y), 2.0);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  *		Find the intersection point of two segments (if any).
  *
  * This returns true if two line segments intersect, false if they do not.
  * This also sets the intersection point to *result, if it is not NULL.
@@ -2281,21 +2291,21 @@ dist_ppath(PG_FUNCTION_ARGS)
 			iprev = i - 1;
 		else
 		{
 			if (!path->closed)
 				continue;
 			iprev = path->npts - 1; /* Include the closure segment */
 		}
 
 		statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
 		tmp = lseg_closept_point(NULL, &lseg, pt);
-		if (!have_min || tmp < result)
+		if (!have_min || float8_lt(tmp, result))
 		{
 			result = tmp;
 			have_min = true;
 		}
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
@@ -2311,33 +2321,28 @@ dist_pb(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
-	float8		result,
-				d2;
+	float8		result;
 
 	if (lseg_interpt_line(NULL, lseg, line))
 		result = 0.0;
 	else
-	{
-		result = line_closept_point(NULL, line, &lseg->p[0]);
-		d2 = line_closept_point(NULL, line, &lseg->p[1]);
 		/* XXX shouldn't we take the min not max? */
-		if (d2 > result)
-			result = d2;
-	}
+		result = float8_max(line_closept_point(NULL, line, &lseg->p[0]),
+							line_closept_point(NULL, line, &lseg->p[1]));
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
@@ -2370,25 +2375,24 @@ dist_lb(PG_FUNCTION_ARGS)
  * Distance from a circle to a polygon
  */
 Datum
 dist_cpoly(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	POLYGON    *poly = PG_GETARG_POLYGON_P(1);
 	float8		result;
 
 	/* calculate distance to center, and subtract radius */
-	result = dist_ppoly_internal(&circle->center, poly);
-
-	result -= circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(dist_ppoly_internal(&circle->center, poly),
+					   circle->radius);
+	if (result < 0.0)
+		result = 0.0;
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a point to a polygon
  */
 Datum
 dist_ppoly(PG_FUNCTION_ARGS)
 {
@@ -2437,21 +2441,21 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
 	for (i = 0; i < poly->npts - 1; i++)
 	{
 		seg.p[0].x = poly->p[i].x;
 		seg.p[0].y = poly->p[i].y;
 		seg.p[1].x = poly->p[i + 1].x;
 		seg.p[1].y = poly->p[i + 1].y;
 		d = lseg_closept_point(NULL, &seg, pt);
 #ifdef GEODEBUG
 		printf("dist_ppoly_internal- segment %d distance is %f\n", (i + 1), d);
 #endif
-		if (d < result)
+		if (float8_lt(d, result))
 			result = d;
 	}
 
 	return result;
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
  *				Intersection point of objects.
@@ -2532,36 +2536,37 @@ line_closept_point(Point *result, LINE *line, Point *point)
 
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	line_closept_point(result, line, pt);
+	if (isnan(line_closept_point(result, line, pt)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point on line segment to specified point.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 lseg_closept_point(Point *result, LSEG *lseg, Point *pt)
 {
-	double		invm;
+	float8		invm;
 	Point		closept;
 	LINE		tmp;
 
 	/*
 	 * To find the closest point, we draw a perpendicular line from the point
 	 * to the line segment.
 	 */
 	invm = slope(lseg->p[0].y, lseg->p[1].y, lseg->p[1].x, lseg->p[0].x);
 	line_construct_pm(&tmp, pt, invm);
 	lseg_closept_line(&closept, lseg, &tmp);
@@ -2594,134 +2599,136 @@ close_ps(PG_FUNCTION_ARGS)
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  *
  * XXX This function is wrong.  If must never set the *result to a point on
  * the second segment.
  */
 static float8
 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
 {
 	Point		point;
-	double		dist;
-	double		d;
+	float8		dist,
+				d;
 
 	d = lseg_closept_point(NULL, l1, &l2->p[0]);
 	dist = d;
 	if (result != NULL)
 		*result = l2->p[0];
 
 	d = lseg_closept_point(NULL, l1, &l2->p[1]);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = l2->p[1];
 	}
 
-	if (lseg_closept_point(&point, l2, &l1->p[0]) < dist)
+	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[0]), dist))
 		d = lseg_closept_point(result, l1, &point);
 
-	if (lseg_closept_point(&point, l2, &l1->p[1]) < dist)
+	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[1]), dist))
 		d = lseg_closept_point(result, l1, &point);
 
-	if (d < dist)
+	if (float8_lt(d, dist))
 		dist = d;
 
 	return dist;
 }
 
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	lseg_closept_lseg(result, l2, l1);
+	if (isnan(lseg_closept_lseg(result, l2, l1)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point on or in box to specified point.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 box_closept_point(Point *result, BOX *box, Point *pt)
 {
-	LSEG		lseg;
+	float8		dist,
+				d;
 	Point		point,
 				closept;
-	double		dist,
-				d;
+	LSEG		lseg;
 
 	if (box_contain_point(box, pt))
 	{
 		if (result != NULL)
 			*result = *pt;
 
 		return 0.0;
 	}
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&lseg, &box->low, &point);
 	dist = lseg_closept_point(result, &lseg, pt);
 
 	statlseg_construct(&lseg, &box->high, &point);
 	d = lseg_closept_point(&closept, &lseg, pt);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&lseg, &box->low, &point);
 	d = lseg_closept_point(&closept, &lseg, pt);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	statlseg_construct(&lseg, &box->high, &point);
 	d = lseg_closept_point(&closept, &lseg, pt);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	return dist;
 }
 
 Datum
 close_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	box_closept_point(result, box, pt);
+	if (isnan(box_closept_point(result, box, pt)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_sl()
  * Closest point on line to line segment.
  *
  * XXX THIS CODE IS WRONG
  * The code is actually calculating the point on the line segment
@@ -2739,21 +2746,21 @@ close_sl(PG_FUNCTION_ARGS)
 	float8		d1,
 				d2;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (lseg_interpt_line(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = line_closept_point(NULL, line, &lseg->p[0]);
 	d2 = line_closept_point(NULL, line, &lseg->p[1]);
-	if (d1 < d2)
+	if (float8_lt(d1, d2))
 		*result = lseg->p[0];
 	else
 		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
 
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_sl\" not implemented")));
@@ -2803,92 +2810,94 @@ lseg_closept_line(Point *result, LSEG *lseg, LINE *line)
 
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	lseg_closept_line(result, lseg, line);
+	if (isnan(lseg_closept_line(result, lseg, line)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point on or in box to line segment.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 box_closept_lseg(Point *result, BOX *box, LSEG *lseg)
 {
+	float8		dist,
+				d;
 	Point		point,
 				closept;
 	LSEG		bseg;
-	double		dist,
-				d;
 
 	if (box_interpt_lseg(result, box, lseg))
 		return 0.0;
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
 	dist = lseg_closept_lseg(result, &bseg, lseg);
 
 	statlseg_construct(&bseg, &box->high, &point);
 	d = lseg_closept_lseg(&closept, &bseg, lseg);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&bseg, &box->low, &point);
 	d = lseg_closept_lseg(&closept, &bseg, lseg);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	statlseg_construct(&bseg, &box->high, &point);
 	d = lseg_closept_lseg(&closept, &bseg, lseg);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	return dist;
 }
 
 Datum
 close_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	box_closept_lseg(result, box, lseg);
+	if (isnan(box_closept_lseg(result, box, lseg)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 Datum
 close_lb(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -2907,21 +2916,23 @@ close_lb(PG_FUNCTION_ARGS)
  *		on_
  *				Whether one object lies completely within another.
  *-------------------------------------------------------------------*/
 
 /*
  *		Does the point satisfy the equation?
  */
 static bool
 line_contain_point(LINE *line, Point *point)
 {
-	return FPzero(line->A * point->x + line->B * point->y + line->C);
+	return FPzero(float8_pl(float8_pl(float8_mul(line->A, point->x),
+									  float8_mul(line->B, point->y)),
+							line->C));
 }
 
 Datum
 on_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
 	PG_RETURN_BOOL(line_contain_point(line, pt));
 }
@@ -2989,33 +3000,32 @@ box_contain_pt(PG_FUNCTION_ARGS)
  *				but not cross.
  *				(we can do p-in-p in lg(n), but it takes preprocessing)
  */
 Datum
 on_ppath(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	PATH	   *path = PG_GETARG_PATH_P(1);
 	int			i,
 				n;
-	double		a,
+	float8		a,
 				b;
 
 	/*-- OPEN --*/
 	if (!path->closed)
 	{
 		n = path->npts - 1;
 		a = point_dt(pt, &path->p[0]);
 		for (i = 0; i < n; i++)
 		{
 			b = point_dt(pt, &path->p[i + 1]);
-			if (FPeq(a + b,
-					 point_dt(&path->p[i], &path->p[i + 1])))
+			if (FPeq(float8_pl(a, b), point_dt(&path->p[i], &path->p[i + 1])))
 				PG_RETURN_BOOL(true);
 			a = b;
 		}
 		PG_RETURN_BOOL(false);
 	}
 
 	/*-- CLOSED --*/
 	PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
 }
 
@@ -3087,24 +3097,24 @@ inter_sl(PG_FUNCTION_ARGS)
  * Optimize for non-intersection by checking for box intersection first.
  * - thomas 1998-01-30
  */
 static bool
 box_interpt_lseg(Point *result, BOX *box, LSEG *lseg)
 {
 	BOX			lbox;
 	LSEG		bseg;
 	Point		point;
 
-	lbox.low.x = Min(lseg->p[0].x, lseg->p[1].x);
-	lbox.low.y = Min(lseg->p[0].y, lseg->p[1].y);
-	lbox.high.x = Max(lseg->p[0].x, lseg->p[1].x);
-	lbox.high.y = Max(lseg->p[0].y, lseg->p[1].y);
+	lbox.low.x = float8_min(lseg->p[0].x, lseg->p[1].x);
+	lbox.low.y = float8_min(lseg->p[0].y, lseg->p[1].y);
+	lbox.high.x = float8_max(lseg->p[0].x, lseg->p[1].x);
+	lbox.high.y = float8_max(lseg->p[0].y, lseg->p[1].y);
 
 	/* nothing close to overlap? then not going to intersect */
 	if (!box_ov(&lbox, box))
 		return false;
 
 	if (result != NULL)
 	{
 		box_cn(&point, box);
 		lseg_closept_point(result, lseg, &point);
 	}
@@ -3197,38 +3207,38 @@ inter_lb(PG_FUNCTION_ARGS)
  * make_bound_box - create the bounding box for the input polygon
  *------------------------------------------------------------------*/
 
 /*---------------------------------------------------------------------
  * Make the smallest bounding box for the given polygon.
  *---------------------------------------------------------------------*/
 static void
 make_bound_box(POLYGON *poly)
 {
 	int			i;
-	double		x1,
+	float8		x1,
 				y1,
 				x2,
 				y2;
 
 	Assert(poly->npts > 0);
 
 	x1 = x2 = poly->p[0].x;
 	y2 = y1 = poly->p[0].y;
 	for (i = 1; i < poly->npts; i++)
 	{
-		if (poly->p[i].x < x1)
+		if (float8_lt(poly->p[i].x, x1))
 			x1 = poly->p[i].x;
-		if (poly->p[i].x > x2)
+		if (float8_gt(poly->p[i].x, x2))
 			x2 = poly->p[i].x;
-		if (poly->p[i].y < y1)
+		if (float8_lt(poly->p[i].y, y1))
 			y1 = poly->p[i].y;
-		if (poly->p[i].y > y2)
+		if (float8_gt(poly->p[i].y, y2))
 			y2 = poly->p[i].y;
 	}
 
 	poly->boundbox.low.x = x1;
 	poly->boundbox.high.x = x2;
 	poly->boundbox.low.y = y1;
 	poly->boundbox.high.y = y2;
 }
 
 /*------------------------------------------------------------------
@@ -3726,22 +3736,22 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 	}
 
 	if (res && !intersection)
 	{
 		Point		p;
 
 		/*
 		 * if X-intersection wasn't found  then check central point of tested
 		 * segment. In opposite case we already check all subsegments
 		 */
-		p.x = (t.p[0].x + t.p[1].x) / 2.0;
-		p.y = (t.p[0].y + t.p[1].y) / 2.0;
+		p.x = float8_div(float8_pl(t.p[0].x, t.p[1].x), 2.0);
+		p.y = float8_div(float8_pl(t.p[0].y, t.p[1].y), 2.0);
 
 		res = point_inside(&p, poly->npts, poly->p);
 	}
 
 	return res;
 }
 
 /*-----------------------------------------------------------------
  * Determine if polygon A contains polygon B.
  *-----------------------------------------------------------------*/
@@ -3867,22 +3877,22 @@ construct_point(PG_FUNCTION_ARGS)
 	point_construct(result, x, y);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_add_point(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x + pt2->x,
-					pt1->y + pt2->y);
+					float8_pl(pt1->x, pt2->x),
+					float8_pl(pt1->y, pt2->y));
 }
 
 Datum
 point_add(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -3890,22 +3900,22 @@ point_add(PG_FUNCTION_ARGS)
 	point_add_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_sub_point(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x - pt2->x,
-					pt1->y - pt2->y);
+					float8_mi(pt1->x, pt2->x),
+					float8_mi(pt1->y, pt2->y));
 }
 
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -3913,54 +3923,53 @@ point_sub(PG_FUNCTION_ARGS)
 	point_sub_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_mul_point(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					(pt1->x * pt2->x) - (pt1->y * pt2->y),
-					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+					float8_mi(float8_mul(pt1->x, pt2->x),
+							  float8_mul(pt1->y, pt2->y)),
+					float8_pl(float8_mul(pt1->x, pt2->y),
+							  float8_mul(pt1->y, pt2->x)));
 }
 
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	point_mul_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_div_point(Point *result, Point *pt1, Point *pt2)
 {
-	double		div;
+	float8		div;
 
-	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
-
-	if (div == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
+	div = float8_pl(float8_mul(pt2->x, pt2->x), float8_mul(pt2->y, pt2->y));
 
 	point_construct(result,
-					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
-					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+					float8_div(float8_pl(float8_mul(pt1->x, pt2->x),
+										 float8_mul(pt1->y, pt2->y)), div),
+					float8_div(float8_mi(float8_mul(pt1->y, pt2->x),
+										 float8_mul(pt1->x, pt2->y)), div));
 }
 
 Datum
 point_div(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -4083,24 +4092,24 @@ point_box(PG_FUNCTION_ARGS)
  */
 Datum
 boxes_bound_box(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0),
 			   *box2 = PG_GETARG_BOX_P(1),
 			   *container;
 
 	container = (BOX *) palloc(sizeof(BOX));
 
-	container->high.x = Max(box1->high.x, box2->high.x);
-	container->low.x = Min(box1->low.x, box2->low.x);
-	container->high.y = Max(box1->high.y, box2->high.y);
-	container->low.y = Min(box1->low.y, box2->low.y);
+	container->high.x = float8_max(box1->high.x, box2->high.x);
+	container->low.x = float8_min(box1->low.x, box2->low.x);
+	container->high.y = float8_max(box1->high.y, box2->high.y);
+	container->low.y = float8_min(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(container);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D paths.
  **
  ***********************************************************************/
@@ -4408,21 +4417,22 @@ circle_in(PG_FUNCTION_ARGS)
 		if (*cp == LDELIM)
 			s = cp;
 	}
 
 	pair_decode(s, &circle->center.x, &circle->center.y, &s, "circle", str);
 
 	if (*s == DELIM)
 		s++;
 
 	circle->radius = single_decode(s, &s, "circle", str);
-	if (circle->radius < 0)
+	/* We have to accept NaN as well. */
+	if (circle->radius < 0.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
 
 	while (depth > 0)
 	{
 		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
@@ -4475,21 +4485,21 @@ circle_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	circle->center.x = pq_getmsgfloat8(buf);
 	circle->center.y = pq_getmsgfloat8(buf);
 	circle->radius = pq_getmsgfloat8(buf);
 
-	if (circle->radius < 0)
+	if (circle->radius <= 0.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
 				 errmsg("invalid radius in external \"circle\" value")));
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 /*
  *		circle_send			- converts circle to binary format
  */
@@ -4513,159 +4523,160 @@ circle_send(PG_FUNCTION_ARGS)
  *---------------------------------------------------------*/
 
 /*		circles identical?
  */
 Datum
 circle_same(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPeq(circle1->radius, circle2->radius) &&
+	PG_RETURN_BOOL(((isnan(circle1->radius) && isnan(circle1->radius)) ||
+					FPeq(circle1->radius, circle2->radius)) &&
 				   point_eq_point(&circle1->center, &circle2->center));
 }
 
 /*		circle_overlap	-		does circle1 overlap circle2?
  */
 Datum
 circle_overlap(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle1->radius + circle2->radius));
+						float8_pl(circle1->radius, circle2->radius)));
 }
 
 /*		circle_overleft -		is the right edge of circle1 at or left of
  *								the right edge of circle2?
  */
 Datum
 circle_overleft(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.x + circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_left		-		is circle1 strictly left of circle2?
  */
 Datum
 circle_left(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.x + circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_right	-		is circle1 strictly right of circle2?
  */
 Datum
 circle_right(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.x - circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_overright	-	is the left edge of circle1 at or right of
  *								the left edge of circle2?
  */
 Datum
 circle_overright(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.x - circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_contained		-		is circle1 contained by circle2?
  */
 Datum
 circle_contained(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle2->radius - circle1->radius));
+						float8_mi(circle2->radius, circle1->radius)));
 }
 
 /*		circle_contain	-		does circle1 contain circle2?
  */
 Datum
 circle_contain(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle1->radius - circle2->radius));
+						float8_mi(circle1->radius, circle2->radius)));
 }
 
 
 /*		circle_below		-		is circle1 strictly below circle2?
  */
 Datum
 circle_below(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.y + circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_above	-		is circle1 strictly above circle2?
  */
 Datum
 circle_above(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.y - circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overbelow -		is the upper edge of circle1 at or below
  *								the upper edge of circle2?
  */
 Datum
 circle_overbelow(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.y + circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overabove	-	is the lower edge of circle1 at or above
  *								the lower edge of circle2?
  */
 Datum
 circle_overabove(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.y - circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 
 /*		circle_relop	-		is area(circle1) relop area(circle2), within
  *								our accuracy constraint?
  */
 Datum
 circle_eq(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
@@ -4764,36 +4775,36 @@ circle_sub_pt(PG_FUNCTION_ARGS)
 Datum
 circle_mul_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_mul_point(&result->center, &circle->center, point);
-	result->radius = circle->radius * HYPOT(point->x, point->y);
+	result->radius = float8_mul(circle->radius, HYPOT(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_div_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_div_point(&result->center, &circle->center, point);
-	result->radius = circle->radius / HYPOT(point->x, point->y);
+	result->radius = float8_div(circle->radius, HYPOT(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /*		circle_area		-		returns the area of the circle.
  */
 Datum
 circle_area(PG_FUNCTION_ARGS)
 {
@@ -4803,21 +4814,21 @@ circle_area(PG_FUNCTION_ARGS)
 }
 
 
 /*		circle_diameter -		returns the diameter of the circle.
  */
 Datum
 circle_diameter(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
-	PG_RETURN_FLOAT8(2 * circle->radius);
+	PG_RETURN_FLOAT8(float8_mul(circle->radius, 2.0));
 }
 
 
 /*		circle_radius	-		returns the radius of the circle.
  */
 Datum
 circle_radius(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
@@ -4828,81 +4839,85 @@ circle_radius(PG_FUNCTION_ARGS)
 /*		circle_distance -		returns the distance between
  *								  two circles.
  */
 Datum
 circle_distance(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(&circle1->center, &circle2->center) -
-		(circle1->radius + circle2->radius);
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(&circle1->center, &circle2->center),
+					   float8_pl(circle1->radius, circle2->radius));
+	if (result < 0.0)
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 
 Datum
 circle_contain_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
 	PG_RETURN_BOOL(d <= circle->radius);
 }
 
 
 Datum
 pt_contained_circle(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
 	PG_RETURN_BOOL(d <= circle->radius);
 }
 
 
 /*		dist_pc -		returns the distance between
  *						  a point and a circle.
  */
 Datum
 dist_pc(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center),
+					   circle->radius);
+	if (result < 0.0)
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a circle to a point
  */
 Datum
 dist_cpoint(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center), circle->radius);
+	if (result < 0.0)
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*		circle_center	-		returns the center point of the circle.
  */
 Datum
 circle_center(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *result;
@@ -4910,24 +4925,24 @@ circle_center(PG_FUNCTION_ARGS)
 	result = (Point *) palloc(sizeof(Point));
 	result->x = circle->center.x;
 	result->y = circle->center.y;
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		circle_ar		-		returns the area of the circle.
  */
-static double
+static float8
 circle_ar(CIRCLE *circle)
 {
-	return M_PI * (circle->radius * circle->radius);
+	return float8_mul(float8_mul(circle->radius, circle->radius), M_PI);
 }
 
 
 /*----------------------------------------------------------
  *	Conversion operators.
  *---------------------------------------------------------*/
 
 Datum
 cr_circle(PG_FUNCTION_ARGS)
 {
@@ -4942,65 +4957,65 @@ cr_circle(PG_FUNCTION_ARGS)
 	result->radius = radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_box(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	BOX		   *box;
-	double		delta;
+	float8		delta;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
-	delta = circle->radius / sqrt(2.0);
+	delta = float8_div(circle->radius, sqrt(2.0));
 
-	box->high.x = circle->center.x + delta;
-	box->low.x = circle->center.x - delta;
-	box->high.y = circle->center.y + delta;
-	box->low.y = circle->center.y - delta;
+	box->high.x = float8_pl(circle->center.x, delta);
+	box->low.x = float8_mi(circle->center.x, delta);
+	box->high.y = float8_pl(circle->center.y, delta);
+	box->low.y = float8_mi(circle->center.y, delta);
 
 	PG_RETURN_BOX_P(box);
 }
 
 /* box_circle()
  * Convert a box to a circle.
  */
 Datum
 box_circle(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	circle->center.x = (box->high.x + box->low.x) / 2;
-	circle->center.y = (box->high.y + box->low.y) / 2;
+	circle->center.x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	circle->center.y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 
 	circle->radius = point_dt(&circle->center, &box->high);
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 
 Datum
 circle_poly(PG_FUNCTION_ARGS)
 {
 	int32		npts = PG_GETARG_INT32(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	POLYGON    *poly;
 	int			base_size,
 				size;
 	int			i;
-	double		angle;
-	double		anglestep;
+	float8		angle;
+	float8		anglestep;
 
 	if (FPzero(circle->radius))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("cannot convert circle with radius zero to polygon")));
 
 	if (npts < 2)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("must request at least 2 points")));
@@ -5011,27 +5026,30 @@ circle_poly(PG_FUNCTION_ARGS)
 	/* Check for integer overflow */
 	if (base_size / npts != sizeof(poly->p[0]) || size <= base_size)
 		ereport(ERROR,
 				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 				 errmsg("too many points requested")));
 
 	poly = (POLYGON *) palloc0(size);	/* zero any holes */
 	SET_VARSIZE(poly, size);
 	poly->npts = npts;
 
-	anglestep = (2.0 * M_PI) / npts;
+	anglestep = float8_div(2.0 * M_PI, npts);
 
 	for (i = 0; i < npts; i++)
 	{
-		angle = i * anglestep;
-		poly->p[i].x = circle->center.x - (circle->radius * cos(angle));
-		poly->p[i].y = circle->center.y + (circle->radius * sin(angle));
+		angle = float8_mul(anglestep, i);
+
+		poly->p[i].x = float8_mi(circle->center.x,
+								 float8_mul(circle->radius, cos(angle)));
+		poly->p[i].y = float8_pl(circle->center.y,
+								 float8_mul(circle->radius, sin(angle)));
 	}
 
 	make_bound_box(poly);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
 /*
  * Convert polygon to circle
  *
@@ -5046,26 +5064,27 @@ poly_to_circle(CIRCLE *result, POLYGON *poly)
 	int			i;
 
 	Assert(poly->npts > 0);
 
 	result->center.x = 0;
 	result->center.y = 0;
 	result->radius = 0;
 
 	for (i = 0; i < poly->npts; i++)
 		point_add_point(&result->center, &result->center, &poly->p[i]);
-	result->center.x /= poly->npts;
-	result->center.y /= poly->npts;
+	result->center.x = float8_div(result->center.x, poly->npts);
+	result->center.y = float8_div(result->center.y, poly->npts);
 
 	for (i = 0; i < poly->npts; i++)
-		result->radius += point_dt(&poly->p[i], &result->center);
-	result->radius /= poly->npts;
+		result->radius = float8_pl(result->radius,
+								   point_dt(&poly->p[i], &result->center));
+	result->radius = float8_div(result->radius, poly->npts);
 }
 
 Datum
 poly_circle(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
@@ -5090,44 +5109,44 @@ poly_circle(PG_FUNCTION_ARGS)
  *	http://hopf.math.northwestern.edu/index.html
  *	Description of algorithm:  http://www.linuxjournal.com/article/2197
  *							   http://www.linuxjournal.com/article/2029
  */
 
 #define POINT_ON_POLYGON INT_MAX
 
 static int
 point_inside(Point *p, int npts, Point *plist)
 {
-	double		x0,
+	float8		x0,
 				y0;
-	double		prev_x,
+	float8		prev_x,
 				prev_y;
 	int			i = 0;
-	double		x,
+	float8		x,
 				y;
 	int			cross,
 				total_cross = 0;
 
 	Assert(npts > 0);
 
 	/* compute first polygon point relative to single point */
-	x0 = plist[0].x - p->x;
-	y0 = plist[0].y - p->y;
+	x0 = float8_mi(plist[0].x, p->x);
+	y0 = float8_mi(plist[0].y, p->y);
 
 	prev_x = x0;
 	prev_y = y0;
 	/* loop over polygon points and aggregate total_cross */
 	for (i = 1; i < npts; i++)
 	{
 		/* compute next polygon point relative to single point */
-		x = plist[i].x - p->x;
-		y = plist[i].y - p->y;
+		x = float8_mi(plist[i].x, p->x);
+		y = float8_mi(plist[i].y, p->y);
 
 		/* compute previous to current point crossing */
 		if ((cross = lseg_crossing(x, y, prev_x, prev_y)) == POINT_ON_POLYGON)
 			return 2;
 		total_cross += cross;
 
 		prev_x = x;
 		prev_y = y;
 	}
 
@@ -5145,69 +5164,74 @@ point_inside(Point *p, int npts, Point *plist)
 /* lseg_crossing()
  * Returns +/-2 if line segment crosses the positive X-axis in a +/- direction.
  * Returns +/-1 if one point is on the positive X-axis.
  * Returns 0 if both points are on the positive X-axis, or there is no crossing.
  * Returns POINT_ON_POLYGON if the segment contains (0,0).
  * Wow, that is one confusing API, but it is used above, and when summed,
  * can tell is if a point is in a polygon.
  */
 
 static int
-lseg_crossing(double x, double y, double prev_x, double prev_y)
+lseg_crossing(float8 x, float8 y, float8 prev_x, float8 prev_y)
 {
-	double		z;
+	float8		z;
 	int			y_sign;
 
 	if (FPzero(y))
 	{							/* y == 0, on X axis */
 		if (FPzero(x))			/* (x,y) is (0,0)? */
 			return POINT_ON_POLYGON;
 		else if (FPgt(x, 0))
 		{						/* x > 0 */
 			if (FPzero(prev_y)) /* y and prev_y are zero */
 				/* prev_x > 0? */
-				return FPgt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
-			return FPlt(prev_y, 0) ? 1 : -1;
+				return FPgt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
+			return FPlt(prev_y, 0.0) ? 1 : -1;
 		}
 		else
 		{						/* x < 0, x not on positive X axis */
 			if (FPzero(prev_y))
 				/* prev_x < 0? */
-				return FPlt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
+				return FPlt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
 			return 0;
 		}
 	}
 	else
 	{							/* y != 0 */
 		/* compute y crossing direction from previous point */
-		y_sign = FPgt(y, 0) ? 1 : -1;
+		y_sign = FPgt(y, 0.0) ? 1 : -1;
 
 		if (FPzero(prev_y))
 			/* previous point was on X axis, so new point is either off or on */
-			return FPlt(prev_x, 0) ? 0 : y_sign;
-		else if (FPgt(y_sign * prev_y, 0))
+			return FPlt(prev_x, 0.0) ? 0 : y_sign;
+		else if ((y_sign < 0 && FPlt(prev_y, 0.0)) ||
+				 (y_sign > 0 && FPgt(prev_y, 0.0)))
 			/* both above or below X axis */
 			return 0;			/* same sign */
 		else
 		{						/* y and prev_y cross X-axis */
-			if (FPge(x, 0) && FPgt(prev_x, 0))
+			if (FPge(x, 0.0) && FPgt(prev_x, 0.0))
 				/* both non-negative so cross positive X-axis */
 				return 2 * y_sign;
-			if (FPlt(x, 0) && FPle(prev_x, 0))
+			if (FPlt(x, 0.0) && FPle(prev_x, 0.0))
 				/* both non-positive so do not cross positive X-axis */
 				return 0;
 
 			/* x and y cross axises, see URL above point_inside() */
-			z = (x - prev_x) * y - (y - prev_y) * x;
+			z = float8_mi(float8_mul(float8_mi(x, prev_x), y),
+						  float8_mul(float8_mi(y, prev_y), x));
 			if (FPzero(z))
 				return POINT_ON_POLYGON;
-			return FPgt((y_sign * z), 0) ? 0 : 2 * y_sign;
+			if ((y_sign < 0 && FPlt(z, 0.0)) ||
+				(y_sign > 0 && FPgt(z, 0.0)))
+				return 0;
+			return 2 * y_sign;
 		}
 	}
 }
 
 
 static bool
 plist_same(int npts, Point *p1, Point *p2)
 {
 	int			i,
 				ii,
@@ -5277,47 +5301,53 @@ plist_same(int npts, Point *p1, Point *p2)
  *					 = x * sqrt( 1 + y^2/x^2 )
  *					 = x * sqrt( 1 + y/x * y/x )
  *
  * It is expected that this routine will eventually be replaced with the
  * C99 hypot() function.
  *
  * This implementation conforms to IEEE Std 1003.1 and GLIBC, in that the
  * case of hypot(inf,nan) results in INF, and not NAN.
  *-----------------------------------------------------------------------
  */
-double
-pg_hypot(double x, double y)
+float8
+pg_hypot(float8 x, float8 y)
 {
-	double		yx;
+	float8		yx,
+				result;
 
 	/* Handle INF and NaN properly */
 	if (isinf(x) || isinf(y))
 		return get_float8_infinity();
 
 	if (isnan(x) || isnan(y))
 		return get_float8_nan();
 
 	/* Else, drop any minus signs */
 	x = fabs(x);
 	y = fabs(y);
 
 	/* Swap x and y if needed to make x the larger one */
 	if (x < y)
 	{
-		double		temp = x;
+		float8		temp = x;
 
 		x = y;
 		y = temp;
 	}
 
 	/*
 	 * If y is zero, the hypotenuse is x.  This test saves a few cycles in
 	 * such cases, but more importantly it also protects against
 	 * divide-by-zero errors, since now x >= y.
 	 */
 	if (y == 0.0)
 		return x;
 
 	/* Determine the hypotenuse */
 	yx = y / x;
-	return x * sqrt(1.0 + (yx * yx));
+	result = x * sqrt(1.0 + (yx * yx));
+
+	check_float8_val(result, false, false);
+	Assert(result >= 0.0);
+
+	return result;
 }
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index c800bb1338..fe8ae200f3 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -76,38 +76,38 @@
 #include "access/spgist.h"
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
 #include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
- * is going only going to be used in a place to effect the performance
+ * is only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
 compareDoubles(const void *a, const void *b)
 {
-	double		x = *(double *) a;
-	double		y = *(double *) b;
+	float8		x = *(float8 *) a;
+	float8		y = *(float8 *) b;
 
 	if (x == y)
 		return 0;
 	return (x > y) ? 1 : -1;
 }
 
 typedef struct
 {
-	double		low;
-	double		high;
+	float8		low;
+	float8		high;
 } Range;
 
 typedef struct
 {
 	Range		left;
 	Range		right;
 } RangeBox;
 
 typedef struct
 {
@@ -167,21 +167,21 @@ getRangeBox(BOX *box)
 /*
  * Initialize the traversal value
  *
  * In the beginning, we don't have any restrictions.  We have to
  * initialize the struct to cover the whole 4D space.
  */
 static RectBox *
 initRectBox(void)
 {
 	RectBox    *rect_box = (RectBox *) palloc(sizeof(RectBox));
-	double		infinity = get_float8_infinity();
+	float8		infinity = get_float8_infinity();
 
 	rect_box->range_box_x.left.low = -infinity;
 	rect_box->range_box_x.left.high = infinity;
 
 	rect_box->range_box_x.right.low = -infinity;
 	rect_box->range_box_x.right.high = infinity;
 
 	rect_box->range_box_y.left.low = -infinity;
 	rect_box->range_box_y.left.high = infinity;
 
@@ -410,40 +410,40 @@ spg_box_quad_choose(PG_FUNCTION_ARGS)
  * point as the median of the coordinates of the boxes.
  */
 Datum
 spg_box_quad_picksplit(PG_FUNCTION_ARGS)
 {
 	spgPickSplitIn *in = (spgPickSplitIn *) PG_GETARG_POINTER(0);
 	spgPickSplitOut *out = (spgPickSplitOut *) PG_GETARG_POINTER(1);
 	BOX		   *centroid;
 	int			median,
 				i;
-	double	   *lowXs = palloc(sizeof(double) * in->nTuples);
-	double	   *highXs = palloc(sizeof(double) * in->nTuples);
-	double	   *lowYs = palloc(sizeof(double) * in->nTuples);
-	double	   *highYs = palloc(sizeof(double) * in->nTuples);
+	float8	   *lowXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *lowYs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highYs = palloc(sizeof(float8) * in->nTuples);
 
 	/* Calculate median of all 4D coordinates */
 	for (i = 0; i < in->nTuples; i++)
 	{
 		BOX		   *box = DatumGetBoxP(in->datums[i]);
 
 		lowXs[i] = box->low.x;
 		highXs[i] = box->high.x;
 		lowYs[i] = box->low.y;
 		highYs[i] = box->high.y;
 	}
 
-	qsort(lowXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(lowYs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highYs, in->nTuples, sizeof(double), compareDoubles);
+	qsort(lowXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(lowYs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highYs, in->nTuples, sizeof(float8), compareDoubles);
 
 	median = in->nTuples / 2;
 
 	centroid = palloc(sizeof(BOX));
 
 	centroid->low.x = lowXs[median];
 	centroid->high.x = highXs[median];
 	centroid->low.y = lowYs[median];
 	centroid->high.y = highYs[median];
 
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index ea2e3690ea..7b8481c70e 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -1,42 +1,41 @@
 /*-------------------------------------------------------------------------
  *
  * geo_decls.h - Declarations for various 2D constructs.
  *
  *
  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * src/include/utils/geo_decls.h
  *
- * NOTE
- *	  These routines do *not* use the float types from adt/.
- *
  *	  XXX These routines were not written by a numerical analyst.
  *
  *	  XXX I have made some attempt to flesh out the operators
  *		and data types. There are still some more to do. - tgl 97/04/19
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEO_DECLS_H
 #define GEO_DECLS_H
 
 #include <math.h>
 
 #include "fmgr.h"
 #include "utils/float.h"
 
 /*--------------------------------------------------------------------
  * Useful floating point utilities and constants.
- *-------------------------------------------------------------------*/
-
+ *-------------------------------------------------------------------
+ *
+ * XXX They are not NaN-aware.
+ */
 
 #define EPSILON					1.0E-06
 
 #ifdef EPSILON
 #define FPzero(A)				(fabs(A) <= EPSILON)
 #define FPeq(A,B)				(fabs((A) - (B)) <= EPSILON)
 #define FPne(A,B)				(fabs((A) - (B)) > EPSILON)
 #define FPlt(A,B)				((B) - (A) > EPSILON)
 #define FPle(A,B)				((A) - (B) <= EPSILON)
 #define FPgt(A,B)				((A) - (B) > EPSILON)
@@ -51,21 +50,21 @@
 #define FPge(A,B)				((A) >= (B))
 #endif
 
 #define HYPOT(A, B)				pg_hypot(A, B)
 
 /*---------------------------------------------------------------------
  * Point - (x,y)
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		x,
+	float8		x,
 				y;
 } Point;
 
 
 /*---------------------------------------------------------------------
  * LSEG - A straight line, specified by endpoints.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		p[2];
@@ -83,21 +82,21 @@ typedef struct
 	int32		dummy;			/* padding to make it double align */
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } PATH;
 
 
 /*---------------------------------------------------------------------
  * LINE - Specified by its general equation (Ax+By+C=0).
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		A,
+	float8		A,
 				B,
 				C;
 } LINE;
 
 
 /*---------------------------------------------------------------------
  * BOX	- Specified by two corner points, which are
  *		 sorted to save calculation time later.
  *-------------------------------------------------------------------*/
 typedef struct
@@ -118,21 +117,21 @@ typedef struct
 	BOX			boundbox;
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } POLYGON;
 
 /*---------------------------------------------------------------------
  * CIRCLE - Specified by a center point and radius.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		center;
-	double		radius;
+	float8		radius;
 } CIRCLE;
 
 /*
  * fmgr interface macros
  *
  * Path and Polygon are toastable varlena types, the others are just
  * fixed-size pass-by-reference types.
  */
 
 #define DatumGetPointP(X)	 ((Point *) DatumGetPointer(X))
@@ -172,13 +171,13 @@ typedef struct
 #define DatumGetCircleP(X)	  ((CIRCLE *) DatumGetPointer(X))
 #define CirclePGetDatum(X)	  PointerGetDatum(X)
 #define PG_GETARG_CIRCLE_P(n) DatumGetCircleP(PG_GETARG_DATUM(n))
 #define PG_RETURN_CIRCLE_P(x) return CirclePGetDatum(x)
 
 
 /*
  * in geo_ops.c
  */
 
-extern double pg_hypot(double x, double y);
+extern float8 pg_hypot(float8 x, float8 y);
 
 #endif							/* GEO_DECLS_H */
-- 
2.13.6 (Apple Git-96)

0004-line-fixes-v06.patchapplication/octet-stream; name=0004-line-fixes-v06.patchDownload
From e93b101fc83114a37b5a5b0f9cbd866d51a6820b Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sun, 28 May 2017 11:35:17 +0200
Subject: [PATCH 4/6] line-fixes-v06

Fix obvious problems around the line datatype

I have noticed some line operators retuning wrong results, and Tom Lane
spotted similar problems on more places.  Source history reveals that
during 1990s, the internal format of the line datatype is changed, but
most functions haven't got the hint.  The fixes include:

* Reject invalid specification A=B=0 on receive
* Avoid division by zero on perpendicular operator
* Fix intersection and distance operators when neither A nor B are 1
* Return NULL for closest point when objects are parallel
* Check whether closest point of line segments is the intersection point
* Fix closest point of line segments being on the wrong segment

The changes are also aiming make line operators more symmetric and less
sensitive to floating point precision loss.  The EPSILON interferes with
every minor change in different ways.  It is hard to guess which
behaviour is more expected, but we can assume threating both sides of
the operators more equally is more expected.

Previous discussion:
https://www.postgresql.org/message-id/flat/CAE2gYzw_-z%3DV2kh8QqFjenu%3D8MJXzOP44wRW%3DAzzeamrmTT1%3DQ%40mail.gmail.com
---
 src/backend/utils/adt/geo_ops.c | 231 +++++++++++++++++++++++++++-------------
 1 file changed, 155 insertions(+), 76 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 16f853ae9b..a33ff3f56b 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -47,20 +47,22 @@ static int	point_inside(Point *p, int npts, Point *plist);
 
 /* Routines for two-dimensional lines */
 static inline void line_construct_pm(LINE *result, Point *pt, float8 m);
 static inline void line_construct_pts(LINE *result, Point *pt1, Point *pt2);
 static bool	line_interpt_line(Point *result, LINE *l1, LINE *l2);
 static bool line_contain_point(LINE *line, Point *point);
 static float8 line_closept_point(Point *result, LINE *line, Point *pt);
 
 /* Routines for two-dimensional line segments */
 static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
+static bool lseg_parallel_line(LSEG *lseg, LINE *line);
+static bool lseg_parallel_lseg(LSEG *l1, LSEG *l2);
 static bool	lseg_interpt_line(Point *result, LSEG *lseg, LINE *line);
 static bool	lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2);
 static int	lseg_crossing(float8 x, float8 y, float8 px, float8 py);
 static bool	lseg_contain_point(LSEG *lseg, Point *point);
 static float8 lseg_closept_point(Point *result, LSEG *lseg, Point *pt);
 static float8 lseg_closept_line(Point *result, LSEG *lseg, LINE *line);
 static float8 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2);
 
 /* Routines for two-dimensional boxes */
 static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
@@ -970,20 +972,25 @@ line_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LINE	   *line;
 
 	line = (LINE *) palloc(sizeof(LINE));
 
 	line->A = pq_getmsgfloat8(buf);
 	line->B = pq_getmsgfloat8(buf);
 	line->C = pq_getmsgfloat8(buf);
 
+	if (FPzero(line->A) && FPzero(line->B))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+				 errmsg("invalid line specification: A and B cannot both be zero")));
+
 	PG_RETURN_LINE_P(line);
 }
 
 /*
  *		line_send			- converts line to binary format
  */
 Datum
 line_send(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -1064,45 +1071,59 @@ line_construct_pp(PG_FUNCTION_ARGS)
 
 Datum
 line_intersect(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	PG_RETURN_BOOL(line_interpt_line(NULL, l1, l2));
 }
 
+
+/*
+ * Check whether the two lines are parallel
+ *
+ * They are parallel if their slopes are FPeq().
+ */
 Datum
 line_parallel(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
+	float8		m1,
+				m2;
 
-	if (FPzero(l1->B))
-		PG_RETURN_BOOL(FPzero(l2->B));
+	m1 = slope(0.0, l1->B, l1->A, 0.0);
+	m2 = slope(0.0, l2->B, l2->A, 0.0);
 
-	PG_RETURN_BOOL(FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))));
+	PG_RETURN_BOOL(FPeq(m1, m2));
 }
 
+
+/*
+ * Check whether the two lines are perpendicular
+ *
+ * They are perpendicular if the slope of one is FPeq() with the inverse
+ * slope of the other.
+ */
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
+	float8		m1,
+				m2;
 
-	if (FPzero(l1->A))
-		PG_RETURN_BOOL(FPzero(l2->B));
-	else if (FPzero(l1->B))
-		PG_RETURN_BOOL(FPzero(l2->A));
+	m1 = slope(0.0, l1->B, l1->A, 0.0);
+	m2 = slope(l2->A, 0.0, l2->B, 0.0);
 
-	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
-								   float8_mul(l1->B, l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(m1, m2));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
@@ -1114,25 +1135,28 @@ line_horizontal(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(FPzero(line->A));
 }
 
 Datum
 line_eq(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		ratio;
 
-	if (!FPzero(l2->A) && !isnan(l2->A))
+	if (!FPzero(l1->A) && !isnan(l1->A) &&
+		!FPzero(l2->A) && !isnan(l2->A))
 		ratio = float8_div(l1->A, l2->A);
-	else if (!FPzero(l2->B) && !isnan(l2->B))
+	else if (!FPzero(l1->B) && !isnan(l1->B) &&
+			 !FPzero(l2->B) && !isnan(l2->B))
 		ratio = float8_div(l1->B, l2->B);
-	else if (!FPzero(l2->C) && !isnan(l2->C))
+	else if (!FPzero(l1->C) && !isnan(l1->C) &&
+			 !FPzero(l2->C) && !isnan(l2->C))
 		ratio = float8_div(l1->C, l2->C);
 	else
 		ratio = 1.0;
 
 	PG_RETURN_BOOL(((isnan(l1->A) && isnan(l2->A)) ||
 					FPeq(l1->A, float8_mul(ratio, l2->A))) &&
 				   ((isnan(l1->B) && isnan(l2->B)) ||
 					FPeq(l1->B, float8_mul(ratio, l2->B))) &&
 				   ((isnan(l1->C) && isnan(l2->C)) ||
 					FPeq(l1->C, float8_mul(ratio, l2->C))));
@@ -1144,30 +1168,35 @@ line_eq(PG_FUNCTION_ARGS)
  *---------------------------------------------------------*/
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	float8		result;
-	Point		tmp;
+	float8		ratio;
 
 	if (line_interpt_line(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
-	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
-	point_construct(&tmp, 0.0, l1->C);
-	result = line_closept_point(NULL, l2, &tmp);
-	PG_RETURN_FLOAT8(result);
+
+	if (!FPzero(l1->A) && !isnan(l1->A) && !FPzero(l2->A) && !isnan(l2->A))
+		ratio = float8_div(l1->A, l2->A);
+	else if (!FPzero(l1->B) && !isnan(l1->B) && !FPzero(l2->B) && !isnan(l2->B))
+		ratio = float8_div(l1->B, l2->B);
+	else
+		ratio = 1.0;
+
+	PG_RETURN_FLOAT8(float8_div(fabs(float8_mi(l1->C,
+											   float8_mul(ratio, l2->C))),
+								HYPOT(l1->A, l1->B)));
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
@@ -1194,40 +1223,56 @@ line_interpt(PG_FUNCTION_ARGS)
  * If the lines have NaN constants, we will return true, and the intersection
  * point would have NaN coordinates.  We shouldn't return false in this case
  * because that would mean the lines are parallel.
  */
 static bool
 line_interpt_line(Point *result, LINE *l1, LINE *l2)
 {
 	float8		x,
 				y;
 
-	if (FPzero(l1->B))			/* l1 vertical? */
+	if (FPzero(l1->A))			/* l1 horizontal? */
+	{
+		if (FPzero(l2->A))		/* l2 horizontal? */
+			return false;
+
+		y = float8_div(-l1->C, l1->B);
+		x = float8_div(-float8_pl(float8_mul(l2->B, y), l2->C), l2->A);
+	}
+	else if (FPzero(l2->A))		/* l2 horizontal? */
+	{
+		y = float8_div(-l2->C, l2->B);
+		x = float8_div(-float8_pl(float8_mul(l1->B, y), l1->C), l1->A);
+	}
+	else if (FPzero(l1->B))		/* l1 vertical? */
 	{
 		if (FPzero(l2->B))		/* l2 vertical? */
 			return false;
 
-		x = l1->C;
-		y = float8_pl(float8_mul(l2->A, x), l2->C);
+		x = float8_div(-l1->C, l1->A);
+		y = float8_div(-float8_pl(float8_mul(l2->A, x), l2->C), l2->B);
 	}
 	else if (FPzero(l2->B))		/* l2 vertical? */
 	{
-		x = l2->C;
-		y = float8_pl(float8_mul(l1->A, x), l1->C);
+		x = float8_div(-l2->C, l2->A);
+		y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
 	}
 	else
 	{
-		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
+		if (FPeq(float8_mul(l1->A, l2->B), float8_mul(l2->A, l1->B)))
 			return false;
 
-		x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
-		y = float8_pl(float8_mul(l1->A, x), l1->C);
+		x = float8_div(float8_mi(float8_mul(l1->B, l2->C),
+								 float8_mul(l2->B, l1->C)),
+					   float8_mi(float8_mul(l1->A, l2->B),
+								 float8_mul(l2->A, l1->B)));
+		y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
 	}
 	if (result != NULL)
 		point_construct(result, x, y);
 
 	return true;
 }
 
 
 /***********************************************************************
  **
@@ -2021,59 +2066,83 @@ lseg_length(PG_FUNCTION_ARGS)
 Datum
 lseg_intersect(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_BOOL(lseg_interpt_lseg(NULL, l1, l2));
 }
 
 
+/*
+ * Check whether the line segment is parallel with the line
+ *
+ * They are parallel if their slopes are FPeq().
+ */
+static bool
+lseg_parallel_line(LSEG *lseg, LINE *line)
+{
+	float8		m1,
+				m2;
+
+	m1 = slope(lseg->p[0].x, lseg->p[1].x, lseg->p[0].y, lseg->p[1].y);
+	m2 = slope(0.0, line->B, line->A, 0.0);
+
+	return FPeq(m1, m2);
+}
+
+
+/*
+ * Check whether the two line segment are parallel
+ *
+ * They are parallel if their slopes are FPeq().
+ */
+static bool
+lseg_parallel_lseg(LSEG *l1, LSEG *l2)
+{
+	float8		m1,
+				m2;
+
+	m1 = slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y);
+	m2 = slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y);
+
+	return FPeq(m1, m2);
+}
+
 Datum
 lseg_parallel(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPeq(slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y),
-						slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y)));
+	PG_RETURN_BOOL(lseg_parallel_lseg(l1, l2));
 }
 
+
 /* lseg_perp()
  * Determine if two line segments are perpendicular.
  *
- * This code did not get the correct answer for
- *	'((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg
- * So, modified it to check explicitly for slope of vertical line
- *	returned by slope() and the results seem better.
- * - thomas 1998-01-31
+ * They are perpendicular if the slope of one is FPeq() with the inverse
+ * slope of the other.
  */
 Datum
 lseg_perp(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	float8		m1,
 				m2;
 
 	m1 = slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y);
-	m2 = slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y);
+	m2 = slope(l2->p[0].y, l2->p[1].y, l2->p[1].x, l2->p[0].x);
 
-#ifdef GEODEBUG
-	printf("lseg_perp- slopes are %g and %g\n", m1, m2);
-#endif
-	if (FPzero(m1))
-		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
-	else if (FPzero(m2))
-		PG_RETURN_BOOL(FPeq(m1, DBL_MAX));
-
-	PG_RETURN_BOOL(FPeq(m1 / m2, -1.0));
+	PG_RETURN_BOOL(FPeq(m1, m2));
 }
 
 Datum
 lseg_vertical(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 
 	PG_RETURN_BOOL(FPeq(lseg->p[0].x, lseg->p[1].x));
 }
 
@@ -2321,30 +2390,22 @@ dist_pb(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
-	float8		result;
 
-	if (lseg_interpt_line(NULL, lseg, line))
-		result = 0.0;
-	else
-		/* XXX shouldn't we take the min not max? */
-		result = float8_max(line_closept_point(NULL, line, &lseg->p[0]),
-							line_closept_point(NULL, line, &lseg->p[1]));
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(lseg_closept_line(NULL, lseg, line));
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
@@ -2509,36 +2570,40 @@ lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
 /*
  *		The intersection point of a perpendicular of the line
  *		through the point.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 line_closept_point(Point *result, LINE *line, Point *point)
 {
-	bool		retval;
 	float8		m;
+	Point		closept;
 	LINE		tmp;
 
 	/* Drop a perpendicular and find the intersection point */
 	m = slope(line->A, 0.0, line->B, 0.0);
 	line_construct_pm(&tmp, point, m);
-	retval = line_interpt_line(result, line, &tmp);
-	Assert(retval);		/* XXX We need something better. */
 
 	/*
-	 * XXX We could use the distance to the closest point, but
-	 * line_interpt_line() is currently giving wrong results.
+	 * Ordinarily we should always find an intersection point, but that could
+	 * fail in the presence of NaN coordinates, and perhaps even from simple
+	 * roundoff issues.
 	 */
-	return fabs((line->A * point->x + line->B * point->y + line->C) /
-				HYPOT(line->A, line->B));
+	if (!line_interpt_line(&closept, &tmp, line))
+		closept = *point;
+
+	if (result != NULL)
+		*result = closept;
+
+	return point_dt(&closept, point);
 }
 
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -2590,64 +2655,75 @@ close_ps(PG_FUNCTION_ARGS)
 		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point to l1 on l2.
  *
  * This sets the closest point to the *result if it is not NULL and returns
- * the distance to the closest point.
- *
- * XXX This function is wrong.  If must never set the *result to a point on
- * the second segment.
+ * the distance to the closest point.  We first eliminate the case
+ * the segments intersecting with each other.  Then we try to find
+ * the closest point on the first segment by trying the endpoints of
+ * the second.  Though, it is still possible for the closest point to be
+ * one of the endpoints, so we test them.
  */
 static float8
 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
 {
 	Point		point;
 	float8		dist,
 				d;
 
-	d = lseg_closept_point(NULL, l1, &l2->p[0]);
-	dist = d;
-	if (result != NULL)
-		*result = l2->p[0];
+	if (lseg_interpt_lseg(result, l1, l2))
+		return 0.0;
 
-	d = lseg_closept_point(NULL, l1, &l2->p[1]);
+	dist = lseg_closept_point(result, l1, &l2->p[0]);
+
+	d = lseg_closept_point(&point, l1, &l2->p[1]);
 	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
-			*result = l2->p[1];
+			*result = point;
 	}
 
-	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[0]), dist))
-		d = lseg_closept_point(result, l1, &point);
-
-	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[1]), dist))
-		d = lseg_closept_point(result, l1, &point);
-
+	d = lseg_closept_point(NULL, l2, &l1->p[0]);
 	if (float8_lt(d, dist))
+	{
 		dist = d;
+		if (result != NULL)
+			*result = l1->p[0];
+	}
+
+	d = lseg_closept_point(NULL, l2, &l1->p[1]);
+	if (float8_lt(d, dist))
+	{
+		dist = d;
+		if (result != NULL)
+			*result = l1->p[1];
+	}
 
 	return dist;
 }
 
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
+	if (lseg_parallel_lseg(l1, l2))
+		PG_RETURN_NULL();
+
 	result = (Point *) palloc(sizeof(Point));
 
 	if (isnan(lseg_closept_lseg(result, l2, l1)))
 		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
@@ -2808,20 +2884,23 @@ lseg_closept_line(Point *result, LSEG *lseg, LINE *line)
 	}
 }
 
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
+	if (lseg_parallel_line(lseg, line))
+		PG_RETURN_NULL();
+
 	result = (Point *) palloc(sizeof(Point));
 
 	if (isnan(lseg_closept_line(result, lseg, line)))
 		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
-- 
2.13.6 (Apple Git-96)

0005-float-zero-v02.patchapplication/octet-stream; name=0005-float-zero-v02.patchDownload
From f59b45244a5348b8eb85933b9c39c93f84f11d36 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Thu, 2 Nov 2017 12:21:19 +0100
Subject: [PATCH 5/6] float-zero-v02

Check for float -0 after multiplications and divisions
---
 src/include/utils/float.h | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/src/include/utils/float.h b/src/include/utils/float.h
index c9f5fd30ca..021732d5c6 100644
--- a/src/include/utils/float.h
+++ b/src/include/utils/float.h
@@ -215,64 +215,76 @@ float8_mi(float8 val1, float8 val2)
 
 static inline float4
 float4_mul(float4 val1, float4 val2)
 {
 	float4		result;
 
 	result = val1 * val2;
 	check_float4_val(result, isinf(val1) || isinf(val2),
 					 val1 == 0.0f || val2 == 0.0f);
 
+	if (result == -0.0f)
+		result = 0.0f;
+
 	return result;
 }
 
 static inline float8
 float8_mul(float8 val1, float8 val2)
 {
 	float8		result;
 
 	result = val1 * val2;
 	check_float8_val(result, isinf(val1) || isinf(val2),
 					 val1 == 0.0 || val2 == 0.0);
 
+	if (result == -0.0)
+		result = 0.0;
+
 	return result;
 }
 
 static inline float4
 float4_div(float4 val1, float4 val2)
 {
 	float4		result;
 
 	if (val2 == 0.0f)
 		ereport(ERROR,
 				(errcode(ERRCODE_DIVISION_BY_ZERO),
 				 errmsg("division by zero")));
 
 	result = val1 / val2;
 	check_float4_val(result, isinf(val1) || isinf(val2), val1 == 0.0f);
 
+	if (result == -0.0f)
+		result = 0.0f;
+
 	return result;
 }
 
 static inline float8
 float8_div(float8 val1, float8 val2)
 {
 	float8		result;
 
 	if (val2 == 0.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_DIVISION_BY_ZERO),
 				 errmsg("division by zero")));
 
 	result = val1 / val2;
 	check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
 
+	if (result == -0.0)
+		result = 0.0;
+
 	return result;
 }
 
 /*
  * Routines for NaN-aware comparisons
  *
  * We consider all NANs to be equal and larger than any non-NAN. This is
  * somewhat arbitrary; the important thing is to have a consistent sort
  * order.
  */
-- 
2.13.6 (Apple Git-96)

0006-geo-tests-v02.patchapplication/octet-stream; name=0006-geo-tests-v02.patchDownload
From aa99fad2e2c3aad608fe202946962fb1c8141711 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Tue, 24 Oct 2017 11:28:21 +0200
Subject: [PATCH 6/6] geo-tests-v02

Improve test coverage of geometric types

The tests for the geometric functions and operators were in sad state.
This commit increases test coverage of geo_ops.c significantly.  It
removes the alternative results to expect -0 on some platforms.  We
better try to return the same results on different platforms, but if we
can't we can add them back using the results from build farm.

The tests are added to geometric.sql file.  It is not clear where to
put them as there are many cross datatype operators.  Organising them
on a single file sorted by the left hand side of the operators appear
to be a simple solution.  We may take this further and remove the other
tests later.
---
 src/test/regress/expected/box.out          |   44 +-
 src/test/regress/expected/circle.out       |   39 +-
 src/test/regress/expected/create_index.out |   73 +-
 src/test/regress/expected/geometry.out     | 4974 ++++++++++++++++++++++++++--
 src/test/regress/expected/geometry_1.out   |  563 ----
 src/test/regress/expected/geometry_2.out   |  563 ----
 src/test/regress/expected/line.out         |  267 +-
 src/test/regress/expected/lseg.out         |   24 +-
 src/test/regress/expected/path.out         |   49 +-
 src/test/regress/expected/point.out        |  358 +-
 src/test/regress/expected/polygon.out      |  200 +-
 src/test/regress/sql/box.sql               |    9 +
 src/test/regress/sql/circle.sql            |   10 +-
 src/test/regress/sql/geometry.sql          |  400 ++-
 src/test/regress/sql/line.sql              |   76 +-
 src/test/regress/sql/lseg.sql              |    9 +-
 src/test/regress/sql/path.sql              |   22 +-
 src/test/regress/sql/point.sql             |   10 +
 src/test/regress/sql/polygon.sql           |   91 +-
 19 files changed, 5569 insertions(+), 2212 deletions(-)
 delete mode 100644 src/test/regress/expected/geometry_1.out
 delete mode 100644 src/test/regress/expected/geometry_2.out

diff --git a/src/test/regress/expected/box.out b/src/test/regress/expected/box.out
index 49af242c8c..998b52223c 100644
--- a/src/test/regress/expected/box.out
+++ b/src/test/regress/expected/box.out
@@ -11,92 +11,109 @@
 -- 1	| o-+-o
 --	|   |
 -- 0	+---+
 --
 --	0 1 2 3
 --
 -- boxes are specified by two points, given by four floats x1,y1,x2,y2
 CREATE TABLE BOX_TBL (f1 box);
 INSERT INTO BOX_TBL (f1) VALUES ('(2.0,2.0,0.0,0.0)');
 INSERT INTO BOX_TBL (f1) VALUES ('(1.0,1.0,3.0,3.0)');
+INSERT INTO BOX_TBL (f1) VALUES ('((-8, 2), (-2, -10))');
 -- degenerate cases where the box is a line or a point
 -- note that lines and points boxes all have zero area
 INSERT INTO BOX_TBL (f1) VALUES ('(2.5, 2.5, 2.5,3.5)');
 INSERT INTO BOX_TBL (f1) VALUES ('(3.0, 3.0,3.0,3.0)');
 -- badly formatted box inputs
 INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
 ERROR:  invalid input syntax for type box: "(2.3, 4.5)"
 LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
                                          ^
+INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+ERROR:  invalid input syntax for type box: "[1, 2, 3, 4)"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+                                         ^
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+ERROR:  invalid input syntax for type box: "(1, 2, 3, 4]"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+                                         ^
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+ERROR:  invalid input syntax for type box: "(1, 2, 3, 4) x"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+                                         ^
 INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
 ERROR:  invalid input syntax for type box: "asdfasdf(ad"
 LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
                                          ^
 SELECT '' AS four, * FROM BOX_TBL;
  four |         f1          
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
+      | (-2,2),(-8,-10)
       | (2.5,3.5),(2.5,2.5)
       | (3,3),(3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, b.*, area(b.f1) as barea
    FROM BOX_TBL b;
  four |         f1          | barea 
 ------+---------------------+-------
       | (2,2),(0,0)         |     4
       | (3,3),(1,1)         |     4
+      | (-2,2),(-8,-10)     |    72
       | (2.5,3.5),(2.5,2.5) |     0
       | (3,3),(3,3)         |     0
-(4 rows)
+(5 rows)
 
 -- overlap
 SELECT '' AS three, b.f1
    FROM BOX_TBL b
    WHERE b.f1 && box '(2.5,2.5,1.0,1.0)';
  three |         f1          
 -------+---------------------
        | (2,2),(0,0)
        | (3,3),(1,1)
        | (2.5,3.5),(2.5,2.5)
 (3 rows)
 
 -- left-or-overlap (x only)
 SELECT '' AS two, b1.*
    FROM BOX_TBL b1
    WHERE b1.f1 &< box '(2.0,2.0,2.5,2.5)';
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- right-or-overlap (x only)
 SELECT '' AS two, b1.*
    FROM BOX_TBL b1
    WHERE b1.f1 &> box '(2.0,2.0,2.5,2.5)';
  two |         f1          
 -----+---------------------
      | (2.5,3.5),(2.5,2.5)
      | (3,3),(3,3)
 (2 rows)
 
 -- left of
 SELECT '' AS two, b.f1
    FROM BOX_TBL b
    WHERE b.f1 << box '(3.0,3.0,5.0,5.0)';
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- area <=
 SELECT '' AS four, b.f1
    FROM BOX_TBL b
    WHERE b.f1 <= box '(3.0,3.0,5.0,5.0)';
  four |         f1          
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
       | (2.5,3.5),(2.5,2.5)
@@ -120,47 +137,50 @@ SELECT '' AS two, b.f1
  two |     f1      
 -----+-------------
      | (2,2),(0,0)
      | (3,3),(1,1)
 (2 rows)
 
 -- area >
 SELECT '' AS two, b.f1
    FROM BOX_TBL b				-- zero area
    WHERE b.f1 > box '(3.5,3.0,4.5,3.0)';
- two |     f1      
------+-------------
+ two |       f1        
+-----+-----------------
      | (2,2),(0,0)
      | (3,3),(1,1)
-(2 rows)
+     | (-2,2),(-8,-10)
+(3 rows)
 
 -- area >=
 SELECT '' AS four, b.f1
    FROM BOX_TBL b				-- zero area
    WHERE b.f1 >= box '(3.5,3.0,4.5,3.0)';
  four |         f1          
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
+      | (-2,2),(-8,-10)
       | (2.5,3.5),(2.5,2.5)
       | (3,3),(3,3)
-(4 rows)
+(5 rows)
 
 -- right of
 SELECT '' AS two, b.f1
    FROM BOX_TBL b
    WHERE box '(3.0,3.0,5.0,5.0)' >> b.f1;
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- contained in
 SELECT '' AS three, b.f1
    FROM BOX_TBL b
    WHERE b.f1 <@ box '(0,0,3,3)';
  three |     f1      
 -------+-------------
        | (2,2),(0,0)
        | (3,3),(1,1)
        | (3,3),(3,3)
@@ -186,41 +206,43 @@ SELECT '' AS one, b.f1
      | (3,3),(1,1)
 (1 row)
 
 -- center of box, left unary operator
 SELECT '' AS four, @@(b1.f1) AS p
    FROM BOX_TBL b1;
  four |    p    
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 -- wholly-contained
 SELECT '' AS one, b1.*, b2.*
    FROM BOX_TBL b1, BOX_TBL b2
    WHERE b1.f1 @> b2.f1 and not b1.f1 ~= b2.f1;
  one |     f1      |     f1      
 -----+-------------+-------------
      | (3,3),(1,1) | (3,3),(3,3)
 (1 row)
 
 SELECT '' AS four, height(f1), width(f1) FROM BOX_TBL;
  four | height | width 
 ------+--------+-------
       |      2 |     2
       |      2 |     2
+      |     12 |     6
       |      1 |     0
       |      0 |     0
-(4 rows)
+(5 rows)
 
 --
 -- Test the SP-GiST index
 --
 CREATE TEMPORARY TABLE box_temp (f1 box);
 INSERT INTO box_temp
 	SELECT box(point(i, i), point(i * 2, i * 2))
 	FROM generate_series(1, 50) AS i;
 CREATE INDEX box_spgist ON box_temp USING spgist (f1);
 INSERT INTO box_temp
diff --git a/src/test/regress/expected/circle.out b/src/test/regress/expected/circle.out
index 9ba4a0495d..2ed74cc6aa 100644
--- a/src/test/regress/expected/circle.out
+++ b/src/test/regress/expected/circle.out
@@ -1,99 +1,122 @@
 --
 -- CIRCLE
 --
 CREATE TABLE CIRCLE_TBL (f1 circle);
 INSERT INTO CIRCLE_TBL VALUES ('<(5,1),3>');
 INSERT INTO CIRCLE_TBL VALUES ('<(1,2),100>');
 INSERT INTO CIRCLE_TBL VALUES ('1,3,5');
 INSERT INTO CIRCLE_TBL VALUES ('((1,2),3)');
 INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10>');
-INSERT INTO CIRCLE_TBL VALUES ('<(100,1),115>');
+INSERT INTO CIRCLE_TBL VALUES (' < ( 100 , 1 ) , 115 > ');
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),0>');	-- Zero radius
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),NaN>');	-- NaN radius
 -- bad values
 INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
 ERROR:  invalid input syntax for type circle: "<(-100,0),-100>"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
                                        ^
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+ERROR:  invalid input syntax for type circle: "<(100,200),10"
+LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+                                       ^
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+ERROR:  invalid input syntax for type circle: "<(100,200),10> x"
+LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+                                       ^
 INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
 ERROR:  invalid input syntax for type circle: "1abc,3,5"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
                                        ^
 INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
 ERROR:  invalid input syntax for type circle: "(3,(1,2),3)"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
                                        ^
 SELECT * FROM CIRCLE_TBL;
        f1       
 ----------------
  <(5,1),3>
  <(1,2),100>
  <(1,3),5>
  <(1,2),3>
  <(100,200),10>
  <(100,1),115>
-(6 rows)
+ <(3,5),0>
+ <(3,5),NaN>
+(8 rows)
 
 SELECT '' AS six, center(f1) AS center
   FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS six, radius(f1) AS radius
   FROM CIRCLE_TBL;
  six | radius 
 -----+--------
      |      3
      |    100
      |      5
      |      3
      |     10
      |    115
-(6 rows)
+     |      0
+     |    NaN
+(8 rows)
 
 SELECT '' AS six, diameter(f1) AS diameter
   FROM CIRCLE_TBL;
  six | diameter 
 -----+----------
      |        6
      |      200
      |       10
      |        6
      |       20
      |      230
-(6 rows)
+     |        0
+     |      NaN
+(8 rows)
 
 SELECT '' AS two, f1 FROM CIRCLE_TBL WHERE radius(f1) < 5;
  two |    f1     
 -----+-----------
      | <(5,1),3>
      | <(1,2),3>
-(2 rows)
+     | <(3,5),0>
+(3 rows)
 
 SELECT '' AS four, f1 FROM CIRCLE_TBL WHERE diameter(f1) >= 10;
  four |       f1       
 ------+----------------
       | <(1,2),100>
       | <(1,3),5>
       | <(100,200),10>
       | <(100,1),115>
-(4 rows)
+      | <(3,5),NaN>
+(5 rows)
 
 SELECT '' as five, c1.f1 AS one, c2.f1 AS two, (c1.f1 <-> c2.f1) AS distance
   FROM CIRCLE_TBL c1, CIRCLE_TBL c2
   WHERE (c1.f1 < c2.f1) AND ((c1.f1 <-> c2.f1) > 0)
   ORDER BY distance, area(c1.f1), area(c2.f1);
  five |      one       |      two       |     distance     
 ------+----------------+----------------+------------------
+      | <(3,5),0>      | <(1,2),3>      | 0.60555127546399
+      | <(3,5),0>      | <(5,1),3>      | 1.47213595499958
       | <(100,200),10> | <(100,1),115>  |               74
       | <(100,200),10> | <(1,2),100>    | 111.370729772479
       | <(1,3),5>      | <(100,200),10> | 205.476756144497
       | <(5,1),3>      | <(100,200),10> |  207.51303816328
+      | <(3,5),0>      | <(100,200),10> | 207.793480159531
       | <(1,2),3>      | <(100,200),10> | 208.370729772479
-(5 rows)
+(8 rows)
 
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 031a0bcec9..ac300469b2 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -150,96 +150,103 @@ SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)';
 
 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
+     5
 (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
+     3
 (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
+     4
 (1 row)
 
 SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
  count 
 -------
      1
 (1 row)
 
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
  (-5,-12)
  (5.1,34.5)
+ (1e+300,Infinity)
+ (NaN,NaN)
  
-(7 rows)
+(10 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NULL;
  f1 
 ----
  
 (1 row)
 
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (1e-300,-1e-300)
  (0,0)
  (-3,4)
  (-10,0)
  (10,10)
  (-5,-12)
  (5.1,34.5)
-(6 rows)
+ (1e+300,Infinity)
+ (NaN,NaN)
+(9 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
  count 
 -------
      3
 (1 row)
 
 SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
  count 
 -------
@@ -561,21 +568,21 @@ SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,
                                        QUERY PLAN                                       
 ----------------------------------------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     4
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>';
                      QUERY PLAN                     
 ----------------------------------------------------
  Aggregate
    ->  Index Only Scan using gpointind on point_tbl
          Index Cond: (f1 <@ '<(50,50),50>'::circle)
 (3 rows)
@@ -606,21 +613,21 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     3
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl p WHERE p.f1 <^ '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only Scan using gpointind on point_tbl p
          Index Cond: (f1 <^ '(0,0)'::point)
 (3 rows)
@@ -636,21 +643,21 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 >^ '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     4
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only Scan using gpointind on point_tbl p
          Index Cond: (f1 ~= '(-5,-12)'::point)
 (3 rows)
@@ -663,30 +670,33 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
                   QUERY PLAN                  
 ----------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Order By: (f1 <-> '(0,1)'::point)
 (2 rows)
 
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (10,10)
+ (NaN,NaN)
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
- (10,10)
  (-5,-12)
  (5.1,34.5)
  
-(7 rows)
+ (1e+300,Infinity)
+(10 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 IS NULL;
                   QUERY PLAN                  
 ----------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Index Cond: (f1 IS NULL)
 (2 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NULL;
@@ -698,47 +708,51 @@ SELECT * FROM point_tbl WHERE f1 IS NULL;
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
                   QUERY PLAN                  
 ----------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Index Cond: (f1 IS NOT NULL)
    Order By: (f1 <-> '(0,1)'::point)
 (3 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (10,10)
+ (NaN,NaN)
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
- (10,10)
  (-5,-12)
  (5.1,34.5)
-(6 rows)
+ (1e+300,Infinity)
+(9 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
                    QUERY PLAN                   
 ------------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Index Cond: (f1 <@ '(10,10),(-10,-10)'::box)
    Order By: (f1 <-> '(0,1)'::point)
 (3 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
                         QUERY PLAN                         
 -----------------------------------------------------------
  Aggregate
    ->  Index Only Scan using sp_quad_ind on quad_point_tbl
          Index Cond: (p IS NULL)
 (3 rows)
 
@@ -1240,27 +1254,28 @@ SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0
 ------------------------------------------------------------
  Sort
    Sort Key: ((f1 <-> '(0,1)'::point))
    ->  Bitmap Heap Scan on point_tbl
          Recheck Cond: (f1 <@ '(10,10),(-10,-10)'::box)
          ->  Bitmap Index Scan on gpointind
                Index Cond: (f1 <@ '(10,10),(-10,-10)'::box)
 (6 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
                   QUERY PLAN                  
 ----------------------------------------------
  Aggregate
    ->  Bitmap Heap Scan on quad_point_tbl
          Recheck Cond: (p IS NULL)
          ->  Bitmap Index Scan on sp_quad_ind
                Index Cond: (p IS NULL)
diff --git a/src/test/regress/expected/geometry.out b/src/test/regress/expected/geometry.out
index e4c0039040..c2161a8182 100644
--- a/src/test/regress/expected/geometry.out
+++ b/src/test/regress/expected/geometry.out
@@ -6,558 +6,4980 @@
 SET extra_float_digits TO -3;
 --
 -- Points
 --
 SELECT '' AS four, center(f1) AS center
    FROM BOX_TBL;
  four | center  
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, (@@ f1) AS center
    FROM BOX_TBL;
  four | center  
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS six, point(f1) AS center
    FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS six, (@@ f1) AS center
    FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS two, (@@ f1) AS center
    FROM POLYGON_TBL
    WHERE (# f1) > 2;
  two |            center             
 -----+-------------------------------
      | (1.33333333333,1.33333333333)
      | (2.33333333333,1.33333333333)
-(2 rows)
+     | (4,5)
+     | (4,5)
+     | (4,3)
+(5 rows)
 
 -- "is horizontal" function
 SELECT '' AS two, p1.f1
    FROM POINT_TBL p1
    WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 -- "is horizontal" operator
 SELECT '' AS two, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 -- "is vertical" function
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE isvertical(p1.f1, point '(5.1,34.5)');
  one |     f1     
 -----+------------
      | (5.1,34.5)
 (1 row)
 
 -- "is vertical" operator
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?| point '(5.1,34.5)';
  one |     f1     
 -----+------------
      | (5.1,34.5)
 (1 row)
 
+-- Slope
+SELECT p1.f1, p2.f1, slope(p1.f1, p2.f1) FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |     slope      
+-------------------+-------------------+----------------
+ (0,0)             | (0,0)             |            NaN
+ (0,0)             | (-10,0)           |              0
+ (0,0)             | (-3,4)            | -1.33333333333
+ (0,0)             | (5.1,34.5)        |  6.76470588235
+ (0,0)             | (-5,-12)          |            2.4
+ (0,0)             | (1e-300,-1e-300)  |             -1
+ (0,0)             | (1e+300,Infinity) |       Infinity
+ (0,0)             | (NaN,NaN)         |            NaN
+ (0,0)             | (10,10)           |              1
+ (-10,0)           | (0,0)             |              0
+ (-10,0)           | (-10,0)           |            NaN
+ (-10,0)           | (-3,4)            | 0.571428571429
+ (-10,0)           | (5.1,34.5)        |  2.28476821192
+ (-10,0)           | (-5,-12)          |           -2.4
+ (-10,0)           | (1e-300,-1e-300)  |        -1e-301
+ (-10,0)           | (1e+300,Infinity) |       Infinity
+ (-10,0)           | (NaN,NaN)         |            NaN
+ (-10,0)           | (10,10)           |            0.5
+ (-3,4)            | (0,0)             | -1.33333333333
+ (-3,4)            | (-10,0)           | 0.571428571429
+ (-3,4)            | (-3,4)            |            NaN
+ (-3,4)            | (5.1,34.5)        |  3.76543209877
+ (-3,4)            | (-5,-12)          |              8
+ (-3,4)            | (1e-300,-1e-300)  | -1.33333333333
+ (-3,4)            | (1e+300,Infinity) |       Infinity
+ (-3,4)            | (NaN,NaN)         |            NaN
+ (-3,4)            | (10,10)           | 0.461538461538
+ (5.1,34.5)        | (0,0)             |  6.76470588235
+ (5.1,34.5)        | (-10,0)           |  2.28476821192
+ (5.1,34.5)        | (-3,4)            |  3.76543209877
+ (5.1,34.5)        | (5.1,34.5)        |            NaN
+ (5.1,34.5)        | (-5,-12)          |  4.60396039604
+ (5.1,34.5)        | (1e-300,-1e-300)  |  6.76470588235
+ (5.1,34.5)        | (1e+300,Infinity) |       Infinity
+ (5.1,34.5)        | (NaN,NaN)         |            NaN
+ (5.1,34.5)        | (10,10)           |             -5
+ (-5,-12)          | (0,0)             |            2.4
+ (-5,-12)          | (-10,0)           |           -2.4
+ (-5,-12)          | (-3,4)            |              8
+ (-5,-12)          | (5.1,34.5)        |  4.60396039604
+ (-5,-12)          | (-5,-12)          |            NaN
+ (-5,-12)          | (1e-300,-1e-300)  |            2.4
+ (-5,-12)          | (1e+300,Infinity) |       Infinity
+ (-5,-12)          | (NaN,NaN)         |            NaN
+ (-5,-12)          | (10,10)           |  1.46666666667
+ (1e-300,-1e-300)  | (0,0)             |             -1
+ (1e-300,-1e-300)  | (-10,0)           |        -1e-301
+ (1e-300,-1e-300)  | (-3,4)            | -1.33333333333
+ (1e-300,-1e-300)  | (5.1,34.5)        |  6.76470588235
+ (1e-300,-1e-300)  | (-5,-12)          |            2.4
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  |            NaN
+ (1e-300,-1e-300)  | (1e+300,Infinity) |       Infinity
+ (1e-300,-1e-300)  | (NaN,NaN)         |            NaN
+ (1e-300,-1e-300)  | (10,10)           |              1
+ (1e+300,Infinity) | (0,0)             |       Infinity
+ (1e+300,Infinity) | (-10,0)           |       Infinity
+ (1e+300,Infinity) | (-3,4)            |       Infinity
+ (1e+300,Infinity) | (5.1,34.5)        |       Infinity
+ (1e+300,Infinity) | (-5,-12)          |       Infinity
+ (1e+300,Infinity) | (1e-300,-1e-300)  |       Infinity
+ (1e+300,Infinity) | (1e+300,Infinity) |            NaN
+ (1e+300,Infinity) | (NaN,NaN)         |            NaN
+ (1e+300,Infinity) | (10,10)           |       Infinity
+ (NaN,NaN)         | (0,0)             |            NaN
+ (NaN,NaN)         | (-10,0)           |            NaN
+ (NaN,NaN)         | (-3,4)            |            NaN
+ (NaN,NaN)         | (5.1,34.5)        |            NaN
+ (NaN,NaN)         | (-5,-12)          |            NaN
+ (NaN,NaN)         | (1e-300,-1e-300)  |            NaN
+ (NaN,NaN)         | (1e+300,Infinity) |            NaN
+ (NaN,NaN)         | (NaN,NaN)         |            NaN
+ (NaN,NaN)         | (10,10)           |            NaN
+ (10,10)           | (0,0)             |              1
+ (10,10)           | (-10,0)           |            0.5
+ (10,10)           | (-3,4)            | 0.461538461538
+ (10,10)           | (5.1,34.5)        |             -5
+ (10,10)           | (-5,-12)          |  1.46666666667
+ (10,10)           | (1e-300,-1e-300)  |              1
+ (10,10)           | (1e+300,Infinity) |       Infinity
+ (10,10)           | (NaN,NaN)         |            NaN
+ (10,10)           | (10,10)           |            NaN
+(81 rows)
+
+-- Add point
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |     ?column?      
+-------------------+-------------------+-------------------
+ (0,0)             | (0,0)             | (0,0)
+ (0,0)             | (-10,0)           | (-10,0)
+ (0,0)             | (-3,4)            | (-3,4)
+ (0,0)             | (5.1,34.5)        | (5.1,34.5)
+ (0,0)             | (-5,-12)          | (-5,-12)
+ (0,0)             | (1e-300,-1e-300)  | (1e-300,-1e-300)
+ (0,0)             | (1e+300,Infinity) | (1e+300,Infinity)
+ (0,0)             | (NaN,NaN)         | (NaN,NaN)
+ (0,0)             | (10,10)           | (10,10)
+ (-10,0)           | (0,0)             | (-10,0)
+ (-10,0)           | (-10,0)           | (-20,0)
+ (-10,0)           | (-3,4)            | (-13,4)
+ (-10,0)           | (5.1,34.5)        | (-4.9,34.5)
+ (-10,0)           | (-5,-12)          | (-15,-12)
+ (-10,0)           | (1e-300,-1e-300)  | (-10,-1e-300)
+ (-10,0)           | (1e+300,Infinity) | (1e+300,Infinity)
+ (-10,0)           | (NaN,NaN)         | (NaN,NaN)
+ (-10,0)           | (10,10)           | (0,10)
+ (-3,4)            | (0,0)             | (-3,4)
+ (-3,4)            | (-10,0)           | (-13,4)
+ (-3,4)            | (-3,4)            | (-6,8)
+ (-3,4)            | (5.1,34.5)        | (2.1,38.5)
+ (-3,4)            | (-5,-12)          | (-8,-8)
+ (-3,4)            | (1e-300,-1e-300)  | (-3,4)
+ (-3,4)            | (1e+300,Infinity) | (1e+300,Infinity)
+ (-3,4)            | (NaN,NaN)         | (NaN,NaN)
+ (-3,4)            | (10,10)           | (7,14)
+ (5.1,34.5)        | (0,0)             | (5.1,34.5)
+ (5.1,34.5)        | (-10,0)           | (-4.9,34.5)
+ (5.1,34.5)        | (-3,4)            | (2.1,38.5)
+ (5.1,34.5)        | (5.1,34.5)        | (10.2,69)
+ (5.1,34.5)        | (-5,-12)          | (0.1,22.5)
+ (5.1,34.5)        | (1e-300,-1e-300)  | (5.1,34.5)
+ (5.1,34.5)        | (1e+300,Infinity) | (1e+300,Infinity)
+ (5.1,34.5)        | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5)        | (10,10)           | (15.1,44.5)
+ (-5,-12)          | (0,0)             | (-5,-12)
+ (-5,-12)          | (-10,0)           | (-15,-12)
+ (-5,-12)          | (-3,4)            | (-8,-8)
+ (-5,-12)          | (5.1,34.5)        | (0.1,22.5)
+ (-5,-12)          | (-5,-12)          | (-10,-24)
+ (-5,-12)          | (1e-300,-1e-300)  | (-5,-12)
+ (-5,-12)          | (1e+300,Infinity) | (1e+300,Infinity)
+ (-5,-12)          | (NaN,NaN)         | (NaN,NaN)
+ (-5,-12)          | (10,10)           | (5,-2)
+ (1e-300,-1e-300)  | (0,0)             | (1e-300,-1e-300)
+ (1e-300,-1e-300)  | (-10,0)           | (-10,-1e-300)
+ (1e-300,-1e-300)  | (-3,4)            | (-3,4)
+ (1e-300,-1e-300)  | (5.1,34.5)        | (5.1,34.5)
+ (1e-300,-1e-300)  | (-5,-12)          | (-5,-12)
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | (2e-300,-2e-300)
+ (1e-300,-1e-300)  | (1e+300,Infinity) | (1e+300,Infinity)
+ (1e-300,-1e-300)  | (NaN,NaN)         | (NaN,NaN)
+ (1e-300,-1e-300)  | (10,10)           | (10,10)
+ (1e+300,Infinity) | (0,0)             | (1e+300,Infinity)
+ (1e+300,Infinity) | (-10,0)           | (1e+300,Infinity)
+ (1e+300,Infinity) | (-3,4)            | (1e+300,Infinity)
+ (1e+300,Infinity) | (5.1,34.5)        | (1e+300,Infinity)
+ (1e+300,Infinity) | (-5,-12)          | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e-300,-1e-300)  | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e+300,Infinity) | (2e+300,Infinity)
+ (1e+300,Infinity) | (NaN,NaN)         | (NaN,NaN)
+ (1e+300,Infinity) | (10,10)           | (1e+300,Infinity)
+ (NaN,NaN)         | (0,0)             | (NaN,NaN)
+ (NaN,NaN)         | (-10,0)           | (NaN,NaN)
+ (NaN,NaN)         | (-3,4)            | (NaN,NaN)
+ (NaN,NaN)         | (5.1,34.5)        | (NaN,NaN)
+ (NaN,NaN)         | (-5,-12)          | (NaN,NaN)
+ (NaN,NaN)         | (1e-300,-1e-300)  | (NaN,NaN)
+ (NaN,NaN)         | (1e+300,Infinity) | (NaN,NaN)
+ (NaN,NaN)         | (NaN,NaN)         | (NaN,NaN)
+ (NaN,NaN)         | (10,10)           | (NaN,NaN)
+ (10,10)           | (0,0)             | (10,10)
+ (10,10)           | (-10,0)           | (0,10)
+ (10,10)           | (-3,4)            | (7,14)
+ (10,10)           | (5.1,34.5)        | (15.1,44.5)
+ (10,10)           | (-5,-12)          | (5,-2)
+ (10,10)           | (1e-300,-1e-300)  | (10,10)
+ (10,10)           | (1e+300,Infinity) | (1e+300,Infinity)
+ (10,10)           | (NaN,NaN)         | (NaN,NaN)
+ (10,10)           | (10,10)           | (20,20)
+(81 rows)
+
+-- Subtract point
+SELECT p1.f1, p2.f1, p1.f1 - p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |      ?column?       
+-------------------+-------------------+---------------------
+ (0,0)             | (0,0)             | (0,0)
+ (0,0)             | (-10,0)           | (10,0)
+ (0,0)             | (-3,4)            | (3,-4)
+ (0,0)             | (5.1,34.5)        | (-5.1,-34.5)
+ (0,0)             | (-5,-12)          | (5,12)
+ (0,0)             | (1e-300,-1e-300)  | (-1e-300,1e-300)
+ (0,0)             | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (0,0)             | (NaN,NaN)         | (NaN,NaN)
+ (0,0)             | (10,10)           | (-10,-10)
+ (-10,0)           | (0,0)             | (-10,0)
+ (-10,0)           | (-10,0)           | (0,0)
+ (-10,0)           | (-3,4)            | (-7,-4)
+ (-10,0)           | (5.1,34.5)        | (-15.1,-34.5)
+ (-10,0)           | (-5,-12)          | (-5,12)
+ (-10,0)           | (1e-300,-1e-300)  | (-10,1e-300)
+ (-10,0)           | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-10,0)           | (NaN,NaN)         | (NaN,NaN)
+ (-10,0)           | (10,10)           | (-20,-10)
+ (-3,4)            | (0,0)             | (-3,4)
+ (-3,4)            | (-10,0)           | (7,4)
+ (-3,4)            | (-3,4)            | (0,0)
+ (-3,4)            | (5.1,34.5)        | (-8.1,-30.5)
+ (-3,4)            | (-5,-12)          | (2,16)
+ (-3,4)            | (1e-300,-1e-300)  | (-3,4)
+ (-3,4)            | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-3,4)            | (NaN,NaN)         | (NaN,NaN)
+ (-3,4)            | (10,10)           | (-13,-6)
+ (5.1,34.5)        | (0,0)             | (5.1,34.5)
+ (5.1,34.5)        | (-10,0)           | (15.1,34.5)
+ (5.1,34.5)        | (-3,4)            | (8.1,30.5)
+ (5.1,34.5)        | (5.1,34.5)        | (0,0)
+ (5.1,34.5)        | (-5,-12)          | (10.1,46.5)
+ (5.1,34.5)        | (1e-300,-1e-300)  | (5.1,34.5)
+ (5.1,34.5)        | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (5.1,34.5)        | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5)        | (10,10)           | (-4.9,24.5)
+ (-5,-12)          | (0,0)             | (-5,-12)
+ (-5,-12)          | (-10,0)           | (5,-12)
+ (-5,-12)          | (-3,4)            | (-2,-16)
+ (-5,-12)          | (5.1,34.5)        | (-10.1,-46.5)
+ (-5,-12)          | (-5,-12)          | (0,0)
+ (-5,-12)          | (1e-300,-1e-300)  | (-5,-12)
+ (-5,-12)          | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-5,-12)          | (NaN,NaN)         | (NaN,NaN)
+ (-5,-12)          | (10,10)           | (-15,-22)
+ (1e-300,-1e-300)  | (0,0)             | (1e-300,-1e-300)
+ (1e-300,-1e-300)  | (-10,0)           | (10,-1e-300)
+ (1e-300,-1e-300)  | (-3,4)            | (3,-4)
+ (1e-300,-1e-300)  | (5.1,34.5)        | (-5.1,-34.5)
+ (1e-300,-1e-300)  | (-5,-12)          | (5,12)
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | (0,0)
+ (1e-300,-1e-300)  | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (1e-300,-1e-300)  | (NaN,NaN)         | (NaN,NaN)
+ (1e-300,-1e-300)  | (10,10)           | (-10,-10)
+ (1e+300,Infinity) | (0,0)             | (1e+300,Infinity)
+ (1e+300,Infinity) | (-10,0)           | (1e+300,Infinity)
+ (1e+300,Infinity) | (-3,4)            | (1e+300,Infinity)
+ (1e+300,Infinity) | (5.1,34.5)        | (1e+300,Infinity)
+ (1e+300,Infinity) | (-5,-12)          | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e-300,-1e-300)  | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e+300,Infinity) | (0,NaN)
+ (1e+300,Infinity) | (NaN,NaN)         | (NaN,NaN)
+ (1e+300,Infinity) | (10,10)           | (1e+300,Infinity)
+ (NaN,NaN)         | (0,0)             | (NaN,NaN)
+ (NaN,NaN)         | (-10,0)           | (NaN,NaN)
+ (NaN,NaN)         | (-3,4)            | (NaN,NaN)
+ (NaN,NaN)         | (5.1,34.5)        | (NaN,NaN)
+ (NaN,NaN)         | (-5,-12)          | (NaN,NaN)
+ (NaN,NaN)         | (1e-300,-1e-300)  | (NaN,NaN)
+ (NaN,NaN)         | (1e+300,Infinity) | (NaN,NaN)
+ (NaN,NaN)         | (NaN,NaN)         | (NaN,NaN)
+ (NaN,NaN)         | (10,10)           | (NaN,NaN)
+ (10,10)           | (0,0)             | (10,10)
+ (10,10)           | (-10,0)           | (20,10)
+ (10,10)           | (-3,4)            | (13,6)
+ (10,10)           | (5.1,34.5)        | (4.9,-24.5)
+ (10,10)           | (-5,-12)          | (15,22)
+ (10,10)           | (1e-300,-1e-300)  | (10,10)
+ (10,10)           | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (10,10)           | (NaN,NaN)         | (NaN,NaN)
+ (10,10)           | (10,10)           | (0,0)
+(81 rows)
+
+-- Multiply with point
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+     f1     |        f1         |       ?column?        
+------------+-------------------+-----------------------
+ (5.1,34.5) | (0,0)             | (0,0)
+ (10,10)    | (0,0)             | (0,0)
+ (5.1,34.5) | (-10,0)           | (-51,-345)
+ (10,10)    | (-10,0)           | (-100,-100)
+ (5.1,34.5) | (-3,4)            | (-153.3,-83.1)
+ (10,10)    | (-3,4)            | (-70,10)
+ (5.1,34.5) | (5.1,34.5)        | (-1164.24,351.9)
+ (10,10)    | (5.1,34.5)        | (-294,396)
+ (5.1,34.5) | (-5,-12)          | (388.5,-233.7)
+ (10,10)    | (-5,-12)          | (70,-170)
+ (5.1,34.5) | (1e-300,-1e-300)  | (3.96e-299,2.94e-299)
+ (10,10)    | (1e-300,-1e-300)  | (2e-299,0)
+ (5.1,34.5) | (1e+300,Infinity) | (-Infinity,Infinity)
+ (10,10)    | (1e+300,Infinity) | (-Infinity,Infinity)
+ (5.1,34.5) | (NaN,NaN)         | (NaN,NaN)
+ (10,10)    | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5) | (10,10)           | (-294,396)
+ (10,10)    | (10,10)           | (0,200)
+(18 rows)
+
+-- Underflow error
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] < 1;
+ERROR:  value out of range: underflow
+-- Divide by point
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] BETWEEN 1 AND 1000;
+        f1         |     f1     |                 ?column?                  
+-------------------+------------+-------------------------------------------
+ (0,0)             | (5.1,34.5) | (0,0)
+ (0,0)             | (10,10)    | (0,0)
+ (-10,0)           | (5.1,34.5) | (-0.0419318237877,0.283656455034)
+ (-10,0)           | (10,10)    | (-0.5,0.5)
+ (-3,4)            | (5.1,34.5) | (0.100883034877,0.101869666025)
+ (-3,4)            | (10,10)    | (0.05,0.35)
+ (5.1,34.5)        | (5.1,34.5) | (1,0)
+ (5.1,34.5)        | (10,10)    | (1.98,1.47)
+ (-5,-12)          | (5.1,34.5) | (-0.361353657935,0.0915100389719)
+ (-5,-12)          | (10,10)    | (-0.85,-0.35)
+ (1e-300,-1e-300)  | (5.1,34.5) | (-2.41724631247e-302,-3.25588278822e-302)
+ (1e-300,-1e-300)  | (10,10)    | (0,-1e-301)
+ (1e+300,Infinity) | (5.1,34.5) | (Infinity,Infinity)
+ (1e+300,Infinity) | (10,10)    | (Infinity,Infinity)
+ (NaN,NaN)         | (5.1,34.5) | (NaN,NaN)
+ (NaN,NaN)         | (10,10)    | (NaN,NaN)
+ (10,10)           | (5.1,34.5) | (0.325588278822,-0.241724631247)
+ (10,10)           | (10,10)    | (1,0)
+(18 rows)
+
+-- Overflow error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] > 1000;
+ERROR:  value out of range: overflow
+-- Division by 0 error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to line
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LINE_TBL l;
+        f1         |                   s                   |      ?column?      
+-------------------+---------------------------------------+--------------------
+ (0,0)             | {0,-1,5}                              |                  5
+ (0,0)             | {1,0,5}                               |                  5
+ (0,0)             | {0,3,0}                               |                  0
+ (0,0)             | {1,-1,0}                              |                  0
+ (0,0)             | {-0.4,-1,-6}                          |      5.57086014531
+ (0,0)             | {-0.000184615384615,-1,15.3846153846} |      15.3846151224
+ (0,0)             | {NaN,-1,NaN}                          |                NaN
+ (0,0)             | {3,NaN,5}                             |                NaN
+ (0,0)             | {NaN,NaN,NaN}                         |                NaN
+ (0,0)             | {0,-1,3}                              |                  3
+ (0,0)             | {-1,0,3}                              |                  3
+ (-10,0)           | {0,-1,5}                              |                  5
+ (-10,0)           | {1,0,5}                               |                  5
+ (-10,0)           | {0,3,0}                               |                  0
+ (-10,0)           | {1,-1,0}                              |      7.07106781187
+ (-10,0)           | {-0.4,-1,-6}                          |      1.85695338177
+ (-10,0)           | {-0.000184615384615,-1,15.3846153846} |      15.3864612763
+ (-10,0)           | {NaN,-1,NaN}                          |                NaN
+ (-10,0)           | {3,NaN,5}                             |                NaN
+ (-10,0)           | {NaN,NaN,NaN}                         |                NaN
+ (-10,0)           | {0,-1,3}                              |                  3
+ (-10,0)           | {-1,0,3}                              |                 13
+ (-3,4)            | {0,-1,5}                              |                  1
+ (-3,4)            | {1,0,5}                               |                  2
+ (-3,4)            | {0,3,0}                               |                  4
+ (-3,4)            | {1,-1,0}                              |      4.94974746831
+ (-3,4)            | {-0.4,-1,-6}                          |      8.17059487979
+ (-3,4)            | {-0.000184615384615,-1,15.3846153846} |      11.3851690368
+ (-3,4)            | {NaN,-1,NaN}                          |                NaN
+ (-3,4)            | {3,NaN,5}                             |                NaN
+ (-3,4)            | {NaN,NaN,NaN}                         |                NaN
+ (-3,4)            | {0,-1,3}                              |                  1
+ (-3,4)            | {-1,0,3}                              |                  6
+ (5.1,34.5)        | {0,-1,5}                              |               29.5
+ (5.1,34.5)        | {1,0,5}                               |               10.1
+ (5.1,34.5)        | {0,3,0}                               |               34.5
+ (5.1,34.5)        | {1,-1,0}                              |      20.7889393669
+ (5.1,34.5)        | {-0.4,-1,-6}                          |      39.4973984303
+ (5.1,34.5)        | {-0.000184615384615,-1,15.3846153846} |      19.1163258281
+ (5.1,34.5)        | {NaN,-1,NaN}                          |                NaN
+ (5.1,34.5)        | {3,NaN,5}                             |                NaN
+ (5.1,34.5)        | {NaN,NaN,NaN}                         |                NaN
+ (5.1,34.5)        | {0,-1,3}                              |               31.5
+ (5.1,34.5)        | {-1,0,3}                              |                2.1
+ (-5,-12)          | {0,-1,5}                              |                 17
+ (-5,-12)          | {1,0,5}                               |                  0
+ (-5,-12)          | {0,3,0}                               |                 12
+ (-5,-12)          | {1,-1,0}                              |      4.94974746831
+ (-5,-12)          | {-0.4,-1,-6}                          |      7.42781352708
+ (-5,-12)          | {-0.000184615384615,-1,15.3846153846} |      27.3855379948
+ (-5,-12)          | {NaN,-1,NaN}                          |                NaN
+ (-5,-12)          | {3,NaN,5}                             |                NaN
+ (-5,-12)          | {NaN,NaN,NaN}                         |                NaN
+ (-5,-12)          | {0,-1,3}                              |                 15
+ (-5,-12)          | {-1,0,3}                              |                  8
+ (1e-300,-1e-300)  | {0,-1,5}                              |                  5
+ (1e-300,-1e-300)  | {1,0,5}                               |                  5
+ (1e-300,-1e-300)  | {0,3,0}                               |             1e-300
+ (1e-300,-1e-300)  | {1,-1,0}                              | 1.41421356237e-300
+ (1e-300,-1e-300)  | {-0.4,-1,-6}                          |      5.57086014531
+ (1e-300,-1e-300)  | {-0.000184615384615,-1,15.3846153846} |      15.3846151224
+ (1e-300,-1e-300)  | {NaN,-1,NaN}                          |                NaN
+ (1e-300,-1e-300)  | {3,NaN,5}                             |                NaN
+ (1e-300,-1e-300)  | {NaN,NaN,NaN}                         |                NaN
+ (1e-300,-1e-300)  | {0,-1,3}                              |                  3
+ (1e-300,-1e-300)  | {-1,0,3}                              |                  3
+ (1e+300,Infinity) | {0,-1,5}                              |           Infinity
+ (1e+300,Infinity) | {1,0,5}                               |                NaN
+ (1e+300,Infinity) | {0,3,0}                               |           Infinity
+ (1e+300,Infinity) | {1,-1,0}                              |           Infinity
+ (1e+300,Infinity) | {-0.4,-1,-6}                          |           Infinity
+ (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} |           Infinity
+ (1e+300,Infinity) | {NaN,-1,NaN}                          |                NaN
+ (1e+300,Infinity) | {3,NaN,5}                             |                NaN
+ (1e+300,Infinity) | {NaN,NaN,NaN}                         |                NaN
+ (1e+300,Infinity) | {0,-1,3}                              |           Infinity
+ (1e+300,Infinity) | {-1,0,3}                              |                NaN
+ (NaN,NaN)         | {0,-1,5}                              |                NaN
+ (NaN,NaN)         | {1,0,5}                               |                NaN
+ (NaN,NaN)         | {0,3,0}                               |                NaN
+ (NaN,NaN)         | {1,-1,0}                              |                NaN
+ (NaN,NaN)         | {-0.4,-1,-6}                          |                NaN
+ (NaN,NaN)         | {-0.000184615384615,-1,15.3846153846} |                NaN
+ (NaN,NaN)         | {NaN,-1,NaN}                          |                NaN
+ (NaN,NaN)         | {3,NaN,5}                             |                NaN
+ (NaN,NaN)         | {NaN,NaN,NaN}                         |                NaN
+ (NaN,NaN)         | {0,-1,3}                              |                NaN
+ (NaN,NaN)         | {-1,0,3}                              |                NaN
+ (10,10)           | {0,-1,5}                              |                  5
+ (10,10)           | {1,0,5}                               |                 15
+ (10,10)           | {0,3,0}                               |                 10
+ (10,10)           | {1,-1,0}                              |                  0
+ (10,10)           | {-0.4,-1,-6}                          |      18.5695338177
+ (10,10)           | {-0.000184615384615,-1,15.3846153846} |      5.38276913903
+ (10,10)           | {NaN,-1,NaN}                          |                NaN
+ (10,10)           | {3,NaN,5}                             |                NaN
+ (10,10)           | {NaN,NaN,NaN}                         |                NaN
+ (10,10)           | {0,-1,3}                              |                  7
+ (10,10)           | {-1,0,3}                              |                  7
+(99 rows)
+
+-- Distance to line segment
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LSEG_TBL l;
+        f1         |               s               |      ?column?      
+-------------------+-------------------------------+--------------------
+ (0,0)             | [(1,2),(3,4)]                 |       2.2360679775
+ (0,0)             | [(0,0),(6,6)]                 |                  0
+ (0,0)             | [(10,-10),(-3,-4)]            |      4.88901207039
+ (0,0)             | [(-1000000,200),(300000,-40)] |      15.3846151224
+ (0,0)             | [(11,22),(33,44)]             |      24.5967477525
+ (0,0)             | [(-10,2),(-10,3)]             |      10.1980390272
+ (0,0)             | [(0,-20),(30,-20)]            |                 20
+ (0,0)             | [(NaN,1),(NaN,90)]            |                NaN
+ (-10,0)           | [(1,2),(3,4)]                 |      11.1803398875
+ (-10,0)           | [(0,0),(6,6)]                 |                 10
+ (-10,0)           | [(10,-10),(-3,-4)]            |       8.0622577483
+ (-10,0)           | [(-1000000,200),(300000,-40)] |      15.3864612763
+ (-10,0)           | [(11,22),(33,44)]             |      30.4138126515
+ (-10,0)           | [(-10,2),(-10,3)]             |                  2
+ (-10,0)           | [(0,-20),(30,-20)]            |       22.360679775
+ (-10,0)           | [(NaN,1),(NaN,90)]            |                NaN
+ (-3,4)            | [(1,2),(3,4)]                 |        4.472135955
+ (-3,4)            | [(0,0),(6,6)]                 |      4.94974746831
+ (-3,4)            | [(10,-10),(-3,-4)]            |                  8
+ (-3,4)            | [(-1000000,200),(300000,-40)] |      11.3851690367
+ (-3,4)            | [(11,22),(33,44)]             |       22.803508502
+ (-3,4)            | [(-10,2),(-10,3)]             |      7.07106781187
+ (-3,4)            | [(0,-20),(30,-20)]            |      24.1867732449
+ (-3,4)            | [(NaN,1),(NaN,90)]            |                NaN
+ (5.1,34.5)        | [(1,2),(3,4)]                 |      30.5722096028
+ (5.1,34.5)        | [(0,0),(6,6)]                 |      28.5142069853
+ (5.1,34.5)        | [(10,-10),(-3,-4)]            |      39.3428519556
+ (5.1,34.5)        | [(-1000000,200),(300000,-40)] |      19.1163258281
+ (5.1,34.5)        | [(11,22),(33,44)]             |      13.0107647738
+ (5.1,34.5)        | [(-10,2),(-10,3)]             |       34.932220084
+ (5.1,34.5)        | [(0,-20),(30,-20)]            |               54.5
+ (5.1,34.5)        | [(NaN,1),(NaN,90)]            |                NaN
+ (-5,-12)          | [(1,2),(3,4)]                 |      15.2315462117
+ (-5,-12)          | [(0,0),(6,6)]                 |                 13
+ (-5,-12)          | [(10,-10),(-3,-4)]            |      8.10179143093
+ (-5,-12)          | [(-1000000,200),(300000,-40)] |      27.3855379949
+ (-5,-12)          | [(11,22),(33,44)]             |      37.5765884561
+ (-5,-12)          | [(-10,2),(-10,3)]             |      14.8660687473
+ (-5,-12)          | [(0,-20),(30,-20)]            |      9.43398113206
+ (-5,-12)          | [(NaN,1),(NaN,90)]            |                NaN
+ (1e-300,-1e-300)  | [(1,2),(3,4)]                 |       2.2360679775
+ (1e-300,-1e-300)  | [(0,0),(6,6)]                 | 1.41421356237e-300
+ (1e-300,-1e-300)  | [(10,-10),(-3,-4)]            |      4.88901207039
+ (1e-300,-1e-300)  | [(-1000000,200),(300000,-40)] |      15.3846151224
+ (1e-300,-1e-300)  | [(11,22),(33,44)]             |      24.5967477525
+ (1e-300,-1e-300)  | [(-10,2),(-10,3)]             |      10.1980390272
+ (1e-300,-1e-300)  | [(0,-20),(30,-20)]            |                 20
+ (1e-300,-1e-300)  | [(NaN,1),(NaN,90)]            |                NaN
+ (1e+300,Infinity) | [(1,2),(3,4)]                 |           Infinity
+ (1e+300,Infinity) | [(0,0),(6,6)]                 |           Infinity
+ (1e+300,Infinity) | [(10,-10),(-3,-4)]            |           Infinity
+ (1e+300,Infinity) | [(-1000000,200),(300000,-40)] |           Infinity
+ (1e+300,Infinity) | [(11,22),(33,44)]             |           Infinity
+ (1e+300,Infinity) | [(-10,2),(-10,3)]             |           Infinity
+ (1e+300,Infinity) | [(0,-20),(30,-20)]            |           Infinity
+ (1e+300,Infinity) | [(NaN,1),(NaN,90)]            |           Infinity
+ (NaN,NaN)         | [(1,2),(3,4)]                 |                NaN
+ (NaN,NaN)         | [(0,0),(6,6)]                 |                NaN
+ (NaN,NaN)         | [(10,-10),(-3,-4)]            |                NaN
+ (NaN,NaN)         | [(-1000000,200),(300000,-40)] |                NaN
+ (NaN,NaN)         | [(11,22),(33,44)]             |                NaN
+ (NaN,NaN)         | [(-10,2),(-10,3)]             |                NaN
+ (NaN,NaN)         | [(0,-20),(30,-20)]            |                NaN
+ (NaN,NaN)         | [(NaN,1),(NaN,90)]            |                NaN
+ (10,10)           | [(1,2),(3,4)]                 |      9.21954445729
+ (10,10)           | [(0,0),(6,6)]                 |      5.65685424949
+ (10,10)           | [(10,-10),(-3,-4)]            |        18.15918769
+ (10,10)           | [(-1000000,200),(300000,-40)] |      5.38276913904
+ (10,10)           | [(11,22),(33,44)]             |      12.0415945788
+ (10,10)           | [(-10,2),(-10,3)]             |      21.1896201004
+ (10,10)           | [(0,-20),(30,-20)]            |                 30
+ (10,10)           | [(NaN,1),(NaN,90)]            |                NaN
+(72 rows)
+
+-- Distance to box
+SELECT p.f1, b.f1, p.f1 <-> b.f1 FROM POINT_TBL p, BOX_TBL b;
+        f1         |         f1          |      ?column?      
+-------------------+---------------------+--------------------
+ (0,0)             | (2,2),(0,0)         |                  0
+ (0,0)             | (3,3),(1,1)         |      1.41421356237
+ (0,0)             | (-2,2),(-8,-10)     |                  2
+ (0,0)             | (2.5,3.5),(2.5,2.5) |      3.53553390593
+ (0,0)             | (3,3),(3,3)         |      4.24264068712
+ (-10,0)           | (2,2),(0,0)         |                 10
+ (-10,0)           | (3,3),(1,1)         |      11.0453610172
+ (-10,0)           | (-2,2),(-8,-10)     |                  2
+ (-10,0)           | (2.5,3.5),(2.5,2.5) |       12.747548784
+ (-10,0)           | (3,3),(3,3)         |      13.3416640641
+ (-3,4)            | (2,2),(0,0)         |      3.60555127546
+ (-3,4)            | (3,3),(1,1)         |      4.12310562562
+ (-3,4)            | (-2,2),(-8,-10)     |                  2
+ (-3,4)            | (2.5,3.5),(2.5,2.5) |      5.52268050859
+ (-3,4)            | (3,3),(3,3)         |       6.0827625303
+ (5.1,34.5)        | (2,2),(0,0)         |      32.6475113906
+ (5.1,34.5)        | (3,3),(1,1)         |      31.5699223946
+ (5.1,34.5)        | (-2,2),(-8,-10)     |      33.2664996656
+ (5.1,34.5)        | (2.5,3.5),(2.5,2.5) |       31.108841187
+ (5.1,34.5)        | (3,3),(3,3)         |      31.5699223946
+ (-5,-12)          | (2,2),(0,0)         |                 13
+ (-5,-12)          | (3,3),(1,1)         |      14.3178210633
+ (-5,-12)          | (-2,2),(-8,-10)     |                  2
+ (-5,-12)          | (2.5,3.5),(2.5,2.5) |      16.3248277173
+ (-5,-12)          | (3,3),(3,3)         |                 17
+ (1e-300,-1e-300)  | (2,2),(0,0)         | 1.41421356237e-300
+ (1e-300,-1e-300)  | (3,3),(1,1)         |      1.41421356237
+ (1e-300,-1e-300)  | (-2,2),(-8,-10)     |                  2
+ (1e-300,-1e-300)  | (2.5,3.5),(2.5,2.5) |      3.53553390593
+ (1e-300,-1e-300)  | (3,3),(3,3)         |      4.24264068712
+ (1e+300,Infinity) | (2,2),(0,0)         |           Infinity
+ (1e+300,Infinity) | (3,3),(1,1)         |           Infinity
+ (1e+300,Infinity) | (-2,2),(-8,-10)     |           Infinity
+ (1e+300,Infinity) | (2.5,3.5),(2.5,2.5) |           Infinity
+ (1e+300,Infinity) | (3,3),(3,3)         |           Infinity
+ (NaN,NaN)         | (2,2),(0,0)         |                NaN
+ (NaN,NaN)         | (3,3),(1,1)         |                NaN
+ (NaN,NaN)         | (-2,2),(-8,-10)     |                NaN
+ (NaN,NaN)         | (2.5,3.5),(2.5,2.5) |                NaN
+ (NaN,NaN)         | (3,3),(3,3)         |                NaN
+ (10,10)           | (2,2),(0,0)         |       11.313708499
+ (10,10)           | (3,3),(1,1)         |      9.89949493661
+ (10,10)           | (-2,2),(-8,-10)     |      14.4222051019
+ (10,10)           | (2.5,3.5),(2.5,2.5) |      9.92471662064
+ (10,10)           | (3,3),(3,3)         |      9.89949493661
+(45 rows)
+
+-- Distance to path
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, PATH_TBL p1;
+        f1         |            f1             |      ?column?      
+-------------------+---------------------------+--------------------
+ (0,0)             | [(1,2),(3,4)]             |       2.2360679775
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | [(0,0),(3,0),(4,5),(1,6)] |                  0
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | [(1,2),(3,4)]             |       2.2360679775
+ (0,0)             | ((10,20))                 |       22.360679775
+ (0,0)             | [(11,12),(13,14)]         |      16.2788205961
+ (0,0)             | ((11,12),(13,14))         |      16.2788205961
+ (-10,0)           | [(1,2),(3,4)]             |      11.1803398875
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | [(0,0),(3,0),(4,5),(1,6)] |                 10
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | [(1,2),(3,4)]             |      11.1803398875
+ (-10,0)           | ((10,20))                 |      28.2842712475
+ (-10,0)           | [(11,12),(13,14)]         |      24.1867732449
+ (-10,0)           | ((11,12),(13,14))         |      24.1867732449
+ (-3,4)            | [(1,2),(3,4)]             |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | [(0,0),(3,0),(4,5),(1,6)] |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | [(1,2),(3,4)]             |        4.472135955
+ (-3,4)            | ((10,20))                 |      20.6155281281
+ (-3,4)            | [(11,12),(13,14)]         |      16.1245154966
+ (-3,4)            | ((11,12),(13,14))         |      16.1245154966
+ (5.1,34.5)        | [(1,2),(3,4)]             |      30.5722096028
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | [(0,0),(3,0),(4,5),(1,6)] |       28.793402022
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | [(1,2),(3,4)]             |      30.5722096028
+ (5.1,34.5)        | ((10,20))                 |      15.3055545473
+ (5.1,34.5)        | [(11,12),(13,14)]         |      21.9695243462
+ (5.1,34.5)        | ((11,12),(13,14))         |      21.9695243462
+ (-5,-12)          | [(1,2),(3,4)]             |      15.2315462117
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | [(0,0),(3,0),(4,5),(1,6)] |                 13
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | [(1,2),(3,4)]             |      15.2315462117
+ (-5,-12)          | ((10,20))                 |      35.3411940941
+ (-5,-12)          | [(11,12),(13,14)]         |      28.8444102037
+ (-5,-12)          | ((11,12),(13,14))         |      28.8444102037
+ (1e-300,-1e-300)  | [(1,2),(3,4)]             |       2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | [(0,0),(3,0),(4,5),(1,6)] | 1.41421356237e-300
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | [(1,2),(3,4)]             |       2.2360679775
+ (1e-300,-1e-300)  | ((10,20))                 |       22.360679775
+ (1e-300,-1e-300)  | [(11,12),(13,14)]         |      16.2788205961
+ (1e-300,-1e-300)  | ((11,12),(13,14))         |      16.2788205961
+ (1e+300,Infinity) | [(1,2),(3,4)]             |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | [(0,0),(3,0),(4,5),(1,6)] |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | [(1,2),(3,4)]             |           Infinity
+ (1e+300,Infinity) | ((10,20))                 |           Infinity
+ (1e+300,Infinity) | [(11,12),(13,14)]         |           Infinity
+ (1e+300,Infinity) | ((11,12),(13,14))         |           Infinity
+ (NaN,NaN)         | [(1,2),(3,4)]             |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | [(0,0),(3,0),(4,5),(1,6)] |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | [(1,2),(3,4)]             |                NaN
+ (NaN,NaN)         | ((10,20))                 |                NaN
+ (NaN,NaN)         | [(11,12),(13,14)]         |                NaN
+ (NaN,NaN)         | ((11,12),(13,14))         |                NaN
+ (10,10)           | [(1,2),(3,4)]             |      9.21954445729
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | [(0,0),(3,0),(4,5),(1,6)] |      7.81024967591
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | [(1,2),(3,4)]             |      9.21954445729
+ (10,10)           | ((10,20))                 |                 10
+ (10,10)           | [(11,12),(13,14)]         |       2.2360679775
+ (10,10)           | ((11,12),(13,14))         |       2.2360679775
+(81 rows)
+
+-- Distance to polygon
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, POLYGON_TBL p1;
+        f1         |             f1             |   ?column?    
+-------------------+----------------------------+---------------
+ (0,0)             | ((2,0),(2,4),(0,0))        |             0
+ (0,0)             | ((3,1),(3,3),(1,0))        |             1
+ (0,0)             | ((1,2),(3,4),(5,6),(7,8))  |  2.2360679775
+ (0,0)             | ((7,8),(5,6),(3,4),(1,2))  |  2.2360679775
+ (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | 1.58113883008
+ (0,0)             | ((0,0))                    |             0
+ (0,0)             | ((0,1),(0,1))              |             1
+ (-10,0)           | ((2,0),(2,4),(0,0))        |            10
+ (-10,0)           | ((3,1),(3,3),(1,0))        |            11
+ (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | 11.1803398875
+ (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | 11.1803398875
+ (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | 11.1803398875
+ (-10,0)           | ((0,0))                    |            10
+ (-10,0)           | ((0,1),(0,1))              | 10.0498756211
+ (-3,4)            | ((2,0),(2,4),(0,0))        |   4.472135955
+ (-3,4)            | ((3,1),(3,3),(1,0))        | 5.54700196225
+ (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  |   4.472135955
+ (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  |   4.472135955
+ (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) |   4.472135955
+ (-3,4)            | ((0,0))                    |             5
+ (-3,4)            | ((0,1),(0,1))              | 4.24264068712
+ (5.1,34.5)        | ((2,0),(2,4),(0,0))        | 30.6571362002
+ (5.1,34.5)        | ((3,1),(3,3),(1,0))        | 31.5699223946
+ (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | 26.5680258958
+ (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | 26.5680258958
+ (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | 26.5680258958
+ (5.1,34.5)        | ((0,0))                    | 34.8749193547
+ (5.1,34.5)        | ((0,1),(0,1))              | 33.8859853037
+ (-5,-12)          | ((2,0),(2,4),(0,0))        |            13
+ (-5,-12)          | ((3,1),(3,3),(1,0))        |  13.416407865
+ (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | 15.2315462117
+ (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | 15.2315462117
+ (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) |  11.313708499
+ (-5,-12)          | ((0,0))                    |            13
+ (-5,-12)          | ((0,1),(0,1))              | 13.9283882772
+ (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        |             0
+ (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        |             1
+ (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  |  2.2360679775
+ (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  |  2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | 1.58113883008
+ (1e-300,-1e-300)  | ((0,0))                    |             0
+ (1e-300,-1e-300)  | ((0,1),(0,1))              |             1
+ (1e+300,Infinity) | ((2,0),(2,4),(0,0))        |      Infinity
+ (1e+300,Infinity) | ((3,1),(3,3),(1,0))        |      Infinity
+ (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  |      Infinity
+ (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  |      Infinity
+ (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) |      Infinity
+ (1e+300,Infinity) | ((0,0))                    |      Infinity
+ (1e+300,Infinity) | ((0,1),(0,1))              |      Infinity
+ (NaN,NaN)         | ((2,0),(2,4),(0,0))        |             0
+ (NaN,NaN)         | ((3,1),(3,3),(1,0))        |             0
+ (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  |             0
+ (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  |             0
+ (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) |             0
+ (NaN,NaN)         | ((0,0))                    |             0
+ (NaN,NaN)         | ((0,1),(0,1))              |             0
+ (10,10)           | ((2,0),(2,4),(0,0))        |            10
+ (10,10)           | ((3,1),(3,3),(1,0))        | 9.89949493661
+ (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | 3.60555127546
+ (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | 3.60555127546
+ (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | 3.60555127546
+ (10,10)           | ((0,0))                    | 14.1421356237
+ (10,10)           | ((0,1),(0,1))              | 13.4536240471
+(63 rows)
+
+-- Closest point to line
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LINE_TBL l;
+        f1         |                   s                   |             ?column?             
+-------------------+---------------------------------------+----------------------------------
+ (0,0)             | {0,-1,5}                              | (0,5)
+ (0,0)             | {1,0,5}                               | (-5,0)
+ (0,0)             | {0,3,0}                               | (0,0)
+ (0,0)             | {1,-1,0}                              | (0,0)
+ (0,0)             | {-0.4,-1,-6}                          | (-2.06896551724,-5.1724137931)
+ (0,0)             | {-0.000184615384615,-1,15.3846153846} | (0.00284023658959,15.3846148603)
+ (0,0)             | {NaN,-1,NaN}                          | 
+ (0,0)             | {3,NaN,5}                             | 
+ (0,0)             | {NaN,NaN,NaN}                         | 
+ (0,0)             | {0,-1,3}                              | (0,3)
+ (0,0)             | {-1,0,3}                              | (3,0)
+ (-10,0)           | {0,-1,5}                              | (-10,5)
+ (-10,0)           | {1,0,5}                               | (-5,0)
+ (-10,0)           | {0,3,0}                               | (-10,0)
+ (-10,0)           | {1,-1,0}                              | (-5,-5)
+ (-10,0)           | {-0.4,-1,-6}                          | (-10.6896551724,-1.72413793103)
+ (-10,0)           | {-0.000184615384615,-1,15.3846153846} | (-9.99715942258,15.386461014)
+ (-10,0)           | {NaN,-1,NaN}                          | 
+ (-10,0)           | {3,NaN,5}                             | 
+ (-10,0)           | {NaN,NaN,NaN}                         | 
+ (-10,0)           | {0,-1,3}                              | (-10,3)
+ (-10,0)           | {-1,0,3}                              | (3,0)
+ (-3,4)            | {0,-1,5}                              | (-3,5)
+ (-3,4)            | {1,0,5}                               | (-5,4)
+ (-3,4)            | {0,3,0}                               | (-3,0)
+ (-3,4)            | {1,-1,0}                              | (0.5,0.5)
+ (-3,4)            | {-0.4,-1,-6}                          | (-6.03448275862,-3.58620689655)
+ (-3,4)            | {-0.000184615384615,-1,15.3846153846} | (-2.99789812268,15.3851688427)
+ (-3,4)            | {NaN,-1,NaN}                          | 
+ (-3,4)            | {3,NaN,5}                             | 
+ (-3,4)            | {NaN,NaN,NaN}                         | 
+ (-3,4)            | {0,-1,3}                              | (-3,3)
+ (-3,4)            | {-1,0,3}                              | (3,4)
+ (5.1,34.5)        | {0,-1,5}                              | (5.1,5)
+ (5.1,34.5)        | {1,0,5}                               | (-5,34.5)
+ (5.1,34.5)        | {0,3,0}                               | (5.1,0)
+ (5.1,34.5)        | {1,-1,0}                              | (19.8,19.8)
+ (5.1,34.5)        | {-0.4,-1,-6}                          | (-9.56896551724,-2.1724137931)
+ (5.1,34.5)        | {-0.000184615384615,-1,15.3846153846} | (5.09647083221,15.3836744977)
+ (5.1,34.5)        | {NaN,-1,NaN}                          | 
+ (5.1,34.5)        | {3,NaN,5}                             | 
+ (5.1,34.5)        | {NaN,NaN,NaN}                         | 
+ (5.1,34.5)        | {0,-1,3}                              | (5.1,3)
+ (5.1,34.5)        | {-1,0,3}                              | (3,34.5)
+ (-5,-12)          | {0,-1,5}                              | (-5,5)
+ (-5,-12)          | {1,0,5}                               | (-5,-12)
+ (-5,-12)          | {0,3,0}                               | (-5,0)
+ (-5,-12)          | {1,-1,0}                              | (-8.5,-8.5)
+ (-5,-12)          | {-0.4,-1,-6}                          | (-2.24137931034,-5.10344827586)
+ (-5,-12)          | {-0.000184615384615,-1,15.3846153846} | (-4.99494420846,15.3855375282)
+ (-5,-12)          | {NaN,-1,NaN}                          | 
+ (-5,-12)          | {3,NaN,5}                             | 
+ (-5,-12)          | {NaN,NaN,NaN}                         | 
+ (-5,-12)          | {0,-1,3}                              | (-5,3)
+ (-5,-12)          | {-1,0,3}                              | (3,-12)
+ (1e-300,-1e-300)  | {0,-1,5}                              | (1e-300,5)
+ (1e-300,-1e-300)  | {1,0,5}                               | (-5,-1e-300)
+ (1e-300,-1e-300)  | {0,3,0}                               | (1e-300,0)
+ (1e-300,-1e-300)  | {1,-1,0}                              | (0,0)
+ (1e-300,-1e-300)  | {-0.4,-1,-6}                          | (-2.06896551724,-5.1724137931)
+ (1e-300,-1e-300)  | {-0.000184615384615,-1,15.3846153846} | (0.00284023658959,15.3846148603)
+ (1e-300,-1e-300)  | {NaN,-1,NaN}                          | 
+ (1e-300,-1e-300)  | {3,NaN,5}                             | 
+ (1e-300,-1e-300)  | {NaN,NaN,NaN}                         | 
+ (1e-300,-1e-300)  | {0,-1,3}                              | (1e-300,3)
+ (1e-300,-1e-300)  | {-1,0,3}                              | (3,-1e-300)
+ (1e+300,Infinity) | {0,-1,5}                              | (1e+300,5)
+ (1e+300,Infinity) | {1,0,5}                               | 
+ (1e+300,Infinity) | {0,3,0}                               | (1e+300,0)
+ (1e+300,Infinity) | {1,-1,0}                              | (Infinity,NaN)
+ (1e+300,Infinity) | {-0.4,-1,-6}                          | (-Infinity,NaN)
+ (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} | (-Infinity,NaN)
+ (1e+300,Infinity) | {NaN,-1,NaN}                          | 
+ (1e+300,Infinity) | {3,NaN,5}                             | 
+ (1e+300,Infinity) | {NaN,NaN,NaN}                         | 
+ (1e+300,Infinity) | {0,-1,3}                              | (1e+300,3)
+ (1e+300,Infinity) | {-1,0,3}                              | 
+ (NaN,NaN)         | {0,-1,5}                              | 
+ (NaN,NaN)         | {1,0,5}                               | 
+ (NaN,NaN)         | {0,3,0}                               | 
+ (NaN,NaN)         | {1,-1,0}                              | 
+ (NaN,NaN)         | {-0.4,-1,-6}                          | 
+ (NaN,NaN)         | {-0.000184615384615,-1,15.3846153846} | 
+ (NaN,NaN)         | {NaN,-1,NaN}                          | 
+ (NaN,NaN)         | {3,NaN,5}                             | 
+ (NaN,NaN)         | {NaN,NaN,NaN}                         | 
+ (NaN,NaN)         | {0,-1,3}                              | 
+ (NaN,NaN)         | {-1,0,3}                              | 
+ (10,10)           | {0,-1,5}                              | (10,5)
+ (10,10)           | {1,0,5}                               | (-5,10)
+ (10,10)           | {0,3,0}                               | (10,0)
+ (10,10)           | {1,-1,0}                              | (10,10)
+ (10,10)           | {-0.4,-1,-6}                          | (3.10344827586,-7.24137931034)
+ (10,10)           | {-0.000184615384615,-1,15.3846153846} | (10.000993742,15.3827690473)
+ (10,10)           | {NaN,-1,NaN}                          | 
+ (10,10)           | {3,NaN,5}                             | 
+ (10,10)           | {NaN,NaN,NaN}                         | 
+ (10,10)           | {0,-1,3}                              | (10,3)
+ (10,10)           | {-1,0,3}                              | (3,10)
+(99 rows)
+
+-- Closest point to line segment
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LSEG_TBL l;
+        f1         |               s               |             ?column?             
+-------------------+-------------------------------+----------------------------------
+ (0,0)             | [(1,2),(3,4)]                 | (1,2)
+ (0,0)             | [(0,0),(6,6)]                 | (0,0)
+ (0,0)             | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ (0,0)             | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
+ (0,0)             | [(11,22),(33,44)]             | (11,22)
+ (0,0)             | [(-10,2),(-10,3)]             | (-10,2)
+ (0,0)             | [(0,-20),(30,-20)]            | (0,-20)
+ (0,0)             | [(NaN,1),(NaN,90)]            | 
+ (-10,0)           | [(1,2),(3,4)]                 | (1,2)
+ (-10,0)           | [(0,0),(6,6)]                 | (0,0)
+ (-10,0)           | [(10,-10),(-3,-4)]            | (-3,-4)
+ (-10,0)           | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
+ (-10,0)           | [(11,22),(33,44)]             | (11,22)
+ (-10,0)           | [(-10,2),(-10,3)]             | (-10,2)
+ (-10,0)           | [(0,-20),(30,-20)]            | (0,-20)
+ (-10,0)           | [(NaN,1),(NaN,90)]            | 
+ (-3,4)            | [(1,2),(3,4)]                 | (1,2)
+ (-3,4)            | [(0,0),(6,6)]                 | (0.5,0.5)
+ (-3,4)            | [(10,-10),(-3,-4)]            | (-3,-4)
+ (-3,4)            | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
+ (-3,4)            | [(11,22),(33,44)]             | (11,22)
+ (-3,4)            | [(-10,2),(-10,3)]             | (-10,3)
+ (-3,4)            | [(0,-20),(30,-20)]            | (0,-20)
+ (-3,4)            | [(NaN,1),(NaN,90)]            | 
+ (5.1,34.5)        | [(1,2),(3,4)]                 | (3,4)
+ (5.1,34.5)        | [(0,0),(6,6)]                 | (6,6)
+ (5.1,34.5)        | [(10,-10),(-3,-4)]            | (-3,-4)
+ (5.1,34.5)        | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
+ (5.1,34.5)        | [(11,22),(33,44)]             | (14.3,25.3)
+ (5.1,34.5)        | [(-10,2),(-10,3)]             | (-10,3)
+ (5.1,34.5)        | [(0,-20),(30,-20)]            | (5.1,-20)
+ (5.1,34.5)        | [(NaN,1),(NaN,90)]            | 
+ (-5,-12)          | [(1,2),(3,4)]                 | (1,2)
+ (-5,-12)          | [(0,0),(6,6)]                 | (0,0)
+ (-5,-12)          | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
+ (-5,-12)          | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
+ (-5,-12)          | [(11,22),(33,44)]             | (11,22)
+ (-5,-12)          | [(-10,2),(-10,3)]             | (-10,2)
+ (-5,-12)          | [(0,-20),(30,-20)]            | (0,-20)
+ (-5,-12)          | [(NaN,1),(NaN,90)]            | 
+ (1e-300,-1e-300)  | [(1,2),(3,4)]                 | (1,2)
+ (1e-300,-1e-300)  | [(0,0),(6,6)]                 | (0,0)
+ (1e-300,-1e-300)  | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ (1e-300,-1e-300)  | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
+ (1e-300,-1e-300)  | [(11,22),(33,44)]             | (11,22)
+ (1e-300,-1e-300)  | [(-10,2),(-10,3)]             | (-10,2)
+ (1e-300,-1e-300)  | [(0,-20),(30,-20)]            | (0,-20)
+ (1e-300,-1e-300)  | [(NaN,1),(NaN,90)]            | 
+ (1e+300,Infinity) | [(1,2),(3,4)]                 | (3,4)
+ (1e+300,Infinity) | [(0,0),(6,6)]                 | (6,6)
+ (1e+300,Infinity) | [(10,-10),(-3,-4)]            | (-3,-4)
+ (1e+300,Infinity) | [(-1000000,200),(300000,-40)] | (300000,-40)
+ (1e+300,Infinity) | [(11,22),(33,44)]             | (33,44)
+ (1e+300,Infinity) | [(-10,2),(-10,3)]             | (-10,3)
+ (1e+300,Infinity) | [(0,-20),(30,-20)]            | (30,-20)
+ (1e+300,Infinity) | [(NaN,1),(NaN,90)]            | (NaN,90)
+ (NaN,NaN)         | [(1,2),(3,4)]                 | 
+ (NaN,NaN)         | [(0,0),(6,6)]                 | 
+ (NaN,NaN)         | [(10,-10),(-3,-4)]            | 
+ (NaN,NaN)         | [(-1000000,200),(300000,-40)] | 
+ (NaN,NaN)         | [(11,22),(33,44)]             | 
+ (NaN,NaN)         | [(-10,2),(-10,3)]             | 
+ (NaN,NaN)         | [(0,-20),(30,-20)]            | 
+ (NaN,NaN)         | [(NaN,1),(NaN,90)]            | 
+ (10,10)           | [(1,2),(3,4)]                 | (3,4)
+ (10,10)           | [(0,0),(6,6)]                 | (6,6)
+ (10,10)           | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
+ (10,10)           | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
+ (10,10)           | [(11,22),(33,44)]             | (11,22)
+ (10,10)           | [(-10,2),(-10,3)]             | (-10,3)
+ (10,10)           | [(0,-20),(30,-20)]            | (10,-20)
+ (10,10)           | [(NaN,1),(NaN,90)]            | 
+(72 rows)
+
+-- Closest point to box
+SELECT p.f1, b.f1, p.f1 ## b.f1 FROM POINT_TBL p, BOX_TBL b;
+        f1         |         f1          |   ?column?   
+-------------------+---------------------+--------------
+ (0,0)             | (2,2),(0,0)         | (0,0)
+ (0,0)             | (3,3),(1,1)         | (1,1)
+ (0,0)             | (-2,2),(-8,-10)     | (-2,0)
+ (0,0)             | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (0,0)             | (3,3),(3,3)         | (3,3)
+ (-10,0)           | (2,2),(0,0)         | (0,0)
+ (-10,0)           | (3,3),(1,1)         | (1,1)
+ (-10,0)           | (-2,2),(-8,-10)     | (-8,0)
+ (-10,0)           | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (-10,0)           | (3,3),(3,3)         | (3,3)
+ (-3,4)            | (2,2),(0,0)         | (0,2)
+ (-3,4)            | (3,3),(1,1)         | (1,3)
+ (-3,4)            | (-2,2),(-8,-10)     | (-3,2)
+ (-3,4)            | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (-3,4)            | (3,3),(3,3)         | (3,3)
+ (5.1,34.5)        | (2,2),(0,0)         | (2,2)
+ (5.1,34.5)        | (3,3),(1,1)         | (3,3)
+ (5.1,34.5)        | (-2,2),(-8,-10)     | (-2,2)
+ (5.1,34.5)        | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (5.1,34.5)        | (3,3),(3,3)         | (3,3)
+ (-5,-12)          | (2,2),(0,0)         | (0,0)
+ (-5,-12)          | (3,3),(1,1)         | (1,1)
+ (-5,-12)          | (-2,2),(-8,-10)     | (-5,-10)
+ (-5,-12)          | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (-5,-12)          | (3,3),(3,3)         | (3,3)
+ (1e-300,-1e-300)  | (2,2),(0,0)         | (0,0)
+ (1e-300,-1e-300)  | (3,3),(1,1)         | (1,1)
+ (1e-300,-1e-300)  | (-2,2),(-8,-10)     | (-2,-1e-300)
+ (1e-300,-1e-300)  | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (1e-300,-1e-300)  | (3,3),(3,3)         | (3,3)
+ (1e+300,Infinity) | (2,2),(0,0)         | (0,2)
+ (1e+300,Infinity) | (3,3),(1,1)         | (1,3)
+ (1e+300,Infinity) | (-2,2),(-8,-10)     | (-8,2)
+ (1e+300,Infinity) | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (1e+300,Infinity) | (3,3),(3,3)         | (3,3)
+ (NaN,NaN)         | (2,2),(0,0)         | 
+ (NaN,NaN)         | (3,3),(1,1)         | 
+ (NaN,NaN)         | (-2,2),(-8,-10)     | 
+ (NaN,NaN)         | (2.5,3.5),(2.5,2.5) | 
+ (NaN,NaN)         | (3,3),(3,3)         | 
+ (10,10)           | (2,2),(0,0)         | (2,2)
+ (10,10)           | (3,3),(1,1)         | (3,3)
+ (10,10)           | (-2,2),(-8,-10)     | (-2,2)
+ (10,10)           | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (10,10)           | (3,3),(3,3)         | (3,3)
+(45 rows)
+
+-- On line
+SELECT p.f1, l.s FROM POINT_TBL p, LINE_TBL l WHERE p.f1 <@ l.s;
+        f1        |    s     
+------------------+----------
+ (0,0)            | {0,3,0}
+ (0,0)            | {1,-1,0}
+ (-10,0)          | {0,3,0}
+ (-5,-12)         | {1,0,5}
+ (1e-300,-1e-300) | {0,3,0}
+ (1e-300,-1e-300) | {1,-1,0}
+ (10,10)          | {1,-1,0}
+(7 rows)
+
+-- On line segment
+SELECT p.f1, l.s FROM POINT_TBL p, LSEG_TBL l WHERE p.f1 <@ l.s;
+        f1        |       s       
+------------------+---------------
+ (0,0)            | [(0,0),(6,6)]
+ (1e-300,-1e-300) | [(0,0),(6,6)]
+(2 rows)
+
+-- On path
+SELECT p.f1, p1.f1 FROM POINT_TBL p, PATH_TBL p1 WHERE p.f1 <@ p1.f1;
+        f1        |            f1             
+------------------+---------------------------
+ (0,0)            | [(0,0),(3,0),(4,5),(1,6)]
+ (1e-300,-1e-300) | [(0,0),(3,0),(4,5),(1,6)]
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((10,20))
+ (NaN,NaN)        | ((11,12),(13,14))
+(7 rows)
+
+--
+-- Lines
+--
+-- Vertical
+SELECT s FROM LINE_TBL WHERE ?| s;
+    s     
+----------
+ {1,0,5}
+ {-1,0,3}
+(2 rows)
+
+-- Horizontal
+SELECT s FROM LINE_TBL WHERE ?- s;
+    s     
+----------
+ {0,-1,5}
+ {0,3,0}
+ {0,-1,3}
+(3 rows)
+
+-- Same as line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s = l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {0,-1,5}
+ {1,0,5}                               | {1,0,5}
+ {0,3,0}                               | {0,3,0}
+ {1,-1,0}                              | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846}
+ {NaN,-1,NaN}                          | {NaN,-1,NaN}
+ {3,NaN,5}                             | {3,NaN,5}
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}
+ {0,-1,3}                              | {0,-1,3}
+ {-1,0,3}                              | {-1,0,3}
+(11 rows)
+
+-- Parallel to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?|| l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {0,-1,5}
+ {0,-1,5}                              | {0,3,0}
+ {0,-1,5}                              | {0,-1,3}
+ {1,0,5}                               | {1,0,5}
+ {1,0,5}                               | {-1,0,3}
+ {0,3,0}                               | {0,-1,5}
+ {0,3,0}                               | {0,3,0}
+ {0,3,0}                               | {0,-1,3}
+ {1,-1,0}                              | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,3}                              | {0,-1,5}
+ {0,-1,3}                              | {0,3,0}
+ {0,-1,3}                              | {0,-1,3}
+ {-1,0,3}                              | {1,0,5}
+ {-1,0,3}                              | {-1,0,3}
+(16 rows)
+
+-- Perpendicular to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?-| l2.s;
+    s     |    s     
+----------+----------
+ {0,-1,5} | {1,0,5}
+ {0,-1,5} | {-1,0,3}
+ {1,0,5}  | {0,-1,5}
+ {1,0,5}  | {0,3,0}
+ {1,0,5}  | {0,-1,3}
+ {0,3,0}  | {1,0,5}
+ {0,3,0}  | {-1,0,3}
+ {0,-1,3} | {1,0,5}
+ {0,-1,3} | {-1,0,3}
+ {-1,0,3} | {0,-1,5}
+ {-1,0,3} | {0,3,0}
+ {-1,0,3} | {0,-1,3}
+(12 rows)
+
+-- Distance to line
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2;
+                   s                   |                   s                   | ?column? 
+---------------------------------------+---------------------------------------+----------
+ {0,-1,5}                              | {0,-1,5}                              |        0
+ {0,-1,5}                              | {1,0,5}                               |        0
+ {0,-1,5}                              | {0,3,0}                               |        5
+ {0,-1,5}                              | {1,-1,0}                              |        0
+ {0,-1,5}                              | {-0.4,-1,-6}                          |        0
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,-1,5}                              | {NaN,-1,NaN}                          |        0
+ {0,-1,5}                              | {3,NaN,5}                             |        0
+ {0,-1,5}                              | {NaN,NaN,NaN}                         |        0
+ {0,-1,5}                              | {0,-1,3}                              |        2
+ {0,-1,5}                              | {-1,0,3}                              |        0
+ {1,0,5}                               | {0,-1,5}                              |        0
+ {1,0,5}                               | {1,0,5}                               |        0
+ {1,0,5}                               | {0,3,0}                               |        0
+ {1,0,5}                               | {1,-1,0}                              |        0
+ {1,0,5}                               | {-0.4,-1,-6}                          |        0
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846} |        0
+ {1,0,5}                               | {NaN,-1,NaN}                          |        0
+ {1,0,5}                               | {3,NaN,5}                             |        0
+ {1,0,5}                               | {NaN,NaN,NaN}                         |        0
+ {1,0,5}                               | {0,-1,3}                              |        0
+ {1,0,5}                               | {-1,0,3}                              |        8
+ {0,3,0}                               | {0,-1,5}                              |        5
+ {0,3,0}                               | {1,0,5}                               |        0
+ {0,3,0}                               | {0,3,0}                               |        0
+ {0,3,0}                               | {1,-1,0}                              |        0
+ {0,3,0}                               | {-0.4,-1,-6}                          |        0
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,3,0}                               | {NaN,-1,NaN}                          |        0
+ {0,3,0}                               | {3,NaN,5}                             |        0
+ {0,3,0}                               | {NaN,NaN,NaN}                         |        0
+ {0,3,0}                               | {0,-1,3}                              |        3
+ {0,3,0}                               | {-1,0,3}                              |        0
+ {1,-1,0}                              | {0,-1,5}                              |        0
+ {1,-1,0}                              | {1,0,5}                               |        0
+ {1,-1,0}                              | {0,3,0}                               |        0
+ {1,-1,0}                              | {1,-1,0}                              |        0
+ {1,-1,0}                              | {-0.4,-1,-6}                          |        0
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {1,-1,0}                              | {NaN,-1,NaN}                          |        0
+ {1,-1,0}                              | {3,NaN,5}                             |        0
+ {1,-1,0}                              | {NaN,NaN,NaN}                         |        0
+ {1,-1,0}                              | {0,-1,3}                              |        0
+ {1,-1,0}                              | {-1,0,3}                              |        0
+ {-0.4,-1,-6}                          | {0,-1,5}                              |        0
+ {-0.4,-1,-6}                          | {1,0,5}                               |        0
+ {-0.4,-1,-6}                          | {0,3,0}                               |        0
+ {-0.4,-1,-6}                          | {1,-1,0}                              |        0
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}                          |        0
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846} |        0
+ {-0.4,-1,-6}                          | {NaN,-1,NaN}                          |        0
+ {-0.4,-1,-6}                          | {3,NaN,5}                             |        0
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}                         |        0
+ {-0.4,-1,-6}                          | {0,-1,3}                              |        0
+ {-0.4,-1,-6}                          | {-1,0,3}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}                               |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}                               |        0
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}                          |        0
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} |        0
+ {-0.000184615384615,-1,15.3846153846} | {NaN,-1,NaN}                          |        0
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}                             |        0
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}                         |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}                              |        0
+ {NaN,-1,NaN}                          | {0,-1,5}                              |        0
+ {NaN,-1,NaN}                          | {1,0,5}                               |        0
+ {NaN,-1,NaN}                          | {0,3,0}                               |        0
+ {NaN,-1,NaN}                          | {1,-1,0}                              |        0
+ {NaN,-1,NaN}                          | {-0.4,-1,-6}                          |        0
+ {NaN,-1,NaN}                          | {-0.000184615384615,-1,15.3846153846} |        0
+ {NaN,-1,NaN}                          | {NaN,-1,NaN}                          |        0
+ {NaN,-1,NaN}                          | {3,NaN,5}                             |        0
+ {NaN,-1,NaN}                          | {NaN,NaN,NaN}                         |        0
+ {NaN,-1,NaN}                          | {0,-1,3}                              |        0
+ {NaN,-1,NaN}                          | {-1,0,3}                              |        0
+ {3,NaN,5}                             | {0,-1,5}                              |        0
+ {3,NaN,5}                             | {1,0,5}                               |        0
+ {3,NaN,5}                             | {0,3,0}                               |        0
+ {3,NaN,5}                             | {1,-1,0}                              |        0
+ {3,NaN,5}                             | {-0.4,-1,-6}                          |        0
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846} |        0
+ {3,NaN,5}                             | {NaN,-1,NaN}                          |        0
+ {3,NaN,5}                             | {3,NaN,5}                             |        0
+ {3,NaN,5}                             | {NaN,NaN,NaN}                         |        0
+ {3,NaN,5}                             | {0,-1,3}                              |        0
+ {3,NaN,5}                             | {-1,0,3}                              |        0
+ {NaN,NaN,NaN}                         | {0,-1,5}                              |        0
+ {NaN,NaN,NaN}                         | {1,0,5}                               |        0
+ {NaN,NaN,NaN}                         | {0,3,0}                               |        0
+ {NaN,NaN,NaN}                         | {1,-1,0}                              |        0
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}                          |        0
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846} |        0
+ {NaN,NaN,NaN}                         | {NaN,-1,NaN}                          |        0
+ {NaN,NaN,NaN}                         | {3,NaN,5}                             |        0
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}                         |        0
+ {NaN,NaN,NaN}                         | {0,-1,3}                              |        0
+ {NaN,NaN,NaN}                         | {-1,0,3}                              |        0
+ {0,-1,3}                              | {0,-1,5}                              |        2
+ {0,-1,3}                              | {1,0,5}                               |        0
+ {0,-1,3}                              | {0,3,0}                               |        3
+ {0,-1,3}                              | {1,-1,0}                              |        0
+ {0,-1,3}                              | {-0.4,-1,-6}                          |        0
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,-1,3}                              | {NaN,-1,NaN}                          |        0
+ {0,-1,3}                              | {3,NaN,5}                             |        0
+ {0,-1,3}                              | {NaN,NaN,NaN}                         |        0
+ {0,-1,3}                              | {0,-1,3}                              |        0
+ {0,-1,3}                              | {-1,0,3}                              |        0
+ {-1,0,3}                              | {0,-1,5}                              |        0
+ {-1,0,3}                              | {1,0,5}                               |        8
+ {-1,0,3}                              | {0,3,0}                               |        0
+ {-1,0,3}                              | {1,-1,0}                              |        0
+ {-1,0,3}                              | {-0.4,-1,-6}                          |        0
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {-1,0,3}                              | {NaN,-1,NaN}                          |        0
+ {-1,0,3}                              | {3,NaN,5}                             |        0
+ {-1,0,3}                              | {NaN,NaN,NaN}                         |        0
+ {-1,0,3}                              | {0,-1,3}                              |        0
+ {-1,0,3}                              | {-1,0,3}                              |        0
+(121 rows)
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LINE_TBL l, BOX_TBL b;
+ERROR:  function "dist_lb" not implemented
+-- Intersect with line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?# l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {1,0,5}
+ {0,-1,5}                              | {1,-1,0}
+ {0,-1,5}                              | {-0.4,-1,-6}
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,5}                              | {NaN,-1,NaN}
+ {0,-1,5}                              | {3,NaN,5}
+ {0,-1,5}                              | {NaN,NaN,NaN}
+ {0,-1,5}                              | {-1,0,3}
+ {1,0,5}                               | {0,-1,5}
+ {1,0,5}                               | {0,3,0}
+ {1,0,5}                               | {1,-1,0}
+ {1,0,5}                               | {-0.4,-1,-6}
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846}
+ {1,0,5}                               | {NaN,-1,NaN}
+ {1,0,5}                               | {3,NaN,5}
+ {1,0,5}                               | {NaN,NaN,NaN}
+ {1,0,5}                               | {0,-1,3}
+ {0,3,0}                               | {1,0,5}
+ {0,3,0}                               | {1,-1,0}
+ {0,3,0}                               | {-0.4,-1,-6}
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846}
+ {0,3,0}                               | {NaN,-1,NaN}
+ {0,3,0}                               | {3,NaN,5}
+ {0,3,0}                               | {NaN,NaN,NaN}
+ {0,3,0}                               | {-1,0,3}
+ {1,-1,0}                              | {0,-1,5}
+ {1,-1,0}                              | {1,0,5}
+ {1,-1,0}                              | {0,3,0}
+ {1,-1,0}                              | {-0.4,-1,-6}
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846}
+ {1,-1,0}                              | {NaN,-1,NaN}
+ {1,-1,0}                              | {3,NaN,5}
+ {1,-1,0}                              | {NaN,NaN,NaN}
+ {1,-1,0}                              | {0,-1,3}
+ {1,-1,0}                              | {-1,0,3}
+ {-0.4,-1,-6}                          | {0,-1,5}
+ {-0.4,-1,-6}                          | {1,0,5}
+ {-0.4,-1,-6}                          | {0,3,0}
+ {-0.4,-1,-6}                          | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846}
+ {-0.4,-1,-6}                          | {NaN,-1,NaN}
+ {-0.4,-1,-6}                          | {3,NaN,5}
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}
+ {-0.4,-1,-6}                          | {0,-1,3}
+ {-0.4,-1,-6}                          | {-1,0,3}
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {NaN,-1,NaN}
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}
+ {NaN,-1,NaN}                          | {0,-1,5}
+ {NaN,-1,NaN}                          | {1,0,5}
+ {NaN,-1,NaN}                          | {0,3,0}
+ {NaN,-1,NaN}                          | {1,-1,0}
+ {NaN,-1,NaN}                          | {-0.4,-1,-6}
+ {NaN,-1,NaN}                          | {-0.000184615384615,-1,15.3846153846}
+ {NaN,-1,NaN}                          | {NaN,-1,NaN}
+ {NaN,-1,NaN}                          | {3,NaN,5}
+ {NaN,-1,NaN}                          | {NaN,NaN,NaN}
+ {NaN,-1,NaN}                          | {0,-1,3}
+ {NaN,-1,NaN}                          | {-1,0,3}
+ {3,NaN,5}                             | {0,-1,5}
+ {3,NaN,5}                             | {1,0,5}
+ {3,NaN,5}                             | {0,3,0}
+ {3,NaN,5}                             | {1,-1,0}
+ {3,NaN,5}                             | {-0.4,-1,-6}
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846}
+ {3,NaN,5}                             | {NaN,-1,NaN}
+ {3,NaN,5}                             | {3,NaN,5}
+ {3,NaN,5}                             | {NaN,NaN,NaN}
+ {3,NaN,5}                             | {0,-1,3}
+ {3,NaN,5}                             | {-1,0,3}
+ {NaN,NaN,NaN}                         | {0,-1,5}
+ {NaN,NaN,NaN}                         | {1,0,5}
+ {NaN,NaN,NaN}                         | {0,3,0}
+ {NaN,NaN,NaN}                         | {1,-1,0}
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846}
+ {NaN,NaN,NaN}                         | {NaN,-1,NaN}
+ {NaN,NaN,NaN}                         | {3,NaN,5}
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}
+ {NaN,NaN,NaN}                         | {0,-1,3}
+ {NaN,NaN,NaN}                         | {-1,0,3}
+ {0,-1,3}                              | {1,0,5}
+ {0,-1,3}                              | {1,-1,0}
+ {0,-1,3}                              | {-0.4,-1,-6}
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,3}                              | {NaN,-1,NaN}
+ {0,-1,3}                              | {3,NaN,5}
+ {0,-1,3}                              | {NaN,NaN,NaN}
+ {0,-1,3}                              | {-1,0,3}
+ {-1,0,3}                              | {0,-1,5}
+ {-1,0,3}                              | {0,3,0}
+ {-1,0,3}                              | {1,-1,0}
+ {-1,0,3}                              | {-0.4,-1,-6}
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846}
+ {-1,0,3}                              | {NaN,-1,NaN}
+ {-1,0,3}                              | {3,NaN,5}
+ {-1,0,3}                              | {NaN,NaN,NaN}
+ {-1,0,3}                              | {0,-1,3}
+(105 rows)
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LINE_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+      s       |         f1          
+--------------+---------------------
+ {1,0,5}      | (-2,2),(-8,-10)
+ {0,3,0}      | (2,2),(0,0)
+ {0,3,0}      | (-2,2),(-8,-10)
+ {1,-1,0}     | (2,2),(0,0)
+ {1,-1,0}     | (3,3),(1,1)
+ {1,-1,0}     | (-2,2),(-8,-10)
+ {1,-1,0}     | (2.5,3.5),(2.5,2.5)
+ {-0.4,-1,-6} | (-2,2),(-8,-10)
+ {0,-1,3}     | (3,3),(1,1)
+ {0,-1,3}     | (2.5,3.5),(2.5,2.5)
+ {-1,0,3}     | (3,3),(1,1)
+(11 rows)
+
+-- Intersection point with line
+SELECT l1.s, l2.s, l1.s # l2.s FROM LINE_TBL l1, LINE_TBL l2;
+                   s                   |                   s                   |            ?column?             
+---------------------------------------+---------------------------------------+---------------------------------
+ {0,-1,5}                              | {0,-1,5}                              | 
+ {0,-1,5}                              | {1,0,5}                               | (-5,5)
+ {0,-1,5}                              | {0,3,0}                               | 
+ {0,-1,5}                              | {1,-1,0}                              | (5,5)
+ {0,-1,5}                              | {-0.4,-1,-6}                          | (-27.5,5)
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846} | (56250,5)
+ {0,-1,5}                              | {NaN,-1,NaN}                          | (NaN,5)
+ {0,-1,5}                              | {3,NaN,5}                             | (NaN,5)
+ {0,-1,5}                              | {NaN,NaN,NaN}                         | (NaN,5)
+ {0,-1,5}                              | {0,-1,3}                              | 
+ {0,-1,5}                              | {-1,0,3}                              | (3,5)
+ {1,0,5}                               | {0,-1,5}                              | (-5,5)
+ {1,0,5}                               | {1,0,5}                               | 
+ {1,0,5}                               | {0,3,0}                               | (-5,0)
+ {1,0,5}                               | {1,-1,0}                              | (-5,-5)
+ {1,0,5}                               | {-0.4,-1,-6}                          | (-5,-4)
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846} | (-5,15.3855384615)
+ {1,0,5}                               | {NaN,-1,NaN}                          | (-5,NaN)
+ {1,0,5}                               | {3,NaN,5}                             | (-5,NaN)
+ {1,0,5}                               | {NaN,NaN,NaN}                         | (-5,NaN)
+ {1,0,5}                               | {0,-1,3}                              | (-5,3)
+ {1,0,5}                               | {-1,0,3}                              | 
+ {0,3,0}                               | {0,-1,5}                              | 
+ {0,3,0}                               | {1,0,5}                               | (-5,0)
+ {0,3,0}                               | {0,3,0}                               | 
+ {0,3,0}                               | {1,-1,0}                              | (0,0)
+ {0,3,0}                               | {-0.4,-1,-6}                          | (-15,0)
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846} | (83333.3333333,0)
+ {0,3,0}                               | {NaN,-1,NaN}                          | (NaN,0)
+ {0,3,0}                               | {3,NaN,5}                             | (NaN,0)
+ {0,3,0}                               | {NaN,NaN,NaN}                         | (NaN,0)
+ {0,3,0}                               | {0,-1,3}                              | 
+ {0,3,0}                               | {-1,0,3}                              | (3,0)
+ {1,-1,0}                              | {0,-1,5}                              | (5,5)
+ {1,-1,0}                              | {1,0,5}                               | (-5,-5)
+ {1,-1,0}                              | {0,3,0}                               | (0,0)
+ {1,-1,0}                              | {1,-1,0}                              | 
+ {1,-1,0}                              | {-0.4,-1,-6}                          | (-4.28571428571,-4.28571428571)
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846} | (15.3817756722,15.3817756722)
+ {1,-1,0}                              | {NaN,-1,NaN}                          | (NaN,NaN)
+ {1,-1,0}                              | {3,NaN,5}                             | (NaN,NaN)
+ {1,-1,0}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {1,-1,0}                              | {0,-1,3}                              | (3,3)
+ {1,-1,0}                              | {-1,0,3}                              | (3,3)
+ {-0.4,-1,-6}                          | {0,-1,5}                              | (-27.5,5)
+ {-0.4,-1,-6}                          | {1,0,5}                               | (-5,-4)
+ {-0.4,-1,-6}                          | {0,3,0}                               | (-15,0)
+ {-0.4,-1,-6}                          | {1,-1,0}                              | (-4.28571428571,-4.28571428571)
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}                          | 
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846} | (-53.4862244113,15.3944897645)
+ {-0.4,-1,-6}                          | {NaN,-1,NaN}                          | (NaN,NaN)
+ {-0.4,-1,-6}                          | {3,NaN,5}                             | (NaN,NaN)
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-0.4,-1,-6}                          | {0,-1,3}                              | (-22.5,3)
+ {-0.4,-1,-6}                          | {-1,0,3}                              | (3,-7.2)
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}                              | (56250,5)
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}                               | (-5,15.3855384615)
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}                               | (83333.3333333,0)
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}                              | (15.3817756722,15.3817756722)
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}                          | (-53.4862244113,15.3944897645)
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} | 
+ {-0.000184615384615,-1,15.3846153846} | {NaN,-1,NaN}                          | (NaN,NaN)
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}                             | (NaN,NaN)
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}                              | (67083.3333333,3)
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}                              | (3,15.3840615385)
+ {NaN,-1,NaN}                          | {0,-1,5}                              | (NaN,5)
+ {NaN,-1,NaN}                          | {1,0,5}                               | (-5,NaN)
+ {NaN,-1,NaN}                          | {0,3,0}                               | (NaN,0)
+ {NaN,-1,NaN}                          | {1,-1,0}                              | (NaN,NaN)
+ {NaN,-1,NaN}                          | {-0.4,-1,-6}                          | (NaN,NaN)
+ {NaN,-1,NaN}                          | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ {NaN,-1,NaN}                          | {NaN,-1,NaN}                          | (NaN,NaN)
+ {NaN,-1,NaN}                          | {3,NaN,5}                             | (NaN,NaN)
+ {NaN,-1,NaN}                          | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {NaN,-1,NaN}                          | {0,-1,3}                              | (NaN,3)
+ {NaN,-1,NaN}                          | {-1,0,3}                              | (3,NaN)
+ {3,NaN,5}                             | {0,-1,5}                              | (NaN,5)
+ {3,NaN,5}                             | {1,0,5}                               | (-5,NaN)
+ {3,NaN,5}                             | {0,3,0}                               | (NaN,0)
+ {3,NaN,5}                             | {1,-1,0}                              | (NaN,NaN)
+ {3,NaN,5}                             | {-0.4,-1,-6}                          | (NaN,NaN)
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ {3,NaN,5}                             | {NaN,-1,NaN}                          | (NaN,NaN)
+ {3,NaN,5}                             | {3,NaN,5}                             | (NaN,NaN)
+ {3,NaN,5}                             | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {3,NaN,5}                             | {0,-1,3}                              | (NaN,3)
+ {3,NaN,5}                             | {-1,0,3}                              | (3,NaN)
+ {NaN,NaN,NaN}                         | {0,-1,5}                              | (NaN,5)
+ {NaN,NaN,NaN}                         | {1,0,5}                               | (-5,NaN)
+ {NaN,NaN,NaN}                         | {0,3,0}                               | (NaN,0)
+ {NaN,NaN,NaN}                         | {1,-1,0}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}                          | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {NaN,-1,NaN}                          | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {3,NaN,5}                             | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,-1,3}                              | (NaN,3)
+ {NaN,NaN,NaN}                         | {-1,0,3}                              | (3,NaN)
+ {0,-1,3}                              | {0,-1,5}                              | 
+ {0,-1,3}                              | {1,0,5}                               | (-5,3)
+ {0,-1,3}                              | {0,3,0}                               | 
+ {0,-1,3}                              | {1,-1,0}                              | (3,3)
+ {0,-1,3}                              | {-0.4,-1,-6}                          | (-22.5,3)
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846} | (67083.3333333,3)
+ {0,-1,3}                              | {NaN,-1,NaN}                          | (NaN,3)
+ {0,-1,3}                              | {3,NaN,5}                             | (NaN,3)
+ {0,-1,3}                              | {NaN,NaN,NaN}                         | (NaN,3)
+ {0,-1,3}                              | {0,-1,3}                              | 
+ {0,-1,3}                              | {-1,0,3}                              | (3,3)
+ {-1,0,3}                              | {0,-1,5}                              | (3,5)
+ {-1,0,3}                              | {1,0,5}                               | 
+ {-1,0,3}                              | {0,3,0}                               | (3,0)
+ {-1,0,3}                              | {1,-1,0}                              | (3,3)
+ {-1,0,3}                              | {-0.4,-1,-6}                          | (3,-7.2)
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846} | (3,15.3840615385)
+ {-1,0,3}                              | {NaN,-1,NaN}                          | (3,NaN)
+ {-1,0,3}                              | {3,NaN,5}                             | (3,NaN)
+ {-1,0,3}                              | {NaN,NaN,NaN}                         | (3,NaN)
+ {-1,0,3}                              | {0,-1,3}                              | (3,3)
+ {-1,0,3}                              | {-1,0,3}                              | 
+(121 rows)
+
+-- Closest point to line segment
+SELECT l.s, l1.s, l.s ## l1.s FROM LINE_TBL l, LSEG_TBL l1;
+                   s                   |               s               |            ?column?            
+---------------------------------------+-------------------------------+--------------------------------
+ {0,-1,5}                              | [(1,2),(3,4)]                 | (3,4)
+ {0,-1,5}                              | [(0,0),(6,6)]                 | (5,5)
+ {0,-1,5}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,-1,5}                              | [(-1000000,200),(300000,-40)] | (56250,5)
+ {0,-1,5}                              | [(11,22),(33,44)]             | (11,22)
+ {0,-1,5}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {0,-1,5}                              | [(0,-20),(30,-20)]            | 
+ {0,-1,5}                              | [(NaN,1),(NaN,90)]            | 
+ {1,0,5}                               | [(1,2),(3,4)]                 | (1,2)
+ {1,0,5}                               | [(0,0),(6,6)]                 | (0,0)
+ {1,0,5}                               | [(10,-10),(-3,-4)]            | (-3,-4)
+ {1,0,5}                               | [(-1000000,200),(300000,-40)] | (-5,15.3855384615)
+ {1,0,5}                               | [(11,22),(33,44)]             | (11,22)
+ {1,0,5}                               | [(-10,2),(-10,3)]             | 
+ {1,0,5}                               | [(0,-20),(30,-20)]            | (0,-20)
+ {1,0,5}                               | [(NaN,1),(NaN,90)]            | 
+ {0,3,0}                               | [(1,2),(3,4)]                 | (1,2)
+ {0,3,0}                               | [(0,0),(6,6)]                 | (0,0)
+ {0,3,0}                               | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,3,0}                               | [(-1000000,200),(300000,-40)] | (83333.3333333,0)
+ {0,3,0}                               | [(11,22),(33,44)]             | (11,22)
+ {0,3,0}                               | [(-10,2),(-10,3)]             | (-10,2)
+ {0,3,0}                               | [(0,-20),(30,-20)]            | 
+ {0,3,0}                               | [(NaN,1),(NaN,90)]            | 
+ {1,-1,0}                              | [(1,2),(3,4)]                 | 
+ {1,-1,0}                              | [(0,0),(6,6)]                 | 
+ {1,-1,0}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {1,-1,0}                              | [(-1000000,200),(300000,-40)] | (15.3817756722,15.3817756722)
+ {1,-1,0}                              | [(11,22),(33,44)]             | 
+ {1,-1,0}                              | [(-10,2),(-10,3)]             | (-10,2)
+ {1,-1,0}                              | [(0,-20),(30,-20)]            | (0,-20)
+ {1,-1,0}                              | [(NaN,1),(NaN,90)]            | 
+ {-0.4,-1,-6}                          | [(1,2),(3,4)]                 | (1,2)
+ {-0.4,-1,-6}                          | [(0,0),(6,6)]                 | (0,0)
+ {-0.4,-1,-6}                          | [(10,-10),(-3,-4)]            | (10,-10)
+ {-0.4,-1,-6}                          | [(-1000000,200),(300000,-40)] | (-53.4862244113,15.3944897645)
+ {-0.4,-1,-6}                          | [(11,22),(33,44)]             | (11,22)
+ {-0.4,-1,-6}                          | [(-10,2),(-10,3)]             | (-10,2)
+ {-0.4,-1,-6}                          | [(0,-20),(30,-20)]            | (30,-20)
+ {-0.4,-1,-6}                          | [(NaN,1),(NaN,90)]            | 
+ {-0.000184615384615,-1,15.3846153846} | [(1,2),(3,4)]                 | (3,4)
+ {-0.000184615384615,-1,15.3846153846} | [(0,0),(6,6)]                 | (6,6)
+ {-0.000184615384615,-1,15.3846153846} | [(10,-10),(-3,-4)]            | (-3,-4)
+ {-0.000184615384615,-1,15.3846153846} | [(-1000000,200),(300000,-40)] | 
+ {-0.000184615384615,-1,15.3846153846} | [(11,22),(33,44)]             | (11,22)
+ {-0.000184615384615,-1,15.3846153846} | [(-10,2),(-10,3)]             | (-10,3)
+ {-0.000184615384615,-1,15.3846153846} | [(0,-20),(30,-20)]            | (30,-20)
+ {-0.000184615384615,-1,15.3846153846} | [(NaN,1),(NaN,90)]            | 
+ {NaN,-1,NaN}                          | [(1,2),(3,4)]                 | 
+ {NaN,-1,NaN}                          | [(0,0),(6,6)]                 | 
+ {NaN,-1,NaN}                          | [(10,-10),(-3,-4)]            | 
+ {NaN,-1,NaN}                          | [(-1000000,200),(300000,-40)] | 
+ {NaN,-1,NaN}                          | [(11,22),(33,44)]             | 
+ {NaN,-1,NaN}                          | [(-10,2),(-10,3)]             | 
+ {NaN,-1,NaN}                          | [(0,-20),(30,-20)]            | 
+ {NaN,-1,NaN}                          | [(NaN,1),(NaN,90)]            | 
+ {3,NaN,5}                             | [(1,2),(3,4)]                 | 
+ {3,NaN,5}                             | [(0,0),(6,6)]                 | 
+ {3,NaN,5}                             | [(10,-10),(-3,-4)]            | 
+ {3,NaN,5}                             | [(-1000000,200),(300000,-40)] | 
+ {3,NaN,5}                             | [(11,22),(33,44)]             | 
+ {3,NaN,5}                             | [(-10,2),(-10,3)]             | 
+ {3,NaN,5}                             | [(0,-20),(30,-20)]            | 
+ {3,NaN,5}                             | [(NaN,1),(NaN,90)]            | 
+ {NaN,NaN,NaN}                         | [(1,2),(3,4)]                 | 
+ {NaN,NaN,NaN}                         | [(0,0),(6,6)]                 | 
+ {NaN,NaN,NaN}                         | [(10,-10),(-3,-4)]            | 
+ {NaN,NaN,NaN}                         | [(-1000000,200),(300000,-40)] | 
+ {NaN,NaN,NaN}                         | [(11,22),(33,44)]             | 
+ {NaN,NaN,NaN}                         | [(-10,2),(-10,3)]             | 
+ {NaN,NaN,NaN}                         | [(0,-20),(30,-20)]            | 
+ {NaN,NaN,NaN}                         | [(NaN,1),(NaN,90)]            | 
+ {0,-1,3}                              | [(1,2),(3,4)]                 | (2,3)
+ {0,-1,3}                              | [(0,0),(6,6)]                 | (3,3)
+ {0,-1,3}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,-1,3}                              | [(-1000000,200),(300000,-40)] | (67083.3333333,3)
+ {0,-1,3}                              | [(11,22),(33,44)]             | (11,22)
+ {0,-1,3}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {0,-1,3}                              | [(0,-20),(30,-20)]            | 
+ {0,-1,3}                              | [(NaN,1),(NaN,90)]            | 
+ {-1,0,3}                              | [(1,2),(3,4)]                 | (3,4)
+ {-1,0,3}                              | [(0,0),(6,6)]                 | (3,3)
+ {-1,0,3}                              | [(10,-10),(-3,-4)]            | (3,-6.76923076923)
+ {-1,0,3}                              | [(-1000000,200),(300000,-40)] | (3,15.3840615385)
+ {-1,0,3}                              | [(11,22),(33,44)]             | (11,22)
+ {-1,0,3}                              | [(-10,2),(-10,3)]             | 
+ {-1,0,3}                              | [(0,-20),(30,-20)]            | (3,-20)
+ {-1,0,3}                              | [(NaN,1),(NaN,90)]            | 
+(88 rows)
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LINE_TBL l, BOX_TBL b;
+ERROR:  function "close_lb" not implemented
 --
 -- Line segments
 --
 -- intersection
 SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
    FROM LSEG_TBL l, POINT_TBL p;
 ERROR:  operator does not exist: lseg # point
 LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
                                            ^
 HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (-0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
+-- Length
+SELECT s, @-@ s FROM LSEG_TBL;
+               s               |   ?column?    
+-------------------------------+---------------
+ [(1,2),(3,4)]                 | 2.82842712475
+ [(0,0),(6,6)]                 | 8.48528137424
+ [(10,-10),(-3,-4)]            | 14.3178210633
+ [(-1000000,200),(300000,-40)] | 1300000.02215
+ [(11,22),(33,44)]             | 31.1126983722
+ [(-10,2),(-10,3)]             |             1
+ [(0,-20),(30,-20)]            |            30
+ [(NaN,1),(NaN,90)]            |           NaN
+(8 rows)
+
+-- Vertical
+SELECT s FROM LSEG_TBL WHERE ?| s;
+         s         
+-------------------
+ [(-10,2),(-10,3)]
+(1 row)
+
+-- Horizontal
+SELECT s FROM LSEG_TBL WHERE ?- s;
+         s          
+--------------------
+ [(0,-20),(30,-20)]
+(1 row)
+
+-- Center
+SELECT s, @@ s FROM LSEG_TBL;
+               s               |   ?column?   
+-------------------------------+--------------
+ [(1,2),(3,4)]                 | (2,3)
+ [(0,0),(6,6)]                 | (3,3)
+ [(10,-10),(-3,-4)]            | (3.5,-7)
+ [(-1000000,200),(300000,-40)] | (-350000,80)
+ [(11,22),(33,44)]             | (22,33)
+ [(-10,2),(-10,3)]             | (-10,2.5)
+ [(0,-20),(30,-20)]            | (15,-20)
+ [(NaN,1),(NaN,90)]            | (NaN,45.5)
+(8 rows)
+
+-- To point
+SELECT s, s::point FROM LSEG_TBL;
+               s               |      s       
+-------------------------------+--------------
+ [(1,2),(3,4)]                 | (2,3)
+ [(0,0),(6,6)]                 | (3,3)
+ [(10,-10),(-3,-4)]            | (3.5,-7)
+ [(-1000000,200),(300000,-40)] | (-350000,80)
+ [(11,22),(33,44)]             | (22,33)
+ [(-10,2),(-10,3)]             | (-10,2.5)
+ [(0,-20),(30,-20)]            | (15,-20)
+ [(NaN,1),(NaN,90)]            | (NaN,45.5)
+(8 rows)
+
+-- Has points less than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s < l2.s;
+         s          |               s               
+--------------------+-------------------------------
+ [(1,2),(3,4)]      | [(0,0),(6,6)]
+ [(1,2),(3,4)]      | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]      | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]      | [(11,22),(33,44)]
+ [(1,2),(3,4)]      | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]      | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]      | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]      | [(11,22),(33,44)]
+ [(0,0),(6,6)]      | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)] | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)] | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]  | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]  | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]  | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]  | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]  | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]  | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]  | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)] | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)] | [(11,22),(33,44)]
+(21 rows)
+
+-- Has points less than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s <= l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(28 rows)
+
+-- Has points equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s = l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]
+(8 rows)
+
+-- Has points greater than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s >= l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(28 rows)
+
+-- Has points greater than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s > l2.s;
+               s               |         s          
+-------------------------------+--------------------
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+(21 rows)
+
+-- Has points not equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s != l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)]
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]
+(56 rows)
+
+-- Parallel with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?|| l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(13 rows)
+
+-- Perpendicular with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?-| l2.s;
+         s          |         s          
+--------------------+--------------------
+ [(-10,2),(-10,3)]  | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)] | [(-10,2),(-10,3)]
+(2 rows)
+
+-- Distance to line
+SELECT l.s, l1.s, l.s <-> l1.s FROM LSEG_TBL l, LINE_TBL l1;
+               s               |                   s                   |    ?column?    
+-------------------------------+---------------------------------------+----------------
+ [(1,2),(3,4)]                 | {0,-1,5}                              |              1
+ [(0,0),(6,6)]                 | {0,-1,5}                              |              0
+ [(10,-10),(-3,-4)]            | {0,-1,5}                              |              9
+ [(-1000000,200),(300000,-40)] | {0,-1,5}                              |              0
+ [(11,22),(33,44)]             | {0,-1,5}                              |             17
+ [(-10,2),(-10,3)]             | {0,-1,5}                              |              2
+ [(0,-20),(30,-20)]            | {0,-1,5}                              |             25
+ [(NaN,1),(NaN,90)]            | {0,-1,5}                              |            NaN
+ [(1,2),(3,4)]                 | {1,0,5}                               |              6
+ [(0,0),(6,6)]                 | {1,0,5}                               |              5
+ [(10,-10),(-3,-4)]            | {1,0,5}                               |              2
+ [(-1000000,200),(300000,-40)] | {1,0,5}                               |              0
+ [(11,22),(33,44)]             | {1,0,5}                               |             16
+ [(-10,2),(-10,3)]             | {1,0,5}                               |              5
+ [(0,-20),(30,-20)]            | {1,0,5}                               |              5
+ [(NaN,1),(NaN,90)]            | {1,0,5}                               |            NaN
+ [(1,2),(3,4)]                 | {0,3,0}                               |              2
+ [(0,0),(6,6)]                 | {0,3,0}                               |              0
+ [(10,-10),(-3,-4)]            | {0,3,0}                               |              4
+ [(-1000000,200),(300000,-40)] | {0,3,0}                               |              0
+ [(11,22),(33,44)]             | {0,3,0}                               |             22
+ [(-10,2),(-10,3)]             | {0,3,0}                               |              2
+ [(0,-20),(30,-20)]            | {0,3,0}                               |             20
+ [(NaN,1),(NaN,90)]            | {0,3,0}                               |            NaN
+ [(1,2),(3,4)]                 | {1,-1,0}                              | 0.707106781187
+ [(0,0),(6,6)]                 | {1,-1,0}                              |              0
+ [(10,-10),(-3,-4)]            | {1,-1,0}                              | 0.707106781187
+ [(-1000000,200),(300000,-40)] | {1,-1,0}                              |              0
+ [(11,22),(33,44)]             | {1,-1,0}                              |  7.77817459305
+ [(-10,2),(-10,3)]             | {1,-1,0}                              |  8.48528137424
+ [(0,-20),(30,-20)]            | {1,-1,0}                              |  14.1421356237
+ [(NaN,1),(NaN,90)]            | {1,-1,0}                              |            NaN
+ [(1,2),(3,4)]                 | {-0.4,-1,-6}                          |  7.79920420344
+ [(0,0),(6,6)]                 | {-0.4,-1,-6}                          |  5.57086014531
+ [(10,-10),(-3,-4)]            | {-0.4,-1,-6}                          |              0
+ [(-1000000,200),(300000,-40)] | {-0.4,-1,-6}                          |              0
+ [(11,22),(33,44)]             | {-0.4,-1,-6}                          |  30.0826447847
+ [(-10,2),(-10,3)]             | {-0.4,-1,-6}                          |  3.71390676354
+ [(0,-20),(30,-20)]            | {-0.4,-1,-6}                          |  1.85695338177
+ [(NaN,1),(NaN,90)]            | {-0.4,-1,-6}                          |            NaN
+ [(1,2),(3,4)]                 | {-0.000184615384615,-1,15.3846153846} |  11.3840613445
+ [(0,0),(6,6)]                 | {-0.000184615384615,-1,15.3846153846} |   9.3835075324
+ [(10,-10),(-3,-4)]            | {-0.000184615384615,-1,15.3846153846} |  19.3851689004
+ [(-1000000,200),(300000,-40)] | {-0.000184615384615,-1,15.3846153846} |              0
+ [(11,22),(33,44)]             | {-0.000184615384615,-1,15.3846153846} |  6.61741527185
+ [(-10,2),(-10,3)]             | {-0.000184615384615,-1,15.3846153846} |  12.3864613274
+ [(0,-20),(30,-20)]            | {-0.000184615384615,-1,15.3846153846} |  35.3790763202
+ [(NaN,1),(NaN,90)]            | {-0.000184615384615,-1,15.3846153846} |            NaN
+ [(1,2),(3,4)]                 | {NaN,-1,NaN}                          |            NaN
+ [(0,0),(6,6)]                 | {NaN,-1,NaN}                          |            NaN
+ [(10,-10),(-3,-4)]            | {NaN,-1,NaN}                          |            NaN
+ [(-1000000,200),(300000,-40)] | {NaN,-1,NaN}                          |            NaN
+ [(11,22),(33,44)]             | {NaN,-1,NaN}                          |            NaN
+ [(-10,2),(-10,3)]             | {NaN,-1,NaN}                          |            NaN
+ [(0,-20),(30,-20)]            | {NaN,-1,NaN}                          |            NaN
+ [(NaN,1),(NaN,90)]            | {NaN,-1,NaN}                          |            NaN
+ [(1,2),(3,4)]                 | {3,NaN,5}                             |            NaN
+ [(0,0),(6,6)]                 | {3,NaN,5}                             |            NaN
+ [(10,-10),(-3,-4)]            | {3,NaN,5}                             |            NaN
+ [(-1000000,200),(300000,-40)] | {3,NaN,5}                             |            NaN
+ [(11,22),(33,44)]             | {3,NaN,5}                             |            NaN
+ [(-10,2),(-10,3)]             | {3,NaN,5}                             |            NaN
+ [(0,-20),(30,-20)]            | {3,NaN,5}                             |            NaN
+ [(NaN,1),(NaN,90)]            | {3,NaN,5}                             |            NaN
+ [(1,2),(3,4)]                 | {NaN,NaN,NaN}                         |            NaN
+ [(0,0),(6,6)]                 | {NaN,NaN,NaN}                         |            NaN
+ [(10,-10),(-3,-4)]            | {NaN,NaN,NaN}                         |            NaN
+ [(-1000000,200),(300000,-40)] | {NaN,NaN,NaN}                         |            NaN
+ [(11,22),(33,44)]             | {NaN,NaN,NaN}                         |            NaN
+ [(-10,2),(-10,3)]             | {NaN,NaN,NaN}                         |            NaN
+ [(0,-20),(30,-20)]            | {NaN,NaN,NaN}                         |            NaN
+ [(NaN,1),(NaN,90)]            | {NaN,NaN,NaN}                         |            NaN
+ [(1,2),(3,4)]                 | {0,-1,3}                              |              0
+ [(0,0),(6,6)]                 | {0,-1,3}                              |              0
+ [(10,-10),(-3,-4)]            | {0,-1,3}                              |              7
+ [(-1000000,200),(300000,-40)] | {0,-1,3}                              |              0
+ [(11,22),(33,44)]             | {0,-1,3}                              |             19
+ [(-10,2),(-10,3)]             | {0,-1,3}                              |              0
+ [(0,-20),(30,-20)]            | {0,-1,3}                              |             23
+ [(NaN,1),(NaN,90)]            | {0,-1,3}                              |            NaN
+ [(1,2),(3,4)]                 | {-1,0,3}                              |              0
+ [(0,0),(6,6)]                 | {-1,0,3}                              |              0
+ [(10,-10),(-3,-4)]            | {-1,0,3}                              |              0
+ [(-1000000,200),(300000,-40)] | {-1,0,3}                              |              0
+ [(11,22),(33,44)]             | {-1,0,3}                              |              8
+ [(-10,2),(-10,3)]             | {-1,0,3}                              |             13
+ [(0,-20),(30,-20)]            | {-1,0,3}                              |              0
+ [(NaN,1),(NaN,90)]            | {-1,0,3}                              |            NaN
+(88 rows)
+
+-- Distance to line segment
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               |    ?column?    
+-------------------------------+-------------------------------+----------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 |              0
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 0.707106781187
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            |  7.12398901685
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] |  11.3840613445
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             |  19.6977156036
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             |             11
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            |             22
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            |            NaN
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 0.707106781187
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 |              0
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            |  4.88901207039
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] |   9.3835075324
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             |  16.7630546142
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             |  10.1980390272
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            |             20
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            |            NaN
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 |  7.12398901685
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 |  4.88901207039
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            |              0
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] |  19.3851689004
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             |  29.4737584815
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             |  9.21954445729
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            |             10
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            |            NaN
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 |  11.3840613445
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 |   9.3835075324
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            |  19.3851689004
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] |              0
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             |  6.61741527185
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             |  12.3864613274
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            |  35.3790763202
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            |            NaN
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 |  19.6977156036
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 |  16.7630546142
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            |  29.4737584815
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] |  6.61741527185
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             |              0
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             |   28.319604517
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            |             42
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            |            NaN
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 |             11
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 |  10.1980390272
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            |  9.21954445729
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] |  12.3864613274
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             |   28.319604517
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             |              0
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            |  24.1660919472
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            |            NaN
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 |             22
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 |             20
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            |             10
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] |  35.3790763202
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             |             42
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             |  24.1660919472
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            |              0
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 |            NaN
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 |            NaN
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] |            NaN
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             |            NaN
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             |            NaN
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            |            NaN
+(64 rows)
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LSEG_TBL l, BOX_TBL b;
+               s               |         f1          |    ?column?    
+-------------------------------+---------------------+----------------
+ [(1,2),(3,4)]                 | (2,2),(0,0)         |              0
+ [(1,2),(3,4)]                 | (3,3),(1,1)         |              0
+ [(1,2),(3,4)]                 | (-2,2),(-8,-10)     |              3
+ [(1,2),(3,4)]                 | (2.5,3.5),(2.5,2.5) |              0
+ [(1,2),(3,4)]                 | (3,3),(3,3)         | 0.707106781187
+ [(0,0),(6,6)]                 | (2,2),(0,0)         |              0
+ [(0,0),(6,6)]                 | (3,3),(1,1)         |              0
+ [(0,0),(6,6)]                 | (-2,2),(-8,-10)     |              2
+ [(0,0),(6,6)]                 | (2.5,3.5),(2.5,2.5) |              0
+ [(0,0),(6,6)]                 | (3,3),(3,3)         |              0
+ [(10,-10),(-3,-4)]            | (2,2),(0,0)         |  4.88901207039
+ [(10,-10),(-3,-4)]            | (3,3),(1,1)         |  6.21602963235
+ [(10,-10),(-3,-4)]            | (-2,2),(-8,-10)     |              0
+ [(10,-10),(-3,-4)]            | (2.5,3.5),(2.5,2.5) |  8.20655597529
+ [(10,-10),(-3,-4)]            | (3,3),(3,3)         |  8.87006475627
+ [(-1000000,200),(300000,-40)] | (2,2),(0,0)         |  13.3842459258
+ [(-1000000,200),(300000,-40)] | (3,3),(1,1)         |  12.3840613274
+ [(-1000000,200),(300000,-40)] | (-2,2),(-8,-10)     |  13.3849843873
+ [(-1000000,200),(300000,-40)] | (2.5,3.5),(2.5,2.5) |  11.8841536436
+ [(-1000000,200),(300000,-40)] | (3,3),(3,3)         |  12.3840613274
+ [(11,22),(33,44)]             | (2,2),(0,0)         |  21.9317121995
+ [(11,22),(33,44)]             | (3,3),(1,1)         |  20.6155281281
+ [(11,22),(33,44)]             | (-2,2),(-8,-10)     |  23.8537208838
+ [(11,22),(33,44)]             | (2.5,3.5),(2.5,2.5) |  20.3592730715
+ [(11,22),(33,44)]             | (3,3),(3,3)         |  20.6155281281
+ [(-10,2),(-10,3)]             | (2,2),(0,0)         |             10
+ [(-10,2),(-10,3)]             | (3,3),(1,1)         |             11
+ [(-10,2),(-10,3)]             | (-2,2),(-8,-10)     |              2
+ [(-10,2),(-10,3)]             | (2.5,3.5),(2.5,2.5) |           12.5
+ [(-10,2),(-10,3)]             | (3,3),(3,3)         |             13
+ [(0,-20),(30,-20)]            | (2,2),(0,0)         |             20
+ [(0,-20),(30,-20)]            | (3,3),(1,1)         |             21
+ [(0,-20),(30,-20)]            | (-2,2),(-8,-10)     |  10.1980390272
+ [(0,-20),(30,-20)]            | (2.5,3.5),(2.5,2.5) |           22.5
+ [(0,-20),(30,-20)]            | (3,3),(3,3)         |             23
+ [(NaN,1),(NaN,90)]            | (2,2),(0,0)         |            NaN
+ [(NaN,1),(NaN,90)]            | (3,3),(1,1)         |            NaN
+ [(NaN,1),(NaN,90)]            | (-2,2),(-8,-10)     |            NaN
+ [(NaN,1),(NaN,90)]            | (2.5,3.5),(2.5,2.5) |            NaN
+ [(NaN,1),(NaN,90)]            | (3,3),(3,3)         |            NaN
+(40 rows)
+
+-- Intersect with line segment
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s ?# l1.s;
+               s               |      s       
+-------------------------------+--------------
+ [(0,0),(6,6)]                 | {0,-1,5}
+ [(-1000000,200),(300000,-40)] | {0,-1,5}
+ [(-1000000,200),(300000,-40)] | {1,0,5}
+ [(0,0),(6,6)]                 | {0,3,0}
+ [(-1000000,200),(300000,-40)] | {0,3,0}
+ [(-1000000,200),(300000,-40)] | {1,-1,0}
+ [(10,-10),(-3,-4)]            | {-0.4,-1,-6}
+ [(-1000000,200),(300000,-40)] | {-0.4,-1,-6}
+ [(1,2),(3,4)]                 | {0,-1,3}
+ [(0,0),(6,6)]                 | {0,-1,3}
+ [(-1000000,200),(300000,-40)] | {0,-1,3}
+ [(-10,2),(-10,3)]             | {0,-1,3}
+ [(1,2),(3,4)]                 | {-1,0,3}
+ [(0,0),(6,6)]                 | {-1,0,3}
+ [(10,-10),(-3,-4)]            | {-1,0,3}
+ [(-1000000,200),(300000,-40)] | {-1,0,3}
+ [(0,-20),(30,-20)]            | {-1,0,3}
+(17 rows)
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+         s          |         f1          
+--------------------+---------------------
+ [(1,2),(3,4)]      | (2,2),(0,0)
+ [(1,2),(3,4)]      | (3,3),(1,1)
+ [(1,2),(3,4)]      | (2.5,3.5),(2.5,2.5)
+ [(0,0),(6,6)]      | (2,2),(0,0)
+ [(0,0),(6,6)]      | (3,3),(1,1)
+ [(0,0),(6,6)]      | (2.5,3.5),(2.5,2.5)
+ [(10,-10),(-3,-4)] | (-2,2),(-8,-10)
+(7 rows)
+
+-- Intersection point with line segment
+SELECT l1.s, l2.s, l1.s # l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               | ?column? 
+-------------------------------+-------------------------------+----------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 | 
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            | 
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] | 
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             | 
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             | 
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            | 
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            | 
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 | 
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            | 
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] | 
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             | 
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             | 
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            | 
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            | 
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 | 
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 | 
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            | 
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] | 
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             | 
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             | 
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            | 
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            | 
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 | 
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 | 
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            | 
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] | 
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             | 
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             | 
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            | 
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            | 
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 | 
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 | 
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            | 
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] | 
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             | 
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             | 
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            | 
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            | 
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 | 
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 | 
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            | 
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] | 
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             | 
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             | 
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            | 
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            | 
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 | 
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 | 
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            | 
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] | 
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             | 
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             | 
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            | 
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            | 
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 | 
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 | 
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            | 
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] | 
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             | 
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             | 
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            | 
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            | 
+(64 rows)
+
+-- Closest point to line
+SELECT l.s, l1.s, l.s ## l1.s FROM LSEG_TBL l, LINE_TBL l1;
+ERROR:  function "close_sl" not implemented
+-- Closest point to line segment
+SELECT l1.s, l2.s, l1.s ## l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               |            ?column?             
+-------------------------------+-------------------------------+---------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 | 
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            | (-1.98536585366,-4.46829268293)
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] | (3.00210167283,15.3840611505)
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             | 
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             | (-10,2)
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            | (1,-20)
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            | 
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 | 
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] | (6.00173233982,15.3835073725)
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             | 
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             | (-10,2)
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            | (0,-20)
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            | 
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 | (1,2)
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 | (0,0)
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            | 
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] | (-2.99642119965,15.3851685701)
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             | (11,22)
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             | (-10,2)
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            | (10,-20)
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            | 
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 | (3,4)
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 | (6,6)
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            | (-3,-4)
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] | 
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             | (11,22)
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             | (-10,3)
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            | (30,-20)
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            | 
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 | 
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 | 
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            | (-1.3512195122,-4.76097560976)
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] | (10.9987783234,15.3825848409)
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             | 
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             | (-10,3)
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            | (11,-20)
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            | 
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 | (1,2)
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 | (0,0)
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            | (-3,-4)
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] | (-9.99771326872,15.3864611163)
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             | (11,22)
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             | 
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            | (0,-20)
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            | 
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 | (1,2)
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 | (0,0)
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            | (10,-10)
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] | (30.0065315217,15.3790757173)
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             | (11,22)
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             | (-10,2)
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            | 
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            | 
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 | 
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 | 
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            | 
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] | 
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             | 
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             | 
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            | 
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            | 
+(64 rows)
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LSEG_TBL l, BOX_TBL b;
+               s               |         f1          |  ?column?   
+-------------------------------+---------------------+-------------
+ [(1,2),(3,4)]                 | (2,2),(0,0)         | (1,2)
+ [(1,2),(3,4)]                 | (3,3),(1,1)         | (1.5,2.5)
+ [(1,2),(3,4)]                 | (-2,2),(-8,-10)     | (-2,2)
+ [(1,2),(3,4)]                 | (2.5,3.5),(2.5,2.5) | (2.25,3.25)
+ [(1,2),(3,4)]                 | (3,3),(3,3)         | (3,3)
+ [(0,0),(6,6)]                 | (2,2),(0,0)         | (1,1)
+ [(0,0),(6,6)]                 | (3,3),(1,1)         | (2,2)
+ [(0,0),(6,6)]                 | (-2,2),(-8,-10)     | (-2,0)
+ [(0,0),(6,6)]                 | (2.5,3.5),(2.5,2.5) | (2.75,2.75)
+ [(0,0),(6,6)]                 | (3,3),(3,3)         | (3,3)
+ [(10,-10),(-3,-4)]            | (2,2),(0,0)         | (0,0)
+ [(10,-10),(-3,-4)]            | (3,3),(1,1)         | (1,1)
+ [(10,-10),(-3,-4)]            | (-2,2),(-8,-10)     | (-3,-4)
+ [(10,-10),(-3,-4)]            | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ [(10,-10),(-3,-4)]            | (3,3),(3,3)         | (3,3)
+ [(-1000000,200),(300000,-40)] | (2,2),(0,0)         | (2,2)
+ [(-1000000,200),(300000,-40)] | (3,3),(1,1)         | (3,3)
+ [(-1000000,200),(300000,-40)] | (-2,2),(-8,-10)     | (-2,2)
+ [(-1000000,200),(300000,-40)] | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ [(-1000000,200),(300000,-40)] | (3,3),(3,3)         | (3,3)
+ [(11,22),(33,44)]             | (2,2),(0,0)         | (2,2)
+ [(11,22),(33,44)]             | (3,3),(1,1)         | (3,3)
+ [(11,22),(33,44)]             | (-2,2),(-8,-10)     | (-2,2)
+ [(11,22),(33,44)]             | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ [(11,22),(33,44)]             | (3,3),(3,3)         | (3,3)
+ [(-10,2),(-10,3)]             | (2,2),(0,0)         | (0,2)
+ [(-10,2),(-10,3)]             | (3,3),(1,1)         | (1,2)
+ [(-10,2),(-10,3)]             | (-2,2),(-8,-10)     | (-8,2)
+ [(-10,2),(-10,3)]             | (2.5,3.5),(2.5,2.5) | (2.5,3)
+ [(-10,2),(-10,3)]             | (3,3),(3,3)         | (3,3)
+ [(0,-20),(30,-20)]            | (2,2),(0,0)         | (0,0)
+ [(0,-20),(30,-20)]            | (3,3),(1,1)         | (1,1)
+ [(0,-20),(30,-20)]            | (-2,2),(-8,-10)     | (-2,-10)
+ [(0,-20),(30,-20)]            | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ [(0,-20),(30,-20)]            | (3,3),(3,3)         | (3,3)
+ [(NaN,1),(NaN,90)]            | (2,2),(0,0)         | 
+ [(NaN,1),(NaN,90)]            | (3,3),(1,1)         | 
+ [(NaN,1),(NaN,90)]            | (-2,2),(-8,-10)     | 
+ [(NaN,1),(NaN,90)]            | (2.5,3.5),(2.5,2.5) | 
+ [(NaN,1),(NaN,90)]            | (3,3),(3,3)         | 
+(40 rows)
+
+-- On line
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s <@ l1.s;
+               s               |                   s                   
+-------------------------------+---------------------------------------
+ [(0,0),(6,6)]                 | {1,-1,0}
+ [(-1000000,200),(300000,-40)] | {-0.000184615384615,-1,15.3846153846}
+(2 rows)
+
+-- On box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s <@ b.f1;
+ s | f1 
+---+----
+(0 rows)
 
 --
 -- Boxes
 --
 SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
  six |                              box                               
 -----+----------------------------------------------------------------
      | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
      | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
      | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
      | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
      | (107.071067812,207.071067812),(92.9289321881,192.928932188)
      | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
+     | (3,5),(3,5)
+     | (NaN,NaN),(NaN,NaN)
+(8 rows)
 
 -- translation
 SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
+ twentyfour |             translation             
+------------+-------------------------------------
             | (2,2),(0,0)
             | (3,3),(1,1)
+            | (-2,2),(-8,-10)
             | (2.5,3.5),(2.5,2.5)
             | (3,3),(3,3)
             | (-8,2),(-10,0)
             | (-7,3),(-9,1)
+            | (-12,2),(-18,-10)
             | (-7.5,3.5),(-7.5,2.5)
             | (-7,3),(-7,3)
             | (-1,6),(-3,4)
             | (0,7),(-2,5)
+            | (-5,6),(-11,-6)
             | (-0.5,7.5),(-0.5,6.5)
             | (0,7),(0,7)
             | (7.1,36.5),(5.1,34.5)
             | (8.1,37.5),(6.1,35.5)
+            | (3.1,36.5),(-2.9,24.5)
             | (7.6,38),(7.6,37)
             | (8.1,37.5),(8.1,37.5)
             | (-3,-10),(-5,-12)
             | (-2,-9),(-4,-11)
+            | (-7,-10),(-13,-22)
             | (-2.5,-8.5),(-2.5,-9.5)
             | (-2,-9),(-2,-9)
+            | (2,2),(1e-300,-1e-300)
+            | (3,3),(1,1)
+            | (-2,2),(-8,-10)
+            | (2.5,3.5),(2.5,2.5)
+            | (3,3),(3,3)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
             | (12,12),(10,10)
             | (13,13),(11,11)
+            | (8,12),(2,0)
             | (12.5,13.5),(12.5,12.5)
             | (13,13),(13,13)
-(24 rows)
+(45 rows)
 
 SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
+ twentyfour |               translation               
+------------+-----------------------------------------
             | (2,2),(0,0)
             | (3,3),(1,1)
+            | (-2,2),(-8,-10)
             | (2.5,3.5),(2.5,2.5)
             | (3,3),(3,3)
             | (12,2),(10,0)
             | (13,3),(11,1)
+            | (8,2),(2,-10)
             | (12.5,3.5),(12.5,2.5)
             | (13,3),(13,3)
             | (5,-2),(3,-4)
             | (6,-1),(4,-3)
+            | (1,-2),(-5,-14)
             | (5.5,-0.5),(5.5,-1.5)
             | (6,-1),(6,-1)
             | (-3.1,-32.5),(-5.1,-34.5)
             | (-2.1,-31.5),(-4.1,-33.5)
+            | (-7.1,-32.5),(-13.1,-44.5)
             | (-2.6,-31),(-2.6,-32)
             | (-2.1,-31.5),(-2.1,-31.5)
             | (7,14),(5,12)
             | (8,15),(6,13)
+            | (3,14),(-3,2)
             | (7.5,15.5),(7.5,14.5)
             | (8,15),(8,15)
+            | (2,2),(-1e-300,1e-300)
+            | (3,3),(1,1)
+            | (-2,2),(-8,-10)
+            | (2.5,3.5),(2.5,2.5)
+            | (3,3),(3,3)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
             | (-8,-8),(-10,-10)
             | (-7,-7),(-9,-9)
+            | (-12,-8),(-18,-20)
             | (-7.5,-6.5),(-7.5,-7.5)
             | (-7,-7),(-7,-7)
-(24 rows)
+(45 rows)
 
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (-0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (-0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,-0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
+-- Multiply with point
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+         f1          |     f1     |          ?column?           
+---------------------+------------+-----------------------------
+ (2,2),(0,0)         | (5.1,34.5) | (0,79.2),(-58.8,0)
+ (2,2),(0,0)         | (10,10)    | (0,40),(0,0)
+ (3,3),(1,1)         | (5.1,34.5) | (-29.4,118.8),(-88.2,39.6)
+ (3,3),(1,1)         | (10,10)    | (0,60),(0,20)
+ (-2,2),(-8,-10)     | (5.1,34.5) | (304.2,-58.8),(-79.2,-327)
+ (-2,2),(-8,-10)     | (10,10)    | (20,0),(-40,-180)
+ (2.5,3.5),(2.5,2.5) | (5.1,34.5) | (-73.5,104.1),(-108,99)
+ (2.5,3.5),(2.5,2.5) | (10,10)    | (0,60),(-10,50)
+ (3,3),(3,3)         | (5.1,34.5) | (-88.2,118.8),(-88.2,118.8)
+ (3,3),(3,3)         | (10,10)    | (0,60),(0,60)
+(10 rows)
 
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,-0),(-0.2,-0.2)
-        | (0.08,-0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (-0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
+-- Overflow error
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] > 1000;
+         f1          |        f1         |                  ?column?                  
+---------------------+-------------------+--------------------------------------------
+ (2,2),(0,0)         | (1e+300,Infinity) | (NaN,NaN),(-Infinity,Infinity)
+ (2,2),(0,0)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (3,3),(1,1)         | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (3,3),(1,1)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (-2,2),(-8,-10)     | (1e+300,Infinity) | (Infinity,-Infinity),(-Infinity,-Infinity)
+ (-2,2),(-8,-10)     | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (2.5,3.5),(2.5,2.5) | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (2.5,3.5),(2.5,2.5) | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (3,3),(3,3)         | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (3,3),(3,3)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+(10 rows)
 
+-- Divide by point
+SELECT b.f1, p.f1, b.f1 / p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+         f1          |     f1     |                               ?column?                               
+---------------------+------------+----------------------------------------------------------------------
+ (2,2),(0,0)         | (5.1,34.5) | (0.0651176557644,0),(0,-0.0483449262493)
+ (2,2),(0,0)         | (10,10)    | (0.2,0),(0,0)
+ (3,3),(1,1)         | (5.1,34.5) | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
+ (3,3),(1,1)         | (10,10)    | (0.3,0),(0.1,0)
+ (-2,2),(-8,-10)     | (5.1,34.5) | (0.0483449262493,0.18499334024),(-0.317201914064,0.0651176557644)
+ (-2,2),(-8,-10)     | (10,10)    | (0,0.2),(-0.9,-0.1)
+ (2.5,3.5),(2.5,2.5) | (5.1,34.5) | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
+ (2.5,3.5),(2.5,2.5) | (10,10)    | (0.3,0.05),(0.25,0)
+ (3,3),(3,3)         | (5.1,34.5) | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
+ (3,3),(3,3)         | (10,10)    | (0.3,0),(0.3,0)
+(10 rows)
+
+-- To box
 SELECT f1::box
 	FROM POINT_TBL;
-          f1           
------------------------
+                 f1                  
+-------------------------------------
  (0,0),(0,0)
  (-10,0),(-10,0)
  (-3,4),(-3,4)
  (5.1,34.5),(5.1,34.5)
  (-5,-12),(-5,-12)
+ (1e-300,-1e-300),(1e-300,-1e-300)
+ (1e+300,Infinity),(1e+300,Infinity)
+ (NaN,NaN),(NaN,NaN)
  (10,10),(10,10)
-(6 rows)
+(9 rows)
 
 SELECT bound_box(a.f1, b.f1)
 	FROM BOX_TBL a, BOX_TBL b;
       bound_box      
 ---------------------
  (2,2),(0,0)
  (3,3),(0,0)
+ (2,2),(-8,-10)
  (2.5,3.5),(0,0)
  (3,3),(0,0)
  (3,3),(0,0)
  (3,3),(1,1)
+ (3,3),(-8,-10)
  (3,3.5),(1,1)
  (3,3),(1,1)
+ (2,2),(-8,-10)
+ (3,3),(-8,-10)
+ (-2,2),(-8,-10)
+ (2.5,3.5),(-8,-10)
+ (3,3),(-8,-10)
  (2.5,3.5),(0,0)
  (3,3.5),(1,1)
+ (2.5,3.5),(-8,-10)
  (2.5,3.5),(2.5,2.5)
  (3,3.5),(2.5,2.5)
  (3,3),(0,0)
  (3,3),(1,1)
+ (3,3),(-8,-10)
  (3,3.5),(2.5,2.5)
  (3,3),(3,3)
-(16 rows)
+(25 rows)
+
+-- Below box
+SELECT b1.f1, b2.f1, b1.f1 <^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          | ?column? 
+---------------------+---------------------+----------
+ (2,2),(0,0)         | (2,2),(0,0)         | f
+ (2,2),(0,0)         | (3,3),(1,1)         | f
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | f
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | t
+ (2,2),(0,0)         | (3,3),(3,3)         | t
+ (3,3),(1,1)         | (2,2),(0,0)         | f
+ (3,3),(1,1)         | (3,3),(1,1)         | f
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | f
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(1,1)         | (3,3),(3,3)         | t
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | f
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | f
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | f
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | t
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | t
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | f
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | f
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | f
+ (3,3),(3,3)         | (2,2),(0,0)         | f
+ (3,3),(3,3)         | (3,3),(1,1)         | f
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | f
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(3,3)         | (3,3),(3,3)         | t
+(25 rows)
+
+-- Above box
+SELECT b1.f1, b2.f1, b1.f1 >^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          | ?column? 
+---------------------+---------------------+----------
+ (2,2),(0,0)         | (2,2),(0,0)         | f
+ (2,2),(0,0)         | (3,3),(1,1)         | f
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | f
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | f
+ (2,2),(0,0)         | (3,3),(3,3)         | f
+ (3,3),(1,1)         | (2,2),(0,0)         | f
+ (3,3),(1,1)         | (3,3),(1,1)         | f
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | f
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(1,1)         | (3,3),(3,3)         | f
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | f
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | f
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | f
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | f
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | f
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | t
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | f
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | t
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | f
+ (3,3),(3,3)         | (2,2),(0,0)         | t
+ (3,3),(3,3)         | (3,3),(1,1)         | t
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | t
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(3,3)         | (3,3),(3,3)         | t
+(25 rows)
+
+-- Intersection point with box
+SELECT b1.f1, b2.f1, b1.f1 # b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          |      ?column?       
+---------------------+---------------------+---------------------
+ (2,2),(0,0)         | (2,2),(0,0)         | (2,2),(0,0)
+ (2,2),(0,0)         | (3,3),(1,1)         | (2,2),(1,1)
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | 
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | 
+ (2,2),(0,0)         | (3,3),(3,3)         | 
+ (3,3),(1,1)         | (2,2),(0,0)         | (2,2),(1,1)
+ (3,3),(1,1)         | (3,3),(1,1)         | (3,3),(1,1)
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | 
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | (2.5,3),(2.5,2.5)
+ (3,3),(1,1)         | (3,3),(3,3)         | (3,3),(3,3)
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | 
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | 
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | (-2,2),(-8,-10)
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | 
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | 
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | 
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | (2.5,3),(2.5,2.5)
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | 
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5)
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | 
+ (3,3),(3,3)         | (2,2),(0,0)         | 
+ (3,3),(3,3)         | (3,3),(1,1)         | (3,3),(3,3)
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | 
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | 
+ (3,3),(3,3)         | (3,3),(3,3)         | (3,3),(3,3)
+(25 rows)
+
+-- Diagonal
+SELECT f1, diagonal(f1) FROM BOX_TBL;
+         f1          |       diagonal        
+---------------------+-----------------------
+ (2,2),(0,0)         | [(2,2),(0,0)]
+ (3,3),(1,1)         | [(3,3),(1,1)]
+ (-2,2),(-8,-10)     | [(-2,2),(-8,-10)]
+ (2.5,3.5),(2.5,2.5) | [(2.5,3.5),(2.5,2.5)]
+ (3,3),(3,3)         | [(3,3),(3,3)]
+(5 rows)
+
+-- Distance to box
+SELECT b1.f1, b2.f1, b1.f1 <-> b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          |   ?column?    
+---------------------+---------------------+---------------
+ (2,2),(0,0)         | (2,2),(0,0)         |             0
+ (2,2),(0,0)         | (3,3),(1,1)         | 1.41421356237
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | 7.81024967591
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) |           2.5
+ (2,2),(0,0)         | (3,3),(3,3)         | 2.82842712475
+ (3,3),(1,1)         | (2,2),(0,0)         | 1.41421356237
+ (3,3),(1,1)         | (3,3),(1,1)         |             0
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | 9.21954445729
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | 1.11803398875
+ (3,3),(1,1)         | (3,3),(3,3)         | 1.41421356237
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | 7.81024967591
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | 9.21954445729
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     |             0
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | 10.2591422643
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | 10.6301458127
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         |           2.5
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | 1.11803398875
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | 10.2591422643
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) |             0
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         |           0.5
+ (3,3),(3,3)         | (2,2),(0,0)         | 2.82842712475
+ (3,3),(3,3)         | (3,3),(1,1)         | 1.41421356237
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | 10.6301458127
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) |           0.5
+ (3,3),(3,3)         | (3,3),(3,3)         |             0
+(25 rows)
 
 --
 -- Paths
 --
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
+-- Points
+SELECT f1, npoints(f1) FROM PATH_TBL;
+            f1             | npoints 
+---------------------------+---------
+ [(1,2),(3,4)]             |       2
+ ((1,2),(3,4))             |       2
+ [(0,0),(3,0),(4,5),(1,6)] |       4
+ ((1,2),(3,4))             |       2
+ ((1,2),(3,4))             |       2
+ [(1,2),(3,4)]             |       2
+ ((10,20))                 |       1
+ [(11,12),(13,14)]         |       2
+ ((11,12),(13,14))         |       2
+(9 rows)
 
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
+-- Area
+SELECT f1, area(f1) FROM PATH_TBL;
+            f1             | area 
+---------------------------+------
+ [(1,2),(3,4)]             |     
+ ((1,2),(3,4))             |    0
+ [(0,0),(3,0),(4,5),(1,6)] |     
+ ((1,2),(3,4))             |    0
+ ((1,2),(3,4))             |    0
+ [(1,2),(3,4)]             |     
+ ((10,20))                 |    0
+ [(11,12),(13,14)]         |     
+ ((11,12),(13,14))         |    0
+(9 rows)
 
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
+-- Length
+SELECT f1, @-@ f1 FROM PATH_TBL;
+            f1             |   ?column?    
+---------------------------+---------------
+ [(1,2),(3,4)]             | 2.82842712475
+ ((1,2),(3,4))             | 5.65685424949
+ [(0,0),(3,0),(4,5),(1,6)] | 11.2612971738
+ ((1,2),(3,4))             | 5.65685424949
+ ((1,2),(3,4))             | 5.65685424949
+ [(1,2),(3,4)]             | 2.82842712475
+ ((10,20))                 |             0
+ [(11,12),(13,14)]         | 2.82842712475
+ ((11,12),(13,14))         | 5.65685424949
+(9 rows)
 
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
+-- Center
+SELECT f1, @@ f1 FROM PATH_TBL;
+ERROR:  function "path_center" not implemented
+-- To polygon
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isclosed(f1);
+        f1         |        f1         
+-------------------+-------------------
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((10,20))         | ((10,20))
+ ((11,12),(13,14)) | ((11,12),(13,14))
+(5 rows)
+
+-- Open path cannot be converted to polygon error
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isopen(f1);
+ERROR:  open path cannot be converted to polygon
+-- Has points less than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 < p2.f1;
+        f1         |            f1             
+-------------------+---------------------------
+ [(1,2),(3,4)]     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]     | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))         | [(1,2),(3,4)]
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | [(1,2),(3,4)]
+ ((10,20))         | [(11,12),(13,14)]
+ ((10,20))         | ((11,12),(13,14))
+ [(11,12),(13,14)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((11,12),(13,14)) | [(0,0),(3,0),(4,5),(1,6)]
+(15 rows)
+
+-- Has points less than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 <= p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | [(1,2),(3,4)]
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | [(1,2),(3,4)]
+ ((10,20))                 | ((10,20))
+ ((10,20))                 | [(11,12),(13,14)]
+ ((10,20))                 | ((11,12),(13,14))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(66 rows)
+
+-- Has points equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 = p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | ((10,20))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(51 rows)
+
+-- Has points greater than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 >= p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | ((10,20))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((10,20))
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((10,20))
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(66 rows)
+
+-- Has points greater than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 > p2.f1;
+            f1             |        f1         
+---------------------------+-------------------
+ [(1,2),(3,4)]             | ((10,20))
+ ((1,2),(3,4))             | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | ((10,20))
+ [(1,2),(3,4)]             | ((10,20))
+ [(11,12),(13,14)]         | ((10,20))
+ ((11,12),(13,14))         | ((10,20))
+(15 rows)
+
+-- Add path
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+            f1             |            f1             |                     ?column?                      
+---------------------------+---------------------------+---------------------------------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4),(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))                 | 
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         | [(1,2),(3,4),(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6),(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6),(0,0),(3,0),(4,5),(1,6)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6),(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))                 | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6),(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4),(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))                 | 
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         | [(1,2),(3,4),(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))         | 
+ ((10,20))                 | [(1,2),(3,4)]             | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | [(1,2),(3,4)]             | 
+ ((10,20))                 | ((10,20))                 | 
+ ((10,20))                 | [(11,12),(13,14)]         | 
+ ((10,20))                 | ((11,12),(13,14))         | 
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             | [(11,12),(13,14),(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14),(0,0),(3,0),(4,5),(1,6)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             | [(11,12),(13,14),(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((10,20))                 | 
+ [(11,12),(13,14)]         | [(11,12),(13,14)]         | [(11,12),(13,14),(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))         | 
+ ((11,12),(13,14))         | [(1,2),(3,4)]             | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | [(1,2),(3,4)]             | 
+ ((11,12),(13,14))         | ((10,20))                 | 
+ ((11,12),(13,14))         | [(11,12),(13,14)]         | 
+ ((11,12),(13,14))         | ((11,12),(13,14))         | 
+(81 rows)
+
+-- Add point
+SELECT p.f1, p1.f1, p.f1 + p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                                 ?column?                                  
+---------------------------+-------------------+---------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((10,20))                 | (0,0)             | ((10,20))
+ [(11,12),(13,14)]         | (0,0)             | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (0,0)             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (-10,0)           | [(-9,2),(-7,4)]
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(-10,0),(-7,0),(-6,5),(-9,6)]
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ [(1,2),(3,4)]             | (-10,0)           | [(-9,2),(-7,4)]
+ ((10,20))                 | (-10,0)           | ((0,20))
+ [(11,12),(13,14)]         | (-10,0)           | [(1,12),(3,14)]
+ ((11,12),(13,14))         | (-10,0)           | ((1,12),(3,14))
+ [(1,2),(3,4)]             | (-3,4)            | [(-2,6),(0,8)]
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(-3,4),(0,4),(1,9),(-2,10)]
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ [(1,2),(3,4)]             | (-3,4)            | [(-2,6),(0,8)]
+ ((10,20))                 | (-3,4)            | ((7,24))
+ [(11,12),(13,14)]         | (-3,4)            | [(8,16),(10,18)]
+ ((11,12),(13,14))         | (-3,4)            | ((8,16),(10,18))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(6.1,36.5),(8.1,38.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(5.1,34.5),(8.1,34.5),(9.1,39.5),(6.1,40.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(6.1,36.5),(8.1,38.5)]
+ ((10,20))                 | (5.1,34.5)        | ((15.1,54.5))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(16.1,46.5),(18.1,48.5)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((16.1,46.5),(18.1,48.5))
+ [(1,2),(3,4)]             | (-5,-12)          | [(-4,-10),(-2,-8)]
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(-5,-12),(-2,-12),(-1,-7),(-4,-6)]
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ [(1,2),(3,4)]             | (-5,-12)          | [(-4,-10),(-2,-8)]
+ ((10,20))                 | (-5,-12)          | ((5,8))
+ [(11,12),(13,14)]         | (-5,-12)          | [(6,0),(8,2)]
+ ((11,12),(13,14))         | (-5,-12)          | ((6,0),(8,2))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(1e-300,-1e-300),(3,-1e-300),(4,5),(1,6)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((10,20))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity),(1e+300,Infinity),(1e+300,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((1e+300,Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(11,12),(13,14)]
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(10,10),(13,10),(14,15),(11,16)]
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (10,10)           | [(11,12),(13,14)]
+ ((10,20))                 | (10,10)           | ((20,30))
+ [(11,12),(13,14)]         | (10,10)           | [(21,22),(23,24)]
+ ((11,12),(13,14))         | (10,10)           | ((21,22),(23,24))
+(81 rows)
+
+-- Subtract point
+SELECT p.f1, p1.f1, p.f1 - p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                                     ?column?                                      
+---------------------------+-------------------+-----------------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((10,20))                 | (0,0)             | ((10,20))
+ [(11,12),(13,14)]         | (0,0)             | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (0,0)             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (-10,0)           | [(11,2),(13,4)]
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(10,0),(13,0),(14,5),(11,6)]
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ [(1,2),(3,4)]             | (-10,0)           | [(11,2),(13,4)]
+ ((10,20))                 | (-10,0)           | ((20,20))
+ [(11,12),(13,14)]         | (-10,0)           | [(21,12),(23,14)]
+ ((11,12),(13,14))         | (-10,0)           | ((21,12),(23,14))
+ [(1,2),(3,4)]             | (-3,4)            | [(4,-2),(6,0)]
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(3,-4),(6,-4),(7,1),(4,2)]
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ [(1,2),(3,4)]             | (-3,4)            | [(4,-2),(6,0)]
+ ((10,20))                 | (-3,4)            | ((13,16))
+ [(11,12),(13,14)]         | (-3,4)            | [(14,8),(16,10)]
+ ((11,12),(13,14))         | (-3,4)            | ((14,8),(16,10))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-4.1,-32.5),(-2.1,-30.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(-5.1,-34.5),(-2.1,-34.5),(-1.1,-29.5),(-4.1,-28.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-4.1,-32.5),(-2.1,-30.5)]
+ ((10,20))                 | (5.1,34.5)        | ((4.9,-14.5))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(5.9,-22.5),(7.9,-20.5)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((5.9,-22.5),(7.9,-20.5))
+ [(1,2),(3,4)]             | (-5,-12)          | [(6,14),(8,16)]
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(5,12),(8,12),(9,17),(6,18)]
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ [(1,2),(3,4)]             | (-5,-12)          | [(6,14),(8,16)]
+ ((10,20))                 | (-5,-12)          | ((15,32))
+ [(11,12),(13,14)]         | (-5,-12)          | [(16,24),(18,26)]
+ ((11,12),(13,14))         | (-5,-12)          | ((16,24),(18,26))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(-1e-300,1e-300),(3,1e-300),(4,5),(1,6)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((10,20))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity),(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((-1e+300,-Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(-9,-8),(-7,-6)]
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(-10,-10),(-7,-10),(-6,-5),(-9,-4)]
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ [(1,2),(3,4)]             | (10,10)           | [(-9,-8),(-7,-6)]
+ ((10,20))                 | (10,10)           | ((0,10))
+ [(11,12),(13,14)]         | (10,10)           | [(1,2),(3,4)]
+ ((11,12),(13,14))         | (10,10)           | ((1,2),(3,4))
+(81 rows)
+
+-- Multiply with point
+SELECT p.f1, p1.f1, p.f1 * p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                               ?column?                               
+---------------------------+-------------------+----------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(0,0),(0,0)]
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(0,0),(0,0),(0,0)]
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ [(1,2),(3,4)]             | (0,0)             | [(0,0),(0,0)]
+ ((10,20))                 | (0,0)             | ((0,0))
+ [(11,12),(13,14)]         | (0,0)             | [(0,0),(0,0)]
+ ((11,12),(13,14))         | (0,0)             | ((0,0),(0,0))
+ [(1,2),(3,4)]             | (-10,0)           | [(-10,-20),(-30,-40)]
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(0,0),(-30,0),(-40,-50),(-10,-60)]
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ [(1,2),(3,4)]             | (-10,0)           | [(-10,-20),(-30,-40)]
+ ((10,20))                 | (-10,0)           | ((-100,-200))
+ [(11,12),(13,14)]         | (-10,0)           | [(-110,-120),(-130,-140)]
+ ((11,12),(13,14))         | (-10,0)           | ((-110,-120),(-130,-140))
+ [(1,2),(3,4)]             | (-3,4)            | [(-11,-2),(-25,0)]
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(0,0),(-9,12),(-32,1),(-27,-14)]
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ [(1,2),(3,4)]             | (-3,4)            | [(-11,-2),(-25,0)]
+ ((10,20))                 | (-3,4)            | ((-110,-20))
+ [(11,12),(13,14)]         | (-3,4)            | [(-81,8),(-95,10)]
+ ((11,12),(13,14))         | (-3,4)            | ((-81,8),(-95,10))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-63.9,44.7),(-122.7,123.9)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(0,0),(15.3,103.5),(-152.1,163.5),(-201.9,65.1)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-63.9,44.7),(-122.7,123.9)]
+ ((10,20))                 | (5.1,34.5)        | ((-639,447))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(-357.9,440.7),(-416.7,519.9)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((-357.9,440.7),(-416.7,519.9))
+ [(1,2),(3,4)]             | (-5,-12)          | [(19,-22),(33,-56)]
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(0,0),(-15,-36),(40,-73),(67,-42)]
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ [(1,2),(3,4)]             | (-5,-12)          | [(19,-22),(33,-56)]
+ ((10,20))                 | (-5,-12)          | ((190,-220))
+ [(11,12),(13,14)]         | (-5,-12)          | [(89,-192),(103,-226)]
+ ((11,12),(13,14))         | (-5,-12)          | ((89,-192),(103,-226))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(3e-300,1e-300),(7e-300,1e-300)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(0,0),(3e-300,-3e-300),(9e-300,1e-300),(7e-300,5e-300)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(3e-300,1e-300),(7e-300,1e-300)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((3e-299,1e-299))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(2.3e-299,1e-300),(2.7e-299,1e-300)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((2.3e-299,1e-300),(2.7e-299,1e-300))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(NaN,NaN),(NaN,Infinity),(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((-Infinity,Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(-10,30),(-10,70)]
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(0,0),(30,30),(-10,90),(-50,70)]
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ [(1,2),(3,4)]             | (10,10)           | [(-10,30),(-10,70)]
+ ((10,20))                 | (10,10)           | ((-100,300))
+ [(11,12),(13,14)]         | (10,10)           | [(-10,230),(-10,270)]
+ ((11,12),(13,14))         | (10,10)           | ((-10,230),(-10,270))
+(81 rows)
+
+-- Divide by point
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+            f1             |     f1     |                                                    ?column?                                                     
+---------------------------+------------+-----------------------------------------------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (5.1,34.5) | [(0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952)]
+ [(1,2),(3,4)]             | (10,10)    | [(0.15,0.05),(0.35,0.05)]
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5) | [(0,0),(0.0125795471363,-0.0850969365103),(0.158600957032,-0.0924966701199),(0.174387055399,-0.00320655123082)]
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)    | [(0,0),(0.15,-0.15),(0.45,0.05),(0.35,0.25)]
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ [(1,2),(3,4)]             | (5.1,34.5) | [(0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952)]
+ [(1,2),(3,4)]             | (10,10)    | [(0.15,0.05),(0.35,0.05)]
+ ((10,20))                 | (5.1,34.5) | ((0.609244733856,-0.199792807459))
+ ((10,20))                 | (10,10)    | ((1.5,0.5))
+ [(11,12),(13,14)]         | (5.1,34.5) | [(0.386512752208,-0.261703911993),(0.451630407972,-0.310048838242)]
+ [(11,12),(13,14)]         | (10,10)    | [(1.15,0.05),(1.35,0.05)]
+ ((11,12),(13,14))         | (5.1,34.5) | ((0.386512752208,-0.261703911993),(0.451630407972,-0.310048838242))
+ ((11,12),(13,14))         | (10,10)    | ((1.15,0.05),(1.35,0.05))
+(18 rows)
+
+-- Division by 0 error
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to path
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+            f1             |            f1             |    ?column?    
+---------------------------+---------------------------+----------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((10,20))                 |  17.4642491966
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         |   11.313708499
+ [(1,2),(3,4)]             | ((11,12),(13,14))         |   11.313708499
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)] |              0
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))                 |  16.1554944214
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]         |  9.89949493661
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))         |  9.89949493661
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((10,20))                 |  17.4642491966
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         |   11.313708499
+ [(1,2),(3,4)]             | ((11,12),(13,14))         |   11.313708499
+ ((10,20))                 | [(1,2),(3,4)]             |  17.4642491966
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)] |  16.1554944214
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | [(1,2),(3,4)]             |  17.4642491966
+ ((10,20))                 | ((10,20))                 |              0
+ ((10,20))                 | [(11,12),(13,14)]         |   6.7082039325
+ ((10,20))                 | ((11,12),(13,14))         |   6.7082039325
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             |   11.313708499
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)] |  9.89949493661
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             |   11.313708499
+ [(11,12),(13,14)]         | ((10,20))                 |   6.7082039325
+ [(11,12),(13,14)]         | [(11,12),(13,14)]         |              0
+ [(11,12),(13,14)]         | ((11,12),(13,14))         |              0
+ ((11,12),(13,14))         | [(1,2),(3,4)]             |   11.313708499
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)] |  9.89949493661
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | [(1,2),(3,4)]             |   11.313708499
+ ((11,12),(13,14))         | ((10,20))                 |   6.7082039325
+ ((11,12),(13,14))         | [(11,12),(13,14)]         |              0
+ ((11,12),(13,14))         | ((11,12),(13,14))         |              0
+(81 rows)
 
 --
 -- Polygons
 --
 -- containment
 SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
    FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
+ twentyfour |        f1         |             f1             | contains 
+------------+-------------------+----------------------------+----------
+            | (0,0)             | ((2,0),(2,4),(0,0))        | t
+            | (0,0)             | ((3,1),(3,3),(1,0))        | f
+            | (0,0)             | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (0,0)             | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (0,0)             | ((0,0))                    | t
+            | (0,0)             | ((0,1),(0,1))              | f
+            | (-10,0)           | ((2,0),(2,4),(0,0))        | f
+            | (-10,0)           | ((3,1),(3,3),(1,0))        | f
+            | (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-10,0)           | ((0,0))                    | f
+            | (-10,0)           | ((0,1),(0,1))              | f
+            | (-3,4)            | ((2,0),(2,4),(0,0))        | f
+            | (-3,4)            | ((3,1),(3,3),(1,0))        | f
+            | (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-3,4)            | ((0,0))                    | f
+            | (-3,4)            | ((0,1),(0,1))              | f
+            | (5.1,34.5)        | ((2,0),(2,4),(0,0))        | f
+            | (5.1,34.5)        | ((3,1),(3,3),(1,0))        | f
+            | (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (5.1,34.5)        | ((0,0))                    | f
+            | (5.1,34.5)        | ((0,1),(0,1))              | f
+            | (-5,-12)          | ((2,0),(2,4),(0,0))        | f
+            | (-5,-12)          | ((3,1),(3,3),(1,0))        | f
+            | (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-5,-12)          | ((0,0))                    | f
+            | (-5,-12)          | ((0,1),(0,1))              | f
+            | (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        | t
+            | (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        | f
+            | (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e-300,-1e-300)  | ((0,0))                    | t
+            | (1e-300,-1e-300)  | ((0,1),(0,1))              | f
+            | (1e+300,Infinity) | ((2,0),(2,4),(0,0))        | f
+            | (1e+300,Infinity) | ((3,1),(3,3),(1,0))        | f
+            | (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e+300,Infinity) | ((0,0))                    | f
+            | (1e+300,Infinity) | ((0,1),(0,1))              | f
+            | (NaN,NaN)         | ((2,0),(2,4),(0,0))        | t
+            | (NaN,NaN)         | ((3,1),(3,3),(1,0))        | t
+            | (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  | t
+            | (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  | t
+            | (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) | t
+            | (NaN,NaN)         | ((0,0))                    | t
+            | (NaN,NaN)         | ((0,1),(0,1))              | t
+            | (10,10)           | ((2,0),(2,4),(0,0))        | f
+            | (10,10)           | ((3,1),(3,3),(1,0))        | f
+            | (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (10,10)           | ((0,0))                    | f
+            | (10,10)           | ((0,1),(0,1))              | f
+(63 rows)
 
 SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
    FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
+ twentyfour |        f1         |             f1             | contained 
+------------+-------------------+----------------------------+-----------
+            | (0,0)             | ((2,0),(2,4),(0,0))        | t
+            | (0,0)             | ((3,1),(3,3),(1,0))        | f
+            | (0,0)             | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (0,0)             | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (0,0)             | ((0,0))                    | t
+            | (0,0)             | ((0,1),(0,1))              | f
+            | (-10,0)           | ((2,0),(2,4),(0,0))        | f
+            | (-10,0)           | ((3,1),(3,3),(1,0))        | f
+            | (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-10,0)           | ((0,0))                    | f
+            | (-10,0)           | ((0,1),(0,1))              | f
+            | (-3,4)            | ((2,0),(2,4),(0,0))        | f
+            | (-3,4)            | ((3,1),(3,3),(1,0))        | f
+            | (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-3,4)            | ((0,0))                    | f
+            | (-3,4)            | ((0,1),(0,1))              | f
+            | (5.1,34.5)        | ((2,0),(2,4),(0,0))        | f
+            | (5.1,34.5)        | ((3,1),(3,3),(1,0))        | f
+            | (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (5.1,34.5)        | ((0,0))                    | f
+            | (5.1,34.5)        | ((0,1),(0,1))              | f
+            | (-5,-12)          | ((2,0),(2,4),(0,0))        | f
+            | (-5,-12)          | ((3,1),(3,3),(1,0))        | f
+            | (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-5,-12)          | ((0,0))                    | f
+            | (-5,-12)          | ((0,1),(0,1))              | f
+            | (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        | t
+            | (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        | f
+            | (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e-300,-1e-300)  | ((0,0))                    | t
+            | (1e-300,-1e-300)  | ((0,1),(0,1))              | f
+            | (1e+300,Infinity) | ((2,0),(2,4),(0,0))        | f
+            | (1e+300,Infinity) | ((3,1),(3,3),(1,0))        | f
+            | (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e+300,Infinity) | ((0,0))                    | f
+            | (1e+300,Infinity) | ((0,1),(0,1))              | f
+            | (NaN,NaN)         | ((2,0),(2,4),(0,0))        | t
+            | (NaN,NaN)         | ((3,1),(3,3),(1,0))        | t
+            | (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  | t
+            | (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  | t
+            | (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) | t
+            | (NaN,NaN)         | ((0,0))                    | t
+            | (NaN,NaN)         | ((0,1),(0,1))              | t
+            | (10,10)           | ((2,0),(2,4),(0,0))        | f
+            | (10,10)           | ((3,1),(3,3),(1,0))        | f
+            | (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (10,10)           | ((0,0))                    | f
+            | (10,10)           | ((0,1),(0,1))              | f
+(63 rows)
 
 SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
    FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
+ four | npoints |          polygon           
+------+---------+----------------------------
       |       3 | ((2,0),(2,4),(0,0))
       |       3 | ((3,1),(3,3),(1,0))
+      |       4 | ((1,2),(3,4),(5,6),(7,8))
+      |       4 | ((7,8),(5,6),(3,4),(1,2))
+      |       4 | ((1,2),(7,8),(5,6),(3,-4))
       |       1 | ((0,0))
       |       2 | ((0,1),(0,1))
-(4 rows)
+(7 rows)
 
 SELECT '' AS four, polygon(f1)
    FROM BOX_TBL;
  four |                  polygon                  
 ------+-------------------------------------------
       | ((0,0),(0,2),(2,2),(2,0))
       | ((1,1),(1,3),(3,3),(3,1))
+      | ((-8,-10),(-8,2),(-2,2),(-2,-10))
       | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
       | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, polygon(f1)
    FROM PATH_TBL WHERE isclosed(f1);
  four |      polygon      
 ------+-------------------
       | ((1,2),(3,4))
       | ((1,2),(3,4))
       | ((1,2),(3,4))
+      | ((10,20))
       | ((11,12),(13,14))
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
    FROM PATH_TBL
    WHERE isopen(f1);
  four |         open_path         |          polygon          
 ------+---------------------------+---------------------------
       | [(1,2),(3,4)]             | ((1,2),(3,4))
       | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
       | [(1,2),(3,4)]             | ((1,2),(3,4))
       | [(11,12),(13,14)]         | ((11,12),(13,14))
 (4 rows)
 
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
+-- To box
+SELECT f1, f1::box FROM POLYGON_TBL;
+             f1             |      f1      
+----------------------------+--------------
+ ((2,0),(2,4),(0,0))        | (2,4),(0,0)
+ ((3,1),(3,3),(1,0))        | (3,3),(1,0)
+ ((1,2),(3,4),(5,6),(7,8))  | (7,8),(1,2)
+ ((7,8),(5,6),(3,4),(1,2))  | (7,8),(1,2)
+ ((1,2),(7,8),(5,6),(3,-4)) | (7,8),(1,-4)
+ ((0,0))                    | (0,0),(0,0)
+ ((0,1),(0,1))              | (0,1),(0,1)
+(7 rows)
 
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
+-- To path
+SELECT f1, f1::path FROM POLYGON_TBL;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(7 rows)
 
+-- Same as polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 ~= p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(9 rows)
+
+-- Contained by polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <@ p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(12 rows)
+
+-- Contains polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 @> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(12 rows)
+
+-- Overlap with polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 && p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(25 rows)
+
+-- Left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 << p2.f1;
+      f1       |             f1             
+---------------+----------------------------
+ ((0,0))       | ((3,1),(3,3),(1,0))
+ ((0,0))       | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))       | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))       | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1)) | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1)) | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1)) | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1)) | ((1,2),(7,8),(5,6),(3,-4))
+(8 rows)
+
+-- Overlap of left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &< p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))                    | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1))              | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(32 rows)
+
+-- Right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 >> p2.f1;
+             f1             |      f1       
+----------------------------+---------------
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((0,1),(0,1))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1))
+(8 rows)
+
+-- Overlap of right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((2,0),(2,4),(0,0))        | ((0,1),(0,1))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((0,1),(0,1))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((3,1),(3,3),(1,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(37 rows)
+
+-- Below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <<| p2.f1;
+      f1       |            f1             
+---------------+---------------------------
+ ((0,0))       | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))       | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))       | ((0,1),(0,1))
+ ((0,1),(0,1)) | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1)) | ((7,8),(5,6),(3,4),(1,2))
+(5 rows)
+
+-- Overlap or below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &<| p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))                    | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1))              | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(31 rows)
+
+-- Above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |>> p2.f1;
+            f1             |      f1       
+---------------------------+---------------
+ ((1,2),(3,4),(5,6),(7,8)) | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8)) | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2)) | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2)) | ((0,1),(0,1))
+ ((0,1),(0,1))             | ((0,0))
+(5 rows)
+
+-- Overlap or above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |&> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((3,1),(3,3),(1,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(32 rows)
+
+-- Distance to polygon
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2;
+ERROR:  function "poly_distance" not implemented
 --
 -- Circles
 --
 SELECT '' AS six, circle(f1, 50.0)
    FROM POINT_TBL;
- six |     circle      
------+-----------------
+ six |         circle         
+-----+------------------------
      | <(0,0),50>
      | <(-10,0),50>
      | <(-3,4),50>
      | <(5.1,34.5),50>
      | <(-5,-12),50>
+     | <(1e-300,-1e-300),50>
+     | <(1e+300,Infinity),50>
+     | <(NaN,NaN),50>
      | <(10,10),50>
-(6 rows)
+(9 rows)
 
 SELECT '' AS four, circle(f1)
    FROM BOX_TBL;
- four |        circle         
-------+-----------------------
+ four |         circle         
+------+------------------------
       | <(1,1),1.41421356237>
       | <(2,2),1.41421356237>
+      | <(-5,-4),6.7082039325>
       | <(2.5,3),0.5>
       | <(3,3),0>
-(4 rows)
+(5 rows)
 
 SELECT '' AS two, circle(f1)
    FROM POLYGON_TBL
    WHERE (# f1) >= 3;
  two |                    circle                     
 -----+-----------------------------------------------
      | <(1.33333333333,1.33333333333),2.04168905064>
      | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
+     | <(4,5),2.82842712475>
+     | <(4,5),2.82842712475>
+     | <(4,3),4.80664375676>
+(5 rows)
 
 SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
    FROM CIRCLE_TBL c1, POINT_TBL p1
    WHERE (p1.f1 <-> c1.f1) > 0
    ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
+ twentyfour |     circle     |       point       |   distance    
+------------+----------------+-------------------+---------------
+            | <(1,2),3>      | (-3,4)            |   1.472135955
+            | <(5,1),3>      | (0,0)             | 2.09901951359
+            | <(5,1),3>      | (1e-300,-1e-300)  | 2.09901951359
+            | <(5,1),3>      | (-3,4)            | 5.54400374532
+            | <(3,5),0>      | (0,0)             | 5.83095189485
+            | <(3,5),0>      | (1e-300,-1e-300)  | 5.83095189485
+            | <(3,5),0>      | (-3,4)            |  6.0827625303
+            | <(1,3),5>      | (-10,0)           | 6.40175425099
+            | <(1,3),5>      | (10,10)           | 6.40175425099
+            | <(5,1),3>      | (10,10)           | 7.29563014099
+            | <(1,2),3>      | (-10,0)           |  8.1803398875
+            | <(3,5),0>      | (10,10)           | 8.60232526704
+            | <(1,2),3>      | (10,10)           | 9.04159457879
+            | <(1,3),5>      | (-5,-12)          | 11.1554944214
+            | <(5,1),3>      | (-10,0)           | 12.0332963784
+            | <(1,2),3>      | (-5,-12)          | 12.2315462117
+            | <(5,1),3>      | (-5,-12)          | 13.4012194669
+            | <(3,5),0>      | (-10,0)           | 13.9283882772
+            | <(3,5),0>      | (-5,-12)          | 18.7882942281
+            | <(1,3),5>      | (5.1,34.5)        | 26.7657047773
+            | <(3,5),0>      | (5.1,34.5)        | 29.5746513082
+            | <(1,2),3>      | (5.1,34.5)        | 29.7575945393
+            | <(5,1),3>      | (5.1,34.5)        | 30.5001492534
+            | <(100,200),10> | (5.1,34.5)        | 180.778038568
+            | <(100,200),10> | (10,10)           | 200.237960416
+            | <(100,200),10> | (-3,4)            | 211.415898255
+            | <(100,200),10> | (0,0)             |  213.60679775
+            | <(100,200),10> | (1e-300,-1e-300)  |  213.60679775
+            | <(100,200),10> | (-10,0)           |  218.25424421
+            | <(100,200),10> | (-5,-12)          | 226.577682802
+            | <(3,5),0>      | (1e+300,Infinity) |      Infinity
+            | <(1,2),3>      | (1e+300,Infinity) |      Infinity
+            | <(5,1),3>      | (1e+300,Infinity) |      Infinity
+            | <(1,3),5>      | (1e+300,Infinity) |      Infinity
+            | <(100,200),10> | (1e+300,Infinity) |      Infinity
+            | <(1,2),100>    | (1e+300,Infinity) |      Infinity
+            | <(100,1),115>  | (1e+300,Infinity) |      Infinity
+            | <(3,5),0>      | (NaN,NaN)         |           NaN
+            | <(1,2),3>      | (NaN,NaN)         |           NaN
+            | <(5,1),3>      | (NaN,NaN)         |           NaN
+            | <(1,3),5>      | (NaN,NaN)         |           NaN
+            | <(100,200),10> | (NaN,NaN)         |           NaN
+            | <(1,2),100>    | (NaN,NaN)         |           NaN
+            | <(100,1),115>  | (NaN,NaN)         |           NaN
+            | <(3,5),NaN>    | (-10,0)           |           NaN
+            | <(3,5),NaN>    | (-5,-12)          |           NaN
+            | <(3,5),NaN>    | (-3,4)            |           NaN
+            | <(3,5),NaN>    | (0,0)             |           NaN
+            | <(3,5),NaN>    | (1e-300,-1e-300)  |           NaN
+            | <(3,5),NaN>    | (5.1,34.5)        |           NaN
+            | <(3,5),NaN>    | (10,10)           |           NaN
+            | <(3,5),NaN>    | (1e+300,Infinity) |           NaN
+            | <(3,5),NaN>    | (NaN,NaN)         |           NaN
+(53 rows)
+
+-- To polygon
+SELECT f1, f1::polygon FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+       f1       |                                                                                                          f1                                                                                                          
+----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ <(5,1),3>      | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
+ <(1,2),100>    | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
+ <(1,3),5>      | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
+ <(1,2),3>      | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
+ <(100,200),10> | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
+ <(100,1),115>  | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
+(6 rows)
+
+-- To polygon with less points
+SELECT f1, polygon(8, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+       f1       |                                                                             polygon                                                                              
+----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ <(5,1),3>      | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
+ <(1,2),100>    | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
+ <(1,3),5>      | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
+ <(1,2),3>      | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
+ <(100,200),10> | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
+ <(100,1),115>  | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
+(6 rows)
+
+-- Too less points error
+SELECT f1, polygon(1, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+ERROR:  must request at least 2 points
+-- Zero radius error
+SELECT f1, polygon(10, f1) FROM CIRCLE_TBL WHERE f1 < '<(0,0),1>';
+ERROR:  cannot convert circle with radius zero to polygon
+-- Same as circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 ~= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+ <(3,5),NaN>    | <(3,5),0>
+ <(3,5),NaN>    | <(3,5),NaN>
+(9 rows)
+
+-- Overlap with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 && c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,1),115>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(100,1),115>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(33 rows)
+
+-- Overlap or left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &< c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(28 rows)
+
+-- Left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 << c2.f1;
+    f1     |       f1       
+-----------+----------------
+ <(5,1),3> | <(100,200),10>
+ <(1,3),5> | <(100,200),10>
+ <(1,2),3> | <(100,200),10>
+ <(3,5),0> | <(100,200),10>
+(4 rows)
+
+-- Right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >> c2.f1;
+       f1       |    f1     
+----------------+-----------
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(3,5),0>
+(4 rows)
+
+-- Overlap or right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(28 rows)
+
+-- Contained by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <@ c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(17 rows)
+
+-- Contain by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 @> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(3,5),0>
+(17 rows)
+
+-- Below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <<| c2.f1;
+      f1       |       f1       
+---------------+----------------
+ <(5,1),3>     | <(100,200),10>
+ <(5,1),3>     | <(3,5),0>
+ <(1,2),100>   | <(100,200),10>
+ <(1,3),5>     | <(100,200),10>
+ <(1,2),3>     | <(100,200),10>
+ <(100,1),115> | <(100,200),10>
+ <(3,5),0>     | <(100,200),10>
+(7 rows)
+
+-- Above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |>> c2.f1;
+       f1       |      f1       
+----------------+---------------
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(3,5),0>      | <(5,1),3>
+(7 rows)
+
+-- Overlap or below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &<| c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Overlap or above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |&> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 = c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(9 rows)
+
+-- Area not equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 != c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(40 rows)
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 > c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(3,5),0>
+(20 rows)
+
+-- Area less than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area greater than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Add point
+SELECT c.f1, p.f1, c.f1 + p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |        ?column?         
+----------------+-------------------+-------------------------
+ <(5,1),3>      | (0,0)             | <(5,1),3>
+ <(1,2),100>    | (0,0)             | <(1,2),100>
+ <(1,3),5>      | (0,0)             | <(1,3),5>
+ <(1,2),3>      | (0,0)             | <(1,2),3>
+ <(100,200),10> | (0,0)             | <(100,200),10>
+ <(100,1),115>  | (0,0)             | <(100,1),115>
+ <(3,5),0>      | (0,0)             | <(3,5),0>
+ <(3,5),NaN>    | (0,0)             | <(3,5),NaN>
+ <(5,1),3>      | (-10,0)           | <(-5,1),3>
+ <(1,2),100>    | (-10,0)           | <(-9,2),100>
+ <(1,3),5>      | (-10,0)           | <(-9,3),5>
+ <(1,2),3>      | (-10,0)           | <(-9,2),3>
+ <(100,200),10> | (-10,0)           | <(90,200),10>
+ <(100,1),115>  | (-10,0)           | <(90,1),115>
+ <(3,5),0>      | (-10,0)           | <(-7,5),0>
+ <(3,5),NaN>    | (-10,0)           | <(-7,5),NaN>
+ <(5,1),3>      | (-3,4)            | <(2,5),3>
+ <(1,2),100>    | (-3,4)            | <(-2,6),100>
+ <(1,3),5>      | (-3,4)            | <(-2,7),5>
+ <(1,2),3>      | (-3,4)            | <(-2,6),3>
+ <(100,200),10> | (-3,4)            | <(97,204),10>
+ <(100,1),115>  | (-3,4)            | <(97,5),115>
+ <(3,5),0>      | (-3,4)            | <(0,9),0>
+ <(3,5),NaN>    | (-3,4)            | <(0,9),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(10.1,35.5),3>
+ <(1,2),100>    | (5.1,34.5)        | <(6.1,36.5),100>
+ <(1,3),5>      | (5.1,34.5)        | <(6.1,37.5),5>
+ <(1,2),3>      | (5.1,34.5)        | <(6.1,36.5),3>
+ <(100,200),10> | (5.1,34.5)        | <(105.1,234.5),10>
+ <(100,1),115>  | (5.1,34.5)        | <(105.1,35.5),115>
+ <(3,5),0>      | (5.1,34.5)        | <(8.1,39.5),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(8.1,39.5),NaN>
+ <(5,1),3>      | (-5,-12)          | <(0,-11),3>
+ <(1,2),100>    | (-5,-12)          | <(-4,-10),100>
+ <(1,3),5>      | (-5,-12)          | <(-4,-9),5>
+ <(1,2),3>      | (-5,-12)          | <(-4,-10),3>
+ <(100,200),10> | (-5,-12)          | <(95,188),10>
+ <(100,1),115>  | (-5,-12)          | <(95,-11),115>
+ <(3,5),0>      | (-5,-12)          | <(-2,-7),0>
+ <(3,5),NaN>    | (-5,-12)          | <(-2,-7),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(5,1),3>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(1,2),100>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(1,3),5>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(1,2),3>
+ <(100,200),10> | (1e-300,-1e-300)  | <(100,200),10>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(100,1),115>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(3,5),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(3,5),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(1e+300,Infinity),3>
+ <(1,2),100>    | (1e+300,Infinity) | <(1e+300,Infinity),100>
+ <(1,3),5>      | (1e+300,Infinity) | <(1e+300,Infinity),5>
+ <(1,2),3>      | (1e+300,Infinity) | <(1e+300,Infinity),3>
+ <(100,200),10> | (1e+300,Infinity) | <(1e+300,Infinity),10>
+ <(100,1),115>  | (1e+300,Infinity) | <(1e+300,Infinity),115>
+ <(3,5),0>      | (1e+300,Infinity) | <(1e+300,Infinity),0>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(1e+300,Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),100>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),5>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),10>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),115>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),0>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(15,11),3>
+ <(1,2),100>    | (10,10)           | <(11,12),100>
+ <(1,3),5>      | (10,10)           | <(11,13),5>
+ <(1,2),3>      | (10,10)           | <(11,12),3>
+ <(100,200),10> | (10,10)           | <(110,210),10>
+ <(100,1),115>  | (10,10)           | <(110,11),115>
+ <(3,5),0>      | (10,10)           | <(13,15),0>
+ <(3,5),NaN>    | (10,10)           | <(13,15),NaN>
+(72 rows)
+
+-- Subtract point
+SELECT c.f1, p.f1, c.f1 - p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |         ?column?          
+----------------+-------------------+---------------------------
+ <(5,1),3>      | (0,0)             | <(5,1),3>
+ <(1,2),100>    | (0,0)             | <(1,2),100>
+ <(1,3),5>      | (0,0)             | <(1,3),5>
+ <(1,2),3>      | (0,0)             | <(1,2),3>
+ <(100,200),10> | (0,0)             | <(100,200),10>
+ <(100,1),115>  | (0,0)             | <(100,1),115>
+ <(3,5),0>      | (0,0)             | <(3,5),0>
+ <(3,5),NaN>    | (0,0)             | <(3,5),NaN>
+ <(5,1),3>      | (-10,0)           | <(15,1),3>
+ <(1,2),100>    | (-10,0)           | <(11,2),100>
+ <(1,3),5>      | (-10,0)           | <(11,3),5>
+ <(1,2),3>      | (-10,0)           | <(11,2),3>
+ <(100,200),10> | (-10,0)           | <(110,200),10>
+ <(100,1),115>  | (-10,0)           | <(110,1),115>
+ <(3,5),0>      | (-10,0)           | <(13,5),0>
+ <(3,5),NaN>    | (-10,0)           | <(13,5),NaN>
+ <(5,1),3>      | (-3,4)            | <(8,-3),3>
+ <(1,2),100>    | (-3,4)            | <(4,-2),100>
+ <(1,3),5>      | (-3,4)            | <(4,-1),5>
+ <(1,2),3>      | (-3,4)            | <(4,-2),3>
+ <(100,200),10> | (-3,4)            | <(103,196),10>
+ <(100,1),115>  | (-3,4)            | <(103,-3),115>
+ <(3,5),0>      | (-3,4)            | <(6,1),0>
+ <(3,5),NaN>    | (-3,4)            | <(6,1),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(-0.1,-33.5),3>
+ <(1,2),100>    | (5.1,34.5)        | <(-4.1,-32.5),100>
+ <(1,3),5>      | (5.1,34.5)        | <(-4.1,-31.5),5>
+ <(1,2),3>      | (5.1,34.5)        | <(-4.1,-32.5),3>
+ <(100,200),10> | (5.1,34.5)        | <(94.9,165.5),10>
+ <(100,1),115>  | (5.1,34.5)        | <(94.9,-33.5),115>
+ <(3,5),0>      | (5.1,34.5)        | <(-2.1,-29.5),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(-2.1,-29.5),NaN>
+ <(5,1),3>      | (-5,-12)          | <(10,13),3>
+ <(1,2),100>    | (-5,-12)          | <(6,14),100>
+ <(1,3),5>      | (-5,-12)          | <(6,15),5>
+ <(1,2),3>      | (-5,-12)          | <(6,14),3>
+ <(100,200),10> | (-5,-12)          | <(105,212),10>
+ <(100,1),115>  | (-5,-12)          | <(105,13),115>
+ <(3,5),0>      | (-5,-12)          | <(8,17),0>
+ <(3,5),NaN>    | (-5,-12)          | <(8,17),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(5,1),3>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(1,2),100>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(1,3),5>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(1,2),3>
+ <(100,200),10> | (1e-300,-1e-300)  | <(100,200),10>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(100,1),115>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(3,5),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(3,5),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(-1e+300,-Infinity),3>
+ <(1,2),100>    | (1e+300,Infinity) | <(-1e+300,-Infinity),100>
+ <(1,3),5>      | (1e+300,Infinity) | <(-1e+300,-Infinity),5>
+ <(1,2),3>      | (1e+300,Infinity) | <(-1e+300,-Infinity),3>
+ <(100,200),10> | (1e+300,Infinity) | <(-1e+300,-Infinity),10>
+ <(100,1),115>  | (1e+300,Infinity) | <(-1e+300,-Infinity),115>
+ <(3,5),0>      | (1e+300,Infinity) | <(-1e+300,-Infinity),0>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(-1e+300,-Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),100>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),5>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),10>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),115>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),0>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(-5,-9),3>
+ <(1,2),100>    | (10,10)           | <(-9,-8),100>
+ <(1,3),5>      | (10,10)           | <(-9,-7),5>
+ <(1,2),3>      | (10,10)           | <(-9,-8),3>
+ <(100,200),10> | (10,10)           | <(90,190),10>
+ <(100,1),115>  | (10,10)           | <(90,-9),115>
+ <(3,5),0>      | (10,10)           | <(-7,-5),0>
+ <(3,5),NaN>    | (10,10)           | <(-7,-5),NaN>
+(72 rows)
+
+-- Multiply with point
+SELECT c.f1, p.f1, c.f1 * p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |                  ?column?                  
+----------------+-------------------+--------------------------------------------
+ <(5,1),3>      | (0,0)             | <(0,0),0>
+ <(1,2),100>    | (0,0)             | <(0,0),0>
+ <(1,3),5>      | (0,0)             | <(0,0),0>
+ <(1,2),3>      | (0,0)             | <(0,0),0>
+ <(100,200),10> | (0,0)             | <(0,0),0>
+ <(100,1),115>  | (0,0)             | <(0,0),0>
+ <(3,5),0>      | (0,0)             | <(0,0),0>
+ <(3,5),NaN>    | (0,0)             | <(0,0),NaN>
+ <(5,1),3>      | (-10,0)           | <(-50,-10),30>
+ <(1,2),100>    | (-10,0)           | <(-10,-20),1000>
+ <(1,3),5>      | (-10,0)           | <(-10,-30),50>
+ <(1,2),3>      | (-10,0)           | <(-10,-20),30>
+ <(100,200),10> | (-10,0)           | <(-1000,-2000),100>
+ <(100,1),115>  | (-10,0)           | <(-1000,-10),1150>
+ <(3,5),0>      | (-10,0)           | <(-30,-50),0>
+ <(3,5),NaN>    | (-10,0)           | <(-30,-50),NaN>
+ <(5,1),3>      | (-3,4)            | <(-19,17),15>
+ <(1,2),100>    | (-3,4)            | <(-11,-2),500>
+ <(1,3),5>      | (-3,4)            | <(-15,-5),25>
+ <(1,2),3>      | (-3,4)            | <(-11,-2),15>
+ <(100,200),10> | (-3,4)            | <(-1100,-200),50>
+ <(100,1),115>  | (-3,4)            | <(-304,397),575>
+ <(3,5),0>      | (-3,4)            | <(-29,-3),0>
+ <(3,5),NaN>    | (-3,4)            | <(-29,-3),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(-9,177.6),104.624758064>
+ <(1,2),100>    | (5.1,34.5)        | <(-63.9,44.7),3487.49193547>
+ <(1,3),5>      | (5.1,34.5)        | <(-98.4,49.8),174.374596774>
+ <(1,2),3>      | (5.1,34.5)        | <(-63.9,44.7),104.624758064>
+ <(100,200),10> | (5.1,34.5)        | <(-6390,4470),348.749193547>
+ <(100,1),115>  | (5.1,34.5)        | <(475.5,3455.1),4010.6157258>
+ <(3,5),0>      | (5.1,34.5)        | <(-157.2,129),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(-157.2,129),NaN>
+ <(5,1),3>      | (-5,-12)          | <(-13,-65),39>
+ <(1,2),100>    | (-5,-12)          | <(19,-22),1300>
+ <(1,3),5>      | (-5,-12)          | <(31,-27),65>
+ <(1,2),3>      | (-5,-12)          | <(19,-22),39>
+ <(100,200),10> | (-5,-12)          | <(1900,-2200),130>
+ <(100,1),115>  | (-5,-12)          | <(-488,-1205),1495>
+ <(3,5),0>      | (-5,-12)          | <(45,-61),0>
+ <(3,5),NaN>    | (-5,-12)          | <(45,-61),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(6e-300,-4e-300),4.24264068712e-300>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(3e-300,1e-300),1.41421356237e-298>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(4e-300,2e-300),7.07106781187e-300>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(3e-300,1e-300),4.24264068712e-300>
+ <(100,200),10> | (1e-300,-1e-300)  | <(3e-298,1e-298),1.41421356237e-299>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(1.01e-298,-9.9e-299),1.62634559673e-298>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(8e-300,2e-300),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(8e-300,2e-300),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,2),100>    | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,3),5>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,2),3>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(100,200),10> | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(100,1),115>  | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(3,5),0>      | (1e+300,Infinity) | <(-Infinity,Infinity),NaN>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(-Infinity,Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(40,60),42.4264068712>
+ <(1,2),100>    | (10,10)           | <(-10,30),1414.21356237>
+ <(1,3),5>      | (10,10)           | <(-20,40),70.7106781187>
+ <(1,2),3>      | (10,10)           | <(-10,30),42.4264068712>
+ <(100,200),10> | (10,10)           | <(-1000,3000),141.421356237>
+ <(100,1),115>  | (10,10)           | <(990,1010),1626.34559673>
+ <(3,5),0>      | (10,10)           | <(-20,80),0>
+ <(3,5),NaN>    | (10,10)           | <(-20,80),NaN>
+(72 rows)
+
+-- Divide by point
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+       f1       |     f1     |                       ?column?                       
+----------------+------------+------------------------------------------------------
+ <(5,1),3>      | (5.1,34.5) | <(0.0493315573973,-0.137635045138),0.0860217042937>
+ <(5,1),3>      | (10,10)    | <(0.3,-0.2),0.212132034356>
+ <(1,2),100>    | (5.1,34.5) | <(0.0609244733856,-0.0199792807459),2.86739014312>
+ <(1,2),100>    | (10,10)    | <(0.15,0.05),7.07106781187>
+ <(1,3),5>      | (5.1,34.5) | <(0.0892901188891,-0.0157860983671),0.143369507156>
+ <(1,3),5>      | (10,10)    | <(0.2,0.1),0.353553390593>
+ <(1,2),3>      | (5.1,34.5) | <(0.0609244733856,-0.0199792807459),0.0860217042937>
+ <(1,2),3>      | (10,10)    | <(0.15,0.05),0.212132034356>
+ <(100,200),10> | (5.1,34.5) | <(6.09244733856,-1.99792807459),0.286739014312>
+ <(100,200),10> | (10,10)    | <(15,5),0.707106781187>
+ <(100,1),115>  | (5.1,34.5) | <(0.44768388338,-2.83237136796),3.29749866459>
+ <(100,1),115>  | (10,10)    | <(5.05,-4.95),8.13172798365>
+ <(3,5),0>      | (5.1,34.5) | <(0.154407774653,-0.0641310246164),0>
+ <(3,5),0>      | (10,10)    | <(0.4,0.1),0>
+ <(3,5),NaN>    | (5.1,34.5) | <(0.154407774653,-0.0641310246164),NaN>
+ <(3,5),NaN>    | (10,10)    | <(0.4,0.1),NaN>
+(16 rows)
+
+-- Overflow error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] > 1000;
+ERROR:  value out of range: overflow
+-- Division by 0 error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to polygon
+SELECT c.f1, p.f1, c.f1 <-> p.f1 FROM CIRCLE_TBL c, POLYGON_TBL p;
+       f1       |             f1             |    ?column?    
+----------------+----------------------------+----------------
+ <(5,1),3>      | ((2,0),(2,4),(0,0))        |              0
+ <(5,1),3>      | ((3,1),(3,3),(1,0))        |              0
+ <(5,1),3>      | ((1,2),(3,4),(5,6),(7,8))  | 0.535533905933
+ <(5,1),3>      | ((7,8),(5,6),(3,4),(1,2))  | 0.535533905933
+ <(5,1),3>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(5,1),3>      | ((0,0))                    |  2.09901951359
+ <(5,1),3>      | ((0,1),(0,1))              |              2
+ <(1,2),100>    | ((2,0),(2,4),(0,0))        |              0
+ <(1,2),100>    | ((3,1),(3,3),(1,0))        |              0
+ <(1,2),100>    | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,2),100>    | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,2),100>    | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,2),100>    | ((0,0))                    |              0
+ <(1,2),100>    | ((0,1),(0,1))              |              0
+ <(1,3),5>      | ((2,0),(2,4),(0,0))        |              0
+ <(1,3),5>      | ((3,1),(3,3),(1,0))        |              0
+ <(1,3),5>      | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,3),5>      | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,3),5>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,3),5>      | ((0,0))                    |              0
+ <(1,3),5>      | ((0,1),(0,1))              |              0
+ <(1,2),3>      | ((2,0),(2,4),(0,0))        |              0
+ <(1,2),3>      | ((3,1),(3,3),(1,0))        |              0
+ <(1,2),3>      | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,2),3>      | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,2),3>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,2),3>      | ((0,0))                    |              0
+ <(1,2),3>      | ((0,1),(0,1))              |              0
+ <(100,200),10> | ((2,0),(2,4),(0,0))        |  209.134661795
+ <(100,200),10> | ((3,1),(3,3),(1,0))        |  209.585974051
+ <(100,200),10> | ((1,2),(3,4),(5,6),(7,8))  |  203.337760371
+ <(100,200),10> | ((7,8),(5,6),(3,4),(1,2))  |  203.337760371
+ <(100,200),10> | ((1,2),(7,8),(5,6),(3,-4)) |  203.337760371
+ <(100,200),10> | ((0,0))                    |   213.60679775
+ <(100,200),10> | ((0,1),(0,1))              |  212.712819568
+ <(100,1),115>  | ((2,0),(2,4),(0,0))        |              0
+ <(100,1),115>  | ((3,1),(3,3),(1,0))        |              0
+ <(100,1),115>  | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(100,1),115>  | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(100,1),115>  | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(100,1),115>  | ((0,0))                    |              0
+ <(100,1),115>  | ((0,1),(0,1))              |              0
+ <(3,5),0>      | ((2,0),(2,4),(0,0))        |  1.41421356237
+ <(3,5),0>      | ((3,1),(3,3),(1,0))        |              2
+ <(3,5),0>      | ((1,2),(3,4),(5,6),(7,8))  | 0.707106781187
+ <(3,5),0>      | ((7,8),(5,6),(3,4),(1,2))  | 0.707106781187
+ <(3,5),0>      | ((1,2),(7,8),(5,6),(3,-4)) | 0.707106781187
+ <(3,5),0>      | ((0,0))                    |  5.83095189485
+ <(3,5),0>      | ((0,1),(0,1))              |              5
+ <(3,5),NaN>    | ((2,0),(2,4),(0,0))        |            NaN
+ <(3,5),NaN>    | ((3,1),(3,3),(1,0))        |            NaN
+ <(3,5),NaN>    | ((1,2),(3,4),(5,6),(7,8))  |            NaN
+ <(3,5),NaN>    | ((7,8),(5,6),(3,4),(1,2))  |            NaN
+ <(3,5),NaN>    | ((1,2),(7,8),(5,6),(3,-4)) |            NaN
+ <(3,5),NaN>    | ((0,0))                    |            NaN
+ <(3,5),NaN>    | ((0,1),(0,1))              |            NaN
+(56 rows)
 
diff --git a/src/test/regress/expected/geometry_1.out b/src/test/regress/expected/geometry_1.out
deleted file mode 100644
index 3b92e23059..0000000000
--- a/src/test/regress/expected/geometry_1.out
+++ /dev/null
@@ -1,563 +0,0 @@
---
--- GEOMETRY
---
--- Back off displayed precision a little bit to reduce platform-to-platform
--- variation in results.
-SET extra_float_digits TO -3;
---
--- Points
---
-SELECT '' AS four, center(f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS four, (@@ f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS six, point(f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS six, (@@ f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS two, (@@ f1) AS center
-   FROM POLYGON_TBL
-   WHERE (# f1) > 2;
- two |            center             
------+-------------------------------
-     | (1.33333333333,1.33333333333)
-     | (2.33333333333,1.33333333333)
-(2 rows)
-
--- "is horizontal" function
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is horizontal" operator
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is vertical" function
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE isvertical(p1.f1, point '(5.1,34.5)');
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
--- "is vertical" operator
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?| point '(5.1,34.5)';
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
---
--- Line segments
---
--- intersection
-SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-   FROM LSEG_TBL l, POINT_TBL p;
-ERROR:  operator does not exist: lseg # point
-LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-                                           ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
-
---
--- Boxes
---
-SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
- six |                              box                               
------+----------------------------------------------------------------
-     | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
-     | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
-     | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
-     | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
-     | (107.071067812,207.071067812),(92.9289321881,192.928932188)
-     | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
-
--- translation
-SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (-8,2),(-10,0)
-            | (-7,3),(-9,1)
-            | (-7.5,3.5),(-7.5,2.5)
-            | (-7,3),(-7,3)
-            | (-1,6),(-3,4)
-            | (0,7),(-2,5)
-            | (-0.5,7.5),(-0.5,6.5)
-            | (0,7),(0,7)
-            | (7.1,36.5),(5.1,34.5)
-            | (8.1,37.5),(6.1,35.5)
-            | (7.6,38),(7.6,37)
-            | (8.1,37.5),(8.1,37.5)
-            | (-3,-10),(-5,-12)
-            | (-2,-9),(-4,-11)
-            | (-2.5,-8.5),(-2.5,-9.5)
-            | (-2,-9),(-2,-9)
-            | (12,12),(10,10)
-            | (13,13),(11,11)
-            | (12.5,13.5),(12.5,12.5)
-            | (13,13),(13,13)
-(24 rows)
-
-SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (12,2),(10,0)
-            | (13,3),(11,1)
-            | (12.5,3.5),(12.5,2.5)
-            | (13,3),(13,3)
-            | (5,-2),(3,-4)
-            | (6,-1),(4,-3)
-            | (5.5,-0.5),(5.5,-1.5)
-            | (6,-1),(6,-1)
-            | (-3.1,-32.5),(-5.1,-34.5)
-            | (-2.1,-31.5),(-4.1,-33.5)
-            | (-2.6,-31),(-2.6,-32)
-            | (-2.1,-31.5),(-2.1,-31.5)
-            | (7,14),(5,12)
-            | (8,15),(6,13)
-            | (7.5,15.5),(7.5,14.5)
-            | (8,15),(8,15)
-            | (-8,-8),(-10,-10)
-            | (-7,-7),(-9,-9)
-            | (-7.5,-6.5),(-7.5,-7.5)
-            | (-7,-7),(-7,-7)
-(24 rows)
-
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
-
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,0),(-0.2,-0.2)
-        | (0.08,0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
-
-SELECT f1::box
-	FROM POINT_TBL;
-          f1           
------------------------
- (0,0),(0,0)
- (-10,0),(-10,0)
- (-3,4),(-3,4)
- (5.1,34.5),(5.1,34.5)
- (-5,-12),(-5,-12)
- (10,10),(10,10)
-(6 rows)
-
-SELECT bound_box(a.f1, b.f1)
-	FROM BOX_TBL a, BOX_TBL b;
-      bound_box      
----------------------
- (2,2),(0,0)
- (3,3),(0,0)
- (2.5,3.5),(0,0)
- (3,3),(0,0)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(1,1)
- (3,3),(1,1)
- (2.5,3.5),(0,0)
- (3,3.5),(1,1)
- (2.5,3.5),(2.5,2.5)
- (3,3.5),(2.5,2.5)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(2.5,2.5)
- (3,3),(3,3)
-(16 rows)
-
---
--- Paths
---
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
-
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
-
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
-
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
-
---
--- Polygons
---
--- containment
-SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
-   FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
-      |       3 | ((2,0),(2,4),(0,0))
-      |       3 | ((3,1),(3,3),(1,0))
-      |       1 | ((0,0))
-      |       2 | ((0,1),(0,1))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM BOX_TBL;
- four |                  polygon                  
-------+-------------------------------------------
-      | ((0,0),(0,2),(2,2),(2,0))
-      | ((1,1),(1,3),(3,3),(3,1))
-      | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
-      | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM PATH_TBL WHERE isclosed(f1);
- four |      polygon      
-------+-------------------
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((11,12),(13,14))
-(4 rows)
-
-SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
-   FROM PATH_TBL
-   WHERE isopen(f1);
- four |         open_path         |          polygon          
-------+---------------------------+---------------------------
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(11,12),(13,14)]         | ((11,12),(13,14))
-(4 rows)
-
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
-
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
-
---
--- Circles
---
-SELECT '' AS six, circle(f1, 50.0)
-   FROM POINT_TBL;
- six |     circle      
------+-----------------
-     | <(0,0),50>
-     | <(-10,0),50>
-     | <(-3,4),50>
-     | <(5.1,34.5),50>
-     | <(-5,-12),50>
-     | <(10,10),50>
-(6 rows)
-
-SELECT '' AS four, circle(f1)
-   FROM BOX_TBL;
- four |        circle         
-------+-----------------------
-      | <(1,1),1.41421356237>
-      | <(2,2),1.41421356237>
-      | <(2.5,3),0.5>
-      | <(3,3),0>
-(4 rows)
-
-SELECT '' AS two, circle(f1)
-   FROM POLYGON_TBL
-   WHERE (# f1) >= 3;
- two |                    circle                     
------+-----------------------------------------------
-     | <(1.33333333333,1.33333333333),2.04168905064>
-     | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
-
-SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
-   FROM CIRCLE_TBL c1, POINT_TBL p1
-   WHERE (p1.f1 <-> c1.f1) > 0
-   ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
-
diff --git a/src/test/regress/expected/geometry_2.out b/src/test/regress/expected/geometry_2.out
deleted file mode 100644
index 5a922bcd3f..0000000000
--- a/src/test/regress/expected/geometry_2.out
+++ /dev/null
@@ -1,563 +0,0 @@
---
--- GEOMETRY
---
--- Back off displayed precision a little bit to reduce platform-to-platform
--- variation in results.
-SET extra_float_digits TO -3;
---
--- Points
---
-SELECT '' AS four, center(f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS four, (@@ f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS six, point(f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS six, (@@ f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS two, (@@ f1) AS center
-   FROM POLYGON_TBL
-   WHERE (# f1) > 2;
- two |            center             
------+-------------------------------
-     | (1.33333333333,1.33333333333)
-     | (2.33333333333,1.33333333333)
-(2 rows)
-
--- "is horizontal" function
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is horizontal" operator
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is vertical" function
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE isvertical(p1.f1, point '(5.1,34.5)');
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
--- "is vertical" operator
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?| point '(5.1,34.5)';
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
---
--- Line segments
---
--- intersection
-SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-   FROM LSEG_TBL l, POINT_TBL p;
-ERROR:  operator does not exist: lseg # point
-LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-                                           ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
-
---
--- Boxes
---
-SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
- six |                              box                               
------+----------------------------------------------------------------
-     | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
-     | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
-     | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
-     | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
-     | (107.071067812,207.071067812),(92.9289321881,192.928932188)
-     | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
-
--- translation
-SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (-8,2),(-10,0)
-            | (-7,3),(-9,1)
-            | (-7.5,3.5),(-7.5,2.5)
-            | (-7,3),(-7,3)
-            | (-1,6),(-3,4)
-            | (0,7),(-2,5)
-            | (-0.5,7.5),(-0.5,6.5)
-            | (0,7),(0,7)
-            | (7.1,36.5),(5.1,34.5)
-            | (8.1,37.5),(6.1,35.5)
-            | (7.6,38),(7.6,37)
-            | (8.1,37.5),(8.1,37.5)
-            | (-3,-10),(-5,-12)
-            | (-2,-9),(-4,-11)
-            | (-2.5,-8.5),(-2.5,-9.5)
-            | (-2,-9),(-2,-9)
-            | (12,12),(10,10)
-            | (13,13),(11,11)
-            | (12.5,13.5),(12.5,12.5)
-            | (13,13),(13,13)
-(24 rows)
-
-SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (12,2),(10,0)
-            | (13,3),(11,1)
-            | (12.5,3.5),(12.5,2.5)
-            | (13,3),(13,3)
-            | (5,-2),(3,-4)
-            | (6,-1),(4,-3)
-            | (5.5,-0.5),(5.5,-1.5)
-            | (6,-1),(6,-1)
-            | (-3.1,-32.5),(-5.1,-34.5)
-            | (-2.1,-31.5),(-4.1,-33.5)
-            | (-2.6,-31),(-2.6,-32)
-            | (-2.1,-31.5),(-2.1,-31.5)
-            | (7,14),(5,12)
-            | (8,15),(6,13)
-            | (7.5,15.5),(7.5,14.5)
-            | (8,15),(8,15)
-            | (-8,-8),(-10,-10)
-            | (-7,-7),(-9,-9)
-            | (-7.5,-6.5),(-7.5,-7.5)
-            | (-7,-7),(-7,-7)
-(24 rows)
-
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (-0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (-0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,-0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
-
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,-0),(-0.2,-0.2)
-        | (0.08,-0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (-0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
-
-SELECT f1::box
-	FROM POINT_TBL;
-          f1           
------------------------
- (0,0),(0,0)
- (-10,0),(-10,0)
- (-3,4),(-3,4)
- (5.1,34.5),(5.1,34.5)
- (-5,-12),(-5,-12)
- (10,10),(10,10)
-(6 rows)
-
-SELECT bound_box(a.f1, b.f1)
-	FROM BOX_TBL a, BOX_TBL b;
-      bound_box      
----------------------
- (2,2),(0,0)
- (3,3),(0,0)
- (2.5,3.5),(0,0)
- (3,3),(0,0)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(1,1)
- (3,3),(1,1)
- (2.5,3.5),(0,0)
- (3,3.5),(1,1)
- (2.5,3.5),(2.5,2.5)
- (3,3.5),(2.5,2.5)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(2.5,2.5)
- (3,3),(3,3)
-(16 rows)
-
---
--- Paths
---
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
-
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
-
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
-
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
-
---
--- Polygons
---
--- containment
-SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
-   FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
-      |       3 | ((2,0),(2,4),(0,0))
-      |       3 | ((3,1),(3,3),(1,0))
-      |       1 | ((0,0))
-      |       2 | ((0,1),(0,1))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM BOX_TBL;
- four |                  polygon                  
-------+-------------------------------------------
-      | ((0,0),(0,2),(2,2),(2,0))
-      | ((1,1),(1,3),(3,3),(3,1))
-      | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
-      | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM PATH_TBL WHERE isclosed(f1);
- four |      polygon      
-------+-------------------
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((11,12),(13,14))
-(4 rows)
-
-SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
-   FROM PATH_TBL
-   WHERE isopen(f1);
- four |         open_path         |          polygon          
-------+---------------------------+---------------------------
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(11,12),(13,14)]         | ((11,12),(13,14))
-(4 rows)
-
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
-
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
-
---
--- Circles
---
-SELECT '' AS six, circle(f1, 50.0)
-   FROM POINT_TBL;
- six |     circle      
------+-----------------
-     | <(0,0),50>
-     | <(-10,0),50>
-     | <(-3,4),50>
-     | <(5.1,34.5),50>
-     | <(-5,-12),50>
-     | <(10,10),50>
-(6 rows)
-
-SELECT '' AS four, circle(f1)
-   FROM BOX_TBL;
- four |        circle         
-------+-----------------------
-      | <(1,1),1.41421356237>
-      | <(2,2),1.41421356237>
-      | <(2.5,3),0.5>
-      | <(3,3),0>
-(4 rows)
-
-SELECT '' AS two, circle(f1)
-   FROM POLYGON_TBL
-   WHERE (# f1) >= 3;
- two |                    circle                     
------+-----------------------------------------------
-     | <(1.33333333333,1.33333333333),2.04168905064>
-     | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
-
-SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
-   FROM CIRCLE_TBL c1, POINT_TBL p1
-   WHERE (p1.f1 <-> c1.f1) > 0
-   ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
-
diff --git a/src/test/regress/expected/line.out b/src/test/regress/expected/line.out
index f20abdc430..34d0659519 100644
--- a/src/test/regress/expected/line.out
+++ b/src/test/regress/expected/line.out
@@ -1,271 +1,80 @@
 --
 -- LINE
 -- Infinite lines
 --
 --DROP TABLE LINE_TBL;
 CREATE TABLE LINE_TBL (s line);
-INSERT INTO LINE_TBL VALUES ('{1,-1,1}');
-INSERT INTO LINE_TBL VALUES ('(0,0),(6,6)');
+INSERT INTO LINE_TBL VALUES ('{0,-1,5}');	-- A == 0
+INSERT INTO LINE_TBL VALUES ('{1,0,5}');	-- B == 0
+INSERT INTO LINE_TBL VALUES ('{0,3,0}');	-- A == C == 0
+INSERT INTO LINE_TBL VALUES (' (0,0), (6,6)');
 INSERT INTO LINE_TBL VALUES ('10,-10 ,-5,-4');
 INSERT INTO LINE_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LINE_TBL VALUES ('(11,22,33,44)');
-INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
-ERROR:  invalid line specification: must be two distinct points
-LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
-                                     ^
+INSERT INTO LINE_TBL VALUES (line(point '(1,0)', point '(1,0)'));
+INSERT INTO LINE_TBL VALUES ('{3,NaN,5}');
+INSERT INTO LINE_TBL VALUES ('{NaN,NaN,NaN}');
 -- horizontal
 INSERT INTO LINE_TBL VALUES ('[(1,3),(2,3)]');
 -- vertical
 INSERT INTO LINE_TBL VALUES ('[(3,1),(3,2)]');
 -- bad values for parser testing
+INSERT INTO LINE_TBL VALUES ('{}');
+ERROR:  invalid input syntax for type line: "{}"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{}');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0');
+ERROR:  invalid input syntax for type line: "{0"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0,0}');
+ERROR:  invalid input syntax for type line: "{0,0}"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0}');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0,0,1');
+ERROR:  invalid input syntax for type line: "{0,0,1"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1');
+                                     ^
 INSERT INTO LINE_TBL VALUES ('{0,0,1}');
 ERROR:  invalid line specification: A and B cannot both be zero
 LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1}');
                                      ^
+INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
+ERROR:  invalid input syntax for type line: "{0,0,1} x"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
+                                     ^
 INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
 ERROR:  invalid input syntax for type line: "(3asdf,2 ,3,4r2)"
 LINE 1: INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
                                      ^
 INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
 ERROR:  invalid input syntax for type line: "[1,2,3, 4"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
                                      ^
 INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
 ERROR:  invalid input syntax for type line: "[(,2),(3,4)]"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
                                      ^
 INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
 ERROR:  invalid input syntax for type line: "[(1,2),(3,4)"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
                                      ^
+INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
+ERROR:  invalid line specification: must be two distinct points
+LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
+                                     ^
 select * from LINE_TBL;
                       s                      
 ---------------------------------------------
- {1,-1,1}
+ {0,-1,5}
+ {1,0,5}
+ {0,3,0}
  {1,-1,0}
  {-0.4,-1,-6}
  {-0.000184615384615385,-1,15.3846153846154}
- {1,-1,11}
+ {NaN,-1,NaN}
+ {3,NaN,5}
+ {NaN,NaN,NaN}
  {0,-1,3}
  {-1,0,3}
-(7 rows)
-
--- functions and operators
-SELECT * FROM LINE_TBL WHERE (s <-> line '[(1,2),(3,4)]') < 10;
-                      s                      
----------------------------------------------
- {1,-1,1}
- {1,-1,0}
- {-0.4,-1,-6}
- {-0.000184615384615385,-1,15.3846153846154}
- {1,-1,11}
- {0,-1,3}
- {-1,0,3}
-(7 rows)
-
-SELECT * FROM LINE_TBL WHERE (point '(0.1,0.1)' <-> s) < 1;
-    s     
-----------
- {1,-1,1}
- {1,-1,0}
-(2 rows)
-
-SELECT * FROM LINE_TBL WHERE (lseg '[(0.1,0.1),(0.2,0.2)]' <-> s) < 1;
-    s     
-----------
- {1,-1,1}
- {1,-1,0}
-(2 rows)
-
-SELECT line '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
- ?column? 
-----------
-        2
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
- ?column? 
-----------
-        2
-(1 row)
-
-SELECT point '(-1,1)' <-> line '[(-3,0),(-4,0)]';
- ?column? 
-----------
-        1
-(1 row)
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(2,0),(0,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# box '(0,0,2,2)';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(3,0),(4,1)]' ?# box '(0,0,2,2)';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(1,1)' <@ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT point '(1,1)' <@ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(1,1)' @ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT point '(1,1)' @ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT lseg '[(1,1),(2,2)]' <@ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' <@ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT lseg '[(1,1),(2,2)]' @ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' @ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(0,1)' ## line '[(0,0),(1,1)]';
- ?column?  
------------
- (0.5,0.5)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ## lseg '[(1,0),(2,0)]';
- ?column? 
-----------
- (1,0)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(2,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(1,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(2,1)]';
- ?column? 
-----------
- 
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(1,1)]';
- ?column? 
-----------
- (1,1)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(2,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,0)]' ?-| line '[(0,0),(0,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?-| line '[(1,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT ?- line '[(0,0),(1,0)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT ?- line '[(0,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT ?| line '[(0,0),(0,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT ?| line '[(0,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line(point '(1,2)', point '(3,4)');
-   line   
-----------
- {1,-1,1}
-(1 row)
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,5)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,4)]';  -- false
- ?column? 
-----------
- f
-(1 row)
+(11 rows)
 
diff --git a/src/test/regress/expected/lseg.out b/src/test/regress/expected/lseg.out
index bba1f3ee80..7e878b5577 100644
--- a/src/test/regress/expected/lseg.out
+++ b/src/test/regress/expected/lseg.out
@@ -1,21 +1,24 @@
 --
 -- LSEG
 -- Line segments
 --
 --DROP TABLE LSEG_TBL;
 CREATE TABLE LSEG_TBL (s lseg);
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('(0,0),(6,6)');
 INSERT INTO LSEG_TBL VALUES ('10,-10 ,-3,-4');
 INSERT INTO LSEG_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LSEG_TBL VALUES ('(11,22,33,44)');
+INSERT INTO LSEG_TBL VALUES (lseg(point(11, 22), point(33,44)));
+INSERT INTO LSEG_TBL VALUES ('[(-10,2),(-10,3)]');	-- vertical
+INSERT INTO LSEG_TBL VALUES ('[(0,-20),(30,-20)]');	-- horizontal
+INSERT INTO LSEG_TBL VALUES ('[(NaN,1),(NaN,90)]');	-- NaN
 -- bad values for parser testing
 INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
 ERROR:  invalid input syntax for type lseg: "(3asdf,2 ,3,4r2)"
 LINE 1: INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
                                      ^
 INSERT INTO LSEG_TBL VALUES ('[1,2,3, 4');
 ERROR:  invalid input syntax for type lseg: "[1,2,3, 4"
 LINE 1: INSERT INTO LSEG_TBL VALUES ('[1,2,3, 4');
                                      ^
 INSERT INTO LSEG_TBL VALUES ('[(,2),(3,4)]');
@@ -27,26 +30,15 @@ ERROR:  invalid input syntax for type lseg: "[(1,2),(3,4)"
 LINE 1: INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)');
                                      ^
 select * from LSEG_TBL;
                s               
 -------------------------------
  [(1,2),(3,4)]
  [(0,0),(6,6)]
  [(10,-10),(-3,-4)]
  [(-1000000,200),(300000,-40)]
  [(11,22),(33,44)]
-(5 rows)
-
-SELECT * FROM LSEG_TBL WHERE s <= lseg '[(1,2),(3,4)]';
-       s       
----------------
- [(1,2),(3,4)]
-(1 row)
-
-SELECT * FROM LSEG_TBL WHERE (s <-> lseg '[(1,2),(3,4)]') < 10;
-         s          
---------------------
- [(1,2),(3,4)]
- [(0,0),(6,6)]
- [(10,-10),(-3,-4)]
-(3 rows)
+ [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]
+ [(NaN,1),(NaN,90)]
+(8 rows)
 
diff --git a/src/test/regress/expected/path.out b/src/test/regress/expected/path.out
index 08d6d61dda..bd6e467752 100644
--- a/src/test/regress/expected/path.out
+++ b/src/test/regress/expected/path.out
@@ -1,79 +1,82 @@
 --
 -- PATH
 --
 --DROP TABLE PATH_TBL;
 CREATE TABLE PATH_TBL (f1 path);
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)]');
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
-INSERT INTO PATH_TBL VALUES ('[(0,0),(3,0),(4,5),(1,6)]');
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
-INSERT INTO PATH_TBL VALUES ('1,2 ,3,4');
-INSERT INTO PATH_TBL VALUES ('[1,2,3, 4]');
-INSERT INTO PATH_TBL VALUES ('[11,12,13,14]');
-INSERT INTO PATH_TBL VALUES ('(11,12,13,14)');
+INSERT INTO PATH_TBL VALUES (' ( ( 1 , 2 ) , ( 3 , 4 ) ) ');
+INSERT INTO PATH_TBL VALUES ('[ (0,0),(3,0),(4,5),(1,6) ]');
+INSERT INTO PATH_TBL VALUES ('((1,2) ,(3,4 ))');
+INSERT INTO PATH_TBL VALUES ('1,2 ,3,4 ');
+INSERT INTO PATH_TBL VALUES (' [1,2,3, 4] ');
+INSERT INTO PATH_TBL VALUES ('((10,20))');	-- Only one point
+INSERT INTO PATH_TBL VALUES ('[ 11,12,13,14 ]');
+INSERT INTO PATH_TBL VALUES ('( 11,12,13,14) ');
 -- bad values for parser testing
+INSERT INTO PATH_TBL VALUES ('[]');
+ERROR:  invalid input syntax for type path: "[]"
+LINE 1: INSERT INTO PATH_TBL VALUES ('[]');
+                                     ^
 INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
 ERROR:  invalid input syntax for type path: "[(,2),(3,4)]"
 LINE 1: INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
                                      ^
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
 ERROR:  invalid input syntax for type path: "[(1,2),(3,4)"
 LINE 1: INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
                                      ^
-SELECT f1 FROM PATH_TBL;
-            f1             
----------------------------
- [(1,2),(3,4)]
- ((1,2),(3,4))
- [(0,0),(3,0),(4,5),(1,6)]
- ((1,2),(3,4))
- ((1,2),(3,4))
- [(1,2),(3,4)]
- [(11,12),(13,14)]
- ((11,12),(13,14))
-(8 rows)
-
+INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+ERROR:  invalid input syntax for type path: "(1,2,3,4"
+LINE 1: INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+                                     ^
+INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
+ERROR:  invalid input syntax for type path: "(1,2),(3,4)]"
+LINE 1: INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
+                                     ^
 SELECT '' AS count, f1 AS open_path FROM PATH_TBL WHERE isopen(f1);
  count |         open_path         
 -------+---------------------------
        | [(1,2),(3,4)]
        | [(0,0),(3,0),(4,5),(1,6)]
        | [(1,2),(3,4)]
        | [(11,12),(13,14)]
 (4 rows)
 
 SELECT '' AS count, f1 AS closed_path FROM PATH_TBL WHERE isclosed(f1);
  count |    closed_path    
 -------+-------------------
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
+       | ((10,20))
        | ((11,12),(13,14))
-(4 rows)
+(5 rows)
 
 SELECT '' AS count, pclose(f1) AS closed_path FROM PATH_TBL;
  count |        closed_path        
 -------+---------------------------
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((0,0),(3,0),(4,5),(1,6))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
+       | ((10,20))
        | ((11,12),(13,14))
        | ((11,12),(13,14))
-(8 rows)
+(9 rows)
 
 SELECT '' AS count, popen(f1) AS open_path FROM PATH_TBL;
  count |         open_path         
 -------+---------------------------
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
        | [(0,0),(3,0),(4,5),(1,6)]
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
+       | [(10,20)]
        | [(11,12),(13,14)]
        | [(11,12),(13,14)]
-(8 rows)
+(9 rows)
 
diff --git a/src/test/regress/expected/point.out b/src/test/regress/expected/point.out
index bfc0962749..c18e865370 100644
--- a/src/test/regress/expected/point.out
+++ b/src/test/regress/expected/point.out
@@ -1,43 +1,57 @@
 --
 -- POINT
 --
 CREATE TABLE POINT_TBL(f1 point);
 INSERT INTO POINT_TBL(f1) VALUES ('(0.0,0.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-10.0,0.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-3.0,4.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(5.1, 34.5)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-5.0,-12.0)');
+INSERT INTO POINT_TBL(f1) VALUES ('(1e-300,-1e-300)');	-- To underflow
+INSERT INTO POINT_TBL(f1) VALUES ('(1e+300,Inf)');		-- To overflow
+INSERT INTO POINT_TBL(f1) VALUES (' ( Nan , NaN ) ');
 -- bad format points
 INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
 ERROR:  invalid input syntax for type point: "asdfasdf"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
                                           ^
 INSERT INTO POINT_TBL(f1) VALUES ('10.0,10.0');
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
 ERROR:  invalid input syntax for type point: "(10.0 10.0)"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
                                           ^
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+ERROR:  invalid input syntax for type point: "(10.0, 10.0) x"
+LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+                                          ^
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
 ERROR:  invalid input syntax for type point: "(10.0,10.0"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
                                           ^
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');	-- Out of range
+ERROR:  "1e+500" is out of range for type double precision
+LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');
+                                          ^
 SELECT '' AS six, * FROM POINT_TBL;
- six |     f1     
------+------------
+ six |        f1         
+-----+-------------------
      | (0,0)
      | (-10,0)
      | (-3,4)
      | (5.1,34.5)
      | (-5,-12)
+     | (1e-300,-1e-300)
+     | (1e+300,Infinity)
+     | (NaN,NaN)
      | (10,10)
-(6 rows)
+(9 rows)
 
 -- left of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE p.f1 << '(0.0, 0.0)';
  three |    f1    
 -------+----------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
 (3 rows)
 
@@ -85,172 +99,282 @@ 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    
--------+----------
+ three |        f1         
+-------+-------------------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
-(3 rows)
+       | (1e-300,-1e-300)
+       | (1e+300,Infinity)
+       | (NaN,NaN)
+(6 rows)
 
 SELECT '' AS two, p.* FROM POINT_TBL p
    WHERE p.f1 <@ path '[(0,0),(-10,0),(-10,10)]';
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 SELECT '' AS three, p.* FROM POINT_TBL p
    WHERE not box '(0,0,100,100)' @> p.f1;
- three |    f1    
--------+----------
+ three |        f1         
+-------+-------------------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
-(3 rows)
+       | (1e-300,-1e-300)
+       | (1e+300,Infinity)
+       | (NaN,NaN)
+(6 rows)
 
 SELECT '' AS six, p.f1, p.f1 <-> point '(0,0)' AS dist
    FROM POINT_TBL p
    ORDER BY dist;
- six |     f1     |       dist       
------+------------+------------------
-     | (0,0)      |                0
-     | (-3,4)     |                5
-     | (-10,0)    |               10
-     | (-5,-12)   |               13
-     | (10,10)    |  14.142135623731
-     | (5.1,34.5) | 34.8749193547455
-(6 rows)
+ six |        f1         |         dist         
+-----+-------------------+----------------------
+     | (0,0)             |                    0
+     | (1e-300,-1e-300)  | 1.4142135623731e-300
+     | (-3,4)            |                    5
+     | (-10,0)           |                   10
+     | (-5,-12)          |                   13
+     | (10,10)           |      14.142135623731
+     | (5.1,34.5)        |     34.8749193547455
+     | (1e+300,Infinity) |             Infinity
+     | (NaN,NaN)         |                  NaN
+(9 rows)
 
 SELECT '' AS thirtysix, p1.f1 AS point1, p2.f1 AS point2, p1.f1 <-> p2.f1 AS dist
    FROM POINT_TBL p1, POINT_TBL p2
    ORDER BY dist, p1.f1[0], p2.f1[0];
- thirtysix |   point1   |   point2   |       dist       
------------+------------+------------+------------------
-           | (-10,0)    | (-10,0)    |                0
-           | (-5,-12)   | (-5,-12)   |                0
-           | (-3,4)     | (-3,4)     |                0
-           | (0,0)      | (0,0)      |                0
-           | (5.1,34.5) | (5.1,34.5) |                0
-           | (10,10)    | (10,10)    |                0
-           | (-3,4)     | (0,0)      |                5
-           | (0,0)      | (-3,4)     |                5
-           | (-10,0)    | (-3,4)     | 8.06225774829855
-           | (-3,4)     | (-10,0)    | 8.06225774829855
-           | (-10,0)    | (0,0)      |               10
-           | (0,0)      | (-10,0)    |               10
-           | (-10,0)    | (-5,-12)   |               13
-           | (-5,-12)   | (-10,0)    |               13
-           | (-5,-12)   | (0,0)      |               13
-           | (0,0)      | (-5,-12)   |               13
-           | (0,0)      | (10,10)    |  14.142135623731
-           | (10,10)    | (0,0)      |  14.142135623731
-           | (-3,4)     | (10,10)    | 14.3178210632764
-           | (10,10)    | (-3,4)     | 14.3178210632764
-           | (-5,-12)   | (-3,4)     | 16.1245154965971
-           | (-3,4)     | (-5,-12)   | 16.1245154965971
-           | (-10,0)    | (10,10)    | 22.3606797749979
-           | (10,10)    | (-10,0)    | 22.3606797749979
-           | (5.1,34.5) | (10,10)    | 24.9851956166046
-           | (10,10)    | (5.1,34.5) | 24.9851956166046
-           | (-5,-12)   | (10,10)    | 26.6270539113887
-           | (10,10)    | (-5,-12)   | 26.6270539113887
-           | (-3,4)     | (5.1,34.5) | 31.5572495632937
-           | (5.1,34.5) | (-3,4)     | 31.5572495632937
-           | (0,0)      | (5.1,34.5) | 34.8749193547455
-           | (5.1,34.5) | (0,0)      | 34.8749193547455
-           | (-10,0)    | (5.1,34.5) | 37.6597928831267
-           | (5.1,34.5) | (-10,0)    | 37.6597928831267
-           | (-5,-12)   | (5.1,34.5) | 47.5842410888311
-           | (5.1,34.5) | (-5,-12)   | 47.5842410888311
-(36 rows)
+ thirtysix |      point1       |      point2       |         dist         
+-----------+-------------------+-------------------+----------------------
+           | (-10,0)           | (-10,0)           |                    0
+           | (-5,-12)          | (-5,-12)          |                    0
+           | (-3,4)            | (-3,4)            |                    0
+           | (0,0)             | (0,0)             |                    0
+           | (1e-300,-1e-300)  | (1e-300,-1e-300)  |                    0
+           | (5.1,34.5)        | (5.1,34.5)        |                    0
+           | (10,10)           | (10,10)           |                    0
+           | (0,0)             | (1e-300,-1e-300)  | 1.4142135623731e-300
+           | (1e-300,-1e-300)  | (0,0)             | 1.4142135623731e-300
+           | (-3,4)            | (0,0)             |                    5
+           | (-3,4)            | (1e-300,-1e-300)  |                    5
+           | (0,0)             | (-3,4)            |                    5
+           | (1e-300,-1e-300)  | (-3,4)            |                    5
+           | (-10,0)           | (-3,4)            |     8.06225774829855
+           | (-3,4)            | (-10,0)           |     8.06225774829855
+           | (-10,0)           | (0,0)             |                   10
+           | (-10,0)           | (1e-300,-1e-300)  |                   10
+           | (0,0)             | (-10,0)           |                   10
+           | (1e-300,-1e-300)  | (-10,0)           |                   10
+           | (-10,0)           | (-5,-12)          |                   13
+           | (-5,-12)          | (-10,0)           |                   13
+           | (-5,-12)          | (0,0)             |                   13
+           | (-5,-12)          | (1e-300,-1e-300)  |                   13
+           | (0,0)             | (-5,-12)          |                   13
+           | (1e-300,-1e-300)  | (-5,-12)          |                   13
+           | (0,0)             | (10,10)           |      14.142135623731
+           | (1e-300,-1e-300)  | (10,10)           |      14.142135623731
+           | (10,10)           | (0,0)             |      14.142135623731
+           | (10,10)           | (1e-300,-1e-300)  |      14.142135623731
+           | (-3,4)            | (10,10)           |     14.3178210632764
+           | (10,10)           | (-3,4)            |     14.3178210632764
+           | (-5,-12)          | (-3,4)            |     16.1245154965971
+           | (-3,4)            | (-5,-12)          |     16.1245154965971
+           | (-10,0)           | (10,10)           |     22.3606797749979
+           | (10,10)           | (-10,0)           |     22.3606797749979
+           | (5.1,34.5)        | (10,10)           |     24.9851956166046
+           | (10,10)           | (5.1,34.5)        |     24.9851956166046
+           | (-5,-12)          | (10,10)           |     26.6270539113887
+           | (10,10)           | (-5,-12)          |     26.6270539113887
+           | (-3,4)            | (5.1,34.5)        |     31.5572495632937
+           | (5.1,34.5)        | (-3,4)            |     31.5572495632937
+           | (0,0)             | (5.1,34.5)        |     34.8749193547455
+           | (1e-300,-1e-300)  | (5.1,34.5)        |     34.8749193547455
+           | (5.1,34.5)        | (0,0)             |     34.8749193547455
+           | (5.1,34.5)        | (1e-300,-1e-300)  |     34.8749193547455
+           | (-10,0)           | (5.1,34.5)        |     37.6597928831267
+           | (5.1,34.5)        | (-10,0)           |     37.6597928831267
+           | (-5,-12)          | (5.1,34.5)        |     47.5842410888311
+           | (5.1,34.5)        | (-5,-12)          |     47.5842410888311
+           | (-10,0)           | (1e+300,Infinity) |             Infinity
+           | (-5,-12)          | (1e+300,Infinity) |             Infinity
+           | (-3,4)            | (1e+300,Infinity) |             Infinity
+           | (0,0)             | (1e+300,Infinity) |             Infinity
+           | (1e-300,-1e-300)  | (1e+300,Infinity) |             Infinity
+           | (5.1,34.5)        | (1e+300,Infinity) |             Infinity
+           | (10,10)           | (1e+300,Infinity) |             Infinity
+           | (1e+300,Infinity) | (-10,0)           |             Infinity
+           | (1e+300,Infinity) | (-5,-12)          |             Infinity
+           | (1e+300,Infinity) | (-3,4)            |             Infinity
+           | (1e+300,Infinity) | (0,0)             |             Infinity
+           | (1e+300,Infinity) | (1e-300,-1e-300)  |             Infinity
+           | (1e+300,Infinity) | (5.1,34.5)        |             Infinity
+           | (1e+300,Infinity) | (10,10)           |             Infinity
+           | (-10,0)           | (NaN,NaN)         |                  NaN
+           | (-5,-12)          | (NaN,NaN)         |                  NaN
+           | (-3,4)            | (NaN,NaN)         |                  NaN
+           | (0,0)             | (NaN,NaN)         |                  NaN
+           | (1e-300,-1e-300)  | (NaN,NaN)         |                  NaN
+           | (5.1,34.5)        | (NaN,NaN)         |                  NaN
+           | (10,10)           | (NaN,NaN)         |                  NaN
+           | (1e+300,Infinity) | (1e+300,Infinity) |                  NaN
+           | (1e+300,Infinity) | (NaN,NaN)         |                  NaN
+           | (NaN,NaN)         | (-10,0)           |                  NaN
+           | (NaN,NaN)         | (-5,-12)          |                  NaN
+           | (NaN,NaN)         | (-3,4)            |                  NaN
+           | (NaN,NaN)         | (0,0)             |                  NaN
+           | (NaN,NaN)         | (1e-300,-1e-300)  |                  NaN
+           | (NaN,NaN)         | (5.1,34.5)        |                  NaN
+           | (NaN,NaN)         | (10,10)           |                  NaN
+           | (NaN,NaN)         | (1e+300,Infinity) |                  NaN
+           | (NaN,NaN)         | (NaN,NaN)         |                  NaN
+(81 rows)
 
 SELECT '' AS thirty, p1.f1 AS point1, p2.f1 AS point2
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3;
- thirty |   point1   |   point2   
---------+------------+------------
-        | (0,0)      | (-10,0)
-        | (0,0)      | (-3,4)
-        | (0,0)      | (5.1,34.5)
-        | (0,0)      | (-5,-12)
-        | (0,0)      | (10,10)
-        | (-10,0)    | (0,0)
-        | (-10,0)    | (-3,4)
-        | (-10,0)    | (5.1,34.5)
-        | (-10,0)    | (-5,-12)
-        | (-10,0)    | (10,10)
-        | (-3,4)     | (0,0)
-        | (-3,4)     | (-10,0)
-        | (-3,4)     | (5.1,34.5)
-        | (-3,4)     | (-5,-12)
-        | (-3,4)     | (10,10)
-        | (5.1,34.5) | (0,0)
-        | (5.1,34.5) | (-10,0)
-        | (5.1,34.5) | (-3,4)
-        | (5.1,34.5) | (-5,-12)
-        | (5.1,34.5) | (10,10)
-        | (-5,-12)   | (0,0)
-        | (-5,-12)   | (-10,0)
-        | (-5,-12)   | (-3,4)
-        | (-5,-12)   | (5.1,34.5)
-        | (-5,-12)   | (10,10)
-        | (10,10)    | (0,0)
-        | (10,10)    | (-10,0)
-        | (10,10)    | (-3,4)
-        | (10,10)    | (5.1,34.5)
-        | (10,10)    | (-5,-12)
-(30 rows)
+ thirty |      point1       |      point2       
+--------+-------------------+-------------------
+        | (0,0)             | (-10,0)
+        | (0,0)             | (-3,4)
+        | (0,0)             | (5.1,34.5)
+        | (0,0)             | (-5,-12)
+        | (0,0)             | (1e+300,Infinity)
+        | (0,0)             | (NaN,NaN)
+        | (0,0)             | (10,10)
+        | (-10,0)           | (0,0)
+        | (-10,0)           | (-3,4)
+        | (-10,0)           | (5.1,34.5)
+        | (-10,0)           | (-5,-12)
+        | (-10,0)           | (1e-300,-1e-300)
+        | (-10,0)           | (1e+300,Infinity)
+        | (-10,0)           | (NaN,NaN)
+        | (-10,0)           | (10,10)
+        | (-3,4)            | (0,0)
+        | (-3,4)            | (-10,0)
+        | (-3,4)            | (5.1,34.5)
+        | (-3,4)            | (-5,-12)
+        | (-3,4)            | (1e-300,-1e-300)
+        | (-3,4)            | (1e+300,Infinity)
+        | (-3,4)            | (NaN,NaN)
+        | (-3,4)            | (10,10)
+        | (5.1,34.5)        | (0,0)
+        | (5.1,34.5)        | (-10,0)
+        | (5.1,34.5)        | (-3,4)
+        | (5.1,34.5)        | (-5,-12)
+        | (5.1,34.5)        | (1e-300,-1e-300)
+        | (5.1,34.5)        | (1e+300,Infinity)
+        | (5.1,34.5)        | (NaN,NaN)
+        | (5.1,34.5)        | (10,10)
+        | (-5,-12)          | (0,0)
+        | (-5,-12)          | (-10,0)
+        | (-5,-12)          | (-3,4)
+        | (-5,-12)          | (5.1,34.5)
+        | (-5,-12)          | (1e-300,-1e-300)
+        | (-5,-12)          | (1e+300,Infinity)
+        | (-5,-12)          | (NaN,NaN)
+        | (-5,-12)          | (10,10)
+        | (1e-300,-1e-300)  | (-10,0)
+        | (1e-300,-1e-300)  | (-3,4)
+        | (1e-300,-1e-300)  | (5.1,34.5)
+        | (1e-300,-1e-300)  | (-5,-12)
+        | (1e-300,-1e-300)  | (1e+300,Infinity)
+        | (1e-300,-1e-300)  | (NaN,NaN)
+        | (1e-300,-1e-300)  | (10,10)
+        | (1e+300,Infinity) | (0,0)
+        | (1e+300,Infinity) | (-10,0)
+        | (1e+300,Infinity) | (-3,4)
+        | (1e+300,Infinity) | (5.1,34.5)
+        | (1e+300,Infinity) | (-5,-12)
+        | (1e+300,Infinity) | (1e-300,-1e-300)
+        | (1e+300,Infinity) | (1e+300,Infinity)
+        | (1e+300,Infinity) | (NaN,NaN)
+        | (1e+300,Infinity) | (10,10)
+        | (NaN,NaN)         | (0,0)
+        | (NaN,NaN)         | (-10,0)
+        | (NaN,NaN)         | (-3,4)
+        | (NaN,NaN)         | (5.1,34.5)
+        | (NaN,NaN)         | (-5,-12)
+        | (NaN,NaN)         | (1e-300,-1e-300)
+        | (NaN,NaN)         | (1e+300,Infinity)
+        | (NaN,NaN)         | (NaN,NaN)
+        | (NaN,NaN)         | (10,10)
+        | (10,10)           | (0,0)
+        | (10,10)           | (-10,0)
+        | (10,10)           | (-3,4)
+        | (10,10)           | (5.1,34.5)
+        | (10,10)           | (-5,-12)
+        | (10,10)           | (1e-300,-1e-300)
+        | (10,10)           | (1e+300,Infinity)
+        | (10,10)           | (NaN,NaN)
+(72 rows)
 
 -- put distance result into output to allow sorting with GEQ optimizer - tgl 97/05/10
 SELECT '' AS fifteen, p1.f1 AS point1, p2.f1 AS point2, (p1.f1 <-> p2.f1) AS distance
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3 and p1.f1 << p2.f1
    ORDER BY distance, p1.f1[0], p2.f1[0];
- fifteen |   point1   |   point2   |     distance     
----------+------------+------------+------------------
-         | (-3,4)     | (0,0)      |                5
-         | (-10,0)    | (-3,4)     | 8.06225774829855
-         | (-10,0)    | (0,0)      |               10
-         | (-10,0)    | (-5,-12)   |               13
-         | (-5,-12)   | (0,0)      |               13
-         | (0,0)      | (10,10)    |  14.142135623731
-         | (-3,4)     | (10,10)    | 14.3178210632764
-         | (-5,-12)   | (-3,4)     | 16.1245154965971
-         | (-10,0)    | (10,10)    | 22.3606797749979
-         | (5.1,34.5) | (10,10)    | 24.9851956166046
-         | (-5,-12)   | (10,10)    | 26.6270539113887
-         | (-3,4)     | (5.1,34.5) | 31.5572495632937
-         | (0,0)      | (5.1,34.5) | 34.8749193547455
-         | (-10,0)    | (5.1,34.5) | 37.6597928831267
-         | (-5,-12)   | (5.1,34.5) | 47.5842410888311
-(15 rows)
+ fifteen |      point1      |      point2       |     distance     
+---------+------------------+-------------------+------------------
+         | (-3,4)           | (0,0)             |                5
+         | (-3,4)           | (1e-300,-1e-300)  |                5
+         | (-10,0)          | (-3,4)            | 8.06225774829855
+         | (-10,0)          | (0,0)             |               10
+         | (-10,0)          | (1e-300,-1e-300)  |               10
+         | (-10,0)          | (-5,-12)          |               13
+         | (-5,-12)         | (0,0)             |               13
+         | (-5,-12)         | (1e-300,-1e-300)  |               13
+         | (0,0)            | (10,10)           |  14.142135623731
+         | (1e-300,-1e-300) | (10,10)           |  14.142135623731
+         | (-3,4)           | (10,10)           | 14.3178210632764
+         | (-5,-12)         | (-3,4)            | 16.1245154965971
+         | (-10,0)          | (10,10)           | 22.3606797749979
+         | (5.1,34.5)       | (10,10)           | 24.9851956166046
+         | (-5,-12)         | (10,10)           | 26.6270539113887
+         | (-3,4)           | (5.1,34.5)        | 31.5572495632937
+         | (0,0)            | (5.1,34.5)        | 34.8749193547455
+         | (1e-300,-1e-300) | (5.1,34.5)        | 34.8749193547455
+         | (-10,0)          | (5.1,34.5)        | 37.6597928831267
+         | (-5,-12)         | (5.1,34.5)        | 47.5842410888311
+         | (-10,0)          | (1e+300,Infinity) |         Infinity
+         | (-5,-12)         | (1e+300,Infinity) |         Infinity
+         | (-3,4)           | (1e+300,Infinity) |         Infinity
+         | (0,0)            | (1e+300,Infinity) |         Infinity
+         | (1e-300,-1e-300) | (1e+300,Infinity) |         Infinity
+         | (5.1,34.5)       | (1e+300,Infinity) |         Infinity
+         | (10,10)          | (1e+300,Infinity) |         Infinity
+(27 rows)
 
 -- put distance result into output to allow sorting with GEQ optimizer - tgl 97/05/10
 SELECT '' AS three, p1.f1 AS point1, p2.f1 AS point2, (p1.f1 <-> p2.f1) AS distance
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3 and p1.f1 << p2.f1 and p1.f1 >^ p2.f1
    ORDER BY distance;
- three |   point1   |  point2  |     distance     
--------+------------+----------+------------------
-       | (-3,4)     | (0,0)    |                5
-       | (-10,0)    | (-5,-12) |               13
-       | (5.1,34.5) | (10,10)  | 24.9851956166046
-(3 rows)
+ three |   point1   |      point2      |     distance     
+-------+------------+------------------+------------------
+       | (-3,4)     | (0,0)            |                5
+       | (-3,4)     | (1e-300,-1e-300) |                5
+       | (-10,0)    | (-5,-12)         |               13
+       | (5.1,34.5) | (10,10)          | 24.9851956166046
+(4 rows)
 
 -- Test that GiST indexes provide same behavior as sequential scan
 CREATE TEMP TABLE point_gist_tbl(f1 point);
 INSERT INTO point_gist_tbl SELECT '(0,0)' FROM generate_series(0,1000);
 CREATE INDEX point_gist_tbl_index ON point_gist_tbl USING gist (f1);
 INSERT INTO point_gist_tbl VALUES ('(0.0000009,0.0000009)');
 SET enable_seqscan TO true;
 SET enable_indexscan TO false;
 SET enable_bitmapscan TO false;
 SELECT COUNT(*) FROM point_gist_tbl WHERE f1 ~= '(0.0000009,0.0000009)'::point;
diff --git a/src/test/regress/expected/polygon.out b/src/test/regress/expected/polygon.out
index 2361274f9e..ba78604d76 100644
--- a/src/test/regress/expected/polygon.out
+++ b/src/test/regress/expected/polygon.out
@@ -1,18 +1,21 @@
 --
 -- POLYGON
 --
 -- polygon logic
 --
 CREATE TABLE POLYGON_TBL(f1 polygon);
 INSERT INTO POLYGON_TBL(f1) VALUES ('(2.0,0.0),(2.0,4.0),(0.0,0.0)');
 INSERT INTO POLYGON_TBL(f1) VALUES ('(3.0,1.0),(3.0,3.0),(1.0,0.0)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(3,4),(5,6),(7,8)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(7,8),(5,6),(3,4),(1,2)'); -- Reverse
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(7,8),(5,6),(3,-4)');
 -- degenerate polygons
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,0.0)');
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,1.0),(0.0,1.0)');
 -- bad polygon input strings
 INSERT INTO POLYGON_TBL(f1) VALUES ('0.0');
 ERROR:  invalid input syntax for type polygon: "0.0"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('0.0');
                                             ^
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0 0.0');
 ERROR:  invalid input syntax for type polygon: "(0.0 0.0"
@@ -24,206 +27,21 @@ LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2)');
                                             ^
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2,3');
 ERROR:  invalid input syntax for type polygon: "(0,1,2,3"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2,3');
                                             ^
 INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
 ERROR:  invalid input syntax for type polygon: "asdf"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
                                             ^
 SELECT '' AS four, * FROM POLYGON_TBL;
- four |         f1          
-------+---------------------
+ four |             f1             
+------+----------------------------
       | ((2,0),(2,4),(0,0))
       | ((3,1),(3,3),(1,0))
+      | ((1,2),(3,4),(5,6),(7,8))
+      | ((7,8),(5,6),(3,4),(1,2))
+      | ((1,2),(7,8),(5,6),(3,-4))
       | ((0,0))
       | ((0,1),(0,1))
-(4 rows)
-
--- overlap
-SELECT '' AS three, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 && '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- three |         f1          
--------+---------------------
-       | ((2,0),(2,4),(0,0))
-       | ((3,1),(3,3),(1,0))
-(2 rows)
-
--- left overlap
-SELECT '' AS four, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &< '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- four |         f1          
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
-
--- right overlap
-SELECT '' AS two, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- two |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- left of
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 << '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |      f1       
------+---------------
-     | ((0,0))
-     | ((0,1),(0,1))
-(2 rows)
-
--- right of
-SELECT '' AS zero, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 >> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- zero | f1 
-------+----
-(0 rows)
-
--- contained
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- same
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- contains
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
---
--- polygon logic
---
--- left of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- left overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
- true 
-------
- f
-(1 row)
-
--- right overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' &> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- right of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' >> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- contained in
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- contains
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((0,4),(6,4),(3,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
-SELECT '((1,1),(1,4),(5,4),(5,3),(2,3),(2,2),(5,2),(5,1))'::polygon @> '((3,2),(3,3),(4,3),(4,2))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((0,0),(0,3),(3,3),(3,0))'::polygon @> '((2,1),(2,2),(3,2),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
--- same
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' && polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
- true 
-------
- t
-(1 row)
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon && '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
-SELECT '((1,4),(1,1),(4,1),(4,2),(2,2),(2,4),(1,4))'::polygon && '((3,3),(4,3),(4,4),(3,4),(3,3))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((200,800),(800,800),(800,200),(200,200))' &&  '(1000,1000,0,0)'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
--- distance from a point
-SELECT	'(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
-	'(1,1)'::point <-> '((0,0),(2,2),(1,3))'::polygon as on_segment,
-	'(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;
- on_corner | on_segment | inside |   near_corner   | near_segment 
------------+------------+--------+-----------------+--------------
-         0 |          0 |      0 | 1.4142135623731 |          3.2
-(1 row)
+(7 rows)
 
diff --git a/src/test/regress/sql/box.sql b/src/test/regress/sql/box.sql
index 135ac108eb..6710fc90f5 100644
--- a/src/test/regress/sql/box.sql
+++ b/src/test/regress/sql/box.sql
@@ -18,29 +18,38 @@
 
 -- boxes are specified by two points, given by four floats x1,y1,x2,y2
 
 
 CREATE TABLE BOX_TBL (f1 box);
 
 INSERT INTO BOX_TBL (f1) VALUES ('(2.0,2.0,0.0,0.0)');
 
 INSERT INTO BOX_TBL (f1) VALUES ('(1.0,1.0,3.0,3.0)');
 
+INSERT INTO BOX_TBL (f1) VALUES ('((-8, 2), (-2, -10))');
+
+
 -- degenerate cases where the box is a line or a point
 -- note that lines and points boxes all have zero area
 INSERT INTO BOX_TBL (f1) VALUES ('(2.5, 2.5, 2.5,3.5)');
 
 INSERT INTO BOX_TBL (f1) VALUES ('(3.0, 3.0,3.0,3.0)');
 
 -- badly formatted box inputs
 INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
 
+INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+
 INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
 
 
 SELECT '' AS four, * FROM BOX_TBL;
 
 SELECT '' AS four, b.*, area(b.f1) as barea
    FROM BOX_TBL b;
 
 -- overlap
 SELECT '' AS three, b.f1
diff --git a/src/test/regress/sql/circle.sql b/src/test/regress/sql/circle.sql
index c0284b2b59..46c96e1400 100644
--- a/src/test/regress/sql/circle.sql
+++ b/src/test/regress/sql/circle.sql
@@ -7,26 +7,34 @@ CREATE TABLE CIRCLE_TBL (f1 circle);
 INSERT INTO CIRCLE_TBL VALUES ('<(5,1),3>');
 
 INSERT INTO CIRCLE_TBL VALUES ('<(1,2),100>');
 
 INSERT INTO CIRCLE_TBL VALUES ('1,3,5');
 
 INSERT INTO CIRCLE_TBL VALUES ('((1,2),3)');
 
 INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10>');
 
-INSERT INTO CIRCLE_TBL VALUES ('<(100,1),115>');
+INSERT INTO CIRCLE_TBL VALUES (' < ( 100 , 1 ) , 115 > ');
+
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),0>');	-- Zero radius
+
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),NaN>');	-- NaN radius
 
 -- bad values
 
 INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
 
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+
 INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
 
 INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
 
 SELECT * FROM CIRCLE_TBL;
 
 SELECT '' AS six, center(f1) AS center
   FROM CIRCLE_TBL;
 
 SELECT '' AS six, radius(f1) AS radius
diff --git a/src/test/regress/sql/geometry.sql b/src/test/regress/sql/geometry.sql
index 1429ee772a..ce98b3e90c 100644
--- a/src/test/regress/sql/geometry.sql
+++ b/src/test/regress/sql/geometry.sql
@@ -39,74 +39,298 @@ SELECT '' AS two, p1.f1
 -- "is vertical" function
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE isvertical(p1.f1, point '(5.1,34.5)');
 
 -- "is vertical" operator
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?| point '(5.1,34.5)';
 
+-- Slope
+SELECT p1.f1, p2.f1, slope(p1.f1, p2.f1) FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Add point
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Subtract point
+SELECT p1.f1, p2.f1, p1.f1 - p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Multiply with point
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+
+-- Underflow error
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] < 1;
+
+-- Divide by point
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] BETWEEN 1 AND 1000;
+
+-- Overflow error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] > 1000;
+
+-- Division by 0 error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1 ~= '(0,0)'::point;
+
+-- Distance to line
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LINE_TBL l;
+
+-- Distance to line segment
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LSEG_TBL l;
+
+-- Distance to box
+SELECT p.f1, b.f1, p.f1 <-> b.f1 FROM POINT_TBL p, BOX_TBL b;
+
+-- Distance to path
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, PATH_TBL p1;
+
+-- Distance to polygon
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, POLYGON_TBL p1;
+
+-- Closest point to line
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LINE_TBL l;
+
+-- Closest point to line segment
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LSEG_TBL l;
+
+-- Closest point to box
+SELECT p.f1, b.f1, p.f1 ## b.f1 FROM POINT_TBL p, BOX_TBL b;
+
+-- On line
+SELECT p.f1, l.s FROM POINT_TBL p, LINE_TBL l WHERE p.f1 <@ l.s;
+
+-- On line segment
+SELECT p.f1, l.s FROM POINT_TBL p, LSEG_TBL l WHERE p.f1 <@ l.s;
+
+-- On path
+SELECT p.f1, p1.f1 FROM POINT_TBL p, PATH_TBL p1 WHERE p.f1 <@ p1.f1;
+
+--
+-- Lines
+--
+
+-- Vertical
+SELECT s FROM LINE_TBL WHERE ?| s;
+
+-- Horizontal
+SELECT s FROM LINE_TBL WHERE ?- s;
+
+-- Same as line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s = l2.s;
+
+-- Parallel to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?|| l2.s;
+
+-- Perpendicular to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?-| l2.s;
+
+-- Distance to line
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2;
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LINE_TBL l, BOX_TBL b;
+
+-- Intersect with line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?# l2.s;
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LINE_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+
+-- Intersection point with line
+SELECT l1.s, l2.s, l1.s # l2.s FROM LINE_TBL l1, LINE_TBL l2;
+
+-- Closest point to line segment
+SELECT l.s, l1.s, l.s ## l1.s FROM LINE_TBL l, LSEG_TBL l1;
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LINE_TBL l, BOX_TBL b;
+
 --
 -- Line segments
 --
 
 -- intersection
 SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
    FROM LSEG_TBL l, POINT_TBL p;
 
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
+-- Length
+SELECT s, @-@ s FROM LSEG_TBL;
+
+-- Vertical
+SELECT s FROM LSEG_TBL WHERE ?| s;
+
+-- Horizontal
+SELECT s FROM LSEG_TBL WHERE ?- s;
+
+-- Center
+SELECT s, @@ s FROM LSEG_TBL;
+
+-- To point
+SELECT s, s::point FROM LSEG_TBL;
+
+-- Has points less than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s < l2.s;
+
+-- Has points less than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s <= l2.s;
+
+-- Has points equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s = l2.s;
+
+-- Has points greater than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s >= l2.s;
+
+-- Has points greater than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s > l2.s;
+
+-- Has points not equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s != l2.s;
+
+-- Parallel with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?|| l2.s;
+
+-- Perpendicular with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?-| l2.s;
+
+-- Distance to line
+SELECT l.s, l1.s, l.s <-> l1.s FROM LSEG_TBL l, LINE_TBL l1;
+
+-- Distance to line segment
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LSEG_TBL l, BOX_TBL b;
+
+-- Intersect with line segment
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s ?# l1.s;
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+
+-- Intersection point with line segment
+SELECT l1.s, l2.s, l1.s # l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Closest point to line
+SELECT l.s, l1.s, l.s ## l1.s FROM LSEG_TBL l, LINE_TBL l1;
+
+-- Closest point to line segment
+SELECT l1.s, l2.s, l1.s ## l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LSEG_TBL l, BOX_TBL b;
+
+-- On line
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s <@ l1.s;
+
+-- On box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s <@ b.f1;
 
 --
 -- Boxes
 --
 
 SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
 
 -- translation
 SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
 
 SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
 
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
+-- Multiply with point
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
 
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
+-- Overflow error
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] > 1000;
 
+-- Divide by point
+SELECT b.f1, p.f1, b.f1 / p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+
+-- To box
 SELECT f1::box
 	FROM POINT_TBL;
 
 SELECT bound_box(a.f1, b.f1)
 	FROM BOX_TBL a, BOX_TBL b;
 
+-- Below box
+SELECT b1.f1, b2.f1, b1.f1 <^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Above box
+SELECT b1.f1, b2.f1, b1.f1 >^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Intersection point with box
+SELECT b1.f1, b2.f1, b1.f1 # b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Diagonal
+SELECT f1, diagonal(f1) FROM BOX_TBL;
+
+-- Distance to box
+SELECT b1.f1, b2.f1, b1.f1 <-> b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
 --
 -- Paths
 --
 
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
+-- Points
+SELECT f1, npoints(f1) FROM PATH_TBL;
 
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
+-- Area
+SELECT f1, area(f1) FROM PATH_TBL;
 
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
+-- Length
+SELECT f1, @-@ f1 FROM PATH_TBL;
 
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
+-- Center
+SELECT f1, @@ f1 FROM PATH_TBL;
+
+-- To polygon
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isclosed(f1);
+
+-- Open path cannot be converted to polygon error
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isopen(f1);
+
+-- Has points less than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 < p2.f1;
+
+-- Has points less than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 <= p2.f1;
+
+-- Has points equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 = p2.f1;
+
+-- Has points greater than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 >= p2.f1;
+
+-- Has points greater than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 > p2.f1;
+
+-- Add path
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+
+-- Add point
+SELECT p.f1, p1.f1, p.f1 + p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+
+-- Subtract point
+SELECT p.f1, p1.f1, p.f1 - p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+
+-- Multiply with point
+SELECT p.f1, p1.f1, p.f1 * p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+
+-- Divide by point
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+
+-- Division by 0 error
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1 ~= '(0,0)'::point;
+
+-- Distance to path
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
 
 --
 -- Polygons
 --
 
 -- containment
 SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
    FROM POLYGON_TBL poly, POINT_TBL p;
 
 SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
@@ -118,36 +342,166 @@ SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
 SELECT '' AS four, polygon(f1)
    FROM BOX_TBL;
 
 SELECT '' AS four, polygon(f1)
    FROM PATH_TBL WHERE isclosed(f1);
 
 SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
    FROM PATH_TBL
    WHERE isopen(f1);
 
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
+-- To box
+SELECT f1, f1::box FROM POLYGON_TBL;
 
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
+-- To path
+SELECT f1, f1::path FROM POLYGON_TBL;
+
+-- Same as polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 ~= p2.f1;
+
+-- Contained by polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <@ p2.f1;
+
+-- Contains polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 @> p2.f1;
+
+-- Overlap with polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 && p2.f1;
+
+-- Left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 << p2.f1;
+
+-- Overlap of left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &< p2.f1;
+
+-- Right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 >> p2.f1;
+
+-- Overlap of right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &> p2.f1;
+
+-- Below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <<| p2.f1;
+
+-- Overlap or below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &<| p2.f1;
+
+-- Above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |>> p2.f1;
+
+-- Overlap or above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |&> p2.f1;
+
+-- Distance to polygon
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2;
 
 --
 -- Circles
 --
 
 SELECT '' AS six, circle(f1, 50.0)
    FROM POINT_TBL;
 
 SELECT '' AS four, circle(f1)
    FROM BOX_TBL;
 
 SELECT '' AS two, circle(f1)
    FROM POLYGON_TBL
    WHERE (# f1) >= 3;
 
 SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
    FROM CIRCLE_TBL c1, POINT_TBL p1
    WHERE (p1.f1 <-> c1.f1) > 0
    ORDER BY distance, area(c1.f1), p1.f1[0];
+
+-- To polygon
+SELECT f1, f1::polygon FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+
+-- To polygon with less points
+SELECT f1, polygon(8, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+
+-- Too less points error
+SELECT f1, polygon(1, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+
+-- Zero radius error
+SELECT f1, polygon(10, f1) FROM CIRCLE_TBL WHERE f1 < '<(0,0),1>';
+
+-- Same as circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 ~= c2.f1;
+
+-- Overlap with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 && c2.f1;
+
+-- Overlap or left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &< c2.f1;
+
+-- Left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 << c2.f1;
+
+-- Right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >> c2.f1;
+
+-- Overlap or right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &> c2.f1;
+
+-- Contained by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <@ c2.f1;
+
+-- Contain by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 @> c2.f1;
+
+-- Below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <<| c2.f1;
+
+-- Above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |>> c2.f1;
+
+-- Overlap or below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &<| c2.f1;
+
+-- Overlap or above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |&> c2.f1;
+
+-- Area equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 = c2.f1;
+
+-- Area not equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 != c2.f1;
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 > c2.f1;
+
+-- Area less than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <= c2.f1;
+
+-- Area greater than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >= c2.f1;
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+
+-- Add point
+SELECT c.f1, p.f1, c.f1 + p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Subtract point
+SELECT c.f1, p.f1, c.f1 - p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Multiply with point
+SELECT c.f1, p.f1, c.f1 * p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Divide by point
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+
+-- Overflow error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] > 1000;
+
+-- Division by 0 error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1 ~= '(0,0)'::point;
+
+-- Distance to polygon
+SELECT c.f1, p.f1, c.f1 <-> p.f1 FROM CIRCLE_TBL c, POLYGON_TBL p;
diff --git a/src/test/regress/sql/line.sql b/src/test/regress/sql/line.sql
index 94067b0cee..4a985020d7 100644
--- a/src/test/regress/sql/line.sql
+++ b/src/test/regress/sql/line.sql
@@ -1,87 +1,39 @@
 --
 -- LINE
 -- Infinite lines
 --
 
 --DROP TABLE LINE_TBL;
 CREATE TABLE LINE_TBL (s line);
 
-INSERT INTO LINE_TBL VALUES ('{1,-1,1}');
-INSERT INTO LINE_TBL VALUES ('(0,0),(6,6)');
+INSERT INTO LINE_TBL VALUES ('{0,-1,5}');	-- A == 0
+INSERT INTO LINE_TBL VALUES ('{1,0,5}');	-- B == 0
+INSERT INTO LINE_TBL VALUES ('{0,3,0}');	-- A == C == 0
+INSERT INTO LINE_TBL VALUES (' (0,0), (6,6)');
 INSERT INTO LINE_TBL VALUES ('10,-10 ,-5,-4');
 INSERT INTO LINE_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LINE_TBL VALUES ('(11,22,33,44)');
 
-INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
+INSERT INTO LINE_TBL VALUES (line(point '(1,0)', point '(1,0)'));
+
+INSERT INTO LINE_TBL VALUES ('{3,NaN,5}');
+INSERT INTO LINE_TBL VALUES ('{NaN,NaN,NaN}');
 
 -- horizontal
 INSERT INTO LINE_TBL VALUES ('[(1,3),(2,3)]');
 -- vertical
 INSERT INTO LINE_TBL VALUES ('[(3,1),(3,2)]');
 
 -- bad values for parser testing
+INSERT INTO LINE_TBL VALUES ('{}');
+INSERT INTO LINE_TBL VALUES ('{0');
+INSERT INTO LINE_TBL VALUES ('{0,0}');
+INSERT INTO LINE_TBL VALUES ('{0,0,1');
 INSERT INTO LINE_TBL VALUES ('{0,0,1}');
+INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
 INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
 INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
 INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
 INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
+INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
 
 select * from LINE_TBL;
-
-
--- functions and operators
-
-SELECT * FROM LINE_TBL WHERE (s <-> line '[(1,2),(3,4)]') < 10;
-
-SELECT * FROM LINE_TBL WHERE (point '(0.1,0.1)' <-> s) < 1;
-
-SELECT * FROM LINE_TBL WHERE (lseg '[(0.1,0.1),(0.2,0.2)]' <-> s) < 1;
-
-SELECT line '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
-SELECT lseg '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
-SELECT point '(-1,1)' <-> line '[(-3,0),(-4,0)]';
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(2,0),(0,2)]';  -- true
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(0,0),(1,0)]';  -- false
-
-SELECT line '[(0,0),(1,1)]' ?# box '(0,0,2,2)';  -- true
-SELECT line '[(3,0),(4,1)]' ?# box '(0,0,2,2)';  -- false
-
-SELECT point '(1,1)' <@ line '[(0,0),(2,2)]';  -- true
-SELECT point '(1,1)' <@ line '[(0,0),(1,0)]';  -- false
-
-SELECT point '(1,1)' @ line '[(0,0),(2,2)]';  -- true
-SELECT point '(1,1)' @ line '[(0,0),(1,0)]';  -- false
-
-SELECT lseg '[(1,1),(2,2)]' <@ line '[(0,0),(2,2)]';  -- true
-SELECT lseg '[(1,1),(2,1)]' <@ line '[(0,0),(1,0)]';  -- false
-
-SELECT lseg '[(1,1),(2,2)]' @ line '[(0,0),(2,2)]';  -- true
-SELECT lseg '[(1,1),(2,1)]' @ line '[(0,0),(1,0)]';  -- false
-
-SELECT point '(0,1)' ## line '[(0,0),(1,1)]';
-
-SELECT line '[(0,0),(1,1)]' ## lseg '[(1,0),(2,0)]';
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(2,1)]';  -- false
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(1,1)]';  -- true
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(2,1)]';
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(1,1)]';
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(2,1)]';  -- true
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(1,1)]';  -- false
-
-SELECT line '[(0,0),(1,0)]' ?-| line '[(0,0),(0,1)]';  -- true
-SELECT line '[(0,0),(1,1)]' ?-| line '[(1,0),(1,1)]';  -- false
-
-SELECT ?- line '[(0,0),(1,0)]';  -- true
-SELECT ?- line '[(0,0),(1,1)]';  -- false
-
-SELECT ?| line '[(0,0),(0,1)]';  -- true
-SELECT ?| line '[(0,0),(1,1)]';  -- false
-
-SELECT line(point '(1,2)', point '(3,4)');
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,5)]';  -- true
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,4)]';  -- false
diff --git a/src/test/regress/sql/lseg.sql b/src/test/regress/sql/lseg.sql
index 07c5a29e0a..f266ca3e09 100644
--- a/src/test/regress/sql/lseg.sql
+++ b/src/test/regress/sql/lseg.sql
@@ -3,23 +3,22 @@
 -- Line segments
 --
 
 --DROP TABLE LSEG_TBL;
 CREATE TABLE LSEG_TBL (s lseg);
 
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('(0,0),(6,6)');
 INSERT INTO LSEG_TBL VALUES ('10,-10 ,-3,-4');
 INSERT INTO LSEG_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LSEG_TBL VALUES ('(11,22,33,44)');
+INSERT INTO LSEG_TBL VALUES (lseg(point(11, 22), point(33,44)));
+INSERT INTO LSEG_TBL VALUES ('[(-10,2),(-10,3)]');	-- vertical
+INSERT INTO LSEG_TBL VALUES ('[(0,-20),(30,-20)]');	-- horizontal
+INSERT INTO LSEG_TBL VALUES ('[(NaN,1),(NaN,90)]');	-- NaN
 
 -- bad values for parser testing
 INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
 INSERT INTO LSEG_TBL VALUES ('[1,2,3, 4');
 INSERT INTO LSEG_TBL VALUES ('[(,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)');
 
 select * from LSEG_TBL;
-
-SELECT * FROM LSEG_TBL WHERE s <= lseg '[(1,2),(3,4)]';
-
-SELECT * FROM LSEG_TBL WHERE (s <-> lseg '[(1,2),(3,4)]') < 10;
diff --git a/src/test/regress/sql/path.sql b/src/test/regress/sql/path.sql
index 7e69b539ad..318decf974 100644
--- a/src/test/regress/sql/path.sql
+++ b/src/test/regress/sql/path.sql
@@ -1,38 +1,44 @@
 --
 -- PATH
 --
 
 --DROP TABLE PATH_TBL;
 
 CREATE TABLE PATH_TBL (f1 path);
 
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)]');
 
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
+INSERT INTO PATH_TBL VALUES (' ( ( 1 , 2 ) , ( 3 , 4 ) ) ');
 
-INSERT INTO PATH_TBL VALUES ('[(0,0),(3,0),(4,5),(1,6)]');
+INSERT INTO PATH_TBL VALUES ('[ (0,0),(3,0),(4,5),(1,6) ]');
 
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
+INSERT INTO PATH_TBL VALUES ('((1,2) ,(3,4 ))');
 
-INSERT INTO PATH_TBL VALUES ('1,2 ,3,4');
+INSERT INTO PATH_TBL VALUES ('1,2 ,3,4 ');
 
-INSERT INTO PATH_TBL VALUES ('[1,2,3, 4]');
+INSERT INTO PATH_TBL VALUES (' [1,2,3, 4] ');
 
-INSERT INTO PATH_TBL VALUES ('[11,12,13,14]');
+INSERT INTO PATH_TBL VALUES ('((10,20))');	-- Only one point
 
-INSERT INTO PATH_TBL VALUES ('(11,12,13,14)');
+INSERT INTO PATH_TBL VALUES ('[ 11,12,13,14 ]');
+
+INSERT INTO PATH_TBL VALUES ('( 11,12,13,14) ');
 
 -- bad values for parser testing
+INSERT INTO PATH_TBL VALUES ('[]');
+
 INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
 
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
 
-SELECT f1 FROM PATH_TBL;
+INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+
+INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
 
 SELECT '' AS count, f1 AS open_path FROM PATH_TBL WHERE isopen(f1);
 
 SELECT '' AS count, f1 AS closed_path FROM PATH_TBL WHERE isclosed(f1);
 
 SELECT '' AS count, pclose(f1) AS closed_path FROM PATH_TBL;
 
 SELECT '' AS count, popen(f1) AS open_path FROM PATH_TBL;
diff --git a/src/test/regress/sql/point.sql b/src/test/regress/sql/point.sql
index 63a803a809..a209f3bfeb 100644
--- a/src/test/regress/sql/point.sql
+++ b/src/test/regress/sql/point.sql
@@ -7,29 +7,39 @@ CREATE TABLE POINT_TBL(f1 point);
 INSERT INTO POINT_TBL(f1) VALUES ('(0.0,0.0)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-10.0,0.0)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-3.0,4.0)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(5.1, 34.5)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-5.0,-12.0)');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(1e-300,-1e-300)');	-- To underflow
+
+INSERT INTO POINT_TBL(f1) VALUES ('(1e+300,Inf)');		-- To overflow
+
+INSERT INTO POINT_TBL(f1) VALUES (' ( Nan , NaN ) ');
+
 -- bad format points
 INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
 
 INSERT INTO POINT_TBL(f1) VALUES ('10.0,10.0');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');	-- Out of range
+
 
 SELECT '' AS six, * FROM POINT_TBL;
 
 -- left of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE p.f1 << '(0.0, 0.0)';
 
 -- right of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE '(0.0,0.0)' >> p.f1;
 
 -- above
diff --git a/src/test/regress/sql/polygon.sql b/src/test/regress/sql/polygon.sql
index 7ac8079465..93f222d6d6 100644
--- a/src/test/regress/sql/polygon.sql
+++ b/src/test/regress/sql/polygon.sql
@@ -4,115 +4,32 @@
 -- polygon logic
 --
 
 CREATE TABLE POLYGON_TBL(f1 polygon);
 
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(2.0,0.0),(2.0,4.0),(0.0,0.0)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(3.0,1.0),(3.0,3.0),(1.0,0.0)');
 
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(3,4),(5,6),(7,8)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(7,8),(5,6),(3,4),(1,2)'); -- Reverse
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(7,8),(5,6),(3,-4)');
+
 -- degenerate polygons
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,0.0)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,1.0),(0.0,1.0)');
 
 -- bad polygon input strings
 INSERT INTO POLYGON_TBL(f1) VALUES ('0.0');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0 0.0');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2,3');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
 
 
 SELECT '' AS four, * FROM POLYGON_TBL;
-
--- overlap
-SELECT '' AS three, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 && '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- left overlap
-SELECT '' AS four, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &< '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- right overlap
-SELECT '' AS two, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- left of
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 << '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- right of
-SELECT '' AS zero, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 >> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- contained
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- same
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- contains
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
---
--- polygon logic
---
--- left of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- left overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
-
--- right overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' &> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- right of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' >> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- contained in
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- contains
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "false";
-
-SELECT '((0,4),(6,4),(3,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
-
-SELECT '((1,1),(1,4),(5,4),(5,3),(2,3),(2,2),(5,2),(5,1))'::polygon @> '((3,2),(3,3),(4,3),(4,2))'::polygon AS "false";
-
-SELECT '((0,0),(0,3),(3,3),(3,0))'::polygon @> '((2,1),(2,2),(3,2),(3,1))'::polygon AS "true";
-
--- same
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' && polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon && '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
-
-SELECT '((1,4),(1,1),(4,1),(4,2),(2,2),(2,4),(1,4))'::polygon && '((3,3),(4,3),(4,4),(3,4),(3,3))'::polygon AS "false";
-SELECT '((200,800),(800,800),(800,200),(200,200))' &&  '(1000,1000,0,0)'::polygon AS "true";
-
--- distance from a point
-SELECT	'(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
-	'(1,1)'::point <-> '((0,0),(2,2),(1,3))'::polygon as on_segment,
-	'(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;
-- 
2.13.6 (Apple Git-96)

#34Michael Paquier
michael.paquier@gmail.com
In reply to: Emre Hasegeli (#33)
Re: [HACKERS] [PATCH] Improve geometric types

On Thu, Nov 30, 2017 at 3:28 AM, Emre Hasegeli <emre@hasegeli.com> wrote:

It would at least be dump-and-restore hazard if we don't let them in.
The new version allows NaNs.

This gives a wrong result for NaN-containing objects.

I removed the NaN aware comparisons from FP macros, and carefully
reviewed the places that needs to be NaN aware.

I am sorry that it took so long for me to post the new versions. The
more I get into this the more problems I find. The new versions
include non-trivial changes. I would be glad if you can look into
them.

I have moved this patch to next CF, with "needs review" as status as a
new version has been posted.
--
Michael

#35Alvaro Herrera
alvherre@alvh.no-ip.org
In reply to: Emre Hasegeli (#33)
Re: [HACKERS] [PATCH] Improve geometric types

Does this patch series fix bug #14971?
/messages/by-id/20171213172806.20142.73638@wrigleys.postgresql.org

Eric: see
/messages/by-id/CAE2gYzzvp=uvpw4FytoaEvYK-WZE4jw7u2s1gLRoK35Mr1-kYQ@mail.gmail.com
for last version of patch.

Motivation for patch is at
/messages/by-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt=EqbOURx7ZDg+Vv6ZMTWbg@mail.gmail.com

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

#36Emre Hasegeli
emre@hasegeli.com
In reply to: Alvaro Herrera (#35)
Re: [HACKERS] [PATCH] Improve geometric types

Does this patch series fix bug #14971?

No, it doesn't. I am trying to improve things without touching the EPSILON.

#37Emre Hasegeli
emre@hasegeli.com
In reply to: Emre Hasegeli (#33)
6 attachment(s)
Re: [HACKERS] [PATCH] Improve geometric types

Rebased versions are attached.

Attachments:

0001-geo-funcs-v07.patchapplication/octet-stream; name=0001-geo-funcs-v07.patchDownload
From 17db2d6b86bfe131f1cbe279915fa3ee91dcf8af Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 27 May 2017 11:27:18 -0400
Subject: [PATCH 1/6] geo-funcs-v07

Refactor geometric functions and operators code

Most of the geometric types were not using functions of each other's.
I believe the reason behind this is simpler types line point and line
being developed after more complicated ones.  This patch reduces
duplicate code and makes functions of different datatypes more
compatible.  The changes can be summarised as:

* Eliminate SQL level function calls
* Re-use more functions to implement others
* Unify internal function names and signatures
* Remove private functions from geo_decls.h
* Replace not-possible checks with Assert()
* Add comments to describe some functions
* Remove some unreachable code
* Define delimiter symbols of line datatype like the other ones
* Remove debugging print()s from the refactored functions

This commits aims to not cause any user visible changes, but it is
almost impossible to stay completely bug-compatible with the old code.
---
 src/backend/utils/adt/geo_ops.c    | 1835 ++++++++++++++++--------------------
 src/backend/utils/adt/geo_spgist.c |    3 +-
 src/include/utils/geo_decls.h      |    4 -
 src/test/regress/regress.c         |   11 +-
 4 files changed, 847 insertions(+), 1006 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index f57380a4df..fc5b68d757 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -31,75 +31,102 @@
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
+/* Routines for two-dimensional points */
+static inline void point_construct(Point *result, float8 x, float8 y);
+static inline void point_add_point(Point *result, Point *pt1, Point *pt2);
+static inline void point_sub_point(Point *result, Point *pt1, Point *pt2);
+static inline void point_mul_point(Point *result, Point *pt1, Point *pt2);
+static inline void point_div_point(Point *result, Point *pt1, Point *pt2);
+static inline bool point_eq_point(Point *pt1, Point *pt2);
+static float8 point_dt(Point *pt1, Point *pt2);
+static inline float8 slope(float8 x1, float8 x2, float8 y1, float8 y2);
 static int	point_inside(Point *p, int npts, Point *plist);
+
+/* Routines for two-dimensional lines */
+static inline void line_construct_pm(LINE *result, Point *pt, float8 m);
+static inline void line_construct_pts(LINE *result, Point *pt1, Point *pt2);
+static bool	line_interpt_line(Point *result, LINE *l1, LINE *l2);
+static bool line_contain_point(LINE *line, Point *point);
+static float8 line_closept_point(Point *result, LINE *line, Point *pt);
+
+/* Routines for two-dimensional line segments */
+static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
+static bool	lseg_interpt_line(Point *result, LSEG *lseg, LINE *line);
+static bool	lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2);
 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_fill(BOX *result, double x1, double x2, double y1, double y2);
+static bool	lseg_contain_point(LSEG *lseg, Point *point);
+static float8 lseg_closept_point(Point *result, LSEG *lseg, Point *pt);
+static float8 lseg_closept_line(Point *result, LSEG *lseg, LINE *line);
+static float8 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2);
+
+/* Routines for two-dimensional boxes */
+static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
+static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
+static double box_ar(BOX *box);
 static double box_ht(BOX *box);
 static double box_wd(BOX *box);
+static bool box_contain_point(BOX *box, Point *point);
+static bool box_contain_box(BOX *box1, BOX *box2);
+static bool box_contain_lseg(BOX *box, LSEG *lseg);
+static bool box_interpt_lseg(Point *result, BOX *box, LSEG *lseg);
+static float8 box_closept_point(Point *result, BOX *box, Point *point);
+static float8 box_closept_lseg(Point *result, BOX *box, LSEG *lseg);
+
+/* Routines for two-dimensional circles */
 static double circle_ar(CIRCLE *circle);
-static CIRCLE *circle_copy(CIRCLE *circle);
-static LINE *line_construct_pm(Point *pt, double m);
-static void line_construct_pts(LINE *line, Point *pt1, Point *pt2);
-static bool lseg_intersect_internal(LSEG *l1, LSEG *l2);
-static double lseg_dt(LSEG *l1, LSEG *l2);
-static bool on_ps_internal(Point *pt, LSEG *lseg);
+
+/* Routines for two-dimensional polygons */
 static void make_bound_box(POLYGON *poly);
+static void poly_to_circle(CIRCLE *result, POLYGON *poly);
+static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
+static bool poly_contain_poly(POLYGON *polya, POLYGON *polyb);
 static bool plist_same(int npts, Point *p1, Point *p2);
-static Point *point_construct(double x, double y);
-static Point *point_copy(Point *pt);
+static float8 dist_ppoly_internal(Point *pt, POLYGON *poly);
+
+/* Routines for encoding and decoding */
 static double single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
 static void pair_decode(char *str, double *x, double *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
 static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
-static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
-static double box_ar(BOX *box);
-static void box_cn(Point *center, BOX *box);
-static Point *interpt_sl(LSEG *lseg, LINE *line);
-static bool has_interpt_sl(LSEG *lseg, LINE *line);
-static double dist_pl_internal(Point *pt, LINE *line);
-static double dist_ps_internal(Point *pt, LSEG *lseg);
-static Point *line_interpt_internal(LINE *l1, LINE *l2);
-static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
-static Point *lseg_interpt_internal(LSEG *l1, LSEG *l2);
-static double dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 
 /*
  * Delimiters for input and output strings.
  * LDELIM, RDELIM, and DELIM are left, right, and separator delimiters, respectively.
  * LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints.
  */
 
 #define LDELIM			'('
 #define RDELIM			')'
 #define DELIM			','
 #define LDELIM_EP		'['
 #define RDELIM_EP		']'
 #define LDELIM_C		'<'
 #define RDELIM_C		'>'
+#define LDELIM_L		'{'
+#define RDELIM_L		'}'
 
 
 /*
  * Geometric data types are composed of points.
  * This code tries to support a common format throughout the data types,
  *	to allow for more predictable usage and data type conversion.
  * The fundamental unit is the point. Other units are line segments,
  *	open paths, boxes, closed paths, and polygons (which should be considered
  *	non-intersecting closed paths).
  *
@@ -229,26 +256,23 @@ path_decode(char *str, bool opentype, int npts, Point *p,
 	}
 
 	for (i = 0; i < npts; i++)
 	{
 		pair_decode(str, &(p->x), &(p->y), &str, type_name, orig_string);
 		if (*str == DELIM)
 			str++;
 		p++;
 	}
 
-	while (isspace((unsigned char) *str))
-		str++;
 	while (depth > 0)
 	{
-		if ((*str == RDELIM)
-			|| ((*str == RDELIM_EP) && (*isopen) && (depth == 1)))
+		if (*str == RDELIM || (*str == RDELIM_EP && *isopen && depth == 1))
 		{
 			depth--;
 			str++;
 			while (isspace((unsigned char) *str))
 				str++;
 		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
@@ -433,89 +457,61 @@ box_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, box->high.x);
 	pq_sendfloat8(&buf, box->high.y);
 	pq_sendfloat8(&buf, box->low.x);
 	pq_sendfloat8(&buf, box->low.y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*		box_construct	-		fill in a new box.
  */
-static BOX *
-box_construct(double x1, double x2, double y1, double y2)
+static inline void
+box_construct(BOX *result, Point *pt1, Point *pt2)
 {
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	return box_fill(result, x1, x2, y1, y2);
-}
-
-
-/*		box_fill		-		fill in a given box struct
- */
-static BOX *
-box_fill(BOX *result, double x1, double x2, double y1, double y2)
-{
-	if (x1 > x2)
+	if (pt1->x > pt2->x)
 	{
-		result->high.x = x1;
-		result->low.x = x2;
+		result->high.x = pt1->x;
+		result->low.x = pt2->x;
 	}
 	else
 	{
-		result->high.x = x2;
-		result->low.x = x1;
+		result->high.x = pt2->x;
+		result->low.x = pt1->x;
 	}
-	if (y1 > y2)
+	if (pt1->y > pt2->y)
 	{
-		result->high.y = y1;
-		result->low.y = y2;
+		result->high.y = pt1->y;
+		result->low.y = pt2->y;
 	}
 	else
 	{
-		result->high.y = y2;
-		result->low.y = y1;
+		result->high.y = pt2->y;
+		result->low.y = pt1->y;
 	}
-
-	return result;
-}
-
-
-/*		box_copy		-		copy a box
- */
-BOX *
-box_copy(BOX *box)
-{
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	memcpy((char *) result, (char *) box, sizeof(BOX));
-
-	return result;
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for BOXes.
  *		<, >, <=, >=, and == are based on box area.
  *---------------------------------------------------------*/
 
 /*		box_same		-		are two boxes identical?
  */
 Datum
 box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPeq(box1->high.x, box2->high.x) &&
-				   FPeq(box1->low.x, box2->low.x) &&
-				   FPeq(box1->high.y, box2->high.y) &&
-				   FPeq(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(point_eq_point(&box1->high, &box2->high) &&
+				   point_eq_point(&box1->low, &box2->low));
 }
 
 /*		box_overlap		-		does box1 overlap box2?
  */
 Datum
 box_overlap(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
@@ -630,38 +626,44 @@ box_overabove(PG_FUNCTION_ARGS)
 }
 
 /*		box_contained	-		is box1 contained by box2?
  */
 Datum
 box_contained(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPle(box1->high.x, box2->high.x) &&
-				   FPge(box1->low.x, box2->low.x) &&
-				   FPle(box1->high.y, box2->high.y) &&
-				   FPge(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(box_contain_box(box2, box1));
 }
 
 /*		box_contain		-		does box1 contain box2?
  */
 Datum
 box_contain(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPge(box1->high.x, box2->high.x) &&
-				   FPle(box1->low.x, box2->low.x) &&
-				   FPge(box1->high.y, box2->high.y) &&
-				   FPle(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(box_contain_box(box1, box2));
+}
+
+/*
+ * Check whether the box is in the box or on its border
+ */
+static bool
+box_contain_box(BOX *box1, BOX *box2)
+{
+	return FPge(box1->high.x, box2->high.x) &&
+		   FPle(box1->low.x, box2->low.x) &&
+		   FPge(box1->high.y, box2->high.y) &&
+		   FPle(box1->low.y, box2->low.y);
 }
 
 
 /*		box_positionop	-
  *				is box1 entirely {above,below} box2?
  *
  * box_below_eq and box_above_eq are obsolete versions that (probably
  * erroneously) accept the equal-boundaries case.  Since these are not
  * in sync with the box_left and box_right code, they are deprecated and
  * not supported in the PG 8.1 rtree operator class extension.
@@ -750,51 +752,51 @@ box_area(PG_FUNCTION_ARGS)
 
 
 /*		box_width		-		returns the width of the box
  *								  (horizontal magnitude).
  */
 Datum
 box_width(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.x - box->low.x);
+	PG_RETURN_FLOAT8(box_wd(box));
 }
 
 
 /*		box_height		-		returns the height of the box
  *								  (vertical magnitude).
  */
 Datum
 box_height(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.y - box->low.y);
+	PG_RETURN_FLOAT8(box_ht(box));
 }
 
 
 /*		box_distance	-		returns the distance between the
  *								  center points of two boxes.
  */
 Datum
 box_distance(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 	Point		a,
 				b;
 
 	box_cn(&a, box1);
 	box_cn(&b, box2);
 
-	PG_RETURN_FLOAT8(HYPOT(a.x - b.x, a.y - b.y));
+	PG_RETURN_FLOAT8(point_dt(&a, &b));
 }
 
 
 /*		box_center		-		returns the center point of the box.
  */
 Datum
 box_center(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *result = (Point *) palloc(sizeof(Point));
@@ -898,76 +900,77 @@ static bool
 line_decode(char *s, const char *str, LINE *line)
 {
 	/* s was already advanced over leading '{' */
 	line->A = single_decode(s, &s, "line", str);
 	if (*s++ != DELIM)
 		return false;
 	line->B = single_decode(s, &s, "line", str);
 	if (*s++ != DELIM)
 		return false;
 	line->C = single_decode(s, &s, "line", str);
-	if (*s++ != '}')
+	if (*s++ != RDELIM_L)
 		return false;
 	while (isspace((unsigned char) *s))
 		s++;
 	if (*s != '\0')
 		return false;
 	return true;
 }
 
 Datum
 line_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	LINE	   *line = (LINE *) palloc(sizeof(LINE));
 	LSEG		lseg;
 	bool		isopen;
 	char	   *s;
 
 	s = str;
 	while (isspace((unsigned char) *s))
 		s++;
-	if (*s == '{')
+	if (*s == LDELIM_L)
 	{
 		if (!line_decode(s + 1, str, line))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
 							"line", str)));
 		if (FPzero(line->A) && FPzero(line->B))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: A and B cannot both be zero")));
 	}
 	else
 	{
-		path_decode(s, true, 2, &(lseg.p[0]), &isopen, NULL, "line", str);
-		if (FPeq(lseg.p[0].x, lseg.p[1].x) && FPeq(lseg.p[0].y, lseg.p[1].y))
+		path_decode(s, true, 2, &lseg.p[0], &isopen, NULL, "line", str);
+		if (point_eq_point(&lseg.p[0], &lseg.p[1]))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: must be two distinct points")));
 		line_construct_pts(line, &lseg.p[0], &lseg.p[1]);
 	}
 
 	PG_RETURN_LINE_P(line);
 }
 
 
 Datum
 line_out(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	char	   *astr = float8out_internal(line->A);
 	char	   *bstr = float8out_internal(line->B);
 	char	   *cstr = float8out_internal(line->C);
 
-	PG_RETURN_CSTRING(psprintf("{%s,%s,%s}", astr, bstr, cstr));
+	PG_RETURN_CSTRING(psprintf("%c%s%c%s%c%s%c", LDELIM_L, astr, DELIM, bstr,
+							   DELIM, cstr, RDELIM_L));
 }
 
 /*
  *		line_recv			- converts external binary format to line
  */
 Datum
 line_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LINE	   *line;
@@ -996,86 +999,59 @@ line_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, line->C);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*----------------------------------------------------------
  *	Conversion routines from one line formula to internal.
  *		Internal form:	Ax+By+C=0
  *---------------------------------------------------------*/
 
-/* line_construct_pm()
- * point-slope
+/*
+ * Fill already-allocated LINE struct from the point and the slope
  */
-static LINE *
-line_construct_pm(Point *pt, double m)
+static inline void
+line_construct_pm(LINE *result, Point *pt, float8 m)
 {
-	LINE	   *result = (LINE *) palloc(sizeof(LINE));
-
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
 		result->A = -1;
 		result->B = 0;
 		result->C = pt->x;
 	}
+	else if (m == 0.0)
+	{
+		/* horizontal - use "y = C" */
+		result->A = 0.0;
+		result->B = -1.0;
+		result->C = pt->y;
+	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
 		result->C = pt->y - m * pt->x;
 	}
-
-	return result;
 }
 
 /*
  * Fill already-allocated LINE struct from two points on the line
  */
-static void
-line_construct_pts(LINE *line, Point *pt1, Point *pt2)
+static inline void
+line_construct_pts(LINE *result, Point *pt1, Point *pt2)
 {
-	if (FPeq(pt1->x, pt2->x))
-	{							/* vertical */
-		/* use "x = C" */
-		line->A = -1;
-		line->B = 0;
-		line->C = pt1->x;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is vertical\n");
-#endif
-	}
-	else if (FPeq(pt1->y, pt2->y))
-	{							/* horizontal */
-		/* use "y = C" */
-		line->A = 0;
-		line->B = -1;
-		line->C = pt1->y;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is horizontal\n");
-#endif
-	}
-	else
-	{
-		/* use "mx - y + yinter = 0" */
-		line->A = (pt2->y - pt1->y) / (pt2->x - pt1->x);
-		line->B = -1.0;
-		line->C = pt1->y - line->A * pt1->x;
-		/* on some platforms, the preceding expression tends to produce -0 */
-		if (line->C == 0.0)
-			line->C = 0.0;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is neither vertical nor horizontal (diffs x=%.*g, y=%.*g\n",
-			   DBL_DIG, (pt2->x - pt1->x), DBL_DIG, (pt2->y - pt1->y));
-#endif
-	}
+	float8		m;
+
+	m = slope(pt1->x, pt2->x, pt1->y, pt2->y);
+	line_construct_pm(result, pt1, m);
 }
 
 /* line_construct_pp()
  * two points
  */
 Datum
 line_construct_pp(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
@@ -1089,23 +1065,21 @@ line_construct_pp(PG_FUNCTION_ARGS)
 /*----------------------------------------------------------
  *	Relative position routines.
  *---------------------------------------------------------*/
 
 Datum
 line_intersect(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(!DatumGetBool(DirectFunctionCall2(line_parallel,
-													 LinePGetDatum(l1),
-													 LinePGetDatum(l2))));
+	PG_RETURN_BOOL(line_interpt_line(NULL, l1, l2));
 }
 
 Datum
 line_parallel(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->B));
@@ -1171,96 +1145,90 @@ line_eq(PG_FUNCTION_ARGS)
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
-	Point	   *tmp;
+	Point		tmp;
 
-	if (!DatumGetBool(DirectFunctionCall2(line_parallel,
-										  LinePGetDatum(l1),
-										  LinePGetDatum(l2))))
+	if (line_interpt_line(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
 		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
-	tmp = point_construct(0.0, l1->C);
-	result = dist_pl_internal(tmp, l2);
+	point_construct(&tmp, 0.0, l1->C);
+	result = line_closept_point(NULL, l2, &tmp);
 	PG_RETURN_FLOAT8(result);
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
-	result = line_interpt_internal(l1, l2);
+	result = (Point *) palloc(sizeof(Point));
 
-	if (result == NULL)
+	if (!line_interpt_line(result, l1, l2))
 		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
 
 /*
  * Internal version of line_interpt
  *
- * returns a NULL pointer if no intersection point
+ * This returns true if two lines intersect (they do, if they are not
+ * parallel), false if they do not.  This also sets the intersection point
+ * to *result, if it is not NULL.
+ *
+ * NOTE If the lines are identical then we will find they are parallel
+ * and report "no intersection".  This is a little weird, but since
+ * there's no *unique* intersection, maybe it's appropriate behavior.
  */
-static Point *
-line_interpt_internal(LINE *l1, LINE *l2)
+static bool
+line_interpt_line(Point *result, LINE *l1, LINE *l2)
 {
-	Point	   *result;
 	double		x,
 				y;
 
-	/*
-	 * NOTE: if the lines are identical then we will find they are parallel
-	 * and report "no intersection".  This is a little weird, but since
-	 * there's no *unique* intersection, maybe it's appropriate behavior.
-	 */
-	if (DatumGetBool(DirectFunctionCall2(line_parallel,
-										 LinePGetDatum(l1),
-										 LinePGetDatum(l2))))
-		return NULL;
-
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
+		if (FPzero(l2->B))		/* l2 vertical? */
+			return false;
+
 		x = l1->C;
 		y = (l2->A * x + l2->C);
 	}
 	else if (FPzero(l2->B))		/* l2 vertical? */
 	{
 		x = l2->C;
 		y = (l1->A * x + l1->C);
 	}
 	else
 	{
+		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+			return false;
+
 		x = (l1->C - l2->C) / (l2->A - l1->A);
 		y = (l1->A * x + l1->C);
 	}
-	result = point_construct(x, y);
+	if (result != NULL)
+		point_construct(result, x, y);
 
-#ifdef GEODEBUG
-	printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
-		   DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
-	printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
-#endif
-
-	return result;
+	return true;
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D paths (sequences of line segments, also
  **				called `polylines').
  **
  **				This is not a general package for geometric paths,
  **				which of course include polygons; the emphasis here
@@ -1555,22 +1523,21 @@ path_inter(PG_FUNCTION_ARGS)
 {
 	PATH	   *p1 = PG_GETARG_PATH_P(0);
 	PATH	   *p2 = PG_GETARG_PATH_P(1);
 	BOX			b1,
 				b2;
 	int			i,
 				j;
 	LSEG		seg1,
 				seg2;
 
-	if (p1->npts <= 0 || p2->npts <= 0)
-		PG_RETURN_BOOL(false);
+	Assert(p1->npts > 0 && p2->npts > 0);
 
 	b1.high.x = b1.low.x = p1->p[0].x;
 	b1.high.y = b1.low.y = p1->p[0].y;
 	for (i = 1; i < p1->npts; i++)
 	{
 		b1.high.x = Max(p1->p[i].x, b1.high.x);
 		b1.high.y = Max(p1->p[i].y, b1.high.y);
 		b1.low.x = Min(p1->p[i].x, b1.low.x);
 		b1.low.y = Min(p1->p[i].y, b1.low.y);
 	}
@@ -1608,21 +1575,21 @@ path_inter(PG_FUNCTION_ARGS)
 				jprev = j - 1;
 			else
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
-			if (lseg_intersect_internal(&seg1, &seg2))
+			if (lseg_interpt_lseg(NULL, &seg1, &seg2))
 				PG_RETURN_BOOL(true);
 		}
 	}
 
 	/* if we dropped through, no two segs intersected */
 	PG_RETURN_BOOL(false);
 }
 
 /* path_distance()
  * This essentially does a cartesian product of the lsegs in the
@@ -1663,23 +1630,21 @@ path_distance(PG_FUNCTION_ARGS)
 			else
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
-			tmp = DatumGetFloat8(DirectFunctionCall2(lseg_distance,
-													 LsegPGetDatum(&seg1),
-													 LsegPGetDatum(&seg2)));
+			tmp = lseg_closept_lseg(NULL, &seg1, &seg2);
 			if (!have_min || tmp < min)
 			{
 				min = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	if (!have_min)
 		PG_RETURN_NULL();
@@ -1773,44 +1738,31 @@ point_send(PG_FUNCTION_ARGS)
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	StringInfoData buf;
 
 	pq_begintypsend(&buf);
 	pq_sendfloat8(&buf, pt->x);
 	pq_sendfloat8(&buf, pt->y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
-static Point *
-point_construct(double x, double y)
+/*
+ * Initialize a point
+ *
+ * This function is over-simple, but it is, at least, useful when the new
+ * point is calculated using the existing one.
+ */
+static inline void
+point_construct(Point *result, float8 x, float8 y)
 {
-	Point	   *result = (Point *) palloc(sizeof(Point));
-
 	result->x = x;
 	result->y = y;
-	return result;
-}
-
-
-static Point *
-point_copy(Point *pt)
-{
-	Point	   *result;
-
-	if (!PointerIsValid(pt))
-		return NULL;
-
-	result = (Point *) palloc(sizeof(Point));
-
-	result->x = pt->x;
-	result->y = pt->y;
-	return result;
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for Points.
  *		Since we do have a sense of coordinates being
  *		"equal" to a given accuracy (point_vert, point_horiz),
  *		the other ops must preserve that sense.  This means
  *		that results may, strictly speaking, be a lie (unless
  *		EPSILON = 0.0).
@@ -1869,71 +1821,85 @@ point_horiz(PG_FUNCTION_ARGS)
 
 	PG_RETURN_BOOL(FPeq(pt1->y, pt2->y));
 }
 
 Datum
 point_eq(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y));
+	PG_RETURN_BOOL(point_eq_point(pt1, pt2));
 }
 
 Datum
 point_ne(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPne(pt1->x, pt2->x) || FPne(pt1->y, pt2->y));
+	PG_RETURN_BOOL(!point_eq_point(pt1, pt2));
 }
 
+static inline bool
+point_eq_point(Point *pt1, Point *pt2)
+{
+	return FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y);
+}
+
+
 /*----------------------------------------------------------
  *	"Arithmetic" operators on points.
  *---------------------------------------------------------*/
 
 Datum
 point_distance(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_FLOAT8(HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
+	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
-double
+static float8
 point_dt(Point *pt1, Point *pt2)
 {
-#ifdef GEODEBUG
-	printf("point_dt- segment (%f,%f),(%f,%f) length is %f\n",
-		   pt1->x, pt1->y, pt2->x, pt2->y, HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
-#endif
 	return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
 }
 
 Datum
 point_slope(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_FLOAT8(point_sl(pt1, pt2));
+	PG_RETURN_FLOAT8(slope(pt1->x, pt2->x, pt1->y, pt2->y));
 }
 
 
-double
-point_sl(Point *pt1, Point *pt2)
+/*
+ * Return slope of two points
+ *
+ * This function accepts x and y coordinates separately to let it be used
+ * to calculate inverse slope.  To achieve that, pass the values in
+ * (y1, y2, x2, x1) order.
+ */
+static inline float8
+slope(float8 x1, float8 x2, float8 y1, float8 y2)
 {
-	return (FPeq(pt1->x, pt2->x)
-			? (double) DBL_MAX
-			: (pt1->y - pt2->y) / (pt1->x - pt2->x));
+	/*
+	 * XXX This should be exact checking.  The callers are using the macros
+	 * when necessary.
+	 */
+	if (FPeq(x1, x2))
+		return DBL_MAX;
+	return (y1 - y2) / (x1 - x2);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D line segments.
  **
  ***********************************************************************/
 
 /*----------------------------------------------------------
@@ -1945,31 +1911,31 @@ point_sl(Point *pt1, Point *pt2)
  *		(old form)		"(x1, y1, x2, y2)"
  *---------------------------------------------------------*/
 
 Datum
 lseg_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	LSEG	   *lseg = (LSEG *) palloc(sizeof(LSEG));
 	bool		isopen;
 
-	path_decode(str, true, 2, &(lseg->p[0]), &isopen, NULL, "lseg", str);
+	path_decode(str, true, 2, &lseg->p[0], &isopen, NULL, "lseg", str);
 	PG_RETURN_LSEG_P(lseg);
 }
 
 
 Datum
 lseg_out(PG_FUNCTION_ARGS)
 {
 	LSEG	   *ls = PG_GETARG_LSEG_P(0);
 
-	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, (Point *) &(ls->p[0])));
+	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, &ls->p[0]));
 }
 
 /*
  *		lseg_recv			- converts external binary format to lseg
  */
 Datum
 lseg_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LSEG	   *lseg;
@@ -2014,21 +1980,21 @@ lseg_construct(PG_FUNCTION_ARGS)
 
 	result->p[0].x = pt1->x;
 	result->p[0].y = pt1->y;
 	result->p[1].x = pt2->x;
 	result->p[1].y = pt2->y;
 
 	PG_RETURN_LSEG_P(result);
 }
 
 /* like lseg_construct, but assume space already allocated */
-static void
+static inline void
 statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2)
 {
 	lseg->p[0].x = pt1->x;
 	lseg->p[0].y = pt1->y;
 	lseg->p[1].x = pt2->x;
 	lseg->p[1].y = pt2->y;
 }
 
 Datum
 lseg_length(PG_FUNCTION_ARGS)
@@ -2045,69 +2011,53 @@ lseg_length(PG_FUNCTION_ARGS)
 /*
  **  find intersection of the two lines, and see if it falls on
  **  both segments.
  */
 Datum
 lseg_intersect(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(lseg_intersect_internal(l1, l2));
+	PG_RETURN_BOOL(lseg_interpt_lseg(NULL, l1, l2));
 }
 
-static bool
-lseg_intersect_internal(LSEG *l1, LSEG *l2)
-{
-	LINE		ln;
-	Point	   *interpt;
-	bool		retval;
-
-	line_construct_pts(&ln, &l2->p[0], &l2->p[1]);
-	interpt = interpt_sl(l1, &ln);
-
-	if (interpt != NULL && on_ps_internal(interpt, l2))
-		retval = true;			/* interpt on l1 and l2 */
-	else
-		retval = false;
-	return retval;
-}
 
 Datum
 lseg_parallel(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPeq(point_sl(&l1->p[0], &l1->p[1]),
-						point_sl(&l2->p[0], &l2->p[1])));
+	PG_RETURN_BOOL(FPeq(slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y),
+						slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y)));
 }
 
 /* lseg_perp()
  * Determine if two line segments are perpendicular.
  *
  * This code did not get the correct answer for
  *	'((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg
  * So, modified it to check explicitly for slope of vertical line
- *	returned by point_sl() and the results seem better.
+ *	returned by slope() and the results seem better.
  * - thomas 1998-01-31
  */
 Datum
 lseg_perp(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	double		m1,
 				m2;
 
-	m1 = point_sl(&(l1->p[0]), &(l1->p[1]));
-	m2 = point_sl(&(l2->p[0]), &(l2->p[1]));
+	m1 = slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y);
+	m2 = slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y);
 
 #ifdef GEODEBUG
 	printf("lseg_perp- slopes are %g and %g\n", m1, m2);
 #endif
 	if (FPzero(m1))
 		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
 	else if (FPzero(m2))
 		PG_RETURN_BOOL(FPeq(m1, DBL_MAX));
 
 	PG_RETURN_BOOL(FPeq(m1 / m2, -1.0));
@@ -2129,36 +2079,32 @@ lseg_horizontal(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(FPeq(lseg->p[0].y, lseg->p[1].y));
 }
 
 
 Datum
 lseg_eq(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPeq(l1->p[0].x, l2->p[0].x) &&
-				   FPeq(l1->p[0].y, l2->p[0].y) &&
-				   FPeq(l1->p[1].x, l2->p[1].x) &&
-				   FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(point_eq_point(&l1->p[0], &l2->p[0]) &&
+				   point_eq_point(&l1->p[1], &l2->p[1]));
 }
 
 Datum
 lseg_ne(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(!FPeq(l1->p[0].x, l2->p[0].x) ||
-				   !FPeq(l1->p[0].y, l2->p[0].y) ||
-				   !FPeq(l1->p[1].x, l2->p[1].x) ||
-				   !FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(!point_eq_point(&l1->p[0], &l2->p[0]) ||
+				   !point_eq_point(&l1->p[1], &l2->p[1]));
 }
 
 Datum
 lseg_lt(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_BOOL(FPlt(point_dt(&l1->p[0], &l1->p[1]),
 						point_dt(&l2->p[0], &l2->p[1])));
@@ -2203,126 +2149,81 @@ lseg_ge(PG_FUNCTION_ARGS)
  *		If two segments don't intersect, then the closest
  *		point will be from one of the endpoints to the other
  *		segment.
  */
 Datum
 lseg_distance(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_FLOAT8(lseg_dt(l1, l2));
-}
-
-/* lseg_dt()
- * Distance between two line segments.
- * Must check both sets of endpoints to ensure minimum distance is found.
- * - thomas 1998-02-01
- */
-static double
-lseg_dt(LSEG *l1, LSEG *l2)
-{
-	double		result,
-				d;
-
-	if (lseg_intersect_internal(l1, l2))
-		return 0.0;
-
-	d = dist_ps_internal(&l1->p[0], l2);
-	result = d;
-	d = dist_ps_internal(&l1->p[1], l2);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[0], l1);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[1], l1);
-	result = Min(result, d);
-
-	return result;
+	PG_RETURN_FLOAT8(lseg_closept_lseg(NULL, l1, l2));
 }
 
 
 Datum
 lseg_center(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
 	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
 
 	PG_RETURN_POINT_P(result);
 }
 
-static Point *
-lseg_interpt_internal(LSEG *l1, LSEG *l2)
+
+/*
+ *		Find the intersection point of two segments (if any).
+ *
+ * This returns true if two line segments intersect, false if they do not.
+ * This also sets the intersection point to *result, if it is not NULL.
+ * This function is almost perfectly symmetric, even though it doesn't look
+ * like it.  See lseg_interpt_line() for the other half of it.
+ */
+static bool
+lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2)
 {
-	Point	   *result;
-	LINE		tmp1,
-				tmp2;
+	Point		interpt;
+	LINE		tmp;
+
+	line_construct_pts(&tmp, &l2->p[0], &l2->p[1]);
+	if (!lseg_interpt_line(&interpt, l1, &tmp))
+		return false;
 
 	/*
-	 * Find the intersection of the appropriate lines, if any.
+	 * If the line intersection point isn't within l2, there is no valid
+	 * segment intersection point at all.
 	 */
-	line_construct_pts(&tmp1, &l1->p[0], &l1->p[1]);
-	line_construct_pts(&tmp2, &l2->p[0], &l2->p[1]);
-	result = line_interpt_internal(&tmp1, &tmp2);
-	if (!PointerIsValid(result))
-		return NULL;
+	if (!lseg_contain_point(l2, &interpt))
+		return false;
 
-	/*
-	 * If the line intersection point isn't within l1 (or equivalently l2),
-	 * there is no valid segment intersection point at all.
-	 */
-	if (!on_ps_internal(result, l1) ||
-		!on_ps_internal(result, l2))
-	{
-		pfree(result);
-		return NULL;
-	}
+	if (result != NULL)
+		*result = interpt;
 
-	/*
-	 * If there is an intersection, then check explicitly for matching
-	 * endpoints since there may be rounding effects with annoying lsb
-	 * residue. - tgl 1997-07-09
-	 */
-	if ((FPeq(l1->p[0].x, l2->p[0].x) && FPeq(l1->p[0].y, l2->p[0].y)) ||
-		(FPeq(l1->p[0].x, l2->p[1].x) && FPeq(l1->p[0].y, l2->p[1].y)))
-	{
-		result->x = l1->p[0].x;
-		result->y = l1->p[0].y;
-	}
-	else if ((FPeq(l1->p[1].x, l2->p[0].x) && FPeq(l1->p[1].y, l2->p[0].y)) ||
-			 (FPeq(l1->p[1].x, l2->p[1].x) && FPeq(l1->p[1].y, l2->p[1].y)))
-	{
-		result->x = l1->p[1].x;
-		result->y = l1->p[1].y;
-	}
-
-	return result;
+	return true;
 }
 
-/* lseg_interpt -
- *		Find the intersection point of two segments (if any).
- */
 Datum
 lseg_interpt(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
-	result = lseg_interpt_internal(l1, l2);
-	if (!PointerIsValid(result))
-		PG_RETURN_NULL();
+	result = (Point *) palloc(sizeof(Point));
 
+	if (!lseg_interpt_lseg(result, l1, l2))
+		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
 
 /***********************************************************************
  **
  **		Routines for position comparisons of differently-typed
  **				2D objects.
  **
  ***********************************************************************/
 
@@ -2333,215 +2234,128 @@ lseg_interpt(PG_FUNCTION_ARGS)
 
 /*
  * Distance from a point to a line
  */
 Datum
 dist_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_FLOAT8(dist_pl_internal(pt, line));
+	PG_RETURN_FLOAT8(line_closept_point(NULL, line, pt));
 }
 
-static double
-dist_pl_internal(Point *pt, LINE *line)
-{
-	return fabs((line->A * pt->x + line->B * pt->y + line->C) /
-				HYPOT(line->A, line->B));
-}
 
 /*
  * Distance from a point to a lseg
  */
 Datum
 dist_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_FLOAT8(dist_ps_internal(pt, lseg));
-}
-
-static double
-dist_ps_internal(Point *pt, LSEG *lseg)
-{
-	double		m;				/* slope of perp. */
-	LINE	   *ln;
-	double		result,
-				tmpdist;
-	Point	   *ip;
-
-	/*
-	 * Construct a line perpendicular to the input segment and through the
-	 * input point
-	 */
-	if (lseg->p[1].x == lseg->p[0].x)
-		m = 0;
-	else if (lseg->p[1].y == lseg->p[0].y)
-		m = (double) DBL_MAX;	/* slope is infinite */
-	else
-		m = (lseg->p[0].x - lseg->p[1].x) / (lseg->p[1].y - lseg->p[0].y);
-	ln = line_construct_pm(pt, m);
-
-#ifdef GEODEBUG
-	printf("dist_ps- line is A=%g B=%g C=%g from (point) slope (%f,%f) %g\n",
-		   ln->A, ln->B, ln->C, pt->x, pt->y, m);
-#endif
-
-	/*
-	 * Calculate distance to the line segment or to the nearest endpoint of
-	 * the segment.
-	 */
-
-	/* intersection is on the line segment? */
-	if ((ip = interpt_sl(lseg, ln)) != NULL)
-	{
-		/* yes, so use distance to the intersection point */
-		result = point_dt(pt, ip);
-#ifdef GEODEBUG
-		printf("dist_ps- distance is %f to intersection point is (%f,%f)\n",
-			   result, ip->x, ip->y);
-#endif
-	}
-	else
-	{
-		/* no, so use distance to the nearer endpoint */
-		result = point_dt(pt, &lseg->p[0]);
-		tmpdist = point_dt(pt, &lseg->p[1]);
-		if (tmpdist < result)
-			result = tmpdist;
-	}
-
-	return result;
+	PG_RETURN_FLOAT8(lseg_closept_point(NULL, lseg, pt));
 }
 
 /*
  * Distance from a point to a path
  */
 Datum
 dist_ppath(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	PATH	   *path = PG_GETARG_PATH_P(1);
 	float8		result = 0.0;	/* keep compiler quiet */
 	bool		have_min = false;
 	float8		tmp;
 	int			i;
 	LSEG		lseg;
 
-	switch (path->npts)
+	Assert(path->npts > 0);
+
+	/*
+	 * The distance from a point to a path is the smallest distance
+	 * from the point to any of its constituent segments.
+	 */
+	for (i = 0; i < path->npts; i++)
 	{
-		case 0:
-			/* no points in path? then result is undefined... */
-			PG_RETURN_NULL();
-		case 1:
-			/* one point in path? then get distance between two points... */
-			result = point_dt(pt, &path->p[0]);
-			break;
-		default:
-			/* make sure the path makes sense... */
-			Assert(path->npts > 1);
+		int			iprev;
 
-			/*
-			 * the distance from a point to a path is the smallest distance
-			 * from the point to any of its constituent segments.
-			 */
-			for (i = 0; i < path->npts; i++)
-			{
-				int			iprev;
+		if (i > 0)
+			iprev = i - 1;
+		else
+		{
+			if (!path->closed)
+				continue;
+			iprev = path->npts - 1; /* Include the closure segment */
+		}
 
-				if (i > 0)
-					iprev = i - 1;
-				else
-				{
-					if (!path->closed)
-						continue;
-					iprev = path->npts - 1; /* include the closure segment */
-				}
-
-				statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
-				tmp = dist_ps_internal(pt, &lseg);
-				if (!have_min || tmp < result)
-				{
-					result = tmp;
-					have_min = true;
-				}
-			}
-			break;
+		statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
+		tmp = lseg_closept_point(NULL, &lseg, pt);
+		if (!have_min || tmp < result)
+		{
+			result = tmp;
+			have_min = true;
+		}
 	}
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a point to a box
  */
 Datum
 dist_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
-	float8		result;
-	Point	   *near;
 
-	near = DatumGetPointP(DirectFunctionCall2(close_pb,
-											  PointPGetDatum(pt),
-											  BoxPGetDatum(box)));
-	result = point_dt(near, pt);
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(box_closept_point(NULL, box, pt));
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	float8		result,
 				d2;
 
-	if (has_interpt_sl(lseg, line))
+	if (lseg_interpt_line(NULL, lseg, line))
 		result = 0.0;
 	else
 	{
-		result = dist_pl_internal(&lseg->p[0], line);
-		d2 = dist_pl_internal(&lseg->p[1], line);
+		result = line_closept_point(NULL, line, &lseg->p[0]);
+		d2 = line_closept_point(NULL, line, &lseg->p[1]);
 		/* XXX shouldn't we take the min not max? */
 		if (d2 > result)
 			result = d2;
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
-	Point	   *tmp;
-	Datum		result;
 
-	tmp = DatumGetPointP(DirectFunctionCall2(close_sb,
-											 LsegPGetDatum(lseg),
-											 BoxPGetDatum(box)));
-	result = DirectFunctionCall2(dist_pb,
-								 PointPGetDatum(tmp),
-								 BoxPGetDatum(box));
-
-	PG_RETURN_DATUM(result);
+	PG_RETURN_FLOAT8(box_closept_lseg(NULL, box, lseg));
 }
 
 /*
  * Distance from a line to a box
  */
 Datum
 dist_lb(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -2577,538 +2391,513 @@ dist_cpoly(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a point to a polygon
  */
 Datum
 dist_ppoly(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	POLYGON    *poly = PG_GETARG_POLYGON_P(1);
-	float8		result;
 
-	result = dist_ppoly_internal(point, poly);
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(dist_ppoly_internal(point, poly));
 }
 
 Datum
 dist_polyp(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	float8		result;
 
-	result = dist_ppoly_internal(point, poly);
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(dist_ppoly_internal(point, poly));
 }
 
-static double
+static float8
 dist_ppoly_internal(Point *pt, POLYGON *poly)
 {
 	float8		result;
 	float8		d;
 	int			i;
 	LSEG		seg;
 
 	if (point_inside(pt, poly->npts, poly->p) != 0)
 	{
 #ifdef GEODEBUG
 		printf("dist_ppoly_internal- point inside of polygon\n");
 #endif
 		return 0.0;
 	}
 
 	/* initialize distance with segment between first and last points */
 	seg.p[0].x = poly->p[0].x;
 	seg.p[0].y = poly->p[0].y;
 	seg.p[1].x = poly->p[poly->npts - 1].x;
 	seg.p[1].y = poly->p[poly->npts - 1].y;
-	result = dist_ps_internal(pt, &seg);
+	result = lseg_closept_point(NULL, &seg, pt);
 #ifdef GEODEBUG
-	printf("dist_ppoly_internal- segment 0/n distance is %f\n", result);
+	printf("dist_ppoly_internal- segment 0/n distance is %f\n", *result);
 #endif
 
 	/* check distances for other segments */
-	for (i = 0; (i < poly->npts - 1); i++)
+	for (i = 0; i < poly->npts - 1; i++)
 	{
 		seg.p[0].x = poly->p[i].x;
 		seg.p[0].y = poly->p[i].y;
 		seg.p[1].x = poly->p[i + 1].x;
 		seg.p[1].y = poly->p[i + 1].y;
-		d = dist_ps_internal(pt, &seg);
+		d = lseg_closept_point(NULL, &seg, pt);
 #ifdef GEODEBUG
 		printf("dist_ppoly_internal- segment %d distance is %f\n", (i + 1), d);
 #endif
 		if (d < result)
 			result = d;
 	}
 
 	return result;
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
  *				Intersection point of objects.
  *				We choose to ignore the "point" of intersection between
  *				  lines and boxes, since there are typically two.
  *-------------------------------------------------------------------*/
 
-/* Get intersection point of lseg and line; returns NULL if no intersection */
-static Point *
-interpt_sl(LSEG *lseg, LINE *line)
+/*
+ * Check if the line segment intersects with the line
+ *
+ * This returns true if line segment intersects with line, false if they
+ * do not.  This also sets the intersection point to *result, if it is not
+ * NULL.
+ */
+static bool
+lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
 {
+	Point		interpt;
 	LINE		tmp;
-	Point	   *p;
 
 	line_construct_pts(&tmp, &lseg->p[0], &lseg->p[1]);
-	p = line_interpt_internal(&tmp, line);
-#ifdef GEODEBUG
-	printf("interpt_sl- segment is (%.*g %.*g) (%.*g %.*g)\n",
-		   DBL_DIG, lseg->p[0].x, DBL_DIG, lseg->p[0].y, DBL_DIG, lseg->p[1].x, DBL_DIG, lseg->p[1].y);
-	printf("interpt_sl- segment becomes line A=%.*g B=%.*g C=%.*g\n",
-		   DBL_DIG, tmp.A, DBL_DIG, tmp.B, DBL_DIG, tmp.C);
-#endif
-	if (PointerIsValid(p))
-	{
-#ifdef GEODEBUG
-		printf("interpt_sl- intersection point is (%.*g %.*g)\n", DBL_DIG, p->x, DBL_DIG, p->y);
-#endif
-		if (on_ps_internal(p, lseg))
-		{
-#ifdef GEODEBUG
-			printf("interpt_sl- intersection point is on segment\n");
-#endif
-		}
-		else
-			p = NULL;
-	}
+	if (!line_interpt_line(&interpt, &tmp, line))
+		return false;
 
-	return p;
-}
+	if (!lseg_contain_point(lseg, &interpt))
+		return false;
 
-/* variant: just indicate if intersection point exists */
-static bool
-has_interpt_sl(LSEG *lseg, LINE *line)
-{
-	Point	   *tmp;
-
-	tmp = interpt_sl(lseg, line);
-	if (tmp)
+	if (result == NULL)
 		return true;
-	return false;
+
+	/*
+	 * If there is an intersection, then check explicitly for matching
+	 * endpoints since there may be rounding effects with annoying LSB
+	 * residue.
+	 */
+	if (FPeq(lseg->p[0].x, interpt.x) && FPeq(lseg->p[0].y, interpt.y))
+		*result = lseg->p[0];
+	else if (FPeq(lseg->p[1].x, interpt.x) && FPeq(lseg->p[1].y, interpt.y))
+		*result = lseg->p[1];
+	else
+		*result = interpt;
+
+	return true;
 }
 
 /*---------------------------------------------------------------------
  *		close_
  *				Point of closest proximity between objects.
  *-------------------------------------------------------------------*/
 
-/* close_pl -
+/*
  *		The intersection point of a perpendicular of the line
  *		through the point.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
+static float8
+line_closept_point(Point *result, LINE *line, Point *point)
+{
+	bool		retval;
+	float8		m;
+	LINE		tmp;
+
+	/* Drop a perpendicular and find the intersection point */
+	m = slope(line->A, 0.0, line->B, 0.0);
+	line_construct_pm(&tmp, point, m);
+	retval = line_interpt_line(result, line, &tmp);
+	Assert(retval);		/* XXX We need something better. */
+
+	/*
+	 * XXX We could use the distance to the closest point, but
+	 * line_interpt_line() is currently giving wrong results.
+	 */
+	return fabs((line->A * point->x + line->B * point->y + line->C) /
+				HYPOT(line->A, line->B));
+}
+
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
-	LINE	   *tmp;
-	double		invm;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	if (FPzero(line->B))		/* vertical? */
-	{
-		result->x = line->C;
-		result->y = pt->y;
-		PG_RETURN_POINT_P(result);
-	}
-	if (FPzero(line->A))		/* horizontal? */
-	{
-		result->x = pt->x;
-		result->y = line->C;
-		PG_RETURN_POINT_P(result);
-	}
-	/* drop a perpendicular and find the intersection point */
+	line_closept_point(result, line, pt);
 
-	/* invert and flip the sign on the slope to get a perpendicular */
-	invm = line->B / line->A;
-	tmp = line_construct_pm(pt, invm);
-	result = line_interpt_internal(tmp, line);
-	Assert(result != NULL);
 	PG_RETURN_POINT_P(result);
 }
 
 
-/* close_ps()
+/*
  * Closest point on line segment to specified point.
- * Take the closest endpoint if the point is left, right,
- *	above, or below the segment, otherwise find the intersection
- *	point of the segment and its perpendicular through the point.
  *
- * Some tricky code here, relying on boolean expressions
- *	evaluating to only zero or one to use as an array index.
- *		bug fixes by gthaker@atl.lmco.com; May 1, 1998
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
+static float8
+lseg_closept_point(Point *result, LSEG *lseg, Point *pt)
+{
+	double		invm;
+	Point		closept;
+	LINE		tmp;
+
+	/*
+	 * To find the closest point, we draw a perpendicular line from the point
+	 * to the line segment.
+	 */
+	invm = slope(lseg->p[0].y, lseg->p[1].y, lseg->p[1].x, lseg->p[0].x);
+	line_construct_pm(&tmp, pt, invm);
+	lseg_closept_line(&closept, lseg, &tmp);
+
+	if (result != NULL)
+		*result = closept;
+
+	return point_dt(&closept, pt);
+}
+
 Datum
 close_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
-	LINE	   *tmp;
-	double		invm;
-	int			xh,
-				yh;
+	Point	   *result;
 
-#ifdef GEODEBUG
-	printf("close_sp:pt->x %f pt->y %f\nlseg(0).x %f lseg(0).y %f  lseg(1).x %f lseg(1).y %f\n",
-		   pt->x, pt->y, lseg->p[0].x, lseg->p[0].y,
-		   lseg->p[1].x, lseg->p[1].y);
-#endif
+	result = (Point *) palloc(sizeof(Point));
 
-	/* xh (or yh) is the index of upper x( or y) end point of lseg */
-	/* !xh (or !yh) is the index of lower x( or y) end point of lseg */
-	xh = lseg->p[0].x < lseg->p[1].x;
-	yh = lseg->p[0].y < lseg->p[1].y;
-
-	if (FPeq(lseg->p[0].x, lseg->p[1].x))	/* vertical? */
-	{
-#ifdef GEODEBUG
-		printf("close_ps- segment is vertical\n");
-#endif
-		/* first check if point is below or above the entire lseg. */
-		if (pt->y < lseg->p[!yh].y)
-			result = point_copy(&lseg->p[!yh]); /* below the lseg */
-		else if (pt->y > lseg->p[yh].y)
-			result = point_copy(&lseg->p[yh]);	/* above the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
-
-		/* point lines along (to left or right) of the vertical lseg. */
-
-		result = (Point *) palloc(sizeof(Point));
-		result->x = lseg->p[0].x;
-		result->y = pt->y;
-		PG_RETURN_POINT_P(result);
-	}
-	else if (FPeq(lseg->p[0].y, lseg->p[1].y))	/* horizontal? */
-	{
-#ifdef GEODEBUG
-		printf("close_ps- segment is horizontal\n");
-#endif
-		/* first check if point is left or right of the entire lseg. */
-		if (pt->x < lseg->p[!xh].x)
-			result = point_copy(&lseg->p[!xh]); /* left of the lseg */
-		else if (pt->x > lseg->p[xh].x)
-			result = point_copy(&lseg->p[xh]);	/* right of the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
-
-		/* point lines along (at top or below) the horiz. lseg. */
-		result = (Point *) palloc(sizeof(Point));
-		result->x = pt->x;
-		result->y = lseg->p[0].y;
-		PG_RETURN_POINT_P(result);
-	}
-
-	/*
-	 * vert. and horiz. cases are down, now check if the closest point is one
-	 * of the end points or someplace on the lseg.
-	 */
-
-	invm = -1.0 / point_sl(&(lseg->p[0]), &(lseg->p[1]));
-	tmp = line_construct_pm(&lseg->p[!yh], invm);	/* lower edge of the
-													 * "band" */
-	if (pt->y < (tmp->A * pt->x + tmp->C))
-	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[!yh]); /* below the lseg, take lower end
-											 * pt */
-#ifdef GEODEBUG
-		printf("close_ps below: tmp A %f  B %f   C %f\n",
-			   tmp->A, tmp->B, tmp->C);
-#endif
-		PG_RETURN_POINT_P(result);
-	}
-	tmp = line_construct_pm(&lseg->p[yh], invm);	/* upper edge of the
-													 * "band" */
-	if (pt->y > (tmp->A * pt->x + tmp->C))
-	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[yh]);	/* above the lseg, take higher end
-											 * pt */
-#ifdef GEODEBUG
-		printf("close_ps above: tmp A %f  B %f   C %f\n",
-			   tmp->A, tmp->B, tmp->C);
-#endif
-		PG_RETURN_POINT_P(result);
-	}
-
-	/*
-	 * at this point the "normal" from point will hit lseg. The closest point
-	 * will be somewhere on the lseg
-	 */
-	tmp = line_construct_pm(pt, invm);
-#ifdef GEODEBUG
-	printf("close_ps- tmp A %f  B %f   C %f\n",
-		   tmp->A, tmp->B, tmp->C);
-#endif
-	result = interpt_sl(lseg, tmp);
-
-	/*
-	 * ordinarily we should always find an intersection point, but that could
-	 * fail in the presence of NaN coordinates, and perhaps even from simple
-	 * roundoff issues.  Return a SQL NULL if so.
-	 */
-	if (result == NULL)
+	if (isnan(lseg_closept_point(result, lseg, pt)))
 		PG_RETURN_NULL();
 
-#ifdef GEODEBUG
-	printf("close_ps- result.x %f  result.y %f\n", result->x, result->y);
-#endif
 	PG_RETURN_POINT_P(result);
 }
 
 
-/* close_lseg()
+/*
  * Closest point to l1 on l2.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
+ *
+ * XXX This function is wrong.  If must never set the *result to a point on
+ * the second segment.
  */
+static float8
+lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
+{
+	Point		point;
+	double		dist;
+	double		d;
+
+	d = lseg_closept_point(NULL, l1, &l2->p[0]);
+	dist = d;
+	if (result != NULL)
+		*result = l2->p[0];
+
+	d = lseg_closept_point(NULL, l1, &l2->p[1]);
+	if (d < dist)
+	{
+		dist = d;
+		if (result != NULL)
+			*result = l2->p[1];
+	}
+
+	if (lseg_closept_point(&point, l2, &l1->p[0]) < dist)
+		d = lseg_closept_point(result, l1, &point);
+
+	if (lseg_closept_point(&point, l2, &l1->p[1]) < dist)
+		d = lseg_closept_point(result, l1, &point);
+
+	if (d < dist)
+		dist = d;
+
+	return dist;
+}
+
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
-	Point		point;
-	double		dist;
-	double		d;
+	Point	   *result;
 
-	d = dist_ps_internal(&l1->p[0], l2);
-	dist = d;
-	memcpy(&point, &l1->p[0], sizeof(Point));
+	result = (Point *) palloc(sizeof(Point));
 
-	if ((d = dist_ps_internal(&l1->p[1], l2)) < dist)
-	{
-		dist = d;
-		memcpy(&point, &l1->p[1], sizeof(Point));
-	}
-
-	if (dist_ps_internal(&l2->p[0], l1) < dist)
-	{
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&l2->p[0]),
-													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
-													LsegPGetDatum(l2)));
-	}
-
-	if (dist_ps_internal(&l2->p[1], l1) < dist)
-	{
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&l2->p[1]),
-													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
-													LsegPGetDatum(l2)));
-	}
-
-	if (result == NULL)
-		result = point_copy(&point);
+	lseg_closept_lseg(result, l2, l1);
 
 	PG_RETURN_POINT_P(result);
 }
 
-/* close_pb()
+
+/*
  * Closest point on or in box to specified point.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
-Datum
-close_pb(PG_FUNCTION_ARGS)
+static float8
+box_closept_point(Point *result, BOX *box, Point *pt)
 {
-	Point	   *pt = PG_GETARG_POINT_P(0);
-	BOX		   *box = PG_GETARG_BOX_P(1);
-	LSEG		lseg,
-				seg;
-	Point		point;
+	LSEG		lseg;
+	Point		point,
+				closept;
 	double		dist,
 				d;
 
-	if (DatumGetBool(DirectFunctionCall2(on_pb,
-										 PointPGetDatum(pt),
-										 BoxPGetDatum(box))))
-		PG_RETURN_POINT_P(pt);
+	if (box_contain_point(box, pt))
+	{
+		if (result != NULL)
+			*result = *pt;
+
+		return 0.0;
+	}
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&lseg, &box->low, &point);
-	dist = dist_ps_internal(pt, &lseg);
+	dist = lseg_closept_point(result, &lseg, pt);
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	statlseg_construct(&lseg, &box->high, &point);
+	d = lseg_closept_point(&closept, &lseg, pt);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&lseg, &seg, sizeof(lseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
-	statlseg_construct(&seg, &box->low, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	statlseg_construct(&lseg, &box->low, &point);
+	d = lseg_closept_point(&closept, &lseg, pt);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&lseg, &seg, sizeof(lseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	statlseg_construct(&lseg, &box->high, &point);
+	d = lseg_closept_point(&closept, &lseg, pt);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&lseg, &seg, sizeof(lseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
-										PointPGetDatum(pt),
-										LsegPGetDatum(&lseg)));
+	return dist;
 }
 
+Datum
+close_pb(PG_FUNCTION_ARGS)
+{
+	Point	   *pt = PG_GETARG_POINT_P(0);
+	BOX		   *box = PG_GETARG_BOX_P(1);
+	Point	   *result;
+
+	result = (Point *) palloc(sizeof(Point));
+
+	box_closept_point(result, box, pt);
+
+	PG_RETURN_POINT_P(result);
+}
+
+
 /* close_sl()
  * Closest point on line to line segment.
  *
  * XXX THIS CODE IS WRONG
  * The code is actually calculating the point on the line segment
  *	which is backwards from the routine naming convention.
  * Copied code to new routine close_ls() but haven't fixed this one yet.
  * - thomas 1998-01-31
  */
 Datum
 close_sl(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 	float8		d1,
 				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
+	result = (Point *) palloc(sizeof(Point));
+
+	if (lseg_interpt_line(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
-	d1 = dist_pl_internal(&lseg->p[0], line);
-	d2 = dist_pl_internal(&lseg->p[1], line);
+	d1 = line_closept_point(NULL, line, &lseg->p[0]);
+	d2 = line_closept_point(NULL, line, &lseg->p[1]);
 	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
+		*result = lseg->p[0];
 	else
-		result = point_copy(&lseg->p[1]);
+		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
 
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_sl\" not implemented")));
 
 	PG_RETURN_NULL();
 }
 
-/* close_ls()
+/*
  * Closest point on line segment to line.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
+ *
+ * NOTE When the lines are parallel, endpoints of one of the line segment
+ * are FPeq(), in presence of NaN or Infinitive coordinates, or perhaps =
+ * even because of simple roundoff issues, there may not be a single closest
+ * point.  We are likely to set the result to the second endpoint in these
+ * cases.
  */
+static float8
+lseg_closept_line(Point *result, LSEG *lseg, LINE *line)
+{
+	float8		dist1,
+				dist2;
+
+	if (lseg_interpt_line(result, lseg, line))
+		return 0.0;
+
+	dist1 = line_closept_point(NULL, line, &lseg->p[0]);
+	dist2 = line_closept_point(NULL, line, &lseg->p[1]);
+
+	if (dist1 < dist2)
+	{
+		if (result != NULL)
+			*result = lseg->p[0];
+
+		return dist1;
+	}
+	else
+	{
+		if (result != NULL)
+			*result = lseg->p[1];
+
+		return dist2;
+	}
+}
+
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
-	float8		d1,
-				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
-		PG_RETURN_POINT_P(result);
+	result = (Point *) palloc(sizeof(Point));
 
-	d1 = dist_pl_internal(&lseg->p[0], line);
-	d2 = dist_pl_internal(&lseg->p[1], line);
-	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
-	else
-		result = point_copy(&lseg->p[1]);
+	lseg_closept_line(result, lseg, line);
 
 	PG_RETURN_POINT_P(result);
 }
 
-/* close_sb()
+
+/*
  * Closest point on or in box to line segment.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
-Datum
-close_sb(PG_FUNCTION_ARGS)
+static float8
+box_closept_lseg(Point *result, BOX *box, LSEG *lseg)
 {
-	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
-	BOX		   *box = PG_GETARG_BOX_P(1);
-	Point		point;
-	LSEG		bseg,
-				seg;
+	Point		point,
+				closept;
+	LSEG		bseg;
 	double		dist,
 				d;
 
-	/* segment intersects box? then just return closest point to center */
-	if (DatumGetBool(DirectFunctionCall2(inter_sb,
-										 LsegPGetDatum(lseg),
-										 BoxPGetDatum(box))))
-	{
-		box_cn(&point, box);
-		PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
-											PointPGetDatum(&point),
-											LsegPGetDatum(lseg)));
-	}
+	if (box_interpt_lseg(result, box, lseg))
+		return 0.0;
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	dist = lseg_dt(lseg, &bseg);
+	dist = lseg_closept_lseg(result, &bseg, lseg);
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	statlseg_construct(&bseg, &box->high, &point);
+	d = lseg_closept_lseg(&closept, &bseg, lseg);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&bseg, &seg, sizeof(bseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
-	statlseg_construct(&seg, &box->low, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	statlseg_construct(&bseg, &box->low, &point);
+	d = lseg_closept_lseg(&closept, &bseg, lseg);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&bseg, &seg, sizeof(bseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	statlseg_construct(&bseg, &box->high, &point);
+	d = lseg_closept_lseg(&closept, &bseg, lseg);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&bseg, &seg, sizeof(bseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	/* OK, we now have the closest line segment on the box boundary */
-	PG_RETURN_DATUM(DirectFunctionCall2(close_lseg,
-										LsegPGetDatum(lseg),
-										LsegPGetDatum(&bseg)));
+	return dist;
 }
 
+Datum
+close_sb(PG_FUNCTION_ARGS)
+{
+	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
+	BOX		   *box = PG_GETARG_BOX_P(1);
+	Point	   *result;
+
+	result = (Point *) palloc(sizeof(Point));
+
+	box_closept_lseg(result, box, lseg);
+
+	PG_RETURN_POINT_P(result);
+}
+
+
 Datum
 close_lb(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 #endif
 
 	/* think about this one for a while */
 	ereport(ERROR,
@@ -3116,73 +2905,90 @@ close_lb(PG_FUNCTION_ARGS)
 			 errmsg("function \"close_lb\" not implemented")));
 
 	PG_RETURN_NULL();
 }
 
 /*---------------------------------------------------------------------
  *		on_
  *				Whether one object lies completely within another.
  *-------------------------------------------------------------------*/
 
-/* on_pl -
+/*
  *		Does the point satisfy the equation?
  */
+static bool
+line_contain_point(LINE *line, Point *point)
+{
+	return FPzero(line->A * point->x + line->B * point->y + line->C);
+}
+
 Datum
 on_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(FPzero(line->A * pt->x + line->B * pt->y + line->C));
+	PG_RETURN_BOOL(line_contain_point(line, pt));
 }
 
 
-/* on_ps -
+/*
  *		Determine colinearity by detecting a triangle inequality.
  * This algorithm seems to behave nicely even with lsb residues - tgl 1997-07-09
  */
+static bool
+lseg_contain_point(LSEG *lseg, Point *pt)
+{
+	return FPeq(point_dt(pt, &lseg->p[0]) +
+				point_dt(pt, &lseg->p[1]),
+				point_dt(&lseg->p[0], &lseg->p[1]));
+}
+
 Datum
 on_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(on_ps_internal(pt, lseg));
+	PG_RETURN_BOOL(lseg_contain_point(lseg, pt));
 }
 
+
+/*
+ * Check whether the point is in the box or on its border
+ */
 static bool
-on_ps_internal(Point *pt, LSEG *lseg)
+box_contain_point(BOX *box, Point *point)
 {
-	return FPeq(point_dt(pt, &lseg->p[0]) + point_dt(pt, &lseg->p[1]),
-				point_dt(&lseg->p[0], &lseg->p[1]));
+	return box->high.x >= point->x && box->low.x <= point->x &&
+		   box->high.y >= point->y && box->low.y <= point-> y;
 }
 
 Datum
 on_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_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);
+	PG_RETURN_BOOL(box_contain_point(box, pt));
 }
 
 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);
+	PG_RETURN_BOOL(box_contain_point(box, pt));
 }
 
+
 /* on_ppath -
  *		Whether a point lies within (on) a polyline.
  *		If open, we have to (groan) check each segment.
  * (uses same algorithm as for point intersecting segment - tgl 1997-07-09)
  *		If closed, we use the old O(n) ray method for point-in-polygon.
  *				The ray is horizontal, from pt out to the right.
  *				Each segment that crosses the ray counts as an
  *				intersection; note that an endpoint or edge may touch
  *				but not cross.
  *				(we can do p-in-p in lg(n), but it takes preprocessing)
@@ -3210,158 +3016,184 @@ on_ppath(PG_FUNCTION_ARGS)
 				PG_RETURN_BOOL(true);
 			a = b;
 		}
 		PG_RETURN_BOOL(false);
 	}
 
 	/*-- CLOSED --*/
 	PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
 }
 
+
+/*
+ * Check whether the line segment is on the line or close enough
+ *
+ * It is, if both of its points are on the line or close enough.
+ */
 Datum
 on_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(DatumGetBool(DirectFunctionCall2(on_pl,
-													PointPGetDatum(&lseg->p[0]),
-													LinePGetDatum(line))) &&
-				   DatumGetBool(DirectFunctionCall2(on_pl,
-													PointPGetDatum(&lseg->p[1]),
-													LinePGetDatum(line))));
+	PG_RETURN_BOOL(line_contain_point(line, &lseg->p[0]) &&
+				   line_contain_point(line, &lseg->p[1]));
+}
+
+
+/*
+ * Check whether the line segment is in the box or on its border
+ *
+ * It is, if both of its points are in the box or on its border.
+ */
+static bool
+box_contain_lseg(BOX *box, LSEG *lseg)
+{
+	return box_contain_point(box, &lseg->p[0]) &&
+		   box_contain_point(box, &lseg->p[1]);
 }
 
 Datum
 on_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(DatumGetBool(DirectFunctionCall2(on_pb,
-													PointPGetDatum(&lseg->p[0]),
-													BoxPGetDatum(box))) &&
-				   DatumGetBool(DirectFunctionCall2(on_pb,
-													PointPGetDatum(&lseg->p[1]),
-													BoxPGetDatum(box))));
+	PG_RETURN_BOOL(box_contain_lseg(box, lseg));
 }
 
 /*---------------------------------------------------------------------
  *		inter_
  *				Whether one object intersects another.
  *-------------------------------------------------------------------*/
 
 Datum
 inter_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(has_interpt_sl(lseg, line));
+	PG_RETURN_BOOL(lseg_interpt_line(NULL, lseg, line));
 }
 
-/* inter_sb()
+
+/*
  * Do line segment and box intersect?
  *
  * Segment completely inside box counts as intersection.
  * If you want only segments crossing box boundaries,
  *	try converting box to path first.
  *
+ * This function also sets the *result to the closest point on the line
+ * segment to the center of the box when they overlap and the result is
+ * not NULL.  It is somewhat arbitrary, but maybe the best we can do as
+ * there are typically two points they intersect.
+ *
  * Optimize for non-intersection by checking for box intersection first.
  * - thomas 1998-01-30
  */
-Datum
-inter_sb(PG_FUNCTION_ARGS)
+static bool
+box_interpt_lseg(Point *result, BOX *box, LSEG *lseg)
 {
-	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
-	BOX		   *box = PG_GETARG_BOX_P(1);
 	BOX			lbox;
 	LSEG		bseg;
 	Point		point;
 
 	lbox.low.x = Min(lseg->p[0].x, lseg->p[1].x);
 	lbox.low.y = Min(lseg->p[0].y, lseg->p[1].y);
 	lbox.high.x = Max(lseg->p[0].x, lseg->p[1].x);
 	lbox.high.y = Max(lseg->p[0].y, lseg->p[1].y);
 
 	/* nothing close to overlap? then not going to intersect */
 	if (!box_ov(&lbox, box))
-		PG_RETURN_BOOL(false);
+		return false;
+
+	if (result != NULL)
+	{
+		box_cn(&point, box);
+		lseg_closept_point(result, lseg, &point);
+	}
 
 	/* an endpoint of segment is inside box? then clearly intersects */
-	if (DatumGetBool(DirectFunctionCall2(on_pb,
-										 PointPGetDatum(&lseg->p[0]),
-										 BoxPGetDatum(box))) ||
-		DatumGetBool(DirectFunctionCall2(on_pb,
-										 PointPGetDatum(&lseg->p[1]),
-										 BoxPGetDatum(box))))
-		PG_RETURN_BOOL(true);
+	if (box_contain_point(box, &lseg->p[0]) ||
+		box_contain_point(box, &lseg->p[1]))
+		return true;
 
 	/* pairwise check lseg intersections */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	/* if we dropped through, no two segs intersected */
-	PG_RETURN_BOOL(false);
+	return false;
 }
 
+Datum
+inter_sb(PG_FUNCTION_ARGS)
+{
+	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
+	BOX		   *box = PG_GETARG_BOX_P(1);
+
+	PG_RETURN_BOOL(box_interpt_lseg(NULL, box, lseg));
+}
+
+
 /* inter_lb()
  * Do line and box intersect?
  */
 Datum
 inter_lb(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	LSEG		bseg;
 	Point		p1,
 				p2;
 
 	/* pairwise check lseg intersections */
 	p1.x = box->low.x;
 	p1.y = box->low.y;
 	p2.x = box->low.x;
 	p2.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->high.x;
 	p1.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p2.x = box->high.x;
 	p2.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->low.x;
 	p1.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 
 	/* if we dropped through, no intersection */
 	PG_RETURN_BOOL(false);
 }
 
 /*------------------------------------------------------------------
  * The following routines define a data type and operator class for
  * POLYGONS .... Part of which (the polygon's bounding box) is built on
  * top of the BOX data type.
@@ -3374,42 +3206,40 @@ inter_lb(PG_FUNCTION_ARGS)
  *---------------------------------------------------------------------*/
 static void
 make_bound_box(POLYGON *poly)
 {
 	int			i;
 	double		x1,
 				y1,
 				x2,
 				y2;
 
-	if (poly->npts > 0)
-	{
-		x2 = x1 = poly->p[0].x;
-		y2 = y1 = poly->p[0].y;
-		for (i = 1; i < poly->npts; i++)
-		{
-			if (poly->p[i].x < x1)
-				x1 = poly->p[i].x;
-			if (poly->p[i].x > x2)
-				x2 = poly->p[i].x;
-			if (poly->p[i].y < y1)
-				y1 = poly->p[i].y;
-			if (poly->p[i].y > y2)
-				y2 = poly->p[i].y;
-		}
+	Assert(poly->npts > 0);
 
-		box_fill(&(poly->boundbox), x1, x2, y1, y2);
+	x1 = x2 = poly->p[0].x;
+	y2 = y1 = poly->p[0].y;
+	for (i = 1; i < poly->npts; i++)
+	{
+		if (poly->p[i].x < x1)
+			x1 = poly->p[i].x;
+		if (poly->p[i].x > x2)
+			x2 = poly->p[i].x;
+		if (poly->p[i].y < y1)
+			y1 = poly->p[i].y;
+		if (poly->p[i].y > y2)
+			y2 = poly->p[i].y;
 	}
-	else
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot create bounding box for empty polygon")));
+
+	poly->boundbox.low.x = x1;
+	poly->boundbox.high.x = x2;
+	poly->boundbox.low.y = y1;
+	poly->boundbox.high.y = y2;
 }
 
 /*------------------------------------------------------------------
  * poly_in - read in the polygon from a string specification
  *
  *		External format:
  *				"((x0,y0),...,(xn,yn))"
  *				"x0,y0,...,xn,yn"
  *				also supports the older style "(x1,...,xn,y1,...yn)"
  *------------------------------------------------------------------*/
@@ -3741,63 +3571,62 @@ poly_same(PG_FUNCTION_ARGS)
  *-----------------------------------------------------------------*/
 Datum
 poly_overlap(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
 	/* Quick check by bounding box */
 	result = (polya->npts > 0 && polyb->npts > 0 &&
-			  box_ov(&polya->boundbox, &polyb->boundbox)) ? true : false;
+			  box_ov(&polya->boundbox, &polyb->boundbox));
 
 	/*
 	 * Brute-force algorithm - try to find intersected edges, if so then
 	 * polygons are overlapped else check is one polygon inside other or not
 	 * by testing single point of them.
 	 */
 	if (result)
 	{
 		int			ia,
 					ib;
 		LSEG		sa,
 					sb;
 
 		/* Init first of polya's edge with last point */
 		sa.p[0] = polya->p[polya->npts - 1];
 		result = false;
 
-		for (ia = 0; ia < polya->npts && result == false; ia++)
+		for (ia = 0; ia < polya->npts && !result; ia++)
 		{
 			/* Second point of polya's edge is a current one */
 			sa.p[1] = polya->p[ia];
 
 			/* Init first of polyb's edge with last point */
 			sb.p[0] = polyb->p[polyb->npts - 1];
 
-			for (ib = 0; ib < polyb->npts && result == false; ib++)
+			for (ib = 0; ib < polyb->npts && !result; ib++)
 			{
 				sb.p[1] = polyb->p[ib];
-				result = lseg_intersect_internal(&sa, &sb);
+				result = lseg_interpt_lseg(NULL, &sa, &sb);
 				sb.p[0] = sb.p[1];
 			}
 
 			/*
 			 * move current endpoint to the first point of next edge
 			 */
 			sa.p[0] = sa.p[1];
 		}
 
-		if (result == false)
+		if (!result)
 		{
-			result = (point_inside(polya->p, polyb->npts, polyb->p)
-					  ||
+			result = (point_inside(polya->p, polyb->npts, polyb->p) ||
 					  point_inside(polyb->p, polya->npts, polya->p));
 		}
 	}
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
@@ -3817,36 +3646,35 @@ poly_overlap(PG_FUNCTION_ARGS)
 
 static bool
 touched_lseg_inside_poly(Point *a, Point *b, LSEG *s, POLYGON *poly, int start)
 {
 	/* point a is on s, b is not */
 	LSEG		t;
 
 	t.p[0] = *a;
 	t.p[1] = *b;
 
-#define POINTEQ(pt1, pt2)	(FPeq((pt1)->x, (pt2)->x) && FPeq((pt1)->y, (pt2)->y))
-	if (POINTEQ(a, s->p))
+	if (point_eq_point(a, s->p))
 	{
-		if (on_ps_internal(s->p + 1, &t))
+		if (lseg_contain_point(&t, s->p + 1))
 			return lseg_inside_poly(b, s->p + 1, poly, start);
 	}
-	else if (POINTEQ(a, s->p + 1))
+	else if (point_eq_point(a, s->p + 1))
 	{
-		if (on_ps_internal(s->p, &t))
+		if (lseg_contain_point(&t, s->p))
 			return lseg_inside_poly(b, s->p, poly, start);
 	}
-	else if (on_ps_internal(s->p, &t))
+	else if (lseg_contain_point(&t, s->p))
 	{
 		return lseg_inside_poly(b, s->p, poly, start);
 	}
-	else if (on_ps_internal(s->p + 1, &t))
+	else if (lseg_contain_point(&t, s->p + 1))
 	{
 		return lseg_inside_poly(b, s->p + 1, poly, start);
 	}
 
 	return true;				/* may be not true, but that will check later */
 }
 
 /*
  * Returns true if segment (a,b) is in polygon, option
  * start is used for optimization - function checks
@@ -3860,50 +3688,49 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 	int			i;
 	bool		res = true,
 				intersection = false;
 
 	t.p[0] = *a;
 	t.p[1] = *b;
 	s.p[0] = poly->p[(start == 0) ? (poly->npts - 1) : (start - 1)];
 
 	for (i = start; i < poly->npts && res; i++)
 	{
-		Point	   *interpt;
+		Point		interpt;
 
 		CHECK_FOR_INTERRUPTS();
 
 		s.p[1] = poly->p[i];
 
-		if (on_ps_internal(t.p, &s))
+		if (lseg_contain_point(&s, t.p))
 		{
-			if (on_ps_internal(t.p + 1, &s))
+			if (lseg_contain_point(&s, t.p + 1))
 				return true;	/* t is contained by s */
 
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p, t.p + 1, &s, poly, i + 1);
 		}
-		else if (on_ps_internal(t.p + 1, &s))
+		else if (lseg_contain_point(&s, t.p + 1))
 		{
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p + 1, t.p, &s, poly, i + 1);
 		}
-		else if ((interpt = lseg_interpt_internal(&t, &s)) != NULL)
+		else if (lseg_interpt_lseg(&interpt, &t, &s))
 		{
 			/*
 			 * segments are X-crossing, go to check each subsegment
 			 */
 
 			intersection = true;
-			res = lseg_inside_poly(t.p, interpt, poly, i + 1);
+			res = lseg_inside_poly(t.p, &interpt, poly, i + 1);
 			if (res)
-				res = lseg_inside_poly(t.p + 1, interpt, poly, i + 1);
-			pfree(interpt);
+				res = lseg_inside_poly(t.p + 1, &interpt, poly, i + 1);
 		}
 
 		s.p[0] = s.p[1];
 	}
 
 	if (res && !intersection)
 	{
 		Point		p;
 
 		/*
@@ -3915,74 +3742,86 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 
 		res = point_inside(&p, poly->npts, poly->p);
 	}
 
 	return res;
 }
 
 /*-----------------------------------------------------------------
  * Determine if polygon A contains polygon B.
  *-----------------------------------------------------------------*/
+static bool
+poly_contain_poly(POLYGON *polya, POLYGON *polyb)
+{
+	int			i;
+	LSEG		s;
+
+	Assert(polya->npts > 0 && polyb->npts > 0);
+
+	/*
+	 * Quick check to see if bounding box is contained.
+	 */
+	if (!box_contain_box(&polya->boundbox, &polyb->boundbox))
+		return false;
+
+	s.p[0] = polyb->p[polyb->npts - 1];
+
+	for (i = 0; i < polyb->npts; i++)
+	{
+		s.p[1] = polyb->p[i];
+		if (!lseg_inside_poly(s.p, s.p + 1, polya, 0))
+			return false;
+		s.p[0] = s.p[1];
+	}
+
+	return true;
+}
+
 Datum
 poly_contain(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	/*
-	 * Quick check to see if bounding box is contained.
-	 */
-	if (polya->npts > 0 && polyb->npts > 0 &&
-		DatumGetBool(DirectFunctionCall2(box_contain,
-										 BoxPGetDatum(&polya->boundbox),
-										 BoxPGetDatum(&polyb->boundbox))))
-	{
-		int			i;
-		LSEG		s;
-
-		s.p[0] = polyb->p[polyb->npts - 1];
-		result = true;
-
-		for (i = 0; i < polyb->npts && result; i++)
-		{
-			s.p[1] = polyb->p[i];
-			result = lseg_inside_poly(s.p, s.p + 1, polya, 0);
-			s.p[0] = s.p[1];
-		}
-	}
-	else
-	{
-		result = false;
-	}
+	result = poly_contain_poly(polya, polyb);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
 
 /*-----------------------------------------------------------------
  * Determine if polygon A is contained by polygon B
  *-----------------------------------------------------------------*/
 Datum
 poly_contained(PG_FUNCTION_ARGS)
 {
-	Datum		polya = PG_GETARG_DATUM(0);
-	Datum		polyb = PG_GETARG_DATUM(1);
+	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
+	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
+	bool		result;
 
 	/* Just switch the arguments and pass it off to poly_contain */
-	PG_RETURN_DATUM(DirectFunctionCall2(poly_contain, polyb, polya));
+	result = poly_contain_poly(polyb, polya);
+
+	/*
+	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
+	 */
+	PG_FREE_IF_COPY(polya, 0);
+	PG_FREE_IF_COPY(polyb, 1);
+
+	PG_RETURN_BOOL(result);
 }
 
 
 Datum
 poly_contain_pt(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_BOOL(point_inside(p, poly->npts, poly->p) != 0);
@@ -4018,170 +3857,215 @@ poly_distance(PG_FUNCTION_ARGS)
  **
  **		Routines for 2D points.
  **
  ***********************************************************************/
 
 Datum
 construct_point(PG_FUNCTION_ARGS)
 {
 	float8		x = PG_GETARG_FLOAT8(0);
 	float8		y = PG_GETARG_FLOAT8(1);
+	Point	   *result;
 
-	PG_RETURN_POINT_P(point_construct(x, y));
+	result = (Point *) palloc(sizeof(Point));
+
+	point_construct(result, x, y);
+
+	PG_RETURN_POINT_P(result);
+}
+
+
+static inline void
+point_add_point(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x + pt2->x,
+					pt1->y + pt2->y);
 }
 
 Datum
 point_add(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x + p2->x);
-	result->y = (p1->y + p2->y);
+	point_add_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+
+static inline void
+point_sub_point(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x - pt2->x,
+					pt1->y - pt2->y);
+}
+
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x - p2->x);
-	result->y = (p1->y - p2->y);
+	point_sub_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+
+static inline void
+point_mul_point(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					(pt1->x * pt2->x) - (pt1->y * pt2->y),
+					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+}
+
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x * p2->x) - (p1->y * p2->y);
-	result->y = (p1->x * p2->y) + (p1->y * p2->x);
+	point_mul_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+
+static inline void
+point_div_point(Point *result, Point *pt1, Point *pt2)
+{
+	double		div;
+
+	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
+
+	if (div == 0.0)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	point_construct(result,
+					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
+					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+}
+
 Datum
 point_div(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
-	double		div;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	div = (p2->x * p2->x) + (p2->y * p2->y);
-
-	if (div == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result->x = ((p1->x * p2->x) + (p1->y * p2->y)) / div;
-	result->y = ((p2->x * p1->y) - (p2->y * p1->x)) / div;
+	point_div_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D boxes.
  **
  ***********************************************************************/
 
 Datum
 points_box(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct(p1->x, p2->x, p1->y, p2->y));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	box_construct(result, p1, p2);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_add(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct((box->high.x + p->x),
-								  (box->low.x + p->x),
-								  (box->high.y + p->y),
-								  (box->low.y + p->y)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_add_point(&result->high, &box->high, p);
+	point_add_point(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_sub(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct((box->high.x - p->x),
-								  (box->low.x - p->x),
-								  (box->high.y - p->y),
-								  (box->low.y - p->y)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_sub_point(&result->high, &box->high, p);
+	point_sub_point(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_mul(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
 
-	high = DatumGetPointP(DirectFunctionCall2(point_mul,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_mul,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	result = (BOX *) palloc(sizeof(BOX));
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	point_mul_point(&high, &box->high, p);
+	point_mul_point(&low, &box->low, p);
+
+	box_construct(result, &high, &low);
 
 	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_div(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
 
-	high = DatumGetPointP(DirectFunctionCall2(point_div,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_div,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	result = (BOX *) palloc(sizeof(BOX));
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	point_div_point(&high, &box->high, p);
+	point_div_point(&low, &box->low, p);
+
+	box_construct(result, &high, &low);
 
 	PG_RETURN_BOX_P(result);
 }
 
 /*
  * Convert point to empty box
  */
 Datum
 point_box(PG_FUNCTION_ARGS)
 {
@@ -4277,83 +4161,63 @@ path_add(PG_FUNCTION_ARGS)
  * Translation operators.
  */
 Datum
 path_add_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x += point->x;
-		path->p[i].y += point->y;
-	}
+		point_add_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_sub_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x -= point->x;
-		path->p[i].y -= point->y;
-	}
+		point_sub_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 /* path_mul_pt()
  * Rotation and scaling operators.
  */
 Datum
 path_mul_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_mul,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_mul_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_div_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_div,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_div_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 
 Datum
 path_center(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	PATH	   *path = PG_GETARG_PATH_P(0);
@@ -4414,42 +4278,40 @@ poly_npoints(PG_FUNCTION_ARGS)
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 
 	PG_RETURN_INT32(poly->npts);
 }
 
 
 Datum
 poly_center(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
-	Datum		result;
-	CIRCLE	   *circle;
+	Point	   *result;
+	CIRCLE		circle;
 
-	circle = DatumGetCircleP(DirectFunctionCall1(poly_circle,
-												 PolygonPGetDatum(poly)));
-	result = DirectFunctionCall1(circle_center,
-								 CirclePGetDatum(circle));
+	result = (Point *) palloc(sizeof(Point));
 
-	PG_RETURN_DATUM(result);
+	poly_to_circle(&circle, poly);
+	*result = circle.center;
+
+	PG_RETURN_POINT_P(result);
 }
 
 
 Datum
 poly_box(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	BOX		   *box;
 
-	if (poly->npts < 1)
-		PG_RETURN_NULL();
-
-	box = box_copy(&poly->boundbox);
+	box = (BOX *) palloc(sizeof(BOX));
+	*box = poly->boundbox;
 
 	PG_RETURN_BOX_P(box);
 }
 
 
 /* box_poly()
  * Convert a box to a polygon.
  */
 Datum
 box_poly(PG_FUNCTION_ARGS)
@@ -4467,22 +4329,21 @@ box_poly(PG_FUNCTION_ARGS)
 
 	poly->p[0].x = box->low.x;
 	poly->p[0].y = box->low.y;
 	poly->p[1].x = box->low.x;
 	poly->p[1].y = box->high.y;
 	poly->p[2].x = box->high.x;
 	poly->p[2].y = box->high.y;
 	poly->p[3].x = box->high.x;
 	poly->p[3].y = box->low.y;
 
-	box_fill(&poly->boundbox, box->high.x, box->low.x,
-			 box->high.y, box->low.y);
+	box_construct(&poly->boundbox, &box->high, &box->low);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
 
 Datum
 poly_path(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	PATH	   *path;
@@ -4557,22 +4418,21 @@ circle_in(PG_FUNCTION_ARGS)
 
 	circle->radius = single_decode(s, &s, "circle", str);
 	if (circle->radius < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
 
 	while (depth > 0)
 	{
-		if ((*s == RDELIM)
-			|| ((*s == RDELIM_C) && (depth == 1)))
+		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
 			s++;
 			while (isspace((unsigned char) *s))
 				s++;
 		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
@@ -4656,22 +4516,21 @@ circle_send(PG_FUNCTION_ARGS)
 
 /*		circles identical?
  */
 Datum
 circle_same(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPeq(circle1->radius, circle2->radius) &&
-				   FPeq(circle1->center.x, circle2->center.x) &&
-				   FPeq(circle1->center.y, circle2->center.y));
+				   point_eq_point(&circle1->center, &circle2->center));
 }
 
 /*		circle_overlap	-		does circle1 overlap circle2?
  */
 Datum
 circle_overlap(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
@@ -4730,32 +4589,34 @@ circle_overright(PG_FUNCTION_ARGS)
 }
 
 /*		circle_contained		-		is circle1 contained by circle2?
  */
 Datum
 circle_contained(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle1->radius), circle2->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						circle2->radius - circle1->radius));
 }
 
 /*		circle_contain	-		does circle1 contain circle2?
  */
 Datum
 circle_contain(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle2->radius), circle1->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						circle1->radius - circle2->radius));
 }
 
 
 /*		circle_below		-		is circle1 strictly below circle2?
  */
 Datum
 circle_below(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
@@ -4858,107 +4719,83 @@ circle_ge(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPge(circle_ar(circle1), circle_ar(circle2)));
 }
 
 
 /*----------------------------------------------------------
  *	"Arithmetic" operators on circles.
  *---------------------------------------------------------*/
 
-static CIRCLE *
-circle_copy(CIRCLE *circle)
-{
-	CIRCLE	   *result;
-
-	if (!PointerIsValid(circle))
-		return NULL;
-
-	result = (CIRCLE *) palloc(sizeof(CIRCLE));
-	memcpy((char *) result, (char *) circle, sizeof(CIRCLE));
-	return result;
-}
-
-
 /* circle_add_pt()
  * Translation operator.
  */
 Datum
 circle_add_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x += point->x;
-	result->center.y += point->y;
+	point_add_point(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_sub_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x -= point->x;
-	result->center.y -= point->y;
+	point_sub_point(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /* circle_mul_pt()
  * Rotation and scaling operators.
  */
 Datum
 circle_mul_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_mul,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
-	result->radius *= HYPOT(point->x, point->y);
+	point_mul_point(&result->center, &circle->center, point);
+	result->radius = circle->radius * HYPOT(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_div_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_div,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
-	result->radius /= HYPOT(point->x, point->y);
+	point_div_point(&result->center, &circle->center, point);
+	result->radius = circle->radius / HYPOT(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /*		circle_area		-		returns the area of the circle.
  */
 Datum
 circle_area(PG_FUNCTION_ARGS)
 {
@@ -4993,22 +4830,22 @@ circle_radius(PG_FUNCTION_ARGS)
 /*		circle_distance -		returns the distance between
  *								  two circles.
  */
 Datum
 circle_distance(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(&circle1->center, &circle2->center)
-		- (circle1->radius + circle2->radius);
+	result = point_dt(&circle1->center, &circle2->center) -
+		(circle1->radius + circle2->radius);
 	if (result < 0)
 		result = 0;
 	PG_RETURN_FLOAT8(result);
 }
 
 
 Datum
 circle_contain_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
@@ -5190,56 +5027,60 @@ circle_poly(PG_FUNCTION_ARGS)
 		angle = i * anglestep;
 		poly->p[i].x = circle->center.x - (circle->radius * cos(angle));
 		poly->p[i].y = circle->center.y + (circle->radius * sin(angle));
 	}
 
 	make_bound_box(poly);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
-/*		poly_circle		- convert polygon to circle
+/*
+ * Convert polygon to circle
+ *
+ * The result must be preallocated.
  *
  * XXX This algorithm should use weighted means of line segments
  *	rather than straight average values of points - tgl 97/01/21.
  */
+static void
+poly_to_circle(CIRCLE *result, POLYGON *poly)
+{
+	int			i;
+
+	Assert(poly->npts > 0);
+
+	result->center.x = 0;
+	result->center.y = 0;
+	result->radius = 0;
+
+	for (i = 0; i < poly->npts; i++)
+		point_add_point(&result->center, &result->center, &poly->p[i]);
+	result->center.x /= poly->npts;
+	result->center.y /= poly->npts;
+
+	for (i = 0; i < poly->npts; i++)
+		result->radius += point_dt(&poly->p[i], &result->center);
+	result->radius /= poly->npts;
+}
+
 Datum
 poly_circle(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
-	CIRCLE	   *circle;
-	int			i;
+	CIRCLE	   *result;
 
-	if (poly->npts < 1)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot convert empty polygon to circle")));
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
+	poly_to_circle(result, poly);
 
-	circle->center.x = 0;
-	circle->center.y = 0;
-	circle->radius = 0;
-
-	for (i = 0; i < poly->npts; i++)
-	{
-		circle->center.x += poly->p[i].x;
-		circle->center.y += poly->p[i].y;
-	}
-	circle->center.x /= poly->npts;
-	circle->center.y /= poly->npts;
-
-	for (i = 0; i < poly->npts; i++)
-		circle->radius += point_dt(&poly->p[i], &circle->center);
-	circle->radius /= poly->npts;
-
-	PG_RETURN_CIRCLE_P(circle);
+	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /***********************************************************************
  **
  **		Private routines for multiple types.
  **
  ***********************************************************************/
 
 /*
@@ -5261,22 +5102,21 @@ point_inside(Point *p, int npts, Point *plist)
 	double		x0,
 				y0;
 	double		prev_x,
 				prev_y;
 	int			i = 0;
 	double		x,
 				y;
 	int			cross,
 				total_cross = 0;
 
-	if (npts <= 0)
-		return 0;
+	Assert(npts > 0);
 
 	/* compute first polygon point relative to single point */
 	x0 = plist[0].x - p->x;
 	y0 = plist[0].y - p->y;
 
 	prev_x = x0;
 	prev_y = y0;
 	/* loop over polygon points and aggregate total_cross */
 	for (i = 1; i < npts; i++)
 	{
@@ -5371,51 +5211,48 @@ lseg_crossing(double x, double y, double prev_x, double prev_y)
 static bool
 plist_same(int npts, Point *p1, Point *p2)
 {
 	int			i,
 				ii,
 				j;
 
 	/* find match for first point */
 	for (i = 0; i < npts; i++)
 	{
-		if ((FPeq(p2[i].x, p1[0].x))
-			&& (FPeq(p2[i].y, p1[0].y)))
+		if (point_eq_point(&p2[i], &p1[0]))
 		{
 
 			/* match found? then look forward through remaining points */
 			for (ii = 1, j = i + 1; ii < npts; ii++, j++)
 			{
 				if (j >= npts)
 					j = 0;
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_point(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed forward match with %d\n", j, ii);
 #endif
 					break;
 				}
 			}
 #ifdef GEODEBUG
 			printf("plist_same- ii = %d/%d after forward match\n", ii, npts);
 #endif
 			if (ii == npts)
 				return true;
 
 			/* match not found forwards? then look backwards */
 			for (ii = 1, j = i - 1; ii < npts; ii++, j--)
 			{
 				if (j < 0)
 					j = (npts - 1);
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_point(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed reverse match with %d\n", j, ii);
 #endif
 					break;
 				}
 			}
 #ifdef GEODEBUG
 			printf("plist_same- ii = %d/%d after reverse match\n", ii, npts);
 #endif
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index 3f1a755cbb..0fe40499e0 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -786,14 +786,15 @@ spg_bbox_quad_config(PG_FUNCTION_ARGS)
 
 /*
  * 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);
+	box = (BOX *) palloc(sizeof(BOX));
+	*box = polygon->boundbox;
 
 	PG_RETURN_BOX_P(box);
 }
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index a589e4239f..0e066894cd 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -171,17 +171,13 @@ typedef struct
 #define DatumGetCircleP(X)	  ((CIRCLE *) DatumGetPointer(X))
 #define CirclePGetDatum(X)	  PointerGetDatum(X)
 #define PG_GETARG_CIRCLE_P(n) DatumGetCircleP(PG_GETARG_DATUM(n))
 #define PG_RETURN_CIRCLE_P(x) return CirclePGetDatum(x)
 
 
 /*
  * 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/regress.c b/src/test/regress/regress.c
index 13e7207457..994697d338 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -62,21 +62,23 @@ regress_dist_ptpath(PG_FUNCTION_ARGS)
 	float8		result = 0.0;	/* keep compiler quiet */
 	float8		tmp;
 	int			i;
 	LSEG		lseg;
 
 	switch (path->npts)
 	{
 		case 0:
 			PG_RETURN_NULL();
 		case 1:
-			result = point_dt(pt, &path->p[0]);
+			result = DatumGetFloat8(DirectFunctionCall2(point_distance,
+														PointPGetDatum(pt),
+												PointPGetDatum(&path->p[0])));
 			break;
 		default:
 
 			/*
 			 * the distance from a point to a path is the smallest distance
 			 * from the point to any of its constituent segments.
 			 */
 			Assert(path->npts > 1);
 			for (i = 0; i < path->npts - 1; ++i)
 			{
@@ -280,22 +282,27 @@ widget_out(PG_FUNCTION_ARGS)
 	PG_RETURN_CSTRING(str);
 }
 
 PG_FUNCTION_INFO_V1(pt_in_widget);
 
 Datum
 pt_in_widget(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	WIDGET	   *widget = (WIDGET *) PG_GETARG_POINTER(1);
+	float8		distance;
 
-	PG_RETURN_BOOL(point_dt(point, &widget->center) < widget->radius);
+	distance = DatumGetFloat8(DirectFunctionCall2(point_distance,
+												  PointPGetDatum(point),
+											PointPGetDatum(&widget->center)));
+
+	PG_RETURN_BOOL(distance < widget->radius);
 }
 
 PG_FUNCTION_INFO_V1(boxarea);
 
 Datum
 boxarea(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	double		width,
 				height;
-- 
2.14.3 (Apple Git-98)

0002-float-header-v11.patchapplication/octet-stream; name=0002-float-header-v11.patchDownload
From 6e1458bba06d5382ab14fdf49b3201f766a62a00 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 28 May 2016 18:16:05 +0200
Subject: [PATCH 2/6] float-header-v11

Provide header file for built-in float datatypes

Even though, some datatypes under adt/ have separate header files,
most of the simple ones do not.  Their public functions were on
the builtins.h.  We would need to make more functions of floats public
to let the geometric types built on top of them.  This is a good
opportunity to make a separate header file for floats.

1acf7572554515b99ef6e783750aaea8777524ec made _cmp functions public
to solve NaN problem locally for GiST indexes.  This patch reworks it
in favour of a more extensive API.  Kevin Grittner suggested to design
the API using inline functions.  They are easier to use compared
to macros, and avoid double-evaluation hazards.
---
 contrib/btree_gin/btree_gin.c                 |   1 +
 contrib/btree_gist/btree_ts.c                 |   1 +
 contrib/cube/cube.c                           |   2 +-
 contrib/cube/cubeparse.y                      |   2 +-
 contrib/postgres_fdw/postgres_fdw.c           |   1 +
 src/backend/access/gist/gistget.c             |   2 +-
 src/backend/access/gist/gistproc.c            |  55 +--
 src/backend/access/gist/gistutil.c            |   2 +-
 src/backend/utils/adt/float.c                 | 589 ++++++--------------------
 src/backend/utils/adt/formatting.c            |   1 +
 src/backend/utils/adt/geo_ops.c               |   6 +-
 src/backend/utils/adt/geo_spgist.c            |   2 +-
 src/backend/utils/adt/numeric.c               |   1 +
 src/backend/utils/adt/rangetypes_gist.c       |   3 +-
 src/backend/utils/adt/rangetypes_selfuncs.c   |   3 +-
 src/backend/utils/adt/rangetypes_typanalyze.c |   3 +-
 src/backend/utils/adt/timestamp.c             |   1 +
 src/backend/utils/misc/guc.c                  |   1 +
 src/include/utils/builtins.h                  |  14 -
 src/include/utils/float.h                     | 376 ++++++++++++++++
 src/include/utils/geo_decls.h                 |   1 +
 21 files changed, 554 insertions(+), 513 deletions(-)
 create mode 100644 src/include/utils/float.h

diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index 2473f79ca1..301caefd47 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -3,20 +3,21 @@
  */
 #include "postgres.h"
 
 #include <limits.h>
 
 #include "access/stratnum.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/cash.h"
 #include "utils/date.h"
+#include "utils/float.h"
 #include "utils/inet.h"
 #include "utils/numeric.h"
 #include "utils/timestamp.h"
 #include "utils/varbit.h"
 
 PG_MODULE_MAGIC;
 
 typedef struct QueryInfo
 {
 	StrategyNumber strategy;
diff --git a/contrib/btree_gist/btree_ts.c b/contrib/btree_gist/btree_ts.c
index 18740cad38..49d1849d88 100644
--- a/contrib/btree_gist/btree_ts.c
+++ b/contrib/btree_gist/btree_ts.c
@@ -2,20 +2,21 @@
  * contrib/btree_gist/btree_ts.c
  */
 #include "postgres.h"
 
 #include <limits.h>
 
 #include "btree_gist.h"
 #include "btree_utils_num.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 typedef struct
 {
 	Timestamp	lower;
 	Timestamp	upper;
 } tsKEY;
 
 /*
 ** timestamp ops
 */
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c
index 3e3d83323c..ed41110a17 100644
--- a/contrib/cube/cube.c
+++ b/contrib/cube/cube.c
@@ -7,21 +7,21 @@
 ******************************************************************************/
 
 #include "postgres.h"
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 
 #include "cubedata.h"
 
 PG_MODULE_MAGIC;
 
 /*
  * Taken from the intarray contrib header
  */
 #define ARRPTR(x)  ( (double *) ARR_DATA_PTR(x) )
 #define ARRNELEMS(x)  ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x))
diff --git a/contrib/cube/cubeparse.y b/contrib/cube/cubeparse.y
index 1b65fa967c..deb2efdc0d 100644
--- a/contrib/cube/cubeparse.y
+++ b/contrib/cube/cubeparse.y
@@ -1,20 +1,20 @@
 %{
 /* contrib/cube/cubeparse.y */
 
 /* NdBox = [(lowerleft),(upperright)] */
 /* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */
 
 #include "postgres.h"
 
 #include "cubedata.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 
 /* All grammar constructs return strings */
 #define YYSTYPE char *
 
 /*
  * Bison doesn't allocate anything that needs to live across parser calls,
  * so we can easily have it use palloc instead of malloc.  This prevents
  * memory leaks if we error out during parsing.  Note this only works with
  * bison >= 2.0.  However, in bison 1.875 the default is to use alloca()
  * if possible, so there's not really much problem anyhow, at least if
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 7992ba5852..80043badc3 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -28,20 +28,21 @@
 #include "optimizer/cost.h"
 #include "optimizer/clauses.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
 #include "optimizer/planmain.h"
 #include "optimizer/restrictinfo.h"
 #include "optimizer/var.h"
 #include "optimizer/tlist.h"
 #include "parser/parsetree.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 #include "utils/sampling.h"
 #include "utils/selfuncs.h"
 
 PG_MODULE_MAGIC;
 
 /* Default CPU cost to start up a foreign query. */
diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c
index ca21cf7047..de0bcabb55 100644
--- a/src/backend/access/gist/gistget.c
+++ b/src/backend/access/gist/gistget.c
@@ -13,21 +13,21 @@
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/gist_private.h"
 #include "access/relscan.h"
 #include "catalog/pg_type.h"
 #include "miscadmin.h"
 #include "pgstat.h"
 #include "lib/pairingheap.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 
 /*
  * gistkillitems() -- set LP_DEAD state for items an indexscan caller has
  * told us were killed.
  *
  * We re-read page here, so it's important to check page LSN. If the page
  * has been modified since the last read (as determined by LSN), we cannot
  * flag any entries because it is possible that the old entry was vacuumed
diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index 97e6dc9910..4bbfdadf9f 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -27,62 +27,53 @@
 
 
 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
 						 StrategyNumber strategy);
 static bool rtree_internal_consistent(BOX *key, BOX *query,
 						  StrategyNumber strategy);
 
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
 
-/* Convenience macros for NaN-aware comparisons */
-#define FLOAT8_EQ(a,b)	(float8_cmp_internal(a, b) == 0)
-#define FLOAT8_LT(a,b)	(float8_cmp_internal(a, b) < 0)
-#define FLOAT8_LE(a,b)	(float8_cmp_internal(a, b) <= 0)
-#define FLOAT8_GT(a,b)	(float8_cmp_internal(a, b) > 0)
-#define FLOAT8_GE(a,b)	(float8_cmp_internal(a, b) >= 0)
-#define FLOAT8_MAX(a,b)  (FLOAT8_GT(a, b) ? (a) : (b))
-#define FLOAT8_MIN(a,b)  (FLOAT8_LT(a, b) ? (a) : (b))
-
 
 /**************************************************
  * Box ops
  **************************************************/
 
 /*
  * Calculates union of two boxes, a and b. The result is stored in *n.
  */
 static void
 rt_box_union(BOX *n, const BOX *a, const BOX *b)
 {
-	n->high.x = FLOAT8_MAX(a->high.x, b->high.x);
-	n->high.y = FLOAT8_MAX(a->high.y, b->high.y);
-	n->low.x = FLOAT8_MIN(a->low.x, b->low.x);
-	n->low.y = FLOAT8_MIN(a->low.y, b->low.y);
+	n->high.x = float8_max(a->high.x, b->high.x);
+	n->high.y = float8_max(a->high.y, b->high.y);
+	n->low.x = float8_min(a->low.x, b->low.x);
+	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
 static double
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
-	if (FLOAT8_LE(box->high.x, box->low.x) ||
-		FLOAT8_LE(box->high.y, box->low.y))
+	if (float8_le(box->high.x, box->low.x) ||
+		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
 	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
@@ -137,27 +128,27 @@ gist_box_consistent(PG_FUNCTION_ARGS)
 												 query,
 												 strategy));
 }
 
 /*
  * Increase BOX b to include addon.
  */
 static void
 adjustBox(BOX *b, const BOX *addon)
 {
-	if (FLOAT8_LT(b->high.x, addon->high.x))
+	if (float8_lt(b->high.x, addon->high.x))
 		b->high.x = addon->high.x;
-	if (FLOAT8_GT(b->low.x, addon->low.x))
+	if (float8_gt(b->low.x, addon->low.x))
 		b->low.x = addon->low.x;
-	if (FLOAT8_LT(b->high.y, addon->high.y))
+	if (float8_lt(b->high.y, addon->high.y))
 		b->high.y = addon->high.y;
-	if (FLOAT8_GT(b->low.y, addon->low.y))
+	if (float8_gt(b->low.y, addon->low.y))
 		b->low.y = addon->low.y;
 }
 
 /*
  * The GiST Union method for boxes
  *
  * returns the minimal bounding box that encloses all the entries in entryvec
  */
 Datum
 gist_box_union(PG_FUNCTION_ARGS)
@@ -609,36 +600,36 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		i1 = 0;
 		i2 = 0;
 		rightLower = intervalsLower[i1].lower;
 		leftUpper = intervalsUpper[i2].lower;
 		while (true)
 		{
 			/*
 			 * Find next lower bound of right group.
 			 */
 			while (i1 < nentries &&
-				   FLOAT8_EQ(rightLower, intervalsLower[i1].lower))
+				   float8_eq(rightLower, intervalsLower[i1].lower))
 			{
-				if (FLOAT8_LT(leftUpper, intervalsLower[i1].upper))
+				if (float8_lt(leftUpper, intervalsLower[i1].upper))
 					leftUpper = intervalsLower[i1].upper;
 				i1++;
 			}
 			if (i1 >= nentries)
 				break;
 			rightLower = intervalsLower[i1].lower;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * left group.
 			 */
 			while (i2 < nentries &&
-				   FLOAT8_LE(intervalsUpper[i2].upper, leftUpper))
+				   float8_le(intervalsUpper[i2].upper, leftUpper))
 				i2++;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim, rightLower, i1, leftUpper, i2);
 		}
 
 		/*
 		 * Iterate over upper bound of left group finding greatest possible
@@ -646,35 +637,35 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		 */
 		i1 = nentries - 1;
 		i2 = nentries - 1;
 		rightLower = intervalsLower[i1].upper;
 		leftUpper = intervalsUpper[i2].upper;
 		while (true)
 		{
 			/*
 			 * Find next upper bound of left group.
 			 */
-			while (i2 >= 0 && FLOAT8_EQ(leftUpper, intervalsUpper[i2].upper))
+			while (i2 >= 0 && float8_eq(leftUpper, intervalsUpper[i2].upper))
 			{
-				if (FLOAT8_GT(rightLower, intervalsUpper[i2].lower))
+				if (float8_gt(rightLower, intervalsUpper[i2].lower))
 					rightLower = intervalsUpper[i2].lower;
 				i2--;
 			}
 			if (i2 < 0)
 				break;
 			leftUpper = intervalsUpper[i2].upper;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * right group.
 			 */
-			while (i1 >= 0 && FLOAT8_GE(intervalsLower[i1].lower, rightLower))
+			while (i1 >= 0 && float8_ge(intervalsLower[i1].lower, rightLower))
 				i1--;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim,
 								 rightLower, i1 + 1, leftUpper, i2 + 1);
 		}
 	}
 
@@ -748,42 +739,42 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
 		}
 		else
 		{
 			lower = box->low.y;
 			upper = box->high.y;
 		}
 
-		if (FLOAT8_LE(upper, context.leftUpper))
+		if (float8_le(upper, context.leftUpper))
 		{
 			/* Fits to the left group */
-			if (FLOAT8_GE(lower, context.rightLower))
+			if (float8_ge(lower, context.rightLower))
 			{
 				/* Fits also to the right group, so "common entry" */
 				commonEntries[commonEntriesCount++].index = i;
 			}
 			else
 			{
 				/* Doesn't fit to the right group, so join to the left group */
 				PLACE_LEFT(box, i);
 			}
 		}
 		else
 		{
 			/*
 			 * Each entry should fit on either left or right group. Since this
 			 * entry didn't fit on the left group, it better fit in the right
 			 * group.
 			 */
-			Assert(FLOAT8_GE(lower, context.rightLower));
+			Assert(float8_ge(lower, context.rightLower));
 
 			/* Doesn't fit to the left group, so join to the right group */
 			PLACE_RIGHT(box, i);
 		}
 	}
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
@@ -853,24 +844,24 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
  * equivalent to box_same().
  */
 Datum
 gist_box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *b1 = PG_GETARG_BOX_P(0);
 	BOX		   *b2 = PG_GETARG_BOX_P(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
 	if (b1 && b2)
-		*result = (FLOAT8_EQ(b1->low.x, b2->low.x) &&
-				   FLOAT8_EQ(b1->low.y, b2->low.y) &&
-				   FLOAT8_EQ(b1->high.x, b2->high.x) &&
-				   FLOAT8_EQ(b1->high.y, b2->high.y));
+		*result = (float8_eq(b1->low.x, b2->low.x) &&
+				   float8_eq(b1->low.y, b2->low.y) &&
+				   float8_eq(b1->high.x, b2->high.x) &&
+				   float8_eq(b1->high.y, b2->high.y));
 	else
 		*result = (b1 == NULL && b2 == NULL);
 	PG_RETURN_POINTER(result);
 }
 
 /*
  * Leaf-level consistency for boxes: just apply the query operator
  */
 static bool
 gist_box_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy)
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 55cccd247a..7e43b8fc87 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -15,21 +15,21 @@
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist_private.h"
 #include "access/htup_details.h"
 #include "access/reloptions.h"
 #include "catalog/pg_opclass.h"
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/syscache.h"
 
 
 /*
  * Write itup vector to page, has no control of free space.
  */
 void
 gistfillbuffer(Page page, IndexTuple *itup, int len, OffsetNumber off)
 {
 	OffsetNumber l = InvalidOffsetNumber;
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index bc6a3e09b5..e4d097c6a0 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -16,62 +16,29 @@
 
 #include <ctype.h>
 #include <float.h>
 #include <math.h>
 #include <limits.h>
 
 #include "catalog/pg_type.h"
 #include "common/int.h"
 #include "libpq/pqformat.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/sortsupport.h"
 
 
-#ifndef M_PI
-/* from my RH5.2 gcc math.h file - thomas 2000-04-03 */
-#define M_PI 3.14159265358979323846
-#endif
-
-/* Radians per degree, a.k.a. PI / 180 */
-#define RADIANS_PER_DEGREE 0.0174532925199432957692
-
-/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0.  NAN definition from
- * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfNotNumberNANItems.asp
- */
-#if defined(WIN32) && !defined(NAN)
-static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
-
-#define NAN (*(const double *) nan)
-#endif
-
 /* not sure what the following should be, but better to make it over-sufficient */
 #define MAXFLOATWIDTH	64
 #define MAXDOUBLEWIDTH	128
 
-/*
- * check to see if a float4/8 val has underflowed or overflowed
- */
-#define CHECKFLOATVAL(val, inf_is_valid, zero_is_valid)			\
-do {															\
-	if (isinf(val) && !(inf_is_valid))							\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		  errmsg("value out of range: overflow")));				\
-																\
-	if ((val) == 0.0 && !(zero_is_valid))						\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		 errmsg("value out of range: underflow")));				\
-} while(0)
-
-
 /* Configurable GUC parameter */
 int			extra_float_digits = 0; /* Added to DBL_DIG or FLT_DIG */
 
 /* Cached constants for degree-based trig functions */
 static bool degree_consts_set = false;
 static float8 sin_30 = 0;
 static float8 one_minus_cos_60 = 0;
 static float8 asin_0_5 = 0;
 static float8 acos_0_5 = 0;
 static float8 atan_1_0 = 0;
@@ -102,100 +69,20 @@ static void init_degree_constants(void);
  * function, which causes configure to not set HAVE_CBRT.  Furthermore,
  * their compilers spit up at the mismatch between extern declaration
  * and static definition.  We work around that here by the expedient
  * of a #define to make the actual name of the static function different.
  */
 #define cbrt my_cbrt
 static double cbrt(double x);
 #endif							/* HAVE_CBRT */
 
 
-/*
- * Routines to provide reasonably platform-independent handling of
- * infinity and NaN.  We assume that isinf() and isnan() are available
- * and work per spec.  (On some platforms, we have to supply our own;
- * see src/port.)  However, generating an Infinity or NaN in the first
- * place is less well standardized; pre-C99 systems tend not to have C99's
- * INFINITY and NAN macros.  We centralize our workarounds for this here.
- */
-
-double
-get_float8_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (double) INFINITY;
-#else
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (double) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-/*
-* The funny placements of the two #pragmas is necessary because of a
-* long lived bug in the Microsoft compilers.
-* See http://support.microsoft.com/kb/120968/en-us for details
-*/
-#if (_MSC_VER >= 1800)
-#pragma warning(disable:4756)
-#endif
-float
-get_float4_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (float) INFINITY;
-#else
-#if (_MSC_VER >= 1800)
-#pragma warning(default:4756)
-#endif
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (float) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-double
-get_float8_nan(void)
-{
-	/* (double) NAN doesn't work on some NetBSD/MIPS releases */
-#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
-	/* C99 standard way */
-	return (double) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (double) (0.0 / 0.0);
-#endif
-}
-
-float
-get_float4_nan(void)
-{
-#ifdef NAN
-	/* C99 standard way */
-	return (float) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (float) (0.0 / 0.0);
-#endif
-}
-
-
 /*
  * Returns -1 if 'val' represents negative infinity, 1 if 'val'
  * represents (positive) infinity, and 0 otherwise. On some platforms,
  * this is equivalent to the isinf() macro, but not everywhere: C99
  * does not specify that isinf() needs to distinguish between positive
  * and negative infinity.
  */
 int
 is_infinite(double val)
 {
@@ -340,21 +227,21 @@ float4in(PG_FUNCTION_ARGS)
 	if (*endptr != '\0')
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"real", orig_num)));
 
 	/*
 	 * if we get here, we have a legal double, still need to check to see if
 	 * it's a legal float4
 	 */
-	CHECKFLOATVAL((float4) val, isinf(val), val == 0);
+	check_float4_val((float4) val, isinf(val), val == 0);
 
 	PG_RETURN_FLOAT4((float4) val);
 }
 
 /*
  *		float4out		- converts a float4 number to a string
  *						  using a standard output format
  */
 Datum
 float4out(PG_FUNCTION_ARGS)
@@ -690,35 +577,35 @@ float4up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT4(arg);
 }
 
 Datum
 float4larger(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) > 0)
+	if (float4_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 Datum
 float4smaller(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) < 0)
+	if (float4_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 /*
  *		======================
  *		FLOAT8 BASE OPERATIONS
  *		======================
@@ -757,35 +644,35 @@ float8up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT8(arg);
 }
 
 Datum
 float8larger(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) > 0)
+	if (float8_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 Datum
 float8smaller(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) < 0)
+	if (float8_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		====================
  *		ARITHMETIC OPERATORS
@@ -796,234 +683,165 @@ float8smaller(PG_FUNCTION_ARGS)
  *		float4pl		- returns arg1 + arg2
  *		float4mi		- returns arg1 - arg2
  *		float4mul		- returns arg1 * arg2
  *		float4div		- returns arg1 / arg2
  */
 Datum
 float4pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 + arg2;
-
-	/*
-	 * There isn't any way to check for underflow of addition/subtraction
-	 * because numbers near the underflow value have already been rounded to
-	 * the point where we can't detect that the two values were originally
-	 * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
-	 * 1.4013e-45.
-	 */
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_pl(arg1, arg2));
 }
 
 Datum
 float4mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mi(arg1, arg2));
 }
 
 Datum
 float4mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mul(arg1, arg2));
 }
 
 Datum
 float4div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_div(arg1, arg2));
 }
 
 /*
  *		float8pl		- returns arg1 + arg2
  *		float8mi		- returns arg1 - arg2
  *		float8mul		- returns arg1 * arg2
  *		float8div		- returns arg1 / arg2
  */
 Datum
 float8pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 + arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, arg2));
 }
 
 Datum
 float8mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 - arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, arg2));
 }
 
 Datum
 float8mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 * arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, arg2));
 }
 
 Datum
 float8div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, arg2));
 }
 
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float4{eq,ne,lt,le,gt,ge}		- float4/float4 comparison operations
  */
 int
 float4_cmp_internal(float4 a, float4 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float4_gt(a, b))
+		return 1;
+	if (float4_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
 float4eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float4_eq(arg1, arg2));
 }
 
 Datum
 float4ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float4_ne(arg1, arg2));
 }
 
 Datum
 float4lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float4_lt(arg1, arg2));
 }
 
 Datum
 float4le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float4_le(arg1, arg2));
 }
 
 Datum
 float4gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float4_gt(arg1, arg2));
 }
 
 Datum
 float4ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float4_ge(arg1, arg2));
 }
 
 Datum
 btfloat4cmp(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
 	PG_RETURN_INT32(float4_cmp_internal(arg1, arg2));
 }
@@ -1045,99 +863,79 @@ btfloat4sortsupport(PG_FUNCTION_ARGS)
 	ssup->comparator = btfloat4fastcmp;
 	PG_RETURN_VOID();
 }
 
 /*
  *		float8{eq,ne,lt,le,gt,ge}		- float8/float8 comparison operations
  */
 int
 float8_cmp_internal(float8 a, float8 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float8_gt(a, b))
+		return 1;
+	if (float8_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
 float8eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, arg2));
 }
 
 Datum
 float8ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, arg2));
 }
 
 Datum
 float8lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, arg2));
 }
 
 Datum
 float8le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, arg2));
 }
 
 Datum
 float8gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, arg2));
 }
 
 Datum
 float8ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, arg2));
 }
 
 Datum
 btfloat8cmp(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
 	PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
 }
@@ -1200,21 +998,21 @@ ftod(PG_FUNCTION_ARGS)
 
 
 /*
  *		dtof			- converts a float8 number to a float4 number
  */
 Datum
 dtof(PG_FUNCTION_ARGS)
 {
 	float8		num = PG_GETARG_FLOAT8(0);
 
-	CHECKFLOATVAL((float4) num, isinf(num), num == 0);
+	check_float4_val((float4) num, isinf(num), num == 0);
 
 	PG_RETURN_FLOAT4((float4) num);
 }
 
 
 /*
  *		dtoi4			- converts a float8 number to an int4 number
  */
 Datum
 dtoi4(PG_FUNCTION_ARGS)
@@ -1425,36 +1223,36 @@ dsqrt(PG_FUNCTION_ARGS)
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
 				 errmsg("cannot take square root of a negative number")));
 
 	result = sqrt(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcbrt			- returns cube root of arg1
  */
 Datum
 dcbrt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	result = cbrt(arg1);
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dpow			- returns pow(arg1,arg2)
  */
 Datum
 dpow(PG_FUNCTION_ARGS)
 {
@@ -1493,40 +1291,40 @@ dpow(PG_FUNCTION_ARGS)
 			/* The sign of Inf is not significant in this case. */
 			result = get_float8_infinity();
 		else if (fabs(arg1) != 1)
 			result = 0;
 		else
 			result = 1;
 	}
 	else if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
+	check_float8_val(result, isinf(arg1) || isinf(arg2), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dexp			- returns the exponential function of arg1
  */
 Datum
 dexp(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	errno = 0;
 	result = exp(arg1);
 	if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1), false);
+	check_float8_val(result, isinf(arg1), false);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dlog1			- returns the natural logarithm of arg1
  */
 Datum
 dlog1(PG_FUNCTION_ARGS)
 {
@@ -1541,21 +1339,21 @@ dlog1(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of zero")));
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of a negative number")));
 
 	result = log(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dlog10			- returns the base 10 logarithm of arg1
  */
 Datum
 dlog10(PG_FUNCTION_ARGS)
 {
@@ -1571,21 +1369,21 @@ dlog10(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of zero")));
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of a negative number")));
 
 	result = log10(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dacos			- returns the arccos of arg1 (radians)
  */
 Datum
 dacos(PG_FUNCTION_ARGS)
 {
@@ -1601,21 +1399,21 @@ dacos(PG_FUNCTION_ARGS)
 	 * range [-1, 1] to values in the range [0, Pi], so we should reject any
 	 * inputs outside that range and the result will always be finite.
 	 */
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = acos(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dasin			- returns the arcsin of arg1 (radians)
  */
 Datum
 dasin(PG_FUNCTION_ARGS)
 {
@@ -1631,21 +1429,21 @@ dasin(PG_FUNCTION_ARGS)
 	 * range [-1, 1] to values in the range [-Pi/2, Pi/2], so we should reject
 	 * any inputs outside that range and the result will always be finite.
 	 */
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = asin(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		datan			- returns the arctan of arg1 (radians)
  */
 Datum
 datan(PG_FUNCTION_ARGS)
 {
@@ -1656,21 +1454,21 @@ datan(PG_FUNCTION_ARGS)
 	if (isnan(arg1))
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/*
 	 * The principal branch of the inverse tangent function maps all inputs to
 	 * values in the range [-Pi/2, Pi/2], so the result should always be
 	 * finite, even if the input is infinite.
 	 */
 	result = atan(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		atan2			- returns the arctan of arg1/arg2 (radians)
  */
 Datum
 datan2(PG_FUNCTION_ARGS)
 {
@@ -1681,21 +1479,21 @@ datan2(PG_FUNCTION_ARGS)
 	/* Per the POSIX spec, return NaN if either input is NaN */
 	if (isnan(arg1) || isnan(arg2))
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/*
 	 * atan2 maps all inputs to values in the range [-Pi, Pi], so the result
 	 * should always be finite, even if the inputs are infinite.
 	 */
 	result = atan2(arg1, arg2);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcos			- returns the cosine of arg1 (radians)
  */
 Datum
 dcos(PG_FUNCTION_ARGS)
 {
@@ -1721,21 +1519,21 @@ dcos(PG_FUNCTION_ARGS)
 	 * platform reports via errno, so also explicitly test for infinite
 	 * inputs.
 	 */
 	errno = 0;
 	result = cos(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcot			- returns the cotangent of arg1 (radians)
  */
 Datum
 dcot(PG_FUNCTION_ARGS)
 {
@@ -1748,21 +1546,21 @@ dcot(PG_FUNCTION_ARGS)
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = tan(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = 1.0 / result;
-	CHECKFLOATVAL(result, true /* cot(0) == Inf */ , true);
+	check_float8_val(result, true /* cot(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dsin			- returns the sine of arg1 (radians)
  */
 Datum
 dsin(PG_FUNCTION_ARGS)
 {
@@ -1774,21 +1572,21 @@ dsin(PG_FUNCTION_ARGS)
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = sin(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dtan			- returns the tangent of arg1 (radians)
  */
 Datum
 dtan(PG_FUNCTION_ARGS)
 {
@@ -1800,21 +1598,21 @@ dtan(PG_FUNCTION_ARGS)
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = tan(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, true /* tan(pi/2) == Inf */ , true);
+	check_float8_val(result, true /* tan(pi/2) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /* ========== DEGREE-BASED TRIGONOMETRIC FUNCTIONS ========== */
 
 
 /*
  * Initialize the cached constants declared at the head of this file
  * (sin_30 etc).  The fact that we need those at all, let alone need this
@@ -1952,21 +1750,21 @@ dacosd(PG_FUNCTION_ARGS)
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	if (arg1 >= 0.0)
 		result = acosd_q1(arg1);
 	else
 		result = 90.0 + asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dasind			- returns the arcsin of arg1 (degrees)
  */
 Datum
 dasind(PG_FUNCTION_ARGS)
 {
@@ -1987,21 +1785,21 @@ dasind(PG_FUNCTION_ARGS)
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	if (arg1 >= 0.0)
 		result = asind_q1(arg1);
 	else
 		result = -asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		datand			- returns the arctan of arg1 (degrees)
  */
 Datum
 datand(PG_FUNCTION_ARGS)
 {
@@ -2017,21 +1815,21 @@ datand(PG_FUNCTION_ARGS)
 
 	/*
 	 * The principal branch of the inverse tangent function maps all inputs to
 	 * values in the range [-90, 90], so the result should always be finite,
 	 * even if the input is infinite.  Additionally, we take care to ensure
 	 * than when arg1 is 1, the result is exactly 45.
 	 */
 	atan_arg1 = atan(arg1);
 	result = (atan_arg1 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		atan2d			- returns the arctan of arg1/arg2 (degrees)
  */
 Datum
 datan2d(PG_FUNCTION_ARGS)
 {
@@ -2051,21 +1849,21 @@ datan2d(PG_FUNCTION_ARGS)
 	 * result should always be finite, even if the inputs are infinite.
 	 *
 	 * Note: this coding assumes that atan(1.0) is a suitable scaling constant
 	 * to get an exact result from atan2().  This might well fail on us at
 	 * some point, requiring us to decide exactly what inputs we think we're
 	 * going to guarantee an exact result for.
 	 */
 	atan2_arg1_arg2 = atan2(arg1, arg2);
 	result = (atan2_arg1_arg2 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		sind_0_to_30	- returns the sine of an angle that lies between 0 and
  *						  30 degrees.  This will return exactly 0 when x is 0,
  *						  and exactly 0.5 when x is 30 degrees.
  */
 static double
@@ -2172,21 +1970,21 @@ dcosd(PG_FUNCTION_ARGS)
 
 	if (arg1 > 90.0)
 	{
 		/* cosd(180-x) = -cosd(x) */
 		arg1 = 180.0 - arg1;
 		sign = -sign;
 	}
 
 	result = sign * cosd_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcotd			- returns the cotangent of arg1 (degrees)
  */
 Datum
 dcotd(PG_FUNCTION_ARGS)
 {
@@ -2237,21 +2035,21 @@ dcotd(PG_FUNCTION_ARGS)
 	result = sign * (cot_arg1 / cot_45);
 
 	/*
 	 * On some machines we get cotd(270) = minus zero, but this isn't always
 	 * true.  For portability, and because the user constituency for this
 	 * function probably doesn't want minus zero, force it to plain zero.
 	 */
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* cotd(0) == Inf */ , true);
+	check_float8_val(result, true /* cotd(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dsind			- returns the sine of arg1 (degrees)
  */
 Datum
 dsind(PG_FUNCTION_ARGS)
 {
@@ -2291,21 +2089,21 @@ dsind(PG_FUNCTION_ARGS)
 	}
 
 	if (arg1 > 90.0)
 	{
 		/* sind(180-x) = sind(x) */
 		arg1 = 180.0 - arg1;
 	}
 
 	result = sign * sind_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dtand			- returns the tangent of arg1 (degrees)
  */
 Datum
 dtand(PG_FUNCTION_ARGS)
 {
@@ -2356,64 +2154,56 @@ dtand(PG_FUNCTION_ARGS)
 	result = sign * (tan_arg1 / tan_45);
 
 	/*
 	 * On some machines we get tand(180) = minus zero, but this isn't always
 	 * true.  For portability, and because the user constituency for this
 	 * function probably doesn't want minus zero, force it to plain zero.
 	 */
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* tand(90) == Inf */ , true);
+	check_float8_val(result, true /* tand(90) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		degrees		- returns degrees converted from radians
  */
 Datum
 degrees(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
 
-	result = arg1 / RADIANS_PER_DEGREE;
-
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, RADIANS_PER_DEGREE));
 }
 
 
 /*
  *		dpi				- returns the constant PI
  */
 Datum
 dpi(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_FLOAT8(M_PI);
 }
 
 
 /*
  *		radians		- returns radians converted from degrees
  */
 Datum
 radians(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
 
-	result = arg1 * RADIANS_PER_DEGREE;
-
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, RADIANS_PER_DEGREE));
 }
 
 
 /*
  *		drandom		- returns a random number
  */
 Datum
 drandom(PG_FUNCTION_ARGS)
 {
 	float8		result;
@@ -2491,144 +2281,105 @@ check_float8_array(ArrayType *transarray, const char *caller, int n)
  * This function is used only in two stage aggregation and
  * shouldn't be called outside aggregate context.
  */
 Datum
 float8_combine(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_combine", 3);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-
 	transvalues2 = check_float8_array(transarray2, "float8_combine", 3);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
 
 Datum
 float8_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8		newval = PG_GETARG_FLOAT8(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float8_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
 	else
 	{
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
 								 sizeof(float8), FLOAT8PASSBYVAL, 'd');
 
 		PG_RETURN_ARRAYTYPE_P(result);
 	}
 }
 
 Datum
 float4_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 
 	/* do computations as float8 */
 	float8		newval = PG_GETARG_FLOAT4(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float4_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
 	else
 	{
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
 								 sizeof(float8), FLOAT8PASSBYVAL, 'd');
 
 		PG_RETURN_ARRAYTYPE_P(result);
 	}
 }
 
 Datum
@@ -2664,21 +2415,21 @@ float8_var_pop(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_var_pop", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Population variance is undefined when N is 0, so return NULL */
 	if (N == 0.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / (N * N));
 }
 
 Datum
 float8_var_samp(PG_FUNCTION_ARGS)
@@ -2693,21 +2444,21 @@ float8_var_samp(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_var_samp", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Sample variance is undefined when N is 0 or 1, so return NULL */
 	if (N <= 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
 }
 
 Datum
 float8_stddev_pop(PG_FUNCTION_ARGS)
@@ -2722,21 +2473,21 @@ float8_stddev_pop(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_stddev_pop", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Population stddev is undefined when N is 0, so return NULL */
 	if (N == 0.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(sqrt(numerator / (N * N)));
 }
 
 Datum
 float8_stddev_samp(PG_FUNCTION_ARGS)
@@ -2751,21 +2502,21 @@ float8_stddev_samp(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_stddev_samp", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Sample stddev is undefined when N is 0 or 1, so return NULL */
 	if (N <= 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(sqrt(numerator / (N * (N - 1.0))));
 }
 
 /*
  *		=========================
@@ -2800,30 +2551,30 @@ float8_regr_accum(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_accum", 6);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	N += 1.0;
 	sumX += newvalX;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
+	check_float8_val(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
 	sumX2 += newvalX * newvalX;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
+	check_float8_val(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
 	sumY += newvalY;
-	CHECKFLOATVAL(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
+	check_float8_val(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
 	sumY2 += newvalY * newvalY;
-	CHECKFLOATVAL(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
+	check_float8_val(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
 	sumXY += newvalX * newvalY;
-	CHECKFLOATVAL(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
-				  isinf(newvalY), true);
+	check_float8_val(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
+					 isinf(newvalY), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
 		transvalues[0] = N;
 		transvalues[1] = sumX;
@@ -2862,63 +2613,33 @@ float8_regr_accum(PG_FUNCTION_ARGS)
  * This function is used only in two stage aggregation and
  * shouldn't be called outside aggregate context.
  */
 Datum
 float8_regr_combine(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2,
-				sumY,
-				sumY2,
-				sumXY;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_regr_combine", 6);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-	sumY = transvalues1[3];
-	sumY2 = transvalues1[4];
-	sumXY = transvalues1[5];
-
 	transvalues2 = check_float8_array(transarray2, "float8_regr_combine", 6);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-	sumY += transvalues2[3];
-	CHECKFLOATVAL(sumY, isinf(transvalues1[3]) || isinf(transvalues2[3]),
-				  true);
-	sumY2 += transvalues2[4];
-	CHECKFLOATVAL(sumY2, isinf(transvalues1[4]) || isinf(transvalues2[4]),
-				  true);
-	sumXY += transvalues2[5];
-	CHECKFLOATVAL(sumXY, isinf(transvalues1[5]) || isinf(transvalues2[5]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
-	transvalues1[3] = sumY;
-	transvalues1[4] = sumY2;
-	transvalues1[5] = sumXY;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
+	transvalues1[3] = float8_pl(transvalues1[3], transvalues2[3]);
+	transvalues1[4] = float8_pl(transvalues1[4], transvalues2[4]);
+	transvalues1[5] = float8_pl(transvalues1[5], transvalues2[5]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
 
 
 Datum
 float8_regr_sxx(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
@@ -2930,21 +2651,21 @@ float8_regr_sxx(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_sxx", 6);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_syy(PG_FUNCTION_ARGS)
@@ -2959,21 +2680,21 @@ float8_regr_syy(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_syy", 6);
 	N = transvalues[0];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumY2) || isinf(sumY), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_sxy(PG_FUNCTION_ARGS)
@@ -2990,22 +2711,22 @@ float8_regr_sxy(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	/* A negative result is valid here */
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_avgx(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3058,22 +2779,22 @@ float8_covar_pop(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * N));
 }
 
 Datum
 float8_covar_samp(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
 	float8		N,
@@ -3086,22 +2807,22 @@ float8_covar_samp(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is <= 1 we should return NULL */
 	if (N < 2.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
 }
 
 Datum
 float8_corr(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
 	float8		N,
@@ -3120,26 +2841,26 @@ float8_corr(PG_FUNCTION_ARGS)
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0 || numeratorY <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXY / sqrt(numeratorX * numeratorY));
 }
 
 Datum
 float8_regr_r2(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3160,26 +2881,26 @@ float8_regr_r2(PG_FUNCTION_ARGS)
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 	/* per spec, horizontal line produces 1.0 */
 	if (numeratorY <= 0)
 		PG_RETURN_FLOAT8(1.0);
 
 	PG_RETURN_FLOAT8((numeratorXY * numeratorXY) /
 					 (numeratorX * numeratorY));
 }
 
@@ -3201,24 +2922,24 @@ float8_regr_slope(PG_FUNCTION_ARGS)
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXY / numeratorX);
 }
 
 Datum
 float8_regr_intercept(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3236,24 +2957,24 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXXY = sumY * sumX2 - sumX * sumXY;
-	CHECKFLOATVAL(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
-				  isinf(sumX) || isinf(sumXY), true);
+	check_float8_val(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
+					 isinf(sumX) || isinf(sumXY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXXY / numeratorX);
 }
 
 
 /*
  *		====================================
  *		MIXED-PRECISION ARITHMETIC OPERATORS
@@ -3264,251 +2985,211 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
  *		float48pl		- returns arg1 + arg2
  *		float48mi		- returns arg1 - arg2
  *		float48mul		- returns arg1 * arg2
  *		float48div		- returns arg1 / arg2
  */
 Datum
 float48pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 + arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl((float8) arg1, arg2));
 }
 
 Datum
 float48mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi((float8) arg1, arg2));
 }
 
 Datum
 float48mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul((float8) arg1, arg2));
 }
 
 Datum
 float48div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div((float8) arg1, arg2));
 }
 
 /*
  *		float84pl		- returns arg1 + arg2
  *		float84mi		- returns arg1 - arg2
  *		float84mul		- returns arg1 * arg2
  *		float84div		- returns arg1 / arg2
  */
 Datum
 float84pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 + arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, (float8) arg2));
 }
 
 Datum
 float84mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 - arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, (float8) arg2));
 }
 
 Datum
 float84mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 * arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, (float8) arg2));
 }
 
 Datum
 float84div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, (float8) arg2));
 }
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float48{eq,ne,lt,le,gt,ge}		- float4/float8 comparison operations
  */
 Datum
 float48eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq((float8) arg1, arg2));
 }
 
 Datum
 float48ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne((float8) arg1, arg2));
 }
 
 Datum
 float48lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt((float8) arg1, arg2));
 }
 
 Datum
 float48le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le((float8) arg1, arg2));
 }
 
 Datum
 float48gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt((float8) arg1, arg2));
 }
 
 Datum
 float48ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge((float8) arg1, arg2));
 }
 
 /*
  *		float84{eq,ne,lt,le,gt,ge}		- float8/float4 comparison operations
  */
 Datum
 float84eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, (float8) arg2));
 }
 
 Datum
 float84ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, (float8) arg2));
 }
 
 Datum
 float84lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, (float8) arg2));
 }
 
 Datum
 float84le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, (float8) arg2));
 }
 
 Datum
 float84gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, (float8) arg2));
 }
 
 Datum
 float84ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, (float8) arg2));
 }
 
 /*
  * Implements the float8 version of the width_bucket() function
  * defined by SQL2003. See also width_bucket_numeric().
  *
  * 'bound1' and 'bound2' are the lower and upper bounds of the
  * histogram's range, respectively. 'count' is the number of buckets
  * in the histogram. width_bucket() returns an integer indicating the
  * bucket number that 'operand' belongs to in an equiwidth histogram
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c
index 0e30810ae4..593da9f481 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -84,20 +84,21 @@
 
 #ifdef USE_ICU
 #include <unicode/ustring.h>
 #endif
 
 #include "catalog/pg_collation.h"
 #include "mb/pg_wchar.h"
 #include "utils/builtins.h"
 #include "utils/date.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 #include "utils/formatting.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/pg_locale.h"
 
 /* ----------
  * Routines type
  * ----------
  */
 #define DCH_TYPE		1		/* DATE-TIME version	*/
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index fc5b68d757..16bda3087c 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -14,27 +14,23 @@
  */
 #include "postgres.h"
 
 #include <math.h>
 #include <limits.h>
 #include <float.h>
 #include <ctype.h>
 
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
-#include "utils/builtins.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index 0fe40499e0..096e59f817 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -69,21 +69,21 @@
  *			src/backend/utils/adt/geo_spgist.c
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
 
 #include "access/spgist.h"
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
  * is going only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index a1792f0b01..5fbfdaa9de 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -29,20 +29,21 @@
 #include "access/hash.h"
 #include "catalog/pg_type.h"
 #include "common/int.h"
 #include "funcapi.h"
 #include "lib/hyperloglog.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/sortsupport.h"
 
 /* ----------
  * Uncomment the following to enable compilation of dump_numeric()
  * and dump_var() and to get a dump of any result produced by make_result().
  * ----------
 #define NUMERIC_DEBUG
diff --git a/src/backend/utils/adt/rangetypes_gist.c b/src/backend/utils/adt/rangetypes_gist.c
index 2fe61043d9..450479e31c 100644
--- a/src/backend/utils/adt/rangetypes_gist.c
+++ b/src/backend/utils/adt/rangetypes_gist.c
@@ -9,21 +9,22 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_gist.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/gist.h"
 #include "access/stratnum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/datum.h"
 #include "utils/rangetypes.h"
 
 
 /*
  * Range class properties used to segregate different classes of ranges in
  * GiST.  Each unique combination of properties is a class.  CLS_EMPTY cannot
  * be combined with anything else.
  */
 #define CLS_NORMAL			0	/* Ordinary finite range (no bits set) */
diff --git a/src/backend/utils/adt/rangetypes_selfuncs.c b/src/backend/utils/adt/rangetypes_selfuncs.c
index 59761ecf34..f9a5117492 100644
--- a/src/backend/utils/adt/rangetypes_selfuncs.c
+++ b/src/backend/utils/adt/rangetypes_selfuncs.c
@@ -14,21 +14,22 @@
  *	  src/backend/utils/adt/rangetypes_selfuncs.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/htup_details.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 #include "utils/selfuncs.h"
 #include "utils/typcache.h"
 
 static double calc_rangesel(TypeCacheEntry *typcache, VariableStatData *vardata,
 			  RangeType *constval, Oid operator);
 static double default_range_selectivity(Oid operator);
 static double calc_hist_selectivity(TypeCacheEntry *typcache,
 					  VariableStatData *vardata, RangeType *constval,
diff --git a/src/backend/utils/adt/rangetypes_typanalyze.c b/src/backend/utils/adt/rangetypes_typanalyze.c
index f2c11f54bc..9c50e4c1be 100644
--- a/src/backend/utils/adt/rangetypes_typanalyze.c
+++ b/src/backend/utils/adt/rangetypes_typanalyze.c
@@ -19,21 +19,22 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_typanalyze.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "catalog/pg_operator.h"
 #include "commands/vacuum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 
 static int	float8_qsort_cmp(const void *a1, const void *a2);
 static int	range_bound_qsort_cmp(const void *a1, const void *a2, void *arg);
 static void compute_range_stats(VacAttrStats *stats,
 					AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows);
 
 /*
  * range_typanalyze -- typanalyze function for range columns
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index e6a1eed191..f8ffa8aa4f 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -27,20 +27,21 @@
 #include "common/int128.h"
 #include "funcapi.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
 #include "parser/scansup.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 /*
  * gcc's -ffast-math switch breaks routines that expect exact results from
  * expressions like timeval / SECS_PER_HOUR, where timeval is double.
  */
 #ifdef __FAST_MATH__
 #error -ffast-math is known to break this code
 #endif
 
 #define SAMESIGN(a,b)	(((a) < 0) == ((b) < 0))
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 72f6be329e..9530a53ecb 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -72,20 +72,21 @@
 #include "storage/fd.h"
 #include "storage/large_object.h"
 #include "storage/pg_shmem.h"
 #include "storage/proc.h"
 #include "storage/predicate.h"
 #include "tcop/tcopprot.h"
 #include "tsearch/ts_cache.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/guc_tables.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/pg_locale.h"
 #include "utils/plancache.h"
 #include "utils/portal.h"
 #include "utils/ps_status.h"
 #include "utils/rls.h"
 #include "utils/snapmgr.h"
 #include "utils/tzparser.h"
 #include "utils/varlena.h"
 #include "utils/xml.h"
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 8bb57c5829..6432222a76 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -43,34 +43,20 @@ extern int	namestrcmp(Name name, const char *str);
 
 /* numutils.c */
 extern int32 pg_atoi(const char *s, int size, int c);
 extern void pg_itoa(int16 i, char *a);
 extern void pg_ltoa(int32 l, char *a);
 extern void pg_lltoa(int64 ll, char *a);
 extern char *pg_ltostr_zeropad(char *str, int32 value, int32 minwidth);
 extern char *pg_ltostr(char *str, int32 value);
 extern uint64 pg_strtouint64(const char *str, char **endptr, int base);
 
-/* float.c */
-extern PGDLLIMPORT int extra_float_digits;
-
-extern double get_float8_infinity(void);
-extern float get_float4_infinity(void);
-extern double get_float8_nan(void);
-extern float get_float4_nan(void);
-extern int	is_infinite(double val);
-extern double float8in_internal(char *num, char **endptr_p,
-				  const char *type_name, const char *orig_string);
-extern char *float8out_internal(double num);
-extern int	float4_cmp_internal(float4 a, float4 b);
-extern int	float8_cmp_internal(float8 a, float8 b);
-
 /* oid.c */
 extern oidvector *buildoidvector(const Oid *oids, int n);
 extern Oid	oidparse(Node *node);
 extern int	oid_cmp(const void *p1, const void *p2);
 
 /* regexp.c */
 extern char *regexp_fixed_prefix(text *text_re, bool case_insensitive,
 					Oid collation, bool *exact);
 
 /* ruleutils.c */
diff --git a/src/include/utils/float.h b/src/include/utils/float.h
new file mode 100644
index 0000000000..c9f5fd30ca
--- /dev/null
+++ b/src/include/utils/float.h
@@ -0,0 +1,376 @@
+/*-------------------------------------------------------------------------
+ *
+ * float.h
+ *	  Definitions for the built-in floating-point types
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/include/utils/float.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef FLOAT_H
+#define FLOAT_H
+
+#include <math.h>
+
+#ifndef M_PI
+/* From my RH5.2 gcc math.h file - thomas 2000-04-03 */
+#define M_PI 3.14159265358979323846
+#endif
+
+/* Radians per degree, a.k.a. PI / 180 */
+#define RADIANS_PER_DEGREE 0.0174532925199432957692
+
+/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0.  NAN definition from
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfNotNumberNANItems.asp
+ */
+#if defined(WIN32) && !defined(NAN)
+static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
+
+#define NAN (*(const float8 *) nan)
+#endif
+
+extern PGDLLIMPORT int extra_float_digits;
+
+/*
+ * Utility functions in float.c
+ */
+extern int	is_infinite(float8 val);
+extern float8 float8in_internal(char *num, char **endptr_p,
+				  const char *type_name, const char *orig_string);
+extern char *float8out_internal(float8 num);
+extern int	float4_cmp_internal(float4 a, float4 b);
+extern int	float8_cmp_internal(float8 a, float8 b);
+
+/*
+ * Routines to provide reasonably platform-independent handling of
+ * infinity and NaN
+ *
+ * We assume that isinf() and isnan() are available and work per spec.
+ * (On some platforms, we have to supply our own; see src/port.)  However,
+ * generating an Infinity or NaN in the first place is less well standardized;
+ * pre-C99 systems tend not to have C99's INFINITY and NAN macros.  We
+ * centralize our workarounds for this here.
+ */
+
+/*
+ * The funny placements of the two #pragmas is necessary because of a
+ * long lived bug in the Microsoft compilers.
+ * See http://support.microsoft.com/kb/120968/en-us for details
+ */
+#if (_MSC_VER >= 1800)
+#pragma warning(disable:4756)
+#endif
+static inline float
+get_float4_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float) INFINITY;
+#else
+#if (_MSC_VER >= 1800)
+#pragma warning(default:4756)
+#endif
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float8
+get_float8_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float8) INFINITY;
+#else
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float8) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float4
+get_float4_nan(void)
+{
+#ifdef NAN
+	/* C99 standard way */
+	return (float) NAN;
+#else
+	/* Assume we can get a NAN via zero divide */
+	return (float) (0.0 / 0.0);
+#endif
+}
+
+static inline float8
+get_float8_nan(void)
+{
+	/* (float8) NAN doesn't work on some NetBSD/MIPS releases */
+#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
+	/* C99 standard way */
+	return (float8) NAN;
+#else
+	/* Assume we can get a NAN via zero divide */
+	return (float8) (0.0 / 0.0);
+#endif
+}
+
+/*
+ * Checks to see if a float4/8 val has underflowed or overflowed
+ */
+
+static inline void
+check_float4_val(float4 val, bool inf_is_valid, bool zero_is_valid)
+{
+	if (isinf(val) && !inf_is_valid)
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if (val == 0.0 && !zero_is_valid)
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+static inline void
+check_float8_val(float8 val, bool inf_is_valid, bool zero_is_valid)
+{
+	if (isinf(val) && !inf_is_valid)
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if (val == 0.0 && !zero_is_valid)
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+/*
+ * Routines for operations with the checks above
+ *
+ * There isn't any way to check for underflow of addition/subtraction
+ * because numbers near the underflow value have already been rounded to
+ * the point where we can't detect that the two values were originally
+ * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
+ * 1.4013e-45.
+ */
+
+static inline float4
+float4_pl(float4 val1, float4 val2)
+{
+	float4		result;
+
+	result = val1 + val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_pl(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = val1 + val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mi(float4 val1, float4 val2)
+{
+	float4		result;
+
+	result = val1 - val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_mi(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = val1 - val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mul(float4 val1, float4 val2)
+{
+	float4		result;
+
+	result = val1 * val2;
+	check_float4_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0f || val2 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_mul(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = val1 * val2;
+	check_float8_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0 || val2 == 0.0);
+
+	return result;
+}
+
+static inline float4
+float4_div(float4 val1, float4 val2)
+{
+	float4		result;
+
+	if (val2 == 0.0f)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), val1 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_div(float8 val1, float8 val2)
+{
+	float8		result;
+
+	if (val2 == 0.0)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
+
+	return result;
+}
+
+/*
+ * Routines for NaN-aware comparisons
+ *
+ * We consider all NANs to be equal and larger than any non-NAN. This is
+ * somewhat arbitrary; the important thing is to have a consistent sort
+ * order.
+ */
+
+static inline bool
+float4_eq(float4 val1, float4 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float8_eq(float8 val1, float8 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float4_ne(float4 val1, float4 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float8_ne(float8 val1, float8 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float4_lt(float4 val1, float4 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float8_lt(float8 val1, float8 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float4_le(float4 val1, float4 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float8_le(float8 val1, float8 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float4_gt(float4 val1, float4 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float8_gt(float8 val1, float8 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float4_ge(float4 val1, float4 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline bool
+float8_ge(float8 val1, float8 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline float4
+float4_min(float4 val1, float4 val2)
+{
+	return float4_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_min(float8 val1, float8 val2)
+{
+	return float8_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float4
+float4_max(float4 val1, float4 val2)
+{
+	return float4_gt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_max(float8 val1, float8 val2)
+{
+	return float8_gt(val1, val2) ? val1 : val2;
+}
+
+#endif							/* FLOAT_H */
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 0e066894cd..aeb31515e4 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -17,20 +17,21 @@
  *		and data types. There are still some more to do. - tgl 97/04/19
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEO_DECLS_H
 #define GEO_DECLS_H
 
 #include <math.h>
 
 #include "fmgr.h"
+#include "utils/float.h"
 
 /*--------------------------------------------------------------------
  * Useful floating point utilities and constants.
  *-------------------------------------------------------------------*/
 
 
 #define EPSILON					1.0E-06
 
 #ifdef EPSILON
 #define FPzero(A)				(fabs(A) <= EPSILON)
-- 
2.14.3 (Apple Git-98)

0003-geo-float-v08.patchapplication/octet-stream; name=0003-geo-float-v08.patchDownload
From 89b5669a201de0cb597e3facda51eccbc3884e8e Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 27 May 2017 16:17:42 -0400
Subject: [PATCH 3/6] geo-float-v08

Use the built-in float datatype to implement geometric types

The changes can be summarised as:

* Check for underflow and overflow
* Check for division by zero
* Let the objects with NaN values to be the same
* Return NULL when the distance is NaN for all closest point operators
* Don't round the slope to DBL_MAX
* Use NaN as the slope of two equal points
* Favour not-NaN over NaN where it makes sense

The patch also replaces all occurrences of "double" as "float8".  They
are the same, but were randomly spread on the same file.
---
 src/backend/access/gist/gistproc.c |  91 +++----
 src/backend/utils/adt/geo_ops.c    | 494 ++++++++++++++++++++-----------------
 src/backend/utils/adt/geo_spgist.c |  28 +--
 src/include/utils/geo_decls.h      |  17 +-
 4 files changed, 331 insertions(+), 299 deletions(-)

diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index 4bbfdadf9f..4b6233f212 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -16,20 +16,21 @@
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/geo_decls.h"
 
 
 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
 						 StrategyNumber strategy);
 static bool rtree_internal_consistent(BOX *key, BOX *query,
 						  StrategyNumber strategy);
 
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
@@ -48,55 +49,56 @@ rt_box_union(BOX *n, const BOX *a, const BOX *b)
 	n->high.x = float8_max(a->high.x, b->high.x);
 	n->high.y = float8_max(a->high.y, b->high.y);
 	n->low.x = float8_min(a->low.x, b->low.x);
 	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
 	if (float8_le(box->high.x, box->low.x) ||
 		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
-	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
+	return float8_mul(float8_mi(box->high.x, box->low.x),
+					  float8_mi(box->high.y, box->low.y));
 }
 
 /*
  * Return amount by which the union of the two boxes is larger than
  * the original BOX's area.  The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 box_penalty(const BOX *original, const BOX *new)
 {
 	BOX			unionbox;
 
 	rt_box_union(&unionbox, original, new);
-	return size_box(&unionbox) - size_box(original);
+	return float8_mi(size_box(&unionbox), size_box(original));
 }
 
 /*
  * The GiST Consistent method for boxes
  *
  * Should return false if for all data items x below entry,
  * the predicate x op query must be false, where op is the oper
  * corresponding to strategy in the pg_amop table.
  */
 Datum
@@ -256,74 +258,74 @@ fallbackSplit(GistEntryVector *entryvec, GIST_SPLITVEC *v)
 
 /*
  * Represents information about an entry that can be placed to either group
  * without affecting overlap over selected axis ("common entry").
  */
 typedef struct
 {
 	/* Index of entry in the initial array */
 	int			index;
 	/* Delta between penalties of entry insertion into different groups */
-	double		delta;
+	float8		delta;
 } CommonEntry;
 
 /*
  * Context for g_box_consider_split. Contains information about currently
  * selected split and some general information.
  */
 typedef struct
 {
 	int			entriesCount;	/* total number of entries being split */
 	BOX			boundingBox;	/* minimum bounding box across all entries */
 
 	/* Information about currently selected split follows */
 
 	bool		first;			/* true if no split was selected yet */
 
-	double		leftUpper;		/* upper bound of left interval */
-	double		rightLower;		/* lower bound of right interval */
+	float8		leftUpper;		/* upper bound of left interval */
+	float8		rightLower;		/* lower bound of right interval */
 
 	float4		ratio;
 	float4		overlap;
 	int			dim;			/* axis of this split */
-	double		range;			/* width of general MBR projection to the
+	float8		range;			/* width of general MBR projection to the
 								 * selected axis */
 } ConsiderSplitContext;
 
 /*
  * Interval represents projection of box to axis.
  */
 typedef struct
 {
-	double		lower,
+	float8		lower,
 				upper;
 } SplitInterval;
 
 /*
  * Interval comparison function by lower bound of the interval;
  */
 static int
 interval_cmp_lower(const void *i1, const void *i2)
 {
-	double		lower1 = ((const SplitInterval *) i1)->lower,
+	float8		lower1 = ((const SplitInterval *) i1)->lower,
 				lower2 = ((const SplitInterval *) i2)->lower;
 
 	return float8_cmp_internal(lower1, lower2);
 }
 
 /*
  * Interval comparison function by upper bound of the interval;
  */
 static int
 interval_cmp_upper(const void *i1, const void *i2)
 {
-	double		upper1 = ((const SplitInterval *) i1)->upper,
+	float8		upper1 = ((const SplitInterval *) i1)->upper,
 				upper2 = ((const SplitInterval *) i2)->upper;
 
 	return float8_cmp_internal(upper1, upper2);
 }
 
 /*
  * Replace negative (or NaN) value with zero.
  */
 static inline float
 non_negative(float val)
@@ -332,28 +334,28 @@ non_negative(float val)
 		return val;
 	else
 		return 0.0f;
 }
 
 /*
  * Consider replacement of currently selected split with the better one.
  */
 static inline void
 g_box_consider_split(ConsiderSplitContext *context, int dimNum,
-					 double rightLower, int minLeftCount,
-					 double leftUpper, int maxLeftCount)
+					 float8 rightLower, int minLeftCount,
+					 float8 leftUpper, int maxLeftCount)
 {
 	int			leftCount,
 				rightCount;
 	float4		ratio,
 				overlap;
-	double		range;
+	float8		range;
 
 	/*
 	 * Calculate entries distribution ratio assuming most uniform distribution
 	 * of common entries.
 	 */
 	if (minLeftCount >= (context->entriesCount + 1) / 2)
 	{
 		leftCount = minLeftCount;
 	}
 	else
@@ -362,40 +364,41 @@ g_box_consider_split(ConsiderSplitContext *context, int dimNum,
 			leftCount = maxLeftCount;
 		else
 			leftCount = context->entriesCount / 2;
 	}
 	rightCount = context->entriesCount - leftCount;
 
 	/*
 	 * Ratio of split - quotient between size of lesser group and total
 	 * entries count.
 	 */
-	ratio = ((float4) Min(leftCount, rightCount)) /
-		((float4) context->entriesCount);
+	ratio = float4_div(Min(leftCount, rightCount), context->entriesCount);
 
 	if (ratio > LIMIT_RATIO)
 	{
 		bool		selectthis = false;
 
 		/*
 		 * The ratio is acceptable, so compare current split with previously
 		 * selected one. Between splits of one dimension we search for minimal
 		 * overlap (allowing negative values) and minimal ration (between same
 		 * overlaps. We switch dimension if find less overlap (non-negative)
 		 * or less range with same overlap.
 		 */
 		if (dimNum == 0)
-			range = context->boundingBox.high.x - context->boundingBox.low.x;
+			range = float8_mi(context->boundingBox.high.x,
+							  context->boundingBox.low.x);
 		else
-			range = context->boundingBox.high.y - context->boundingBox.low.y;
+			range = float8_mi(context->boundingBox.high.y,
+							  context->boundingBox.low.y);
 
-		overlap = (leftUpper - rightLower) / range;
+		overlap = float8_div(float8_mi(leftUpper, rightLower), range);
 
 		/* If there is no previous selection, select this */
 		if (context->first)
 			selectthis = true;
 		else if (context->dim == dimNum)
 		{
 			/*
 			 * Within the same dimension, choose the new split if it has a
 			 * smaller overlap, or same overlap but better ratio.
 			 */
@@ -524,21 +527,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		else
 			adjustBox(&context.boundingBox, box);
 	}
 
 	/*
 	 * Iterate over axes for optimal split searching.
 	 */
 	context.first = true;		/* nothing selected yet */
 	for (dim = 0; dim < 2; dim++)
 	{
-		double		leftUpper,
+		float8		leftUpper,
 					rightLower;
 		int			i1,
 					i2;
 
 		/* Project each entry as an interval on the selected axis. */
 		for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 		{
 			box = DatumGetBoxP(entryvec->vector[i].key);
 			if (dim == 0)
 			{
@@ -721,21 +724,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 			*rightBox = *(box);					\
 		v->spl_right[v->spl_nright++] = off;	\
 	} while(0)
 
 	/*
 	 * Distribute entries which can be distributed unambiguously, and collect
 	 * common entries.
 	 */
 	for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 	{
-		double		lower,
+		float8		lower,
 					upper;
 
 		/*
 		 * Get upper and lower bounds along selected axis.
 		 */
 		box = DatumGetBoxP(entryvec->vector[i].key);
 		if (context.dim == 0)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
@@ -776,31 +779,31 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
 	{
 		/*
 		 * Calculate minimum number of entries that must be placed in both
 		 * groups, to reach LIMIT_RATIO.
 		 */
-		int			m = ceil(LIMIT_RATIO * (double) nentries);
+		int			m = ceil(LIMIT_RATIO * (float8) nentries);
 
 		/*
 		 * Calculate delta between penalties of join "common entries" to
 		 * different groups.
 		 */
 		for (i = 0; i < commonEntriesCount; i++)
 		{
 			box = DatumGetBoxP(entryvec->vector[commonEntries[i].index].key);
-			commonEntries[i].delta = Abs(box_penalty(leftBox, box) -
-										 box_penalty(rightBox, box));
+			commonEntries[i].delta = Abs(float8_mi(box_penalty(leftBox, box),
+												   box_penalty(rightBox, box)));
 		}
 
 		/*
 		 * Sort "common entries" by calculated deltas in order to distribute
 		 * the most ambiguous entries first.
 		 */
 		qsort(commonEntries, commonEntriesCount, sizeof(CommonEntry), common_entry_cmp);
 
 		/*
 		 * Distribute "common entries" between groups.
@@ -1100,24 +1103,24 @@ gist_circle_compress(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	GISTENTRY  *retval;
 
 	if (entry->leafkey)
 	{
 		CIRCLE	   *in = DatumGetCircleP(entry->key);
 		BOX		   *r;
 
 		r = (BOX *) palloc(sizeof(BOX));
-		r->high.x = in->center.x + in->radius;
-		r->low.x = in->center.x - in->radius;
-		r->high.y = in->center.y + in->radius;
-		r->low.y = in->center.y - in->radius;
+		r->high.x = float8_pl(in->center.x, in->radius);
+		r->low.x = float8_mi(in->center.x, in->radius);
+		r->high.y = float8_pl(in->center.y, in->radius);
+		r->low.y = float8_mi(in->center.y, in->radius);
 
 		retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
 		gistentryinit(*retval, PointerGetDatum(r),
 					  entry->rel, entry->page,
 					  entry->offset, false);
 	}
 	else
 		retval = entry;
 	PG_RETURN_POINTER(retval);
 }
@@ -1141,24 +1144,24 @@ gist_circle_consistent(PG_FUNCTION_ARGS)
 	*recheck = true;
 
 	if (DatumGetBoxP(entry->key) == NULL || query == NULL)
 		PG_RETURN_BOOL(false);
 
 	/*
 	 * Since the operators require recheck anyway, we can just use
 	 * rtree_internal_consistent even at leaf nodes.  (This works in part
 	 * because the index entries are bounding boxes not circles.)
 	 */
-	bbox.high.x = query->center.x + query->radius;
-	bbox.low.x = query->center.x - query->radius;
-	bbox.high.y = query->center.y + query->radius;
-	bbox.low.y = query->center.y - query->radius;
+	bbox.high.x = float8_pl(query->center.x, query->radius);
+	bbox.low.x = float8_mi(query->center.x, query->radius);
+	bbox.high.y = float8_pl(query->center.y, query->radius);
+	bbox.low.y = float8_mi(query->center.y, query->radius);
 
 	result = rtree_internal_consistent(DatumGetBoxP(entry->key),
 									   &bbox, strategy);
 
 	PG_RETURN_BOOL(result);
 }
 
 /**************************************************
  * Point ops
  **************************************************/
@@ -1209,63 +1212,63 @@ gist_point_fetch(PG_FUNCTION_ARGS)
 				  entry->offset, false);
 
 	PG_RETURN_POINTER(retval);
 }
 
 
 #define point_point_distance(p1,p2) \
 	DatumGetFloat8(DirectFunctionCall2(point_distance, \
 									   PointPGetDatum(p1), PointPGetDatum(p2)))
 
-static double
+static float8
 computeDistance(bool isLeaf, BOX *box, Point *point)
 {
-	double		result = 0.0;
+	float8		result = 0.0;
 
 	if (isLeaf)
 	{
 		/* simple point to point distance */
 		result = point_point_distance(point, &box->low);
 	}
 	else if (point->x <= box->high.x && point->x >= box->low.x &&
 			 point->y <= box->high.y && point->y >= box->low.y)
 	{
 		/* point inside the box */
 		result = 0.0;
 	}
 	else if (point->x <= box->high.x && point->x >= box->low.x)
 	{
 		/* point is over or below box */
 		Assert(box->low.y <= box->high.y);
 		if (point->y > box->high.y)
-			result = point->y - box->high.y;
+			result = float8_mi(point->y, box->high.y);
 		else if (point->y < box->low.y)
-			result = box->low.y - point->y;
+			result = float8_mi(box->low.y, point->y);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
 	else if (point->y <= box->high.y && point->y >= box->low.y)
 	{
 		/* point is to left or right of box */
 		Assert(box->low.x <= box->high.x);
 		if (point->x > box->high.x)
-			result = point->x - box->high.x;
+			result = float8_mi(point->x, box->high.x);
 		else if (point->x < box->low.x)
-			result = box->low.x - point->x;
+			result = float8_mi(box->low.x, point->x);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
 	else
 	{
 		/* closest point will be a vertex */
 		Point		p;
-		double		subresult;
+		float8		subresult;
 
 		result = point_point_distance(point, &box->low);
 
 		subresult = point_point_distance(point, &box->high);
 		if (result > subresult)
 			result = subresult;
 
 		p.x = box->low.x;
 		p.y = box->high.y;
 		subresult = point_point_distance(point, &p);
@@ -1442,21 +1445,21 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 	}
 
 	PG_RETURN_BOOL(result);
 }
 
 Datum
 gist_point_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(GIST_LEAF(entry),
 									   DatumGetBoxP(entry->key),
 									   PG_GETARG_POINT_P(1));
 			break;
 		default:
@@ -1471,25 +1474,25 @@ gist_point_distance(PG_FUNCTION_ARGS)
 /*
  * The inexact GiST distance method for geometric types that store bounding
  * boxes.
  *
  * Compute lossy distance from point to index entries.  The result is inexact
  * because index entries are bounding boxes, not the exact shapes of the
  * indexed geometric types.  We use distance from point to MBR of index entry.
  * This is a lower bound estimate of distance from point to indexed geometric
  * type.
  */
-static double
+static float8
 gist_bbox_distance(GISTENTRY *entry, Datum query,
 				   StrategyNumber strategy, bool *recheck)
 {
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	/* Bounding box distance is always inexact. */
 	*recheck = true;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(false,
 									   DatumGetBoxP(entry->key),
@@ -1505,32 +1508,32 @@ gist_bbox_distance(GISTENTRY *entry, Datum query,
 
 Datum
 gist_circle_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
 
 Datum
 gist_poly_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 16bda3087c..2334da10fe 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -49,56 +49,56 @@ static int	point_inside(Point *p, int npts, Point *plist);
 static inline void line_construct_pm(LINE *result, Point *pt, float8 m);
 static inline void line_construct_pts(LINE *result, Point *pt1, Point *pt2);
 static bool	line_interpt_line(Point *result, LINE *l1, LINE *l2);
 static bool line_contain_point(LINE *line, Point *point);
 static float8 line_closept_point(Point *result, LINE *line, Point *pt);
 
 /* Routines for two-dimensional line segments */
 static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
 static bool	lseg_interpt_line(Point *result, LSEG *lseg, LINE *line);
 static bool	lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2);
-static int	lseg_crossing(double x, double y, double px, double py);
+static int	lseg_crossing(float8 x, float8 y, float8 px, float8 py);
 static bool	lseg_contain_point(LSEG *lseg, Point *point);
 static float8 lseg_closept_point(Point *result, LSEG *lseg, Point *pt);
 static float8 lseg_closept_line(Point *result, LSEG *lseg, LINE *line);
 static float8 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2);
 
 /* Routines for two-dimensional boxes */
 static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
 static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
-static double box_ar(BOX *box);
-static double box_ht(BOX *box);
-static double box_wd(BOX *box);
+static float8 box_ar(BOX *box);
+static float8 box_ht(BOX *box);
+static float8 box_wd(BOX *box);
 static bool box_contain_point(BOX *box, Point *point);
 static bool box_contain_box(BOX *box1, BOX *box2);
 static bool box_contain_lseg(BOX *box, LSEG *lseg);
 static bool box_interpt_lseg(Point *result, BOX *box, LSEG *lseg);
 static float8 box_closept_point(Point *result, BOX *box, Point *point);
 static float8 box_closept_lseg(Point *result, BOX *box, LSEG *lseg);
 
 /* Routines for two-dimensional circles */
-static double circle_ar(CIRCLE *circle);
+static float8 circle_ar(CIRCLE *circle);
 
 /* Routines for two-dimensional polygons */
 static void make_bound_box(POLYGON *poly);
 static void poly_to_circle(CIRCLE *result, POLYGON *poly);
 static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
 static bool poly_contain_poly(POLYGON *polya, POLYGON *polyb);
 static bool plist_same(int npts, Point *p1, Point *p2);
 static float8 dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 /* Routines for encoding and decoding */
-static double single_decode(char *num, char **endptr_p,
+static float8 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
-static void pair_decode(char *str, double *x, double *y, char **endptr_p,
+static void pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
 static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
 
 
 /*
@@ -136,38 +136,38 @@ static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
  *
  * For boxes, the points are opposite corners with the first point at the top right.
  * For closed paths and polygons, the points should be reordered to allow
  *	fast and correct equality comparisons.
  *
  * XXX perhaps points in complex shapes should be reordered internally
  *	to allow faster internal operations, but should keep track of input order
  *	and restore that order for text output - tgl 97/01/16
  */
 
-static double
+static float8
 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string)
 {
 	return float8in_internal(num, endptr_p, type_name, orig_string);
 }								/* single_decode() */
 
 static void
 single_encode(float8 x, StringInfo str)
 {
 	char	   *xstr = float8out_internal(x);
 
 	appendStringInfoString(str, xstr);
 	pfree(xstr);
 }								/* single_encode() */
 
 static void
-pair_decode(char *str, double *x, double *y, char **endptr_p,
+pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string)
 {
 	bool		has_delim;
 
 	while (isspace((unsigned char) *str))
 		str++;
 	if ((has_delim = (*str == LDELIM)))
 		str++;
 
 	*x = float8in_internal(str, &str, type_name, orig_string);
@@ -366,33 +366,33 @@ pair_count(char *s, char delim)
  *		External format: (two corners of box)
  *				"(f8, f8), (f8, f8)"
  *				also supports the older style "(f8, f8, f8, f8)"
  */
 Datum
 box_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	BOX		   *box = (BOX *) palloc(sizeof(BOX));
 	bool		isopen;
-	double		x,
+	float8		x,
 				y;
 
 	path_decode(str, false, 2, &(box->high), &isopen, NULL, "box", str);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*		box_out -		convert a box to external form.
@@ -406,38 +406,38 @@ box_out(PG_FUNCTION_ARGS)
 }
 
 /*
  *		box_recv			- converts external binary format to box
  */
 Datum
 box_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	BOX		   *box;
-	double		x,
+	float8		x,
 				y;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
 	box->high.x = pq_getmsgfloat8(buf);
 	box->high.y = pq_getmsgfloat8(buf);
 	box->low.x = pq_getmsgfloat8(buf);
 	box->low.y = pq_getmsgfloat8(buf);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*
@@ -456,31 +456,31 @@ box_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, box->low.y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*		box_construct	-		fill in a new box.
  */
 static inline void
 box_construct(BOX *result, Point *pt1, Point *pt2)
 {
-	if (pt1->x > pt2->x)
+	if (float8_gt(pt1->x, pt2->x))
 	{
 		result->high.x = pt1->x;
 		result->low.x = pt2->x;
 	}
 	else
 	{
 		result->high.x = pt2->x;
 		result->low.x = pt1->x;
 	}
-	if (pt1->y > pt2->y)
+	if (float8_gt(pt1->y, pt2->y))
 	{
 		result->high.y = pt1->y;
 		result->low.y = pt2->y;
 	}
 	else
 	{
 		result->high.y = pt2->y;
 		result->low.y = pt1->y;
 	}
 }
@@ -798,54 +798,54 @@ box_center(PG_FUNCTION_ARGS)
 	Point	   *result = (Point *) palloc(sizeof(Point));
 
 	box_cn(result, box);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		box_ar	-		returns the area of the box.
  */
-static double
+static float8
 box_ar(BOX *box)
 {
-	return box_wd(box) * box_ht(box);
+	return float8_mul(box_wd(box), box_ht(box));
 }
 
 
 /*		box_cn	-		stores the centerpoint of the box into *center.
  */
 static void
 box_cn(Point *center, BOX *box)
 {
-	center->x = (box->high.x + box->low.x) / 2.0;
-	center->y = (box->high.y + box->low.y) / 2.0;
+	center->x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	center->y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 }
 
 
 /*		box_wd	-		returns the width (length) of the box
  *								  (horizontal magnitude).
  */
-static double
+static float8
 box_wd(BOX *box)
 {
-	return box->high.x - box->low.x;
+	return float8_mi(box->high.x, box->low.x);
 }
 
 
 /*		box_ht	-		returns the height of the box
  *								  (vertical magnitude).
  */
-static double
+static float8
 box_ht(BOX *box)
 {
-	return box->high.y - box->low.y;
+	return float8_mi(box->high.y, box->low.y);
 }
 
 
 /*----------------------------------------------------------
  *	Funky operations.
  *---------------------------------------------------------*/
 
 /*		box_intersect	-
  *				returns the overlapping portion of two boxes,
  *				  or NULL if they do not intersect.
@@ -855,24 +855,24 @@ box_intersect(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 	BOX		   *result;
 
 	if (!box_ov(box1, box2))
 		PG_RETURN_NULL();
 
 	result = (BOX *) palloc(sizeof(BOX));
 
-	result->high.x = Min(box1->high.x, box2->high.x);
-	result->low.x = Max(box1->low.x, box2->low.x);
-	result->high.y = Min(box1->high.y, box2->high.y);
-	result->low.y = Max(box1->low.y, box2->low.y);
+	result->high.x = float8_min(box1->high.x, box2->high.x);
+	result->low.x = float8_max(box1->low.x, box2->low.x);
+	result->high.y = float8_min(box1->high.y, box2->high.y);
+	result->low.y = float8_max(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(result);
 }
 
 
 /*		box_diagonal	-
  *				returns a line segment which happens to be the
  *				  positive-slope diagonal of "box".
  */
 Datum
@@ -1004,37 +1004,37 @@ line_send(PG_FUNCTION_ARGS)
 
 /*
  * Fill already-allocated LINE struct from the point and the slope
  */
 static inline void
 line_construct_pm(LINE *result, Point *pt, float8 m)
 {
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
-		result->A = -1;
-		result->B = 0;
+		result->A = -1.0;
+		result->B = 0.0;
 		result->C = pt->x;
 	}
 	else if (m == 0.0)
 	{
 		/* horizontal - use "y = C" */
 		result->A = 0.0;
 		result->B = -1.0;
 		result->C = pt->y;
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
-		result->C = pt->y - m * pt->x;
+		result->C = float8_mi(pt->y, float8_mul(m, pt->x));
 	}
 }
 
 /*
  * Fill already-allocated LINE struct from two points on the line
  */
 static inline void
 line_construct_pts(LINE *result, Point *pt1, Point *pt2)
 {
 	float8		m;
@@ -1073,35 +1073,36 @@ line_intersect(PG_FUNCTION_ARGS)
 
 Datum
 line_parallel(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->B));
 
-	PG_RETURN_BOOL(FPeq(l2->A, l1->A * (l2->B / l1->B)));
+	PG_RETURN_BOOL(FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))));
 }
 
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
 	else if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
 
-	PG_RETURN_BOOL(FPeq(((l1->A * l2->B) / (l1->B * l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
+								   float8_mul(l1->B, l2->A)), -1.0));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
@@ -1111,34 +1112,37 @@ line_horizontal(PG_FUNCTION_ARGS)
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->A));
 }
 
 Datum
 line_eq(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	double		k;
+	float8		ratio;
 
-	if (!FPzero(l2->A))
-		k = l1->A / l2->A;
-	else if (!FPzero(l2->B))
-		k = l1->B / l2->B;
-	else if (!FPzero(l2->C))
-		k = l1->C / l2->C;
+	if (!FPzero(l2->A) && !isnan(l2->A))
+		ratio = float8_div(l1->A, l2->A);
+	else if (!FPzero(l2->B) && !isnan(l2->B))
+		ratio = float8_div(l1->B, l2->B);
+	else if (!FPzero(l2->C) && !isnan(l2->C))
+		ratio = float8_div(l1->C, l2->C);
 	else
-		k = 1.0;
+		ratio = 1.0;
 
-	PG_RETURN_BOOL(FPeq(l1->A, k * l2->A) &&
-				   FPeq(l1->B, k * l2->B) &&
-				   FPeq(l1->C, k * l2->C));
+	PG_RETURN_BOOL(((isnan(l1->A) && isnan(l2->A)) ||
+					FPeq(l1->A, float8_mul(ratio, l2->A))) &&
+				   ((isnan(l1->B) && isnan(l2->B)) ||
+					FPeq(l1->B, float8_mul(ratio, l2->B))) &&
+				   ((isnan(l1->C) && isnan(l2->C)) ||
+					FPeq(l1->C, float8_mul(ratio, l2->C))));
 }
 
 
 /*----------------------------------------------------------
  *	Line arithmetic routines.
  *---------------------------------------------------------*/
 
 /* line_distance()
  * Distance between two lines.
  */
@@ -1146,21 +1150,21 @@ Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
 	Point		tmp;
 
 	if (line_interpt_line(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
+		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
 	point_construct(&tmp, 0.0, l1->C);
 	result = line_closept_point(NULL, l2, &tmp);
 	PG_RETURN_FLOAT8(result);
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
@@ -1179,47 +1183,51 @@ line_interpt(PG_FUNCTION_ARGS)
 /*
  * Internal version of line_interpt
  *
  * This returns true if two lines intersect (they do, if they are not
  * parallel), false if they do not.  This also sets the intersection point
  * to *result, if it is not NULL.
  *
  * NOTE If the lines are identical then we will find they are parallel
  * and report "no intersection".  This is a little weird, but since
  * there's no *unique* intersection, maybe it's appropriate behavior.
+ *
+ * If the lines have NaN constants, we will return true, and the intersection
+ * point would have NaN coordinates.  We shouldn't return false in this case
+ * because that would mean the lines are parallel.
  */
 static bool
 line_interpt_line(Point *result, LINE *l1, LINE *l2)
 {
-	double		x,
+	float8		x,
 				y;
 
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
 		if (FPzero(l2->B))		/* l2 vertical? */
 			return false;
 
 		x = l1->C;
-		y = (l2->A * x + l2->C);
+		y = float8_pl(float8_mul(l2->A, x), l2->C);
 	}
 	else if (FPzero(l2->B))		/* l2 vertical? */
 	{
 		x = l2->C;
-		y = (l1->A * x + l1->C);
+		y = float8_pl(float8_mul(l1->A, x), l1->C);
 	}
 	else
 	{
-		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
 			return false;
 
-		x = (l1->C - l2->C) / (l2->A - l1->A);
-		y = (l1->A * x + l1->C);
+		x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
+		y = float8_pl(float8_mul(l1->A, x), l1->C);
 	}
 	if (result != NULL)
 		point_construct(result, x, y);
 
 	return true;
 }
 
 
 /***********************************************************************
  **
@@ -1240,36 +1248,35 @@ line_interpt_line(Point *result, LINE *l1, LINE *l2)
  *				"(xcoord, ycoord),... "
  *				"[xcoord, ycoord,... ]"
  *		Also support older format:
  *				"(closed, npts, xcoord, ycoord,... )"
  *---------------------------------------------------------*/
 
 Datum
 path_area(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P(0);
-	double		area = 0.0;
+	float8		area = 0.0;
 	int			i,
 				j;
 
 	if (!path->closed)
 		PG_RETURN_NULL();
 
 	for (i = 0; i < path->npts; i++)
 	{
 		j = (i + 1) % path->npts;
-		area += path->p[i].x * path->p[j].y;
-		area -= path->p[i].y * path->p[j].x;
+		area = float8_pl(area, float8_mul(path->p[i].x, path->p[j].y));
+		area = float8_mi(area, float8_mul(path->p[i].y, path->p[j].x));
 	}
 
-	area *= 0.5;
-	PG_RETURN_FLOAT8(area < 0.0 ? -area : area);
+	PG_RETURN_FLOAT8(float8_div(fabs(area), 2.0));
 }
 
 
 Datum
 path_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	PATH	   *path;
 	bool		isopen;
 	char	   *s;
@@ -1525,33 +1532,33 @@ path_inter(PG_FUNCTION_ARGS)
 				j;
 	LSEG		seg1,
 				seg2;
 
 	Assert(p1->npts > 0 && p2->npts > 0);
 
 	b1.high.x = b1.low.x = p1->p[0].x;
 	b1.high.y = b1.low.y = p1->p[0].y;
 	for (i = 1; i < p1->npts; i++)
 	{
-		b1.high.x = Max(p1->p[i].x, b1.high.x);
-		b1.high.y = Max(p1->p[i].y, b1.high.y);
-		b1.low.x = Min(p1->p[i].x, b1.low.x);
-		b1.low.y = Min(p1->p[i].y, b1.low.y);
+		b1.high.x = float8_max(p1->p[i].x, b1.high.x);
+		b1.high.y = float8_max(p1->p[i].y, b1.high.y);
+		b1.low.x = float8_min(p1->p[i].x, b1.low.x);
+		b1.low.y = float8_min(p1->p[i].y, b1.low.y);
 	}
 	b2.high.x = b2.low.x = p2->p[0].x;
 	b2.high.y = b2.low.y = p2->p[0].y;
 	for (i = 1; i < p2->npts; i++)
 	{
-		b2.high.x = Max(p2->p[i].x, b2.high.x);
-		b2.high.y = Max(p2->p[i].y, b2.high.y);
-		b2.low.x = Min(p2->p[i].x, b2.low.x);
-		b2.low.y = Min(p2->p[i].y, b2.low.y);
+		b2.high.x = float8_max(p2->p[i].x, b2.high.x);
+		b2.high.y = float8_max(p2->p[i].y, b2.high.y);
+		b2.low.x = float8_min(p2->p[i].x, b2.low.x);
+		b2.low.y = float8_min(p2->p[i].y, b2.low.y);
 	}
 	if (!box_ov(&b1, &b2))
 		PG_RETURN_BOOL(false);
 
 	/* pairwise check lseg intersections */
 	for (i = 0; i < p1->npts; i++)
 	{
 		int			iprev;
 
 		if (i > 0)
@@ -1627,21 +1634,21 @@ path_distance(PG_FUNCTION_ARGS)
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
 			tmp = lseg_closept_lseg(NULL, &seg1, &seg2);
-			if (!have_min || tmp < min)
+			if (!have_min || float8_lt(tmp, min))
 			{
 				min = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	if (!have_min)
 		PG_RETURN_NULL();
 
@@ -1666,21 +1673,21 @@ path_length(PG_FUNCTION_ARGS)
 
 		if (i > 0)
 			iprev = i - 1;
 		else
 		{
 			if (!path->closed)
 				continue;
 			iprev = path->npts - 1; /* include the closure segment */
 		}
 
-		result += point_dt(&path->p[iprev], &path->p[i]);
+		result = float8_pl(result, point_dt(&path->p[iprev], &path->p[i]));
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /***********************************************************************
  **
  **		Routines for 2D points.
  **
  ***********************************************************************/
@@ -1832,41 +1839,42 @@ point_ne(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_BOOL(!point_eq_point(pt1, pt2));
 }
 
 static inline bool
 point_eq_point(Point *pt1, Point *pt2)
 {
-	return FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y);
+	return ((isnan(pt1->x) && isnan(pt2->x)) || FPeq(pt1->x, pt2->x)) &&
+		   ((isnan(pt1->y) && isnan(pt2->y)) || FPeq(pt1->y, pt2->y));
 }
 
 
 /*----------------------------------------------------------
  *	"Arithmetic" operators on points.
  *---------------------------------------------------------*/
 
 Datum
 point_distance(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
 static float8
 point_dt(Point *pt1, Point *pt2)
 {
-	return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
+	return HYPOT(float8_mi(pt1->x, pt2->x), float8_mi(pt1->y, pt2->y));
 }
 
 Datum
 point_slope(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(slope(pt1->x, pt2->x, pt1->y, pt2->y));
 }
@@ -1875,27 +1883,29 @@ point_slope(PG_FUNCTION_ARGS)
 /*
  * Return slope of two points
  *
  * This function accepts x and y coordinates separately to let it be used
  * to calculate inverse slope.  To achieve that, pass the values in
  * (y1, y2, x2, x1) order.
  */
 static inline float8
 slope(float8 x1, float8 x2, float8 y1, float8 y2)
 {
-	/*
-	 * XXX This should be exact checking.  The callers are using the macros
-	 * when necessary.
-	 */
-	if (FPeq(x1, x2))
+	if (x1 == x2)
+	{
+		if (y1 == y2)
+			return NAN;
+
 		return DBL_MAX;
-	return (y1 - y2) / (x1 - x2);
+	}
+
+	return float8_div(float8_mi(y1, y2), float8_mi(x1, x2));
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D line segments.
  **
  ***********************************************************************/
 
 /*----------------------------------------------------------
@@ -2035,21 +2045,21 @@ lseg_parallel(PG_FUNCTION_ARGS)
  *	'((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg
  * So, modified it to check explicitly for slope of vertical line
  *	returned by slope() and the results seem better.
  * - thomas 1998-01-31
  */
 Datum
 lseg_perp(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	double		m1,
+	float8		m1,
 				m2;
 
 	m1 = slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y);
 	m2 = slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y);
 
 #ifdef GEODEBUG
 	printf("lseg_perp- slopes are %g and %g\n", m1, m2);
 #endif
 	if (FPzero(m1))
 		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
@@ -2157,22 +2167,22 @@ lseg_distance(PG_FUNCTION_ARGS)
 
 
 Datum
 lseg_center(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
-	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
+	result->x = float8_div(float8_pl(lseg->p[0].x, lseg->p[1].x), 2.0);
+	result->y = float8_div(float8_pl(lseg->p[0].y, lseg->p[1].y), 2.0);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  *		Find the intersection point of two segments (if any).
  *
  * This returns true if two line segments intersect, false if they do not.
  * This also sets the intersection point to *result, if it is not NULL.
@@ -2281,21 +2291,21 @@ dist_ppath(PG_FUNCTION_ARGS)
 			iprev = i - 1;
 		else
 		{
 			if (!path->closed)
 				continue;
 			iprev = path->npts - 1; /* Include the closure segment */
 		}
 
 		statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
 		tmp = lseg_closept_point(NULL, &lseg, pt);
-		if (!have_min || tmp < result)
+		if (!have_min || float8_lt(tmp, result))
 		{
 			result = tmp;
 			have_min = true;
 		}
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
@@ -2311,33 +2321,28 @@ dist_pb(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
-	float8		result,
-				d2;
+	float8		result;
 
 	if (lseg_interpt_line(NULL, lseg, line))
 		result = 0.0;
 	else
-	{
-		result = line_closept_point(NULL, line, &lseg->p[0]);
-		d2 = line_closept_point(NULL, line, &lseg->p[1]);
 		/* XXX shouldn't we take the min not max? */
-		if (d2 > result)
-			result = d2;
-	}
+		result = float8_max(line_closept_point(NULL, line, &lseg->p[0]),
+							line_closept_point(NULL, line, &lseg->p[1]));
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
@@ -2370,25 +2375,24 @@ dist_lb(PG_FUNCTION_ARGS)
  * Distance from a circle to a polygon
  */
 Datum
 dist_cpoly(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	POLYGON    *poly = PG_GETARG_POLYGON_P(1);
 	float8		result;
 
 	/* calculate distance to center, and subtract radius */
-	result = dist_ppoly_internal(&circle->center, poly);
-
-	result -= circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(dist_ppoly_internal(&circle->center, poly),
+					   circle->radius);
+	if (result < 0.0)
+		result = 0.0;
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a point to a polygon
  */
 Datum
 dist_ppoly(PG_FUNCTION_ARGS)
 {
@@ -2437,21 +2441,21 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
 	for (i = 0; i < poly->npts - 1; i++)
 	{
 		seg.p[0].x = poly->p[i].x;
 		seg.p[0].y = poly->p[i].y;
 		seg.p[1].x = poly->p[i + 1].x;
 		seg.p[1].y = poly->p[i + 1].y;
 		d = lseg_closept_point(NULL, &seg, pt);
 #ifdef GEODEBUG
 		printf("dist_ppoly_internal- segment %d distance is %f\n", (i + 1), d);
 #endif
-		if (d < result)
+		if (float8_lt(d, result))
 			result = d;
 	}
 
 	return result;
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
  *				Intersection point of objects.
@@ -2532,36 +2536,37 @@ line_closept_point(Point *result, LINE *line, Point *point)
 
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	line_closept_point(result, line, pt);
+	if (isnan(line_closept_point(result, line, pt)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point on line segment to specified point.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 lseg_closept_point(Point *result, LSEG *lseg, Point *pt)
 {
-	double		invm;
+	float8		invm;
 	Point		closept;
 	LINE		tmp;
 
 	/*
 	 * To find the closest point, we draw a perpendicular line from the point
 	 * to the line segment.
 	 */
 	invm = slope(lseg->p[0].y, lseg->p[1].y, lseg->p[1].x, lseg->p[0].x);
 	line_construct_pm(&tmp, pt, invm);
 	lseg_closept_line(&closept, lseg, &tmp);
@@ -2594,134 +2599,136 @@ close_ps(PG_FUNCTION_ARGS)
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  *
  * XXX This function is wrong.  If must never set the *result to a point on
  * the second segment.
  */
 static float8
 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
 {
 	Point		point;
-	double		dist;
-	double		d;
+	float8		dist,
+				d;
 
 	d = lseg_closept_point(NULL, l1, &l2->p[0]);
 	dist = d;
 	if (result != NULL)
 		*result = l2->p[0];
 
 	d = lseg_closept_point(NULL, l1, &l2->p[1]);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = l2->p[1];
 	}
 
-	if (lseg_closept_point(&point, l2, &l1->p[0]) < dist)
+	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[0]), dist))
 		d = lseg_closept_point(result, l1, &point);
 
-	if (lseg_closept_point(&point, l2, &l1->p[1]) < dist)
+	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[1]), dist))
 		d = lseg_closept_point(result, l1, &point);
 
-	if (d < dist)
+	if (float8_lt(d, dist))
 		dist = d;
 
 	return dist;
 }
 
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	lseg_closept_lseg(result, l2, l1);
+	if (isnan(lseg_closept_lseg(result, l2, l1)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point on or in box to specified point.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 box_closept_point(Point *result, BOX *box, Point *pt)
 {
-	LSEG		lseg;
+	float8		dist,
+				d;
 	Point		point,
 				closept;
-	double		dist,
-				d;
+	LSEG		lseg;
 
 	if (box_contain_point(box, pt))
 	{
 		if (result != NULL)
 			*result = *pt;
 
 		return 0.0;
 	}
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&lseg, &box->low, &point);
 	dist = lseg_closept_point(result, &lseg, pt);
 
 	statlseg_construct(&lseg, &box->high, &point);
 	d = lseg_closept_point(&closept, &lseg, pt);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&lseg, &box->low, &point);
 	d = lseg_closept_point(&closept, &lseg, pt);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	statlseg_construct(&lseg, &box->high, &point);
 	d = lseg_closept_point(&closept, &lseg, pt);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	return dist;
 }
 
 Datum
 close_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	box_closept_point(result, box, pt);
+	if (isnan(box_closept_point(result, box, pt)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_sl()
  * Closest point on line to line segment.
  *
  * XXX THIS CODE IS WRONG
  * The code is actually calculating the point on the line segment
@@ -2739,21 +2746,21 @@ close_sl(PG_FUNCTION_ARGS)
 	float8		d1,
 				d2;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (lseg_interpt_line(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = line_closept_point(NULL, line, &lseg->p[0]);
 	d2 = line_closept_point(NULL, line, &lseg->p[1]);
-	if (d1 < d2)
+	if (float8_lt(d1, d2))
 		*result = lseg->p[0];
 	else
 		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
 
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_sl\" not implemented")));
@@ -2803,92 +2810,94 @@ lseg_closept_line(Point *result, LSEG *lseg, LINE *line)
 
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	lseg_closept_line(result, lseg, line);
+	if (isnan(lseg_closept_line(result, lseg, line)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point on or in box to line segment.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 box_closept_lseg(Point *result, BOX *box, LSEG *lseg)
 {
+	float8		dist,
+				d;
 	Point		point,
 				closept;
 	LSEG		bseg;
-	double		dist,
-				d;
 
 	if (box_interpt_lseg(result, box, lseg))
 		return 0.0;
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
 	dist = lseg_closept_lseg(result, &bseg, lseg);
 
 	statlseg_construct(&bseg, &box->high, &point);
 	d = lseg_closept_lseg(&closept, &bseg, lseg);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&bseg, &box->low, &point);
 	d = lseg_closept_lseg(&closept, &bseg, lseg);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	statlseg_construct(&bseg, &box->high, &point);
 	d = lseg_closept_lseg(&closept, &bseg, lseg);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	return dist;
 }
 
 Datum
 close_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	box_closept_lseg(result, box, lseg);
+	if (isnan(box_closept_lseg(result, box, lseg)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 Datum
 close_lb(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -2907,21 +2916,23 @@ close_lb(PG_FUNCTION_ARGS)
  *		on_
  *				Whether one object lies completely within another.
  *-------------------------------------------------------------------*/
 
 /*
  *		Does the point satisfy the equation?
  */
 static bool
 line_contain_point(LINE *line, Point *point)
 {
-	return FPzero(line->A * point->x + line->B * point->y + line->C);
+	return FPzero(float8_pl(float8_pl(float8_mul(line->A, point->x),
+									  float8_mul(line->B, point->y)),
+							line->C));
 }
 
 Datum
 on_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
 	PG_RETURN_BOOL(line_contain_point(line, pt));
 }
@@ -2989,33 +3000,32 @@ box_contain_pt(PG_FUNCTION_ARGS)
  *				but not cross.
  *				(we can do p-in-p in lg(n), but it takes preprocessing)
  */
 Datum
 on_ppath(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	PATH	   *path = PG_GETARG_PATH_P(1);
 	int			i,
 				n;
-	double		a,
+	float8		a,
 				b;
 
 	/*-- OPEN --*/
 	if (!path->closed)
 	{
 		n = path->npts - 1;
 		a = point_dt(pt, &path->p[0]);
 		for (i = 0; i < n; i++)
 		{
 			b = point_dt(pt, &path->p[i + 1]);
-			if (FPeq(a + b,
-					 point_dt(&path->p[i], &path->p[i + 1])))
+			if (FPeq(float8_pl(a, b), point_dt(&path->p[i], &path->p[i + 1])))
 				PG_RETURN_BOOL(true);
 			a = b;
 		}
 		PG_RETURN_BOOL(false);
 	}
 
 	/*-- CLOSED --*/
 	PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
 }
 
@@ -3087,24 +3097,24 @@ inter_sl(PG_FUNCTION_ARGS)
  * Optimize for non-intersection by checking for box intersection first.
  * - thomas 1998-01-30
  */
 static bool
 box_interpt_lseg(Point *result, BOX *box, LSEG *lseg)
 {
 	BOX			lbox;
 	LSEG		bseg;
 	Point		point;
 
-	lbox.low.x = Min(lseg->p[0].x, lseg->p[1].x);
-	lbox.low.y = Min(lseg->p[0].y, lseg->p[1].y);
-	lbox.high.x = Max(lseg->p[0].x, lseg->p[1].x);
-	lbox.high.y = Max(lseg->p[0].y, lseg->p[1].y);
+	lbox.low.x = float8_min(lseg->p[0].x, lseg->p[1].x);
+	lbox.low.y = float8_min(lseg->p[0].y, lseg->p[1].y);
+	lbox.high.x = float8_max(lseg->p[0].x, lseg->p[1].x);
+	lbox.high.y = float8_max(lseg->p[0].y, lseg->p[1].y);
 
 	/* nothing close to overlap? then not going to intersect */
 	if (!box_ov(&lbox, box))
 		return false;
 
 	if (result != NULL)
 	{
 		box_cn(&point, box);
 		lseg_closept_point(result, lseg, &point);
 	}
@@ -3197,38 +3207,38 @@ inter_lb(PG_FUNCTION_ARGS)
  * make_bound_box - create the bounding box for the input polygon
  *------------------------------------------------------------------*/
 
 /*---------------------------------------------------------------------
  * Make the smallest bounding box for the given polygon.
  *---------------------------------------------------------------------*/
 static void
 make_bound_box(POLYGON *poly)
 {
 	int			i;
-	double		x1,
+	float8		x1,
 				y1,
 				x2,
 				y2;
 
 	Assert(poly->npts > 0);
 
 	x1 = x2 = poly->p[0].x;
 	y2 = y1 = poly->p[0].y;
 	for (i = 1; i < poly->npts; i++)
 	{
-		if (poly->p[i].x < x1)
+		if (float8_lt(poly->p[i].x, x1))
 			x1 = poly->p[i].x;
-		if (poly->p[i].x > x2)
+		if (float8_gt(poly->p[i].x, x2))
 			x2 = poly->p[i].x;
-		if (poly->p[i].y < y1)
+		if (float8_lt(poly->p[i].y, y1))
 			y1 = poly->p[i].y;
-		if (poly->p[i].y > y2)
+		if (float8_gt(poly->p[i].y, y2))
 			y2 = poly->p[i].y;
 	}
 
 	poly->boundbox.low.x = x1;
 	poly->boundbox.high.x = x2;
 	poly->boundbox.low.y = y1;
 	poly->boundbox.high.y = y2;
 }
 
 /*------------------------------------------------------------------
@@ -3726,22 +3736,22 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 	}
 
 	if (res && !intersection)
 	{
 		Point		p;
 
 		/*
 		 * if X-intersection wasn't found  then check central point of tested
 		 * segment. In opposite case we already check all subsegments
 		 */
-		p.x = (t.p[0].x + t.p[1].x) / 2.0;
-		p.y = (t.p[0].y + t.p[1].y) / 2.0;
+		p.x = float8_div(float8_pl(t.p[0].x, t.p[1].x), 2.0);
+		p.y = float8_div(float8_pl(t.p[0].y, t.p[1].y), 2.0);
 
 		res = point_inside(&p, poly->npts, poly->p);
 	}
 
 	return res;
 }
 
 /*-----------------------------------------------------------------
  * Determine if polygon A contains polygon B.
  *-----------------------------------------------------------------*/
@@ -3867,22 +3877,22 @@ construct_point(PG_FUNCTION_ARGS)
 	point_construct(result, x, y);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_add_point(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x + pt2->x,
-					pt1->y + pt2->y);
+					float8_pl(pt1->x, pt2->x),
+					float8_pl(pt1->y, pt2->y));
 }
 
 Datum
 point_add(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -3890,22 +3900,22 @@ point_add(PG_FUNCTION_ARGS)
 	point_add_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_sub_point(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x - pt2->x,
-					pt1->y - pt2->y);
+					float8_mi(pt1->x, pt2->x),
+					float8_mi(pt1->y, pt2->y));
 }
 
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -3913,54 +3923,53 @@ point_sub(PG_FUNCTION_ARGS)
 	point_sub_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_mul_point(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					(pt1->x * pt2->x) - (pt1->y * pt2->y),
-					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+					float8_mi(float8_mul(pt1->x, pt2->x),
+							  float8_mul(pt1->y, pt2->y)),
+					float8_pl(float8_mul(pt1->x, pt2->y),
+							  float8_mul(pt1->y, pt2->x)));
 }
 
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	point_mul_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_div_point(Point *result, Point *pt1, Point *pt2)
 {
-	double		div;
+	float8		div;
 
-	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
-
-	if (div == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
+	div = float8_pl(float8_mul(pt2->x, pt2->x), float8_mul(pt2->y, pt2->y));
 
 	point_construct(result,
-					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
-					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+					float8_div(float8_pl(float8_mul(pt1->x, pt2->x),
+										 float8_mul(pt1->y, pt2->y)), div),
+					float8_div(float8_mi(float8_mul(pt1->y, pt2->x),
+										 float8_mul(pt1->x, pt2->y)), div));
 }
 
 Datum
 point_div(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -4083,24 +4092,24 @@ point_box(PG_FUNCTION_ARGS)
  */
 Datum
 boxes_bound_box(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0),
 			   *box2 = PG_GETARG_BOX_P(1),
 			   *container;
 
 	container = (BOX *) palloc(sizeof(BOX));
 
-	container->high.x = Max(box1->high.x, box2->high.x);
-	container->low.x = Min(box1->low.x, box2->low.x);
-	container->high.y = Max(box1->high.y, box2->high.y);
-	container->low.y = Min(box1->low.y, box2->low.y);
+	container->high.x = float8_max(box1->high.x, box2->high.x);
+	container->low.x = float8_min(box1->low.x, box2->low.x);
+	container->high.y = float8_max(box1->high.y, box2->high.y);
+	container->low.y = float8_min(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(container);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D paths.
  **
  ***********************************************************************/
@@ -4406,21 +4415,22 @@ circle_in(PG_FUNCTION_ARGS)
 		if (*cp == LDELIM)
 			s = cp;
 	}
 
 	pair_decode(s, &circle->center.x, &circle->center.y, &s, "circle", str);
 
 	if (*s == DELIM)
 		s++;
 
 	circle->radius = single_decode(s, &s, "circle", str);
-	if (circle->radius < 0)
+	/* We have to accept NaN as well. */
+	if (circle->radius < 0.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
 
 	while (depth > 0)
 	{
 		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
@@ -4473,21 +4483,21 @@ circle_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	circle->center.x = pq_getmsgfloat8(buf);
 	circle->center.y = pq_getmsgfloat8(buf);
 	circle->radius = pq_getmsgfloat8(buf);
 
-	if (circle->radius < 0)
+	if (circle->radius <= 0.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
 				 errmsg("invalid radius in external \"circle\" value")));
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 /*
  *		circle_send			- converts circle to binary format
  */
@@ -4511,159 +4521,160 @@ circle_send(PG_FUNCTION_ARGS)
  *---------------------------------------------------------*/
 
 /*		circles identical?
  */
 Datum
 circle_same(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPeq(circle1->radius, circle2->radius) &&
+	PG_RETURN_BOOL(((isnan(circle1->radius) && isnan(circle1->radius)) ||
+					FPeq(circle1->radius, circle2->radius)) &&
 				   point_eq_point(&circle1->center, &circle2->center));
 }
 
 /*		circle_overlap	-		does circle1 overlap circle2?
  */
 Datum
 circle_overlap(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle1->radius + circle2->radius));
+						float8_pl(circle1->radius, circle2->radius)));
 }
 
 /*		circle_overleft -		is the right edge of circle1 at or left of
  *								the right edge of circle2?
  */
 Datum
 circle_overleft(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.x + circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_left		-		is circle1 strictly left of circle2?
  */
 Datum
 circle_left(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.x + circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_right	-		is circle1 strictly right of circle2?
  */
 Datum
 circle_right(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.x - circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_overright	-	is the left edge of circle1 at or right of
  *								the left edge of circle2?
  */
 Datum
 circle_overright(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.x - circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_contained		-		is circle1 contained by circle2?
  */
 Datum
 circle_contained(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle2->radius - circle1->radius));
+						float8_mi(circle2->radius, circle1->radius)));
 }
 
 /*		circle_contain	-		does circle1 contain circle2?
  */
 Datum
 circle_contain(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle1->radius - circle2->radius));
+						float8_mi(circle1->radius, circle2->radius)));
 }
 
 
 /*		circle_below		-		is circle1 strictly below circle2?
  */
 Datum
 circle_below(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.y + circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_above	-		is circle1 strictly above circle2?
  */
 Datum
 circle_above(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.y - circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overbelow -		is the upper edge of circle1 at or below
  *								the upper edge of circle2?
  */
 Datum
 circle_overbelow(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.y + circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overabove	-	is the lower edge of circle1 at or above
  *								the lower edge of circle2?
  */
 Datum
 circle_overabove(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.y - circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 
 /*		circle_relop	-		is area(circle1) relop area(circle2), within
  *								our accuracy constraint?
  */
 Datum
 circle_eq(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
@@ -4762,36 +4773,36 @@ circle_sub_pt(PG_FUNCTION_ARGS)
 Datum
 circle_mul_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_mul_point(&result->center, &circle->center, point);
-	result->radius = circle->radius * HYPOT(point->x, point->y);
+	result->radius = float8_mul(circle->radius, HYPOT(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_div_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_div_point(&result->center, &circle->center, point);
-	result->radius = circle->radius / HYPOT(point->x, point->y);
+	result->radius = float8_div(circle->radius, HYPOT(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /*		circle_area		-		returns the area of the circle.
  */
 Datum
 circle_area(PG_FUNCTION_ARGS)
 {
@@ -4801,21 +4812,21 @@ circle_area(PG_FUNCTION_ARGS)
 }
 
 
 /*		circle_diameter -		returns the diameter of the circle.
  */
 Datum
 circle_diameter(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
-	PG_RETURN_FLOAT8(2 * circle->radius);
+	PG_RETURN_FLOAT8(float8_mul(circle->radius, 2.0));
 }
 
 
 /*		circle_radius	-		returns the radius of the circle.
  */
 Datum
 circle_radius(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
@@ -4826,81 +4837,85 @@ circle_radius(PG_FUNCTION_ARGS)
 /*		circle_distance -		returns the distance between
  *								  two circles.
  */
 Datum
 circle_distance(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(&circle1->center, &circle2->center) -
-		(circle1->radius + circle2->radius);
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(&circle1->center, &circle2->center),
+					   float8_pl(circle1->radius, circle2->radius));
+	if (result < 0.0)
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 
 Datum
 circle_contain_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
 	PG_RETURN_BOOL(d <= circle->radius);
 }
 
 
 Datum
 pt_contained_circle(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
 	PG_RETURN_BOOL(d <= circle->radius);
 }
 
 
 /*		dist_pc -		returns the distance between
  *						  a point and a circle.
  */
 Datum
 dist_pc(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center),
+					   circle->radius);
+	if (result < 0.0)
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a circle to a point
  */
 Datum
 dist_cpoint(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center), circle->radius);
+	if (result < 0.0)
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*		circle_center	-		returns the center point of the circle.
  */
 Datum
 circle_center(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *result;
@@ -4908,24 +4923,24 @@ circle_center(PG_FUNCTION_ARGS)
 	result = (Point *) palloc(sizeof(Point));
 	result->x = circle->center.x;
 	result->y = circle->center.y;
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		circle_ar		-		returns the area of the circle.
  */
-static double
+static float8
 circle_ar(CIRCLE *circle)
 {
-	return M_PI * (circle->radius * circle->radius);
+	return float8_mul(float8_mul(circle->radius, circle->radius), M_PI);
 }
 
 
 /*----------------------------------------------------------
  *	Conversion operators.
  *---------------------------------------------------------*/
 
 Datum
 cr_circle(PG_FUNCTION_ARGS)
 {
@@ -4940,65 +4955,65 @@ cr_circle(PG_FUNCTION_ARGS)
 	result->radius = radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_box(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	BOX		   *box;
-	double		delta;
+	float8		delta;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
-	delta = circle->radius / sqrt(2.0);
+	delta = float8_div(circle->radius, sqrt(2.0));
 
-	box->high.x = circle->center.x + delta;
-	box->low.x = circle->center.x - delta;
-	box->high.y = circle->center.y + delta;
-	box->low.y = circle->center.y - delta;
+	box->high.x = float8_pl(circle->center.x, delta);
+	box->low.x = float8_mi(circle->center.x, delta);
+	box->high.y = float8_pl(circle->center.y, delta);
+	box->low.y = float8_mi(circle->center.y, delta);
 
 	PG_RETURN_BOX_P(box);
 }
 
 /* box_circle()
  * Convert a box to a circle.
  */
 Datum
 box_circle(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	circle->center.x = (box->high.x + box->low.x) / 2;
-	circle->center.y = (box->high.y + box->low.y) / 2;
+	circle->center.x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	circle->center.y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 
 	circle->radius = point_dt(&circle->center, &box->high);
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 
 Datum
 circle_poly(PG_FUNCTION_ARGS)
 {
 	int32		npts = PG_GETARG_INT32(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	POLYGON    *poly;
 	int			base_size,
 				size;
 	int			i;
-	double		angle;
-	double		anglestep;
+	float8		angle;
+	float8		anglestep;
 
 	if (FPzero(circle->radius))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("cannot convert circle with radius zero to polygon")));
 
 	if (npts < 2)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("must request at least 2 points")));
@@ -5009,27 +5024,30 @@ circle_poly(PG_FUNCTION_ARGS)
 	/* Check for integer overflow */
 	if (base_size / npts != sizeof(poly->p[0]) || size <= base_size)
 		ereport(ERROR,
 				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 				 errmsg("too many points requested")));
 
 	poly = (POLYGON *) palloc0(size);	/* zero any holes */
 	SET_VARSIZE(poly, size);
 	poly->npts = npts;
 
-	anglestep = (2.0 * M_PI) / npts;
+	anglestep = float8_div(2.0 * M_PI, npts);
 
 	for (i = 0; i < npts; i++)
 	{
-		angle = i * anglestep;
-		poly->p[i].x = circle->center.x - (circle->radius * cos(angle));
-		poly->p[i].y = circle->center.y + (circle->radius * sin(angle));
+		angle = float8_mul(anglestep, i);
+
+		poly->p[i].x = float8_mi(circle->center.x,
+								 float8_mul(circle->radius, cos(angle)));
+		poly->p[i].y = float8_pl(circle->center.y,
+								 float8_mul(circle->radius, sin(angle)));
 	}
 
 	make_bound_box(poly);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
 /*
  * Convert polygon to circle
  *
@@ -5044,26 +5062,27 @@ poly_to_circle(CIRCLE *result, POLYGON *poly)
 	int			i;
 
 	Assert(poly->npts > 0);
 
 	result->center.x = 0;
 	result->center.y = 0;
 	result->radius = 0;
 
 	for (i = 0; i < poly->npts; i++)
 		point_add_point(&result->center, &result->center, &poly->p[i]);
-	result->center.x /= poly->npts;
-	result->center.y /= poly->npts;
+	result->center.x = float8_div(result->center.x, poly->npts);
+	result->center.y = float8_div(result->center.y, poly->npts);
 
 	for (i = 0; i < poly->npts; i++)
-		result->radius += point_dt(&poly->p[i], &result->center);
-	result->radius /= poly->npts;
+		result->radius = float8_pl(result->radius,
+								   point_dt(&poly->p[i], &result->center));
+	result->radius = float8_div(result->radius, poly->npts);
 }
 
 Datum
 poly_circle(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
@@ -5088,44 +5107,44 @@ poly_circle(PG_FUNCTION_ARGS)
  *	http://hopf.math.northwestern.edu/index.html
  *	Description of algorithm:  http://www.linuxjournal.com/article/2197
  *							   http://www.linuxjournal.com/article/2029
  */
 
 #define POINT_ON_POLYGON INT_MAX
 
 static int
 point_inside(Point *p, int npts, Point *plist)
 {
-	double		x0,
+	float8		x0,
 				y0;
-	double		prev_x,
+	float8		prev_x,
 				prev_y;
 	int			i = 0;
-	double		x,
+	float8		x,
 				y;
 	int			cross,
 				total_cross = 0;
 
 	Assert(npts > 0);
 
 	/* compute first polygon point relative to single point */
-	x0 = plist[0].x - p->x;
-	y0 = plist[0].y - p->y;
+	x0 = float8_mi(plist[0].x, p->x);
+	y0 = float8_mi(plist[0].y, p->y);
 
 	prev_x = x0;
 	prev_y = y0;
 	/* loop over polygon points and aggregate total_cross */
 	for (i = 1; i < npts; i++)
 	{
 		/* compute next polygon point relative to single point */
-		x = plist[i].x - p->x;
-		y = plist[i].y - p->y;
+		x = float8_mi(plist[i].x, p->x);
+		y = float8_mi(plist[i].y, p->y);
 
 		/* compute previous to current point crossing */
 		if ((cross = lseg_crossing(x, y, prev_x, prev_y)) == POINT_ON_POLYGON)
 			return 2;
 		total_cross += cross;
 
 		prev_x = x;
 		prev_y = y;
 	}
 
@@ -5143,69 +5162,74 @@ point_inside(Point *p, int npts, Point *plist)
 /* lseg_crossing()
  * Returns +/-2 if line segment crosses the positive X-axis in a +/- direction.
  * Returns +/-1 if one point is on the positive X-axis.
  * Returns 0 if both points are on the positive X-axis, or there is no crossing.
  * Returns POINT_ON_POLYGON if the segment contains (0,0).
  * Wow, that is one confusing API, but it is used above, and when summed,
  * can tell is if a point is in a polygon.
  */
 
 static int
-lseg_crossing(double x, double y, double prev_x, double prev_y)
+lseg_crossing(float8 x, float8 y, float8 prev_x, float8 prev_y)
 {
-	double		z;
+	float8		z;
 	int			y_sign;
 
 	if (FPzero(y))
 	{							/* y == 0, on X axis */
 		if (FPzero(x))			/* (x,y) is (0,0)? */
 			return POINT_ON_POLYGON;
 		else if (FPgt(x, 0))
 		{						/* x > 0 */
 			if (FPzero(prev_y)) /* y and prev_y are zero */
 				/* prev_x > 0? */
-				return FPgt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
-			return FPlt(prev_y, 0) ? 1 : -1;
+				return FPgt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
+			return FPlt(prev_y, 0.0) ? 1 : -1;
 		}
 		else
 		{						/* x < 0, x not on positive X axis */
 			if (FPzero(prev_y))
 				/* prev_x < 0? */
-				return FPlt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
+				return FPlt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
 			return 0;
 		}
 	}
 	else
 	{							/* y != 0 */
 		/* compute y crossing direction from previous point */
-		y_sign = FPgt(y, 0) ? 1 : -1;
+		y_sign = FPgt(y, 0.0) ? 1 : -1;
 
 		if (FPzero(prev_y))
 			/* previous point was on X axis, so new point is either off or on */
-			return FPlt(prev_x, 0) ? 0 : y_sign;
-		else if (FPgt(y_sign * prev_y, 0))
+			return FPlt(prev_x, 0.0) ? 0 : y_sign;
+		else if ((y_sign < 0 && FPlt(prev_y, 0.0)) ||
+				 (y_sign > 0 && FPgt(prev_y, 0.0)))
 			/* both above or below X axis */
 			return 0;			/* same sign */
 		else
 		{						/* y and prev_y cross X-axis */
-			if (FPge(x, 0) && FPgt(prev_x, 0))
+			if (FPge(x, 0.0) && FPgt(prev_x, 0.0))
 				/* both non-negative so cross positive X-axis */
 				return 2 * y_sign;
-			if (FPlt(x, 0) && FPle(prev_x, 0))
+			if (FPlt(x, 0.0) && FPle(prev_x, 0.0))
 				/* both non-positive so do not cross positive X-axis */
 				return 0;
 
 			/* x and y cross axises, see URL above point_inside() */
-			z = (x - prev_x) * y - (y - prev_y) * x;
+			z = float8_mi(float8_mul(float8_mi(x, prev_x), y),
+						  float8_mul(float8_mi(y, prev_y), x));
 			if (FPzero(z))
 				return POINT_ON_POLYGON;
-			return FPgt((y_sign * z), 0) ? 0 : 2 * y_sign;
+			if ((y_sign < 0 && FPlt(z, 0.0)) ||
+				(y_sign > 0 && FPgt(z, 0.0)))
+				return 0;
+			return 2 * y_sign;
 		}
 	}
 }
 
 
 static bool
 plist_same(int npts, Point *p1, Point *p2)
 {
 	int			i,
 				ii,
@@ -5275,47 +5299,53 @@ plist_same(int npts, Point *p1, Point *p2)
  *					 = x * sqrt( 1 + y^2/x^2 )
  *					 = x * sqrt( 1 + y/x * y/x )
  *
  * It is expected that this routine will eventually be replaced with the
  * C99 hypot() function.
  *
  * This implementation conforms to IEEE Std 1003.1 and GLIBC, in that the
  * case of hypot(inf,nan) results in INF, and not NAN.
  *-----------------------------------------------------------------------
  */
-double
-pg_hypot(double x, double y)
+float8
+pg_hypot(float8 x, float8 y)
 {
-	double		yx;
+	float8		yx,
+				result;
 
 	/* Handle INF and NaN properly */
 	if (isinf(x) || isinf(y))
 		return get_float8_infinity();
 
 	if (isnan(x) || isnan(y))
 		return get_float8_nan();
 
 	/* Else, drop any minus signs */
 	x = fabs(x);
 	y = fabs(y);
 
 	/* Swap x and y if needed to make x the larger one */
 	if (x < y)
 	{
-		double		temp = x;
+		float8		temp = x;
 
 		x = y;
 		y = temp;
 	}
 
 	/*
 	 * If y is zero, the hypotenuse is x.  This test saves a few cycles in
 	 * such cases, but more importantly it also protects against
 	 * divide-by-zero errors, since now x >= y.
 	 */
 	if (y == 0.0)
 		return x;
 
 	/* Determine the hypotenuse */
 	yx = y / x;
-	return x * sqrt(1.0 + (yx * yx));
+	result = x * sqrt(1.0 + (yx * yx));
+
+	check_float8_val(result, false, false);
+	Assert(result >= 0.0);
+
+	return result;
 }
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index 096e59f817..b4008d7423 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -76,38 +76,38 @@
 #include "access/spgist.h"
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
 #include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
- * is going only going to be used in a place to effect the performance
+ * is only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
 compareDoubles(const void *a, const void *b)
 {
-	double		x = *(double *) a;
-	double		y = *(double *) b;
+	float8		x = *(float8 *) a;
+	float8		y = *(float8 *) b;
 
 	if (x == y)
 		return 0;
 	return (x > y) ? 1 : -1;
 }
 
 typedef struct
 {
-	double		low;
-	double		high;
+	float8		low;
+	float8		high;
 } Range;
 
 typedef struct
 {
 	Range		left;
 	Range		right;
 } RangeBox;
 
 typedef struct
 {
@@ -167,21 +167,21 @@ getRangeBox(BOX *box)
 /*
  * Initialize the traversal value
  *
  * In the beginning, we don't have any restrictions.  We have to
  * initialize the struct to cover the whole 4D space.
  */
 static RectBox *
 initRectBox(void)
 {
 	RectBox    *rect_box = (RectBox *) palloc(sizeof(RectBox));
-	double		infinity = get_float8_infinity();
+	float8		infinity = get_float8_infinity();
 
 	rect_box->range_box_x.left.low = -infinity;
 	rect_box->range_box_x.left.high = infinity;
 
 	rect_box->range_box_x.right.low = -infinity;
 	rect_box->range_box_x.right.high = infinity;
 
 	rect_box->range_box_y.left.low = -infinity;
 	rect_box->range_box_y.left.high = infinity;
 
@@ -410,40 +410,40 @@ spg_box_quad_choose(PG_FUNCTION_ARGS)
  * point as the median of the coordinates of the boxes.
  */
 Datum
 spg_box_quad_picksplit(PG_FUNCTION_ARGS)
 {
 	spgPickSplitIn *in = (spgPickSplitIn *) PG_GETARG_POINTER(0);
 	spgPickSplitOut *out = (spgPickSplitOut *) PG_GETARG_POINTER(1);
 	BOX		   *centroid;
 	int			median,
 				i;
-	double	   *lowXs = palloc(sizeof(double) * in->nTuples);
-	double	   *highXs = palloc(sizeof(double) * in->nTuples);
-	double	   *lowYs = palloc(sizeof(double) * in->nTuples);
-	double	   *highYs = palloc(sizeof(double) * in->nTuples);
+	float8	   *lowXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *lowYs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highYs = palloc(sizeof(float8) * in->nTuples);
 
 	/* Calculate median of all 4D coordinates */
 	for (i = 0; i < in->nTuples; i++)
 	{
 		BOX		   *box = DatumGetBoxP(in->datums[i]);
 
 		lowXs[i] = box->low.x;
 		highXs[i] = box->high.x;
 		lowYs[i] = box->low.y;
 		highYs[i] = box->high.y;
 	}
 
-	qsort(lowXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(lowYs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highYs, in->nTuples, sizeof(double), compareDoubles);
+	qsort(lowXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(lowYs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highYs, in->nTuples, sizeof(float8), compareDoubles);
 
 	median = in->nTuples / 2;
 
 	centroid = palloc(sizeof(BOX));
 
 	centroid->low.x = lowXs[median];
 	centroid->high.x = highXs[median];
 	centroid->low.y = lowYs[median];
 	centroid->high.y = highYs[median];
 
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index aeb31515e4..d14e8c8f72 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -1,42 +1,41 @@
 /*-------------------------------------------------------------------------
  *
  * geo_decls.h - Declarations for various 2D constructs.
  *
  *
  * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * src/include/utils/geo_decls.h
  *
- * NOTE
- *	  These routines do *not* use the float types from adt/.
- *
  *	  XXX These routines were not written by a numerical analyst.
  *
  *	  XXX I have made some attempt to flesh out the operators
  *		and data types. There are still some more to do. - tgl 97/04/19
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEO_DECLS_H
 #define GEO_DECLS_H
 
 #include <math.h>
 
 #include "fmgr.h"
 #include "utils/float.h"
 
 /*--------------------------------------------------------------------
  * Useful floating point utilities and constants.
- *-------------------------------------------------------------------*/
-
+ *-------------------------------------------------------------------
+ *
+ * XXX They are not NaN-aware.
+ */
 
 #define EPSILON					1.0E-06
 
 #ifdef EPSILON
 #define FPzero(A)				(fabs(A) <= EPSILON)
 #define FPeq(A,B)				(fabs((A) - (B)) <= EPSILON)
 #define FPne(A,B)				(fabs((A) - (B)) > EPSILON)
 #define FPlt(A,B)				((B) - (A) > EPSILON)
 #define FPle(A,B)				((A) - (B) <= EPSILON)
 #define FPgt(A,B)				((A) - (B) > EPSILON)
@@ -51,21 +50,21 @@
 #define FPge(A,B)				((A) >= (B))
 #endif
 
 #define HYPOT(A, B)				pg_hypot(A, B)
 
 /*---------------------------------------------------------------------
  * Point - (x,y)
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		x,
+	float8		x,
 				y;
 } Point;
 
 
 /*---------------------------------------------------------------------
  * LSEG - A straight line, specified by endpoints.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		p[2];
@@ -83,21 +82,21 @@ typedef struct
 	int32		dummy;			/* padding to make it double align */
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } PATH;
 
 
 /*---------------------------------------------------------------------
  * LINE - Specified by its general equation (Ax+By+C=0).
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		A,
+	float8		A,
 				B,
 				C;
 } LINE;
 
 
 /*---------------------------------------------------------------------
  * BOX	- Specified by two corner points, which are
  *		 sorted to save calculation time later.
  *-------------------------------------------------------------------*/
 typedef struct
@@ -118,21 +117,21 @@ typedef struct
 	BOX			boundbox;
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } POLYGON;
 
 /*---------------------------------------------------------------------
  * CIRCLE - Specified by a center point and radius.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		center;
-	double		radius;
+	float8		radius;
 } CIRCLE;
 
 /*
  * fmgr interface macros
  *
  * Path and Polygon are toastable varlena types, the others are just
  * fixed-size pass-by-reference types.
  */
 
 #define DatumGetPointP(X)	 ((Point *) DatumGetPointer(X))
@@ -172,13 +171,13 @@ typedef struct
 #define DatumGetCircleP(X)	  ((CIRCLE *) DatumGetPointer(X))
 #define CirclePGetDatum(X)	  PointerGetDatum(X)
 #define PG_GETARG_CIRCLE_P(n) DatumGetCircleP(PG_GETARG_DATUM(n))
 #define PG_RETURN_CIRCLE_P(x) return CirclePGetDatum(x)
 
 
 /*
  * in geo_ops.c
  */
 
-extern double pg_hypot(double x, double y);
+extern float8 pg_hypot(float8 x, float8 y);
 
 #endif							/* GEO_DECLS_H */
-- 
2.14.3 (Apple Git-98)

0004-line-fixes-v07.patchapplication/octet-stream; name=0004-line-fixes-v07.patchDownload
From 518c19fa7e8a5501c91bc37213fdf0a06ad65488 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sun, 28 May 2017 11:35:17 +0200
Subject: [PATCH 4/6] line-fixes-v07

Fix obvious problems around the line datatype

I have noticed some line operators retuning wrong results, and Tom Lane
spotted similar problems on more places.  Source history reveals that
during 1990s, the internal format of the line datatype is changed, but
most functions haven't got the hint.  The fixes include:

* Reject invalid specification A=B=0 on receive
* Avoid division by zero on perpendicular operator
* Fix intersection and distance operators when neither A nor B are 1
* Return NULL for closest point when objects are parallel
* Check whether closest point of line segments is the intersection point
* Fix closest point of line segments being on the wrong segment

The changes are also aiming make line operators more symmetric and less
sensitive to floating point precision loss.  The EPSILON interferes with
every minor change in different ways.  It is hard to guess which
behaviour is more expected, but we can assume threating both sides of
the operators more equally is more expected.

Previous discussion:
https://www.postgresql.org/message-id/flat/CAE2gYzw_-z%3DV2kh8QqFjenu%3D8MJXzOP44wRW%3DAzzeamrmTT1%3DQ%40mail.gmail.com
---
 src/backend/utils/adt/geo_ops.c | 231 +++++++++++++++++++++++++++-------------
 1 file changed, 155 insertions(+), 76 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 2334da10fe..55746b5076 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -47,20 +47,22 @@ static int	point_inside(Point *p, int npts, Point *plist);
 
 /* Routines for two-dimensional lines */
 static inline void line_construct_pm(LINE *result, Point *pt, float8 m);
 static inline void line_construct_pts(LINE *result, Point *pt1, Point *pt2);
 static bool	line_interpt_line(Point *result, LINE *l1, LINE *l2);
 static bool line_contain_point(LINE *line, Point *point);
 static float8 line_closept_point(Point *result, LINE *line, Point *pt);
 
 /* Routines for two-dimensional line segments */
 static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
+static bool lseg_parallel_line(LSEG *lseg, LINE *line);
+static bool lseg_parallel_lseg(LSEG *l1, LSEG *l2);
 static bool	lseg_interpt_line(Point *result, LSEG *lseg, LINE *line);
 static bool	lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2);
 static int	lseg_crossing(float8 x, float8 y, float8 px, float8 py);
 static bool	lseg_contain_point(LSEG *lseg, Point *point);
 static float8 lseg_closept_point(Point *result, LSEG *lseg, Point *pt);
 static float8 lseg_closept_line(Point *result, LSEG *lseg, LINE *line);
 static float8 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2);
 
 /* Routines for two-dimensional boxes */
 static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
@@ -970,20 +972,25 @@ line_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LINE	   *line;
 
 	line = (LINE *) palloc(sizeof(LINE));
 
 	line->A = pq_getmsgfloat8(buf);
 	line->B = pq_getmsgfloat8(buf);
 	line->C = pq_getmsgfloat8(buf);
 
+	if (FPzero(line->A) && FPzero(line->B))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+				 errmsg("invalid line specification: A and B cannot both be zero")));
+
 	PG_RETURN_LINE_P(line);
 }
 
 /*
  *		line_send			- converts line to binary format
  */
 Datum
 line_send(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -1064,45 +1071,59 @@ line_construct_pp(PG_FUNCTION_ARGS)
 
 Datum
 line_intersect(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	PG_RETURN_BOOL(line_interpt_line(NULL, l1, l2));
 }
 
+
+/*
+ * Check whether the two lines are parallel
+ *
+ * They are parallel if their slopes are FPeq().
+ */
 Datum
 line_parallel(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
+	float8		m1,
+				m2;
 
-	if (FPzero(l1->B))
-		PG_RETURN_BOOL(FPzero(l2->B));
+	m1 = slope(0.0, l1->B, l1->A, 0.0);
+	m2 = slope(0.0, l2->B, l2->A, 0.0);
 
-	PG_RETURN_BOOL(FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))));
+	PG_RETURN_BOOL(FPeq(m1, m2));
 }
 
+
+/*
+ * Check whether the two lines are perpendicular
+ *
+ * They are perpendicular if the slope of one is FPeq() with the inverse
+ * slope of the other.
+ */
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
+	float8		m1,
+				m2;
 
-	if (FPzero(l1->A))
-		PG_RETURN_BOOL(FPzero(l2->B));
-	else if (FPzero(l1->B))
-		PG_RETURN_BOOL(FPzero(l2->A));
+	m1 = slope(0.0, l1->B, l1->A, 0.0);
+	m2 = slope(l2->A, 0.0, l2->B, 0.0);
 
-	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
-								   float8_mul(l1->B, l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(m1, m2));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
@@ -1114,25 +1135,28 @@ line_horizontal(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(FPzero(line->A));
 }
 
 Datum
 line_eq(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		ratio;
 
-	if (!FPzero(l2->A) && !isnan(l2->A))
+	if (!FPzero(l1->A) && !isnan(l1->A) &&
+		!FPzero(l2->A) && !isnan(l2->A))
 		ratio = float8_div(l1->A, l2->A);
-	else if (!FPzero(l2->B) && !isnan(l2->B))
+	else if (!FPzero(l1->B) && !isnan(l1->B) &&
+			 !FPzero(l2->B) && !isnan(l2->B))
 		ratio = float8_div(l1->B, l2->B);
-	else if (!FPzero(l2->C) && !isnan(l2->C))
+	else if (!FPzero(l1->C) && !isnan(l1->C) &&
+			 !FPzero(l2->C) && !isnan(l2->C))
 		ratio = float8_div(l1->C, l2->C);
 	else
 		ratio = 1.0;
 
 	PG_RETURN_BOOL(((isnan(l1->A) && isnan(l2->A)) ||
 					FPeq(l1->A, float8_mul(ratio, l2->A))) &&
 				   ((isnan(l1->B) && isnan(l2->B)) ||
 					FPeq(l1->B, float8_mul(ratio, l2->B))) &&
 				   ((isnan(l1->C) && isnan(l2->C)) ||
 					FPeq(l1->C, float8_mul(ratio, l2->C))));
@@ -1144,30 +1168,35 @@ line_eq(PG_FUNCTION_ARGS)
  *---------------------------------------------------------*/
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	float8		result;
-	Point		tmp;
+	float8		ratio;
 
 	if (line_interpt_line(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
-	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
-	point_construct(&tmp, 0.0, l1->C);
-	result = line_closept_point(NULL, l2, &tmp);
-	PG_RETURN_FLOAT8(result);
+
+	if (!FPzero(l1->A) && !isnan(l1->A) && !FPzero(l2->A) && !isnan(l2->A))
+		ratio = float8_div(l1->A, l2->A);
+	else if (!FPzero(l1->B) && !isnan(l1->B) && !FPzero(l2->B) && !isnan(l2->B))
+		ratio = float8_div(l1->B, l2->B);
+	else
+		ratio = 1.0;
+
+	PG_RETURN_FLOAT8(float8_div(fabs(float8_mi(l1->C,
+											   float8_mul(ratio, l2->C))),
+								HYPOT(l1->A, l1->B)));
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
@@ -1194,40 +1223,56 @@ line_interpt(PG_FUNCTION_ARGS)
  * If the lines have NaN constants, we will return true, and the intersection
  * point would have NaN coordinates.  We shouldn't return false in this case
  * because that would mean the lines are parallel.
  */
 static bool
 line_interpt_line(Point *result, LINE *l1, LINE *l2)
 {
 	float8		x,
 				y;
 
-	if (FPzero(l1->B))			/* l1 vertical? */
+	if (FPzero(l1->A))			/* l1 horizontal? */
+	{
+		if (FPzero(l2->A))		/* l2 horizontal? */
+			return false;
+
+		y = float8_div(-l1->C, l1->B);
+		x = float8_div(-float8_pl(float8_mul(l2->B, y), l2->C), l2->A);
+	}
+	else if (FPzero(l2->A))		/* l2 horizontal? */
+	{
+		y = float8_div(-l2->C, l2->B);
+		x = float8_div(-float8_pl(float8_mul(l1->B, y), l1->C), l1->A);
+	}
+	else if (FPzero(l1->B))		/* l1 vertical? */
 	{
 		if (FPzero(l2->B))		/* l2 vertical? */
 			return false;
 
-		x = l1->C;
-		y = float8_pl(float8_mul(l2->A, x), l2->C);
+		x = float8_div(-l1->C, l1->A);
+		y = float8_div(-float8_pl(float8_mul(l2->A, x), l2->C), l2->B);
 	}
 	else if (FPzero(l2->B))		/* l2 vertical? */
 	{
-		x = l2->C;
-		y = float8_pl(float8_mul(l1->A, x), l1->C);
+		x = float8_div(-l2->C, l2->A);
+		y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
 	}
 	else
 	{
-		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
+		if (FPeq(float8_mul(l1->A, l2->B), float8_mul(l2->A, l1->B)))
 			return false;
 
-		x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
-		y = float8_pl(float8_mul(l1->A, x), l1->C);
+		x = float8_div(float8_mi(float8_mul(l1->B, l2->C),
+								 float8_mul(l2->B, l1->C)),
+					   float8_mi(float8_mul(l1->A, l2->B),
+								 float8_mul(l2->A, l1->B)));
+		y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
 	}
 	if (result != NULL)
 		point_construct(result, x, y);
 
 	return true;
 }
 
 
 /***********************************************************************
  **
@@ -2021,59 +2066,83 @@ lseg_length(PG_FUNCTION_ARGS)
 Datum
 lseg_intersect(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_BOOL(lseg_interpt_lseg(NULL, l1, l2));
 }
 
 
+/*
+ * Check whether the line segment is parallel with the line
+ *
+ * They are parallel if their slopes are FPeq().
+ */
+static bool
+lseg_parallel_line(LSEG *lseg, LINE *line)
+{
+	float8		m1,
+				m2;
+
+	m1 = slope(lseg->p[0].x, lseg->p[1].x, lseg->p[0].y, lseg->p[1].y);
+	m2 = slope(0.0, line->B, line->A, 0.0);
+
+	return FPeq(m1, m2);
+}
+
+
+/*
+ * Check whether the two line segment are parallel
+ *
+ * They are parallel if their slopes are FPeq().
+ */
+static bool
+lseg_parallel_lseg(LSEG *l1, LSEG *l2)
+{
+	float8		m1,
+				m2;
+
+	m1 = slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y);
+	m2 = slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y);
+
+	return FPeq(m1, m2);
+}
+
 Datum
 lseg_parallel(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPeq(slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y),
-						slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y)));
+	PG_RETURN_BOOL(lseg_parallel_lseg(l1, l2));
 }
 
+
 /* lseg_perp()
  * Determine if two line segments are perpendicular.
  *
- * This code did not get the correct answer for
- *	'((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg
- * So, modified it to check explicitly for slope of vertical line
- *	returned by slope() and the results seem better.
- * - thomas 1998-01-31
+ * They are perpendicular if the slope of one is FPeq() with the inverse
+ * slope of the other.
  */
 Datum
 lseg_perp(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	float8		m1,
 				m2;
 
 	m1 = slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y);
-	m2 = slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y);
+	m2 = slope(l2->p[0].y, l2->p[1].y, l2->p[1].x, l2->p[0].x);
 
-#ifdef GEODEBUG
-	printf("lseg_perp- slopes are %g and %g\n", m1, m2);
-#endif
-	if (FPzero(m1))
-		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
-	else if (FPzero(m2))
-		PG_RETURN_BOOL(FPeq(m1, DBL_MAX));
-
-	PG_RETURN_BOOL(FPeq(m1 / m2, -1.0));
+	PG_RETURN_BOOL(FPeq(m1, m2));
 }
 
 Datum
 lseg_vertical(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 
 	PG_RETURN_BOOL(FPeq(lseg->p[0].x, lseg->p[1].x));
 }
 
@@ -2321,30 +2390,22 @@ dist_pb(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
-	float8		result;
 
-	if (lseg_interpt_line(NULL, lseg, line))
-		result = 0.0;
-	else
-		/* XXX shouldn't we take the min not max? */
-		result = float8_max(line_closept_point(NULL, line, &lseg->p[0]),
-							line_closept_point(NULL, line, &lseg->p[1]));
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(lseg_closept_line(NULL, lseg, line));
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
@@ -2509,36 +2570,40 @@ lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
 /*
  *		The intersection point of a perpendicular of the line
  *		through the point.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 line_closept_point(Point *result, LINE *line, Point *point)
 {
-	bool		retval;
 	float8		m;
+	Point		closept;
 	LINE		tmp;
 
 	/* Drop a perpendicular and find the intersection point */
 	m = slope(line->A, 0.0, line->B, 0.0);
 	line_construct_pm(&tmp, point, m);
-	retval = line_interpt_line(result, line, &tmp);
-	Assert(retval);		/* XXX We need something better. */
 
 	/*
-	 * XXX We could use the distance to the closest point, but
-	 * line_interpt_line() is currently giving wrong results.
+	 * Ordinarily we should always find an intersection point, but that could
+	 * fail in the presence of NaN coordinates, and perhaps even from simple
+	 * roundoff issues.
 	 */
-	return fabs((line->A * point->x + line->B * point->y + line->C) /
-				HYPOT(line->A, line->B));
+	if (!line_interpt_line(&closept, &tmp, line))
+		closept = *point;
+
+	if (result != NULL)
+		*result = closept;
+
+	return point_dt(&closept, point);
 }
 
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -2590,64 +2655,75 @@ close_ps(PG_FUNCTION_ARGS)
 		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point to l1 on l2.
  *
  * This sets the closest point to the *result if it is not NULL and returns
- * the distance to the closest point.
- *
- * XXX This function is wrong.  If must never set the *result to a point on
- * the second segment.
+ * the distance to the closest point.  We first eliminate the case
+ * the segments intersecting with each other.  Then we try to find
+ * the closest point on the first segment by trying the endpoints of
+ * the second.  Though, it is still possible for the closest point to be
+ * one of the endpoints, so we test them.
  */
 static float8
 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
 {
 	Point		point;
 	float8		dist,
 				d;
 
-	d = lseg_closept_point(NULL, l1, &l2->p[0]);
-	dist = d;
-	if (result != NULL)
-		*result = l2->p[0];
+	if (lseg_interpt_lseg(result, l1, l2))
+		return 0.0;
 
-	d = lseg_closept_point(NULL, l1, &l2->p[1]);
+	dist = lseg_closept_point(result, l1, &l2->p[0]);
+
+	d = lseg_closept_point(&point, l1, &l2->p[1]);
 	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
-			*result = l2->p[1];
+			*result = point;
 	}
 
-	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[0]), dist))
-		d = lseg_closept_point(result, l1, &point);
-
-	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[1]), dist))
-		d = lseg_closept_point(result, l1, &point);
-
+	d = lseg_closept_point(NULL, l2, &l1->p[0]);
 	if (float8_lt(d, dist))
+	{
 		dist = d;
+		if (result != NULL)
+			*result = l1->p[0];
+	}
+
+	d = lseg_closept_point(NULL, l2, &l1->p[1]);
+	if (float8_lt(d, dist))
+	{
+		dist = d;
+		if (result != NULL)
+			*result = l1->p[1];
+	}
 
 	return dist;
 }
 
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
+	if (lseg_parallel_lseg(l1, l2))
+		PG_RETURN_NULL();
+
 	result = (Point *) palloc(sizeof(Point));
 
 	if (isnan(lseg_closept_lseg(result, l2, l1)))
 		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
@@ -2808,20 +2884,23 @@ lseg_closept_line(Point *result, LSEG *lseg, LINE *line)
 	}
 }
 
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
+	if (lseg_parallel_line(lseg, line))
+		PG_RETURN_NULL();
+
 	result = (Point *) palloc(sizeof(Point));
 
 	if (isnan(lseg_closept_line(result, lseg, line)))
 		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
-- 
2.14.3 (Apple Git-98)

0005-float-zero-v03.patchapplication/octet-stream; name=0005-float-zero-v03.patchDownload
From 24972c0979fdf0a2a4c0f8f147e0db6de3a1154d Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Thu, 2 Nov 2017 12:21:19 +0100
Subject: [PATCH 5/6] float-zero-v03

Check for float -0 after multiplications and divisions
---
 src/include/utils/float.h | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/src/include/utils/float.h b/src/include/utils/float.h
index c9f5fd30ca..021732d5c6 100644
--- a/src/include/utils/float.h
+++ b/src/include/utils/float.h
@@ -215,64 +215,76 @@ float8_mi(float8 val1, float8 val2)
 
 static inline float4
 float4_mul(float4 val1, float4 val2)
 {
 	float4		result;
 
 	result = val1 * val2;
 	check_float4_val(result, isinf(val1) || isinf(val2),
 					 val1 == 0.0f || val2 == 0.0f);
 
+	if (result == -0.0f)
+		result = 0.0f;
+
 	return result;
 }
 
 static inline float8
 float8_mul(float8 val1, float8 val2)
 {
 	float8		result;
 
 	result = val1 * val2;
 	check_float8_val(result, isinf(val1) || isinf(val2),
 					 val1 == 0.0 || val2 == 0.0);
 
+	if (result == -0.0)
+		result = 0.0;
+
 	return result;
 }
 
 static inline float4
 float4_div(float4 val1, float4 val2)
 {
 	float4		result;
 
 	if (val2 == 0.0f)
 		ereport(ERROR,
 				(errcode(ERRCODE_DIVISION_BY_ZERO),
 				 errmsg("division by zero")));
 
 	result = val1 / val2;
 	check_float4_val(result, isinf(val1) || isinf(val2), val1 == 0.0f);
 
+	if (result == -0.0f)
+		result = 0.0f;
+
 	return result;
 }
 
 static inline float8
 float8_div(float8 val1, float8 val2)
 {
 	float8		result;
 
 	if (val2 == 0.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_DIVISION_BY_ZERO),
 				 errmsg("division by zero")));
 
 	result = val1 / val2;
 	check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
 
+	if (result == -0.0)
+		result = 0.0;
+
 	return result;
 }
 
 /*
  * Routines for NaN-aware comparisons
  *
  * We consider all NANs to be equal and larger than any non-NAN. This is
  * somewhat arbitrary; the important thing is to have a consistent sort
  * order.
  */
-- 
2.14.3 (Apple Git-98)

0006-geo-tests-v03.patchapplication/octet-stream; name=0006-geo-tests-v03.patchDownload
From 53a897b023d7ab0fa920f2579bff40e37fdfb6fc Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Tue, 24 Oct 2017 11:28:21 +0200
Subject: [PATCH 6/6] geo-tests-v03

Improve test coverage of geometric types

The tests for the geometric functions and operators were in sad state.
This commit increases test coverage of geo_ops.c significantly.  It
removes the alternative results to expect -0 on some platforms.  We
better try to return the same results on different platforms, but if we
can't we can add them back using the results from build farm.

The tests are added to geometric.sql file.  It is not clear where to
put them as there are many cross datatype operators.  Organising them
on a single file sorted by the left hand side of the operators appear
to be a simple solution.  We may take this further and remove the other
tests later.
---
 src/test/regress/expected/box.out          |   44 +-
 src/test/regress/expected/circle.out       |   39 +-
 src/test/regress/expected/create_index.out |   73 +-
 src/test/regress/expected/geometry.out     | 4974 ++++++++++++++++++++++++++--
 src/test/regress/expected/geometry_1.out   |  563 ----
 src/test/regress/expected/geometry_2.out   |  563 ----
 src/test/regress/expected/line.out         |  267 +-
 src/test/regress/expected/lseg.out         |   24 +-
 src/test/regress/expected/path.out         |   49 +-
 src/test/regress/expected/point.out        |  358 +-
 src/test/regress/expected/polygon.out      |  200 +-
 src/test/regress/sql/box.sql               |    9 +
 src/test/regress/sql/circle.sql            |   10 +-
 src/test/regress/sql/geometry.sql          |  400 ++-
 src/test/regress/sql/line.sql              |   76 +-
 src/test/regress/sql/lseg.sql              |    9 +-
 src/test/regress/sql/path.sql              |   22 +-
 src/test/regress/sql/point.sql             |   10 +
 src/test/regress/sql/polygon.sql           |   91 +-
 19 files changed, 5569 insertions(+), 2212 deletions(-)
 delete mode 100644 src/test/regress/expected/geometry_1.out
 delete mode 100644 src/test/regress/expected/geometry_2.out

diff --git a/src/test/regress/expected/box.out b/src/test/regress/expected/box.out
index 49af242c8c..998b52223c 100644
--- a/src/test/regress/expected/box.out
+++ b/src/test/regress/expected/box.out
@@ -11,92 +11,109 @@
 -- 1	| o-+-o
 --	|   |
 -- 0	+---+
 --
 --	0 1 2 3
 --
 -- boxes are specified by two points, given by four floats x1,y1,x2,y2
 CREATE TABLE BOX_TBL (f1 box);
 INSERT INTO BOX_TBL (f1) VALUES ('(2.0,2.0,0.0,0.0)');
 INSERT INTO BOX_TBL (f1) VALUES ('(1.0,1.0,3.0,3.0)');
+INSERT INTO BOX_TBL (f1) VALUES ('((-8, 2), (-2, -10))');
 -- degenerate cases where the box is a line or a point
 -- note that lines and points boxes all have zero area
 INSERT INTO BOX_TBL (f1) VALUES ('(2.5, 2.5, 2.5,3.5)');
 INSERT INTO BOX_TBL (f1) VALUES ('(3.0, 3.0,3.0,3.0)');
 -- badly formatted box inputs
 INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
 ERROR:  invalid input syntax for type box: "(2.3, 4.5)"
 LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
                                          ^
+INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+ERROR:  invalid input syntax for type box: "[1, 2, 3, 4)"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+                                         ^
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+ERROR:  invalid input syntax for type box: "(1, 2, 3, 4]"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+                                         ^
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+ERROR:  invalid input syntax for type box: "(1, 2, 3, 4) x"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+                                         ^
 INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
 ERROR:  invalid input syntax for type box: "asdfasdf(ad"
 LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
                                          ^
 SELECT '' AS four, * FROM BOX_TBL;
  four |         f1          
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
+      | (-2,2),(-8,-10)
       | (2.5,3.5),(2.5,2.5)
       | (3,3),(3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, b.*, area(b.f1) as barea
    FROM BOX_TBL b;
  four |         f1          | barea 
 ------+---------------------+-------
       | (2,2),(0,0)         |     4
       | (3,3),(1,1)         |     4
+      | (-2,2),(-8,-10)     |    72
       | (2.5,3.5),(2.5,2.5) |     0
       | (3,3),(3,3)         |     0
-(4 rows)
+(5 rows)
 
 -- overlap
 SELECT '' AS three, b.f1
    FROM BOX_TBL b
    WHERE b.f1 && box '(2.5,2.5,1.0,1.0)';
  three |         f1          
 -------+---------------------
        | (2,2),(0,0)
        | (3,3),(1,1)
        | (2.5,3.5),(2.5,2.5)
 (3 rows)
 
 -- left-or-overlap (x only)
 SELECT '' AS two, b1.*
    FROM BOX_TBL b1
    WHERE b1.f1 &< box '(2.0,2.0,2.5,2.5)';
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- right-or-overlap (x only)
 SELECT '' AS two, b1.*
    FROM BOX_TBL b1
    WHERE b1.f1 &> box '(2.0,2.0,2.5,2.5)';
  two |         f1          
 -----+---------------------
      | (2.5,3.5),(2.5,2.5)
      | (3,3),(3,3)
 (2 rows)
 
 -- left of
 SELECT '' AS two, b.f1
    FROM BOX_TBL b
    WHERE b.f1 << box '(3.0,3.0,5.0,5.0)';
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- area <=
 SELECT '' AS four, b.f1
    FROM BOX_TBL b
    WHERE b.f1 <= box '(3.0,3.0,5.0,5.0)';
  four |         f1          
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
       | (2.5,3.5),(2.5,2.5)
@@ -120,47 +137,50 @@ SELECT '' AS two, b.f1
  two |     f1      
 -----+-------------
      | (2,2),(0,0)
      | (3,3),(1,1)
 (2 rows)
 
 -- area >
 SELECT '' AS two, b.f1
    FROM BOX_TBL b				-- zero area
    WHERE b.f1 > box '(3.5,3.0,4.5,3.0)';
- two |     f1      
------+-------------
+ two |       f1        
+-----+-----------------
      | (2,2),(0,0)
      | (3,3),(1,1)
-(2 rows)
+     | (-2,2),(-8,-10)
+(3 rows)
 
 -- area >=
 SELECT '' AS four, b.f1
    FROM BOX_TBL b				-- zero area
    WHERE b.f1 >= box '(3.5,3.0,4.5,3.0)';
  four |         f1          
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
+      | (-2,2),(-8,-10)
       | (2.5,3.5),(2.5,2.5)
       | (3,3),(3,3)
-(4 rows)
+(5 rows)
 
 -- right of
 SELECT '' AS two, b.f1
    FROM BOX_TBL b
    WHERE box '(3.0,3.0,5.0,5.0)' >> b.f1;
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- contained in
 SELECT '' AS three, b.f1
    FROM BOX_TBL b
    WHERE b.f1 <@ box '(0,0,3,3)';
  three |     f1      
 -------+-------------
        | (2,2),(0,0)
        | (3,3),(1,1)
        | (3,3),(3,3)
@@ -186,41 +206,43 @@ SELECT '' AS one, b.f1
      | (3,3),(1,1)
 (1 row)
 
 -- center of box, left unary operator
 SELECT '' AS four, @@(b1.f1) AS p
    FROM BOX_TBL b1;
  four |    p    
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 -- wholly-contained
 SELECT '' AS one, b1.*, b2.*
    FROM BOX_TBL b1, BOX_TBL b2
    WHERE b1.f1 @> b2.f1 and not b1.f1 ~= b2.f1;
  one |     f1      |     f1      
 -----+-------------+-------------
      | (3,3),(1,1) | (3,3),(3,3)
 (1 row)
 
 SELECT '' AS four, height(f1), width(f1) FROM BOX_TBL;
  four | height | width 
 ------+--------+-------
       |      2 |     2
       |      2 |     2
+      |     12 |     6
       |      1 |     0
       |      0 |     0
-(4 rows)
+(5 rows)
 
 --
 -- Test the SP-GiST index
 --
 CREATE TEMPORARY TABLE box_temp (f1 box);
 INSERT INTO box_temp
 	SELECT box(point(i, i), point(i * 2, i * 2))
 	FROM generate_series(1, 50) AS i;
 CREATE INDEX box_spgist ON box_temp USING spgist (f1);
 INSERT INTO box_temp
diff --git a/src/test/regress/expected/circle.out b/src/test/regress/expected/circle.out
index 9ba4a0495d..2ed74cc6aa 100644
--- a/src/test/regress/expected/circle.out
+++ b/src/test/regress/expected/circle.out
@@ -1,99 +1,122 @@
 --
 -- CIRCLE
 --
 CREATE TABLE CIRCLE_TBL (f1 circle);
 INSERT INTO CIRCLE_TBL VALUES ('<(5,1),3>');
 INSERT INTO CIRCLE_TBL VALUES ('<(1,2),100>');
 INSERT INTO CIRCLE_TBL VALUES ('1,3,5');
 INSERT INTO CIRCLE_TBL VALUES ('((1,2),3)');
 INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10>');
-INSERT INTO CIRCLE_TBL VALUES ('<(100,1),115>');
+INSERT INTO CIRCLE_TBL VALUES (' < ( 100 , 1 ) , 115 > ');
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),0>');	-- Zero radius
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),NaN>');	-- NaN radius
 -- bad values
 INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
 ERROR:  invalid input syntax for type circle: "<(-100,0),-100>"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
                                        ^
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+ERROR:  invalid input syntax for type circle: "<(100,200),10"
+LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+                                       ^
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+ERROR:  invalid input syntax for type circle: "<(100,200),10> x"
+LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+                                       ^
 INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
 ERROR:  invalid input syntax for type circle: "1abc,3,5"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
                                        ^
 INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
 ERROR:  invalid input syntax for type circle: "(3,(1,2),3)"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
                                        ^
 SELECT * FROM CIRCLE_TBL;
        f1       
 ----------------
  <(5,1),3>
  <(1,2),100>
  <(1,3),5>
  <(1,2),3>
  <(100,200),10>
  <(100,1),115>
-(6 rows)
+ <(3,5),0>
+ <(3,5),NaN>
+(8 rows)
 
 SELECT '' AS six, center(f1) AS center
   FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS six, radius(f1) AS radius
   FROM CIRCLE_TBL;
  six | radius 
 -----+--------
      |      3
      |    100
      |      5
      |      3
      |     10
      |    115
-(6 rows)
+     |      0
+     |    NaN
+(8 rows)
 
 SELECT '' AS six, diameter(f1) AS diameter
   FROM CIRCLE_TBL;
  six | diameter 
 -----+----------
      |        6
      |      200
      |       10
      |        6
      |       20
      |      230
-(6 rows)
+     |        0
+     |      NaN
+(8 rows)
 
 SELECT '' AS two, f1 FROM CIRCLE_TBL WHERE radius(f1) < 5;
  two |    f1     
 -----+-----------
      | <(5,1),3>
      | <(1,2),3>
-(2 rows)
+     | <(3,5),0>
+(3 rows)
 
 SELECT '' AS four, f1 FROM CIRCLE_TBL WHERE diameter(f1) >= 10;
  four |       f1       
 ------+----------------
       | <(1,2),100>
       | <(1,3),5>
       | <(100,200),10>
       | <(100,1),115>
-(4 rows)
+      | <(3,5),NaN>
+(5 rows)
 
 SELECT '' as five, c1.f1 AS one, c2.f1 AS two, (c1.f1 <-> c2.f1) AS distance
   FROM CIRCLE_TBL c1, CIRCLE_TBL c2
   WHERE (c1.f1 < c2.f1) AND ((c1.f1 <-> c2.f1) > 0)
   ORDER BY distance, area(c1.f1), area(c2.f1);
  five |      one       |      two       |     distance     
 ------+----------------+----------------+------------------
+      | <(3,5),0>      | <(1,2),3>      | 0.60555127546399
+      | <(3,5),0>      | <(5,1),3>      | 1.47213595499958
       | <(100,200),10> | <(100,1),115>  |               74
       | <(100,200),10> | <(1,2),100>    | 111.370729772479
       | <(1,3),5>      | <(100,200),10> | 205.476756144497
       | <(5,1),3>      | <(100,200),10> |  207.51303816328
+      | <(3,5),0>      | <(100,200),10> | 207.793480159531
       | <(1,2),3>      | <(100,200),10> | 208.370729772479
-(5 rows)
+(8 rows)
 
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 031a0bcec9..ac300469b2 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -150,96 +150,103 @@ SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)';
 
 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
+     5
 (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
+     3
 (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
+     4
 (1 row)
 
 SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
  count 
 -------
      1
 (1 row)
 
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
  (-5,-12)
  (5.1,34.5)
+ (1e+300,Infinity)
+ (NaN,NaN)
  
-(7 rows)
+(10 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NULL;
  f1 
 ----
  
 (1 row)
 
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (1e-300,-1e-300)
  (0,0)
  (-3,4)
  (-10,0)
  (10,10)
  (-5,-12)
  (5.1,34.5)
-(6 rows)
+ (1e+300,Infinity)
+ (NaN,NaN)
+(9 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
  count 
 -------
      3
 (1 row)
 
 SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
  count 
 -------
@@ -561,21 +568,21 @@ SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,
                                        QUERY PLAN                                       
 ----------------------------------------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     4
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>';
                      QUERY PLAN                     
 ----------------------------------------------------
  Aggregate
    ->  Index Only Scan using gpointind on point_tbl
          Index Cond: (f1 <@ '<(50,50),50>'::circle)
 (3 rows)
@@ -606,21 +613,21 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     3
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl p WHERE p.f1 <^ '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only Scan using gpointind on point_tbl p
          Index Cond: (f1 <^ '(0,0)'::point)
 (3 rows)
@@ -636,21 +643,21 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 >^ '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     4
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only Scan using gpointind on point_tbl p
          Index Cond: (f1 ~= '(-5,-12)'::point)
 (3 rows)
@@ -663,30 +670,33 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
                   QUERY PLAN                  
 ----------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Order By: (f1 <-> '(0,1)'::point)
 (2 rows)
 
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (10,10)
+ (NaN,NaN)
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
- (10,10)
  (-5,-12)
  (5.1,34.5)
  
-(7 rows)
+ (1e+300,Infinity)
+(10 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 IS NULL;
                   QUERY PLAN                  
 ----------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Index Cond: (f1 IS NULL)
 (2 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NULL;
@@ -698,47 +708,51 @@ SELECT * FROM point_tbl WHERE f1 IS NULL;
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
                   QUERY PLAN                  
 ----------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Index Cond: (f1 IS NOT NULL)
    Order By: (f1 <-> '(0,1)'::point)
 (3 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (10,10)
+ (NaN,NaN)
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
- (10,10)
  (-5,-12)
  (5.1,34.5)
-(6 rows)
+ (1e+300,Infinity)
+(9 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
                    QUERY PLAN                   
 ------------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Index Cond: (f1 <@ '(10,10),(-10,-10)'::box)
    Order By: (f1 <-> '(0,1)'::point)
 (3 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
                         QUERY PLAN                         
 -----------------------------------------------------------
  Aggregate
    ->  Index Only Scan using sp_quad_ind on quad_point_tbl
          Index Cond: (p IS NULL)
 (3 rows)
 
@@ -1240,27 +1254,28 @@ SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0
 ------------------------------------------------------------
  Sort
    Sort Key: ((f1 <-> '(0,1)'::point))
    ->  Bitmap Heap Scan on point_tbl
          Recheck Cond: (f1 <@ '(10,10),(-10,-10)'::box)
          ->  Bitmap Index Scan on gpointind
                Index Cond: (f1 <@ '(10,10),(-10,-10)'::box)
 (6 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
                   QUERY PLAN                  
 ----------------------------------------------
  Aggregate
    ->  Bitmap Heap Scan on quad_point_tbl
          Recheck Cond: (p IS NULL)
          ->  Bitmap Index Scan on sp_quad_ind
                Index Cond: (p IS NULL)
diff --git a/src/test/regress/expected/geometry.out b/src/test/regress/expected/geometry.out
index e4c0039040..c2161a8182 100644
--- a/src/test/regress/expected/geometry.out
+++ b/src/test/regress/expected/geometry.out
@@ -6,558 +6,4980 @@
 SET extra_float_digits TO -3;
 --
 -- Points
 --
 SELECT '' AS four, center(f1) AS center
    FROM BOX_TBL;
  four | center  
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, (@@ f1) AS center
    FROM BOX_TBL;
  four | center  
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS six, point(f1) AS center
    FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS six, (@@ f1) AS center
    FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS two, (@@ f1) AS center
    FROM POLYGON_TBL
    WHERE (# f1) > 2;
  two |            center             
 -----+-------------------------------
      | (1.33333333333,1.33333333333)
      | (2.33333333333,1.33333333333)
-(2 rows)
+     | (4,5)
+     | (4,5)
+     | (4,3)
+(5 rows)
 
 -- "is horizontal" function
 SELECT '' AS two, p1.f1
    FROM POINT_TBL p1
    WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 -- "is horizontal" operator
 SELECT '' AS two, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 -- "is vertical" function
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE isvertical(p1.f1, point '(5.1,34.5)');
  one |     f1     
 -----+------------
      | (5.1,34.5)
 (1 row)
 
 -- "is vertical" operator
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?| point '(5.1,34.5)';
  one |     f1     
 -----+------------
      | (5.1,34.5)
 (1 row)
 
+-- Slope
+SELECT p1.f1, p2.f1, slope(p1.f1, p2.f1) FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |     slope      
+-------------------+-------------------+----------------
+ (0,0)             | (0,0)             |            NaN
+ (0,0)             | (-10,0)           |              0
+ (0,0)             | (-3,4)            | -1.33333333333
+ (0,0)             | (5.1,34.5)        |  6.76470588235
+ (0,0)             | (-5,-12)          |            2.4
+ (0,0)             | (1e-300,-1e-300)  |             -1
+ (0,0)             | (1e+300,Infinity) |       Infinity
+ (0,0)             | (NaN,NaN)         |            NaN
+ (0,0)             | (10,10)           |              1
+ (-10,0)           | (0,0)             |              0
+ (-10,0)           | (-10,0)           |            NaN
+ (-10,0)           | (-3,4)            | 0.571428571429
+ (-10,0)           | (5.1,34.5)        |  2.28476821192
+ (-10,0)           | (-5,-12)          |           -2.4
+ (-10,0)           | (1e-300,-1e-300)  |        -1e-301
+ (-10,0)           | (1e+300,Infinity) |       Infinity
+ (-10,0)           | (NaN,NaN)         |            NaN
+ (-10,0)           | (10,10)           |            0.5
+ (-3,4)            | (0,0)             | -1.33333333333
+ (-3,4)            | (-10,0)           | 0.571428571429
+ (-3,4)            | (-3,4)            |            NaN
+ (-3,4)            | (5.1,34.5)        |  3.76543209877
+ (-3,4)            | (-5,-12)          |              8
+ (-3,4)            | (1e-300,-1e-300)  | -1.33333333333
+ (-3,4)            | (1e+300,Infinity) |       Infinity
+ (-3,4)            | (NaN,NaN)         |            NaN
+ (-3,4)            | (10,10)           | 0.461538461538
+ (5.1,34.5)        | (0,0)             |  6.76470588235
+ (5.1,34.5)        | (-10,0)           |  2.28476821192
+ (5.1,34.5)        | (-3,4)            |  3.76543209877
+ (5.1,34.5)        | (5.1,34.5)        |            NaN
+ (5.1,34.5)        | (-5,-12)          |  4.60396039604
+ (5.1,34.5)        | (1e-300,-1e-300)  |  6.76470588235
+ (5.1,34.5)        | (1e+300,Infinity) |       Infinity
+ (5.1,34.5)        | (NaN,NaN)         |            NaN
+ (5.1,34.5)        | (10,10)           |             -5
+ (-5,-12)          | (0,0)             |            2.4
+ (-5,-12)          | (-10,0)           |           -2.4
+ (-5,-12)          | (-3,4)            |              8
+ (-5,-12)          | (5.1,34.5)        |  4.60396039604
+ (-5,-12)          | (-5,-12)          |            NaN
+ (-5,-12)          | (1e-300,-1e-300)  |            2.4
+ (-5,-12)          | (1e+300,Infinity) |       Infinity
+ (-5,-12)          | (NaN,NaN)         |            NaN
+ (-5,-12)          | (10,10)           |  1.46666666667
+ (1e-300,-1e-300)  | (0,0)             |             -1
+ (1e-300,-1e-300)  | (-10,0)           |        -1e-301
+ (1e-300,-1e-300)  | (-3,4)            | -1.33333333333
+ (1e-300,-1e-300)  | (5.1,34.5)        |  6.76470588235
+ (1e-300,-1e-300)  | (-5,-12)          |            2.4
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  |            NaN
+ (1e-300,-1e-300)  | (1e+300,Infinity) |       Infinity
+ (1e-300,-1e-300)  | (NaN,NaN)         |            NaN
+ (1e-300,-1e-300)  | (10,10)           |              1
+ (1e+300,Infinity) | (0,0)             |       Infinity
+ (1e+300,Infinity) | (-10,0)           |       Infinity
+ (1e+300,Infinity) | (-3,4)            |       Infinity
+ (1e+300,Infinity) | (5.1,34.5)        |       Infinity
+ (1e+300,Infinity) | (-5,-12)          |       Infinity
+ (1e+300,Infinity) | (1e-300,-1e-300)  |       Infinity
+ (1e+300,Infinity) | (1e+300,Infinity) |            NaN
+ (1e+300,Infinity) | (NaN,NaN)         |            NaN
+ (1e+300,Infinity) | (10,10)           |       Infinity
+ (NaN,NaN)         | (0,0)             |            NaN
+ (NaN,NaN)         | (-10,0)           |            NaN
+ (NaN,NaN)         | (-3,4)            |            NaN
+ (NaN,NaN)         | (5.1,34.5)        |            NaN
+ (NaN,NaN)         | (-5,-12)          |            NaN
+ (NaN,NaN)         | (1e-300,-1e-300)  |            NaN
+ (NaN,NaN)         | (1e+300,Infinity) |            NaN
+ (NaN,NaN)         | (NaN,NaN)         |            NaN
+ (NaN,NaN)         | (10,10)           |            NaN
+ (10,10)           | (0,0)             |              1
+ (10,10)           | (-10,0)           |            0.5
+ (10,10)           | (-3,4)            | 0.461538461538
+ (10,10)           | (5.1,34.5)        |             -5
+ (10,10)           | (-5,-12)          |  1.46666666667
+ (10,10)           | (1e-300,-1e-300)  |              1
+ (10,10)           | (1e+300,Infinity) |       Infinity
+ (10,10)           | (NaN,NaN)         |            NaN
+ (10,10)           | (10,10)           |            NaN
+(81 rows)
+
+-- Add point
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |     ?column?      
+-------------------+-------------------+-------------------
+ (0,0)             | (0,0)             | (0,0)
+ (0,0)             | (-10,0)           | (-10,0)
+ (0,0)             | (-3,4)            | (-3,4)
+ (0,0)             | (5.1,34.5)        | (5.1,34.5)
+ (0,0)             | (-5,-12)          | (-5,-12)
+ (0,0)             | (1e-300,-1e-300)  | (1e-300,-1e-300)
+ (0,0)             | (1e+300,Infinity) | (1e+300,Infinity)
+ (0,0)             | (NaN,NaN)         | (NaN,NaN)
+ (0,0)             | (10,10)           | (10,10)
+ (-10,0)           | (0,0)             | (-10,0)
+ (-10,0)           | (-10,0)           | (-20,0)
+ (-10,0)           | (-3,4)            | (-13,4)
+ (-10,0)           | (5.1,34.5)        | (-4.9,34.5)
+ (-10,0)           | (-5,-12)          | (-15,-12)
+ (-10,0)           | (1e-300,-1e-300)  | (-10,-1e-300)
+ (-10,0)           | (1e+300,Infinity) | (1e+300,Infinity)
+ (-10,0)           | (NaN,NaN)         | (NaN,NaN)
+ (-10,0)           | (10,10)           | (0,10)
+ (-3,4)            | (0,0)             | (-3,4)
+ (-3,4)            | (-10,0)           | (-13,4)
+ (-3,4)            | (-3,4)            | (-6,8)
+ (-3,4)            | (5.1,34.5)        | (2.1,38.5)
+ (-3,4)            | (-5,-12)          | (-8,-8)
+ (-3,4)            | (1e-300,-1e-300)  | (-3,4)
+ (-3,4)            | (1e+300,Infinity) | (1e+300,Infinity)
+ (-3,4)            | (NaN,NaN)         | (NaN,NaN)
+ (-3,4)            | (10,10)           | (7,14)
+ (5.1,34.5)        | (0,0)             | (5.1,34.5)
+ (5.1,34.5)        | (-10,0)           | (-4.9,34.5)
+ (5.1,34.5)        | (-3,4)            | (2.1,38.5)
+ (5.1,34.5)        | (5.1,34.5)        | (10.2,69)
+ (5.1,34.5)        | (-5,-12)          | (0.1,22.5)
+ (5.1,34.5)        | (1e-300,-1e-300)  | (5.1,34.5)
+ (5.1,34.5)        | (1e+300,Infinity) | (1e+300,Infinity)
+ (5.1,34.5)        | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5)        | (10,10)           | (15.1,44.5)
+ (-5,-12)          | (0,0)             | (-5,-12)
+ (-5,-12)          | (-10,0)           | (-15,-12)
+ (-5,-12)          | (-3,4)            | (-8,-8)
+ (-5,-12)          | (5.1,34.5)        | (0.1,22.5)
+ (-5,-12)          | (-5,-12)          | (-10,-24)
+ (-5,-12)          | (1e-300,-1e-300)  | (-5,-12)
+ (-5,-12)          | (1e+300,Infinity) | (1e+300,Infinity)
+ (-5,-12)          | (NaN,NaN)         | (NaN,NaN)
+ (-5,-12)          | (10,10)           | (5,-2)
+ (1e-300,-1e-300)  | (0,0)             | (1e-300,-1e-300)
+ (1e-300,-1e-300)  | (-10,0)           | (-10,-1e-300)
+ (1e-300,-1e-300)  | (-3,4)            | (-3,4)
+ (1e-300,-1e-300)  | (5.1,34.5)        | (5.1,34.5)
+ (1e-300,-1e-300)  | (-5,-12)          | (-5,-12)
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | (2e-300,-2e-300)
+ (1e-300,-1e-300)  | (1e+300,Infinity) | (1e+300,Infinity)
+ (1e-300,-1e-300)  | (NaN,NaN)         | (NaN,NaN)
+ (1e-300,-1e-300)  | (10,10)           | (10,10)
+ (1e+300,Infinity) | (0,0)             | (1e+300,Infinity)
+ (1e+300,Infinity) | (-10,0)           | (1e+300,Infinity)
+ (1e+300,Infinity) | (-3,4)            | (1e+300,Infinity)
+ (1e+300,Infinity) | (5.1,34.5)        | (1e+300,Infinity)
+ (1e+300,Infinity) | (-5,-12)          | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e-300,-1e-300)  | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e+300,Infinity) | (2e+300,Infinity)
+ (1e+300,Infinity) | (NaN,NaN)         | (NaN,NaN)
+ (1e+300,Infinity) | (10,10)           | (1e+300,Infinity)
+ (NaN,NaN)         | (0,0)             | (NaN,NaN)
+ (NaN,NaN)         | (-10,0)           | (NaN,NaN)
+ (NaN,NaN)         | (-3,4)            | (NaN,NaN)
+ (NaN,NaN)         | (5.1,34.5)        | (NaN,NaN)
+ (NaN,NaN)         | (-5,-12)          | (NaN,NaN)
+ (NaN,NaN)         | (1e-300,-1e-300)  | (NaN,NaN)
+ (NaN,NaN)         | (1e+300,Infinity) | (NaN,NaN)
+ (NaN,NaN)         | (NaN,NaN)         | (NaN,NaN)
+ (NaN,NaN)         | (10,10)           | (NaN,NaN)
+ (10,10)           | (0,0)             | (10,10)
+ (10,10)           | (-10,0)           | (0,10)
+ (10,10)           | (-3,4)            | (7,14)
+ (10,10)           | (5.1,34.5)        | (15.1,44.5)
+ (10,10)           | (-5,-12)          | (5,-2)
+ (10,10)           | (1e-300,-1e-300)  | (10,10)
+ (10,10)           | (1e+300,Infinity) | (1e+300,Infinity)
+ (10,10)           | (NaN,NaN)         | (NaN,NaN)
+ (10,10)           | (10,10)           | (20,20)
+(81 rows)
+
+-- Subtract point
+SELECT p1.f1, p2.f1, p1.f1 - p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |      ?column?       
+-------------------+-------------------+---------------------
+ (0,0)             | (0,0)             | (0,0)
+ (0,0)             | (-10,0)           | (10,0)
+ (0,0)             | (-3,4)            | (3,-4)
+ (0,0)             | (5.1,34.5)        | (-5.1,-34.5)
+ (0,0)             | (-5,-12)          | (5,12)
+ (0,0)             | (1e-300,-1e-300)  | (-1e-300,1e-300)
+ (0,0)             | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (0,0)             | (NaN,NaN)         | (NaN,NaN)
+ (0,0)             | (10,10)           | (-10,-10)
+ (-10,0)           | (0,0)             | (-10,0)
+ (-10,0)           | (-10,0)           | (0,0)
+ (-10,0)           | (-3,4)            | (-7,-4)
+ (-10,0)           | (5.1,34.5)        | (-15.1,-34.5)
+ (-10,0)           | (-5,-12)          | (-5,12)
+ (-10,0)           | (1e-300,-1e-300)  | (-10,1e-300)
+ (-10,0)           | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-10,0)           | (NaN,NaN)         | (NaN,NaN)
+ (-10,0)           | (10,10)           | (-20,-10)
+ (-3,4)            | (0,0)             | (-3,4)
+ (-3,4)            | (-10,0)           | (7,4)
+ (-3,4)            | (-3,4)            | (0,0)
+ (-3,4)            | (5.1,34.5)        | (-8.1,-30.5)
+ (-3,4)            | (-5,-12)          | (2,16)
+ (-3,4)            | (1e-300,-1e-300)  | (-3,4)
+ (-3,4)            | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-3,4)            | (NaN,NaN)         | (NaN,NaN)
+ (-3,4)            | (10,10)           | (-13,-6)
+ (5.1,34.5)        | (0,0)             | (5.1,34.5)
+ (5.1,34.5)        | (-10,0)           | (15.1,34.5)
+ (5.1,34.5)        | (-3,4)            | (8.1,30.5)
+ (5.1,34.5)        | (5.1,34.5)        | (0,0)
+ (5.1,34.5)        | (-5,-12)          | (10.1,46.5)
+ (5.1,34.5)        | (1e-300,-1e-300)  | (5.1,34.5)
+ (5.1,34.5)        | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (5.1,34.5)        | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5)        | (10,10)           | (-4.9,24.5)
+ (-5,-12)          | (0,0)             | (-5,-12)
+ (-5,-12)          | (-10,0)           | (5,-12)
+ (-5,-12)          | (-3,4)            | (-2,-16)
+ (-5,-12)          | (5.1,34.5)        | (-10.1,-46.5)
+ (-5,-12)          | (-5,-12)          | (0,0)
+ (-5,-12)          | (1e-300,-1e-300)  | (-5,-12)
+ (-5,-12)          | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-5,-12)          | (NaN,NaN)         | (NaN,NaN)
+ (-5,-12)          | (10,10)           | (-15,-22)
+ (1e-300,-1e-300)  | (0,0)             | (1e-300,-1e-300)
+ (1e-300,-1e-300)  | (-10,0)           | (10,-1e-300)
+ (1e-300,-1e-300)  | (-3,4)            | (3,-4)
+ (1e-300,-1e-300)  | (5.1,34.5)        | (-5.1,-34.5)
+ (1e-300,-1e-300)  | (-5,-12)          | (5,12)
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | (0,0)
+ (1e-300,-1e-300)  | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (1e-300,-1e-300)  | (NaN,NaN)         | (NaN,NaN)
+ (1e-300,-1e-300)  | (10,10)           | (-10,-10)
+ (1e+300,Infinity) | (0,0)             | (1e+300,Infinity)
+ (1e+300,Infinity) | (-10,0)           | (1e+300,Infinity)
+ (1e+300,Infinity) | (-3,4)            | (1e+300,Infinity)
+ (1e+300,Infinity) | (5.1,34.5)        | (1e+300,Infinity)
+ (1e+300,Infinity) | (-5,-12)          | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e-300,-1e-300)  | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e+300,Infinity) | (0,NaN)
+ (1e+300,Infinity) | (NaN,NaN)         | (NaN,NaN)
+ (1e+300,Infinity) | (10,10)           | (1e+300,Infinity)
+ (NaN,NaN)         | (0,0)             | (NaN,NaN)
+ (NaN,NaN)         | (-10,0)           | (NaN,NaN)
+ (NaN,NaN)         | (-3,4)            | (NaN,NaN)
+ (NaN,NaN)         | (5.1,34.5)        | (NaN,NaN)
+ (NaN,NaN)         | (-5,-12)          | (NaN,NaN)
+ (NaN,NaN)         | (1e-300,-1e-300)  | (NaN,NaN)
+ (NaN,NaN)         | (1e+300,Infinity) | (NaN,NaN)
+ (NaN,NaN)         | (NaN,NaN)         | (NaN,NaN)
+ (NaN,NaN)         | (10,10)           | (NaN,NaN)
+ (10,10)           | (0,0)             | (10,10)
+ (10,10)           | (-10,0)           | (20,10)
+ (10,10)           | (-3,4)            | (13,6)
+ (10,10)           | (5.1,34.5)        | (4.9,-24.5)
+ (10,10)           | (-5,-12)          | (15,22)
+ (10,10)           | (1e-300,-1e-300)  | (10,10)
+ (10,10)           | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (10,10)           | (NaN,NaN)         | (NaN,NaN)
+ (10,10)           | (10,10)           | (0,0)
+(81 rows)
+
+-- Multiply with point
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+     f1     |        f1         |       ?column?        
+------------+-------------------+-----------------------
+ (5.1,34.5) | (0,0)             | (0,0)
+ (10,10)    | (0,0)             | (0,0)
+ (5.1,34.5) | (-10,0)           | (-51,-345)
+ (10,10)    | (-10,0)           | (-100,-100)
+ (5.1,34.5) | (-3,4)            | (-153.3,-83.1)
+ (10,10)    | (-3,4)            | (-70,10)
+ (5.1,34.5) | (5.1,34.5)        | (-1164.24,351.9)
+ (10,10)    | (5.1,34.5)        | (-294,396)
+ (5.1,34.5) | (-5,-12)          | (388.5,-233.7)
+ (10,10)    | (-5,-12)          | (70,-170)
+ (5.1,34.5) | (1e-300,-1e-300)  | (3.96e-299,2.94e-299)
+ (10,10)    | (1e-300,-1e-300)  | (2e-299,0)
+ (5.1,34.5) | (1e+300,Infinity) | (-Infinity,Infinity)
+ (10,10)    | (1e+300,Infinity) | (-Infinity,Infinity)
+ (5.1,34.5) | (NaN,NaN)         | (NaN,NaN)
+ (10,10)    | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5) | (10,10)           | (-294,396)
+ (10,10)    | (10,10)           | (0,200)
+(18 rows)
+
+-- Underflow error
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] < 1;
+ERROR:  value out of range: underflow
+-- Divide by point
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] BETWEEN 1 AND 1000;
+        f1         |     f1     |                 ?column?                  
+-------------------+------------+-------------------------------------------
+ (0,0)             | (5.1,34.5) | (0,0)
+ (0,0)             | (10,10)    | (0,0)
+ (-10,0)           | (5.1,34.5) | (-0.0419318237877,0.283656455034)
+ (-10,0)           | (10,10)    | (-0.5,0.5)
+ (-3,4)            | (5.1,34.5) | (0.100883034877,0.101869666025)
+ (-3,4)            | (10,10)    | (0.05,0.35)
+ (5.1,34.5)        | (5.1,34.5) | (1,0)
+ (5.1,34.5)        | (10,10)    | (1.98,1.47)
+ (-5,-12)          | (5.1,34.5) | (-0.361353657935,0.0915100389719)
+ (-5,-12)          | (10,10)    | (-0.85,-0.35)
+ (1e-300,-1e-300)  | (5.1,34.5) | (-2.41724631247e-302,-3.25588278822e-302)
+ (1e-300,-1e-300)  | (10,10)    | (0,-1e-301)
+ (1e+300,Infinity) | (5.1,34.5) | (Infinity,Infinity)
+ (1e+300,Infinity) | (10,10)    | (Infinity,Infinity)
+ (NaN,NaN)         | (5.1,34.5) | (NaN,NaN)
+ (NaN,NaN)         | (10,10)    | (NaN,NaN)
+ (10,10)           | (5.1,34.5) | (0.325588278822,-0.241724631247)
+ (10,10)           | (10,10)    | (1,0)
+(18 rows)
+
+-- Overflow error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] > 1000;
+ERROR:  value out of range: overflow
+-- Division by 0 error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to line
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LINE_TBL l;
+        f1         |                   s                   |      ?column?      
+-------------------+---------------------------------------+--------------------
+ (0,0)             | {0,-1,5}                              |                  5
+ (0,0)             | {1,0,5}                               |                  5
+ (0,0)             | {0,3,0}                               |                  0
+ (0,0)             | {1,-1,0}                              |                  0
+ (0,0)             | {-0.4,-1,-6}                          |      5.57086014531
+ (0,0)             | {-0.000184615384615,-1,15.3846153846} |      15.3846151224
+ (0,0)             | {NaN,-1,NaN}                          |                NaN
+ (0,0)             | {3,NaN,5}                             |                NaN
+ (0,0)             | {NaN,NaN,NaN}                         |                NaN
+ (0,0)             | {0,-1,3}                              |                  3
+ (0,0)             | {-1,0,3}                              |                  3
+ (-10,0)           | {0,-1,5}                              |                  5
+ (-10,0)           | {1,0,5}                               |                  5
+ (-10,0)           | {0,3,0}                               |                  0
+ (-10,0)           | {1,-1,0}                              |      7.07106781187
+ (-10,0)           | {-0.4,-1,-6}                          |      1.85695338177
+ (-10,0)           | {-0.000184615384615,-1,15.3846153846} |      15.3864612763
+ (-10,0)           | {NaN,-1,NaN}                          |                NaN
+ (-10,0)           | {3,NaN,5}                             |                NaN
+ (-10,0)           | {NaN,NaN,NaN}                         |                NaN
+ (-10,0)           | {0,-1,3}                              |                  3
+ (-10,0)           | {-1,0,3}                              |                 13
+ (-3,4)            | {0,-1,5}                              |                  1
+ (-3,4)            | {1,0,5}                               |                  2
+ (-3,4)            | {0,3,0}                               |                  4
+ (-3,4)            | {1,-1,0}                              |      4.94974746831
+ (-3,4)            | {-0.4,-1,-6}                          |      8.17059487979
+ (-3,4)            | {-0.000184615384615,-1,15.3846153846} |      11.3851690368
+ (-3,4)            | {NaN,-1,NaN}                          |                NaN
+ (-3,4)            | {3,NaN,5}                             |                NaN
+ (-3,4)            | {NaN,NaN,NaN}                         |                NaN
+ (-3,4)            | {0,-1,3}                              |                  1
+ (-3,4)            | {-1,0,3}                              |                  6
+ (5.1,34.5)        | {0,-1,5}                              |               29.5
+ (5.1,34.5)        | {1,0,5}                               |               10.1
+ (5.1,34.5)        | {0,3,0}                               |               34.5
+ (5.1,34.5)        | {1,-1,0}                              |      20.7889393669
+ (5.1,34.5)        | {-0.4,-1,-6}                          |      39.4973984303
+ (5.1,34.5)        | {-0.000184615384615,-1,15.3846153846} |      19.1163258281
+ (5.1,34.5)        | {NaN,-1,NaN}                          |                NaN
+ (5.1,34.5)        | {3,NaN,5}                             |                NaN
+ (5.1,34.5)        | {NaN,NaN,NaN}                         |                NaN
+ (5.1,34.5)        | {0,-1,3}                              |               31.5
+ (5.1,34.5)        | {-1,0,3}                              |                2.1
+ (-5,-12)          | {0,-1,5}                              |                 17
+ (-5,-12)          | {1,0,5}                               |                  0
+ (-5,-12)          | {0,3,0}                               |                 12
+ (-5,-12)          | {1,-1,0}                              |      4.94974746831
+ (-5,-12)          | {-0.4,-1,-6}                          |      7.42781352708
+ (-5,-12)          | {-0.000184615384615,-1,15.3846153846} |      27.3855379948
+ (-5,-12)          | {NaN,-1,NaN}                          |                NaN
+ (-5,-12)          | {3,NaN,5}                             |                NaN
+ (-5,-12)          | {NaN,NaN,NaN}                         |                NaN
+ (-5,-12)          | {0,-1,3}                              |                 15
+ (-5,-12)          | {-1,0,3}                              |                  8
+ (1e-300,-1e-300)  | {0,-1,5}                              |                  5
+ (1e-300,-1e-300)  | {1,0,5}                               |                  5
+ (1e-300,-1e-300)  | {0,3,0}                               |             1e-300
+ (1e-300,-1e-300)  | {1,-1,0}                              | 1.41421356237e-300
+ (1e-300,-1e-300)  | {-0.4,-1,-6}                          |      5.57086014531
+ (1e-300,-1e-300)  | {-0.000184615384615,-1,15.3846153846} |      15.3846151224
+ (1e-300,-1e-300)  | {NaN,-1,NaN}                          |                NaN
+ (1e-300,-1e-300)  | {3,NaN,5}                             |                NaN
+ (1e-300,-1e-300)  | {NaN,NaN,NaN}                         |                NaN
+ (1e-300,-1e-300)  | {0,-1,3}                              |                  3
+ (1e-300,-1e-300)  | {-1,0,3}                              |                  3
+ (1e+300,Infinity) | {0,-1,5}                              |           Infinity
+ (1e+300,Infinity) | {1,0,5}                               |                NaN
+ (1e+300,Infinity) | {0,3,0}                               |           Infinity
+ (1e+300,Infinity) | {1,-1,0}                              |           Infinity
+ (1e+300,Infinity) | {-0.4,-1,-6}                          |           Infinity
+ (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} |           Infinity
+ (1e+300,Infinity) | {NaN,-1,NaN}                          |                NaN
+ (1e+300,Infinity) | {3,NaN,5}                             |                NaN
+ (1e+300,Infinity) | {NaN,NaN,NaN}                         |                NaN
+ (1e+300,Infinity) | {0,-1,3}                              |           Infinity
+ (1e+300,Infinity) | {-1,0,3}                              |                NaN
+ (NaN,NaN)         | {0,-1,5}                              |                NaN
+ (NaN,NaN)         | {1,0,5}                               |                NaN
+ (NaN,NaN)         | {0,3,0}                               |                NaN
+ (NaN,NaN)         | {1,-1,0}                              |                NaN
+ (NaN,NaN)         | {-0.4,-1,-6}                          |                NaN
+ (NaN,NaN)         | {-0.000184615384615,-1,15.3846153846} |                NaN
+ (NaN,NaN)         | {NaN,-1,NaN}                          |                NaN
+ (NaN,NaN)         | {3,NaN,5}                             |                NaN
+ (NaN,NaN)         | {NaN,NaN,NaN}                         |                NaN
+ (NaN,NaN)         | {0,-1,3}                              |                NaN
+ (NaN,NaN)         | {-1,0,3}                              |                NaN
+ (10,10)           | {0,-1,5}                              |                  5
+ (10,10)           | {1,0,5}                               |                 15
+ (10,10)           | {0,3,0}                               |                 10
+ (10,10)           | {1,-1,0}                              |                  0
+ (10,10)           | {-0.4,-1,-6}                          |      18.5695338177
+ (10,10)           | {-0.000184615384615,-1,15.3846153846} |      5.38276913903
+ (10,10)           | {NaN,-1,NaN}                          |                NaN
+ (10,10)           | {3,NaN,5}                             |                NaN
+ (10,10)           | {NaN,NaN,NaN}                         |                NaN
+ (10,10)           | {0,-1,3}                              |                  7
+ (10,10)           | {-1,0,3}                              |                  7
+(99 rows)
+
+-- Distance to line segment
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LSEG_TBL l;
+        f1         |               s               |      ?column?      
+-------------------+-------------------------------+--------------------
+ (0,0)             | [(1,2),(3,4)]                 |       2.2360679775
+ (0,0)             | [(0,0),(6,6)]                 |                  0
+ (0,0)             | [(10,-10),(-3,-4)]            |      4.88901207039
+ (0,0)             | [(-1000000,200),(300000,-40)] |      15.3846151224
+ (0,0)             | [(11,22),(33,44)]             |      24.5967477525
+ (0,0)             | [(-10,2),(-10,3)]             |      10.1980390272
+ (0,0)             | [(0,-20),(30,-20)]            |                 20
+ (0,0)             | [(NaN,1),(NaN,90)]            |                NaN
+ (-10,0)           | [(1,2),(3,4)]                 |      11.1803398875
+ (-10,0)           | [(0,0),(6,6)]                 |                 10
+ (-10,0)           | [(10,-10),(-3,-4)]            |       8.0622577483
+ (-10,0)           | [(-1000000,200),(300000,-40)] |      15.3864612763
+ (-10,0)           | [(11,22),(33,44)]             |      30.4138126515
+ (-10,0)           | [(-10,2),(-10,3)]             |                  2
+ (-10,0)           | [(0,-20),(30,-20)]            |       22.360679775
+ (-10,0)           | [(NaN,1),(NaN,90)]            |                NaN
+ (-3,4)            | [(1,2),(3,4)]                 |        4.472135955
+ (-3,4)            | [(0,0),(6,6)]                 |      4.94974746831
+ (-3,4)            | [(10,-10),(-3,-4)]            |                  8
+ (-3,4)            | [(-1000000,200),(300000,-40)] |      11.3851690367
+ (-3,4)            | [(11,22),(33,44)]             |       22.803508502
+ (-3,4)            | [(-10,2),(-10,3)]             |      7.07106781187
+ (-3,4)            | [(0,-20),(30,-20)]            |      24.1867732449
+ (-3,4)            | [(NaN,1),(NaN,90)]            |                NaN
+ (5.1,34.5)        | [(1,2),(3,4)]                 |      30.5722096028
+ (5.1,34.5)        | [(0,0),(6,6)]                 |      28.5142069853
+ (5.1,34.5)        | [(10,-10),(-3,-4)]            |      39.3428519556
+ (5.1,34.5)        | [(-1000000,200),(300000,-40)] |      19.1163258281
+ (5.1,34.5)        | [(11,22),(33,44)]             |      13.0107647738
+ (5.1,34.5)        | [(-10,2),(-10,3)]             |       34.932220084
+ (5.1,34.5)        | [(0,-20),(30,-20)]            |               54.5
+ (5.1,34.5)        | [(NaN,1),(NaN,90)]            |                NaN
+ (-5,-12)          | [(1,2),(3,4)]                 |      15.2315462117
+ (-5,-12)          | [(0,0),(6,6)]                 |                 13
+ (-5,-12)          | [(10,-10),(-3,-4)]            |      8.10179143093
+ (-5,-12)          | [(-1000000,200),(300000,-40)] |      27.3855379949
+ (-5,-12)          | [(11,22),(33,44)]             |      37.5765884561
+ (-5,-12)          | [(-10,2),(-10,3)]             |      14.8660687473
+ (-5,-12)          | [(0,-20),(30,-20)]            |      9.43398113206
+ (-5,-12)          | [(NaN,1),(NaN,90)]            |                NaN
+ (1e-300,-1e-300)  | [(1,2),(3,4)]                 |       2.2360679775
+ (1e-300,-1e-300)  | [(0,0),(6,6)]                 | 1.41421356237e-300
+ (1e-300,-1e-300)  | [(10,-10),(-3,-4)]            |      4.88901207039
+ (1e-300,-1e-300)  | [(-1000000,200),(300000,-40)] |      15.3846151224
+ (1e-300,-1e-300)  | [(11,22),(33,44)]             |      24.5967477525
+ (1e-300,-1e-300)  | [(-10,2),(-10,3)]             |      10.1980390272
+ (1e-300,-1e-300)  | [(0,-20),(30,-20)]            |                 20
+ (1e-300,-1e-300)  | [(NaN,1),(NaN,90)]            |                NaN
+ (1e+300,Infinity) | [(1,2),(3,4)]                 |           Infinity
+ (1e+300,Infinity) | [(0,0),(6,6)]                 |           Infinity
+ (1e+300,Infinity) | [(10,-10),(-3,-4)]            |           Infinity
+ (1e+300,Infinity) | [(-1000000,200),(300000,-40)] |           Infinity
+ (1e+300,Infinity) | [(11,22),(33,44)]             |           Infinity
+ (1e+300,Infinity) | [(-10,2),(-10,3)]             |           Infinity
+ (1e+300,Infinity) | [(0,-20),(30,-20)]            |           Infinity
+ (1e+300,Infinity) | [(NaN,1),(NaN,90)]            |           Infinity
+ (NaN,NaN)         | [(1,2),(3,4)]                 |                NaN
+ (NaN,NaN)         | [(0,0),(6,6)]                 |                NaN
+ (NaN,NaN)         | [(10,-10),(-3,-4)]            |                NaN
+ (NaN,NaN)         | [(-1000000,200),(300000,-40)] |                NaN
+ (NaN,NaN)         | [(11,22),(33,44)]             |                NaN
+ (NaN,NaN)         | [(-10,2),(-10,3)]             |                NaN
+ (NaN,NaN)         | [(0,-20),(30,-20)]            |                NaN
+ (NaN,NaN)         | [(NaN,1),(NaN,90)]            |                NaN
+ (10,10)           | [(1,2),(3,4)]                 |      9.21954445729
+ (10,10)           | [(0,0),(6,6)]                 |      5.65685424949
+ (10,10)           | [(10,-10),(-3,-4)]            |        18.15918769
+ (10,10)           | [(-1000000,200),(300000,-40)] |      5.38276913904
+ (10,10)           | [(11,22),(33,44)]             |      12.0415945788
+ (10,10)           | [(-10,2),(-10,3)]             |      21.1896201004
+ (10,10)           | [(0,-20),(30,-20)]            |                 30
+ (10,10)           | [(NaN,1),(NaN,90)]            |                NaN
+(72 rows)
+
+-- Distance to box
+SELECT p.f1, b.f1, p.f1 <-> b.f1 FROM POINT_TBL p, BOX_TBL b;
+        f1         |         f1          |      ?column?      
+-------------------+---------------------+--------------------
+ (0,0)             | (2,2),(0,0)         |                  0
+ (0,0)             | (3,3),(1,1)         |      1.41421356237
+ (0,0)             | (-2,2),(-8,-10)     |                  2
+ (0,0)             | (2.5,3.5),(2.5,2.5) |      3.53553390593
+ (0,0)             | (3,3),(3,3)         |      4.24264068712
+ (-10,0)           | (2,2),(0,0)         |                 10
+ (-10,0)           | (3,3),(1,1)         |      11.0453610172
+ (-10,0)           | (-2,2),(-8,-10)     |                  2
+ (-10,0)           | (2.5,3.5),(2.5,2.5) |       12.747548784
+ (-10,0)           | (3,3),(3,3)         |      13.3416640641
+ (-3,4)            | (2,2),(0,0)         |      3.60555127546
+ (-3,4)            | (3,3),(1,1)         |      4.12310562562
+ (-3,4)            | (-2,2),(-8,-10)     |                  2
+ (-3,4)            | (2.5,3.5),(2.5,2.5) |      5.52268050859
+ (-3,4)            | (3,3),(3,3)         |       6.0827625303
+ (5.1,34.5)        | (2,2),(0,0)         |      32.6475113906
+ (5.1,34.5)        | (3,3),(1,1)         |      31.5699223946
+ (5.1,34.5)        | (-2,2),(-8,-10)     |      33.2664996656
+ (5.1,34.5)        | (2.5,3.5),(2.5,2.5) |       31.108841187
+ (5.1,34.5)        | (3,3),(3,3)         |      31.5699223946
+ (-5,-12)          | (2,2),(0,0)         |                 13
+ (-5,-12)          | (3,3),(1,1)         |      14.3178210633
+ (-5,-12)          | (-2,2),(-8,-10)     |                  2
+ (-5,-12)          | (2.5,3.5),(2.5,2.5) |      16.3248277173
+ (-5,-12)          | (3,3),(3,3)         |                 17
+ (1e-300,-1e-300)  | (2,2),(0,0)         | 1.41421356237e-300
+ (1e-300,-1e-300)  | (3,3),(1,1)         |      1.41421356237
+ (1e-300,-1e-300)  | (-2,2),(-8,-10)     |                  2
+ (1e-300,-1e-300)  | (2.5,3.5),(2.5,2.5) |      3.53553390593
+ (1e-300,-1e-300)  | (3,3),(3,3)         |      4.24264068712
+ (1e+300,Infinity) | (2,2),(0,0)         |           Infinity
+ (1e+300,Infinity) | (3,3),(1,1)         |           Infinity
+ (1e+300,Infinity) | (-2,2),(-8,-10)     |           Infinity
+ (1e+300,Infinity) | (2.5,3.5),(2.5,2.5) |           Infinity
+ (1e+300,Infinity) | (3,3),(3,3)         |           Infinity
+ (NaN,NaN)         | (2,2),(0,0)         |                NaN
+ (NaN,NaN)         | (3,3),(1,1)         |                NaN
+ (NaN,NaN)         | (-2,2),(-8,-10)     |                NaN
+ (NaN,NaN)         | (2.5,3.5),(2.5,2.5) |                NaN
+ (NaN,NaN)         | (3,3),(3,3)         |                NaN
+ (10,10)           | (2,2),(0,0)         |       11.313708499
+ (10,10)           | (3,3),(1,1)         |      9.89949493661
+ (10,10)           | (-2,2),(-8,-10)     |      14.4222051019
+ (10,10)           | (2.5,3.5),(2.5,2.5) |      9.92471662064
+ (10,10)           | (3,3),(3,3)         |      9.89949493661
+(45 rows)
+
+-- Distance to path
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, PATH_TBL p1;
+        f1         |            f1             |      ?column?      
+-------------------+---------------------------+--------------------
+ (0,0)             | [(1,2),(3,4)]             |       2.2360679775
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | [(0,0),(3,0),(4,5),(1,6)] |                  0
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | [(1,2),(3,4)]             |       2.2360679775
+ (0,0)             | ((10,20))                 |       22.360679775
+ (0,0)             | [(11,12),(13,14)]         |      16.2788205961
+ (0,0)             | ((11,12),(13,14))         |      16.2788205961
+ (-10,0)           | [(1,2),(3,4)]             |      11.1803398875
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | [(0,0),(3,0),(4,5),(1,6)] |                 10
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | [(1,2),(3,4)]             |      11.1803398875
+ (-10,0)           | ((10,20))                 |      28.2842712475
+ (-10,0)           | [(11,12),(13,14)]         |      24.1867732449
+ (-10,0)           | ((11,12),(13,14))         |      24.1867732449
+ (-3,4)            | [(1,2),(3,4)]             |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | [(0,0),(3,0),(4,5),(1,6)] |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | [(1,2),(3,4)]             |        4.472135955
+ (-3,4)            | ((10,20))                 |      20.6155281281
+ (-3,4)            | [(11,12),(13,14)]         |      16.1245154966
+ (-3,4)            | ((11,12),(13,14))         |      16.1245154966
+ (5.1,34.5)        | [(1,2),(3,4)]             |      30.5722096028
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | [(0,0),(3,0),(4,5),(1,6)] |       28.793402022
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | [(1,2),(3,4)]             |      30.5722096028
+ (5.1,34.5)        | ((10,20))                 |      15.3055545473
+ (5.1,34.5)        | [(11,12),(13,14)]         |      21.9695243462
+ (5.1,34.5)        | ((11,12),(13,14))         |      21.9695243462
+ (-5,-12)          | [(1,2),(3,4)]             |      15.2315462117
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | [(0,0),(3,0),(4,5),(1,6)] |                 13
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | [(1,2),(3,4)]             |      15.2315462117
+ (-5,-12)          | ((10,20))                 |      35.3411940941
+ (-5,-12)          | [(11,12),(13,14)]         |      28.8444102037
+ (-5,-12)          | ((11,12),(13,14))         |      28.8444102037
+ (1e-300,-1e-300)  | [(1,2),(3,4)]             |       2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | [(0,0),(3,0),(4,5),(1,6)] | 1.41421356237e-300
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | [(1,2),(3,4)]             |       2.2360679775
+ (1e-300,-1e-300)  | ((10,20))                 |       22.360679775
+ (1e-300,-1e-300)  | [(11,12),(13,14)]         |      16.2788205961
+ (1e-300,-1e-300)  | ((11,12),(13,14))         |      16.2788205961
+ (1e+300,Infinity) | [(1,2),(3,4)]             |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | [(0,0),(3,0),(4,5),(1,6)] |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | [(1,2),(3,4)]             |           Infinity
+ (1e+300,Infinity) | ((10,20))                 |           Infinity
+ (1e+300,Infinity) | [(11,12),(13,14)]         |           Infinity
+ (1e+300,Infinity) | ((11,12),(13,14))         |           Infinity
+ (NaN,NaN)         | [(1,2),(3,4)]             |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | [(0,0),(3,0),(4,5),(1,6)] |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | [(1,2),(3,4)]             |                NaN
+ (NaN,NaN)         | ((10,20))                 |                NaN
+ (NaN,NaN)         | [(11,12),(13,14)]         |                NaN
+ (NaN,NaN)         | ((11,12),(13,14))         |                NaN
+ (10,10)           | [(1,2),(3,4)]             |      9.21954445729
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | [(0,0),(3,0),(4,5),(1,6)] |      7.81024967591
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | [(1,2),(3,4)]             |      9.21954445729
+ (10,10)           | ((10,20))                 |                 10
+ (10,10)           | [(11,12),(13,14)]         |       2.2360679775
+ (10,10)           | ((11,12),(13,14))         |       2.2360679775
+(81 rows)
+
+-- Distance to polygon
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, POLYGON_TBL p1;
+        f1         |             f1             |   ?column?    
+-------------------+----------------------------+---------------
+ (0,0)             | ((2,0),(2,4),(0,0))        |             0
+ (0,0)             | ((3,1),(3,3),(1,0))        |             1
+ (0,0)             | ((1,2),(3,4),(5,6),(7,8))  |  2.2360679775
+ (0,0)             | ((7,8),(5,6),(3,4),(1,2))  |  2.2360679775
+ (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | 1.58113883008
+ (0,0)             | ((0,0))                    |             0
+ (0,0)             | ((0,1),(0,1))              |             1
+ (-10,0)           | ((2,0),(2,4),(0,0))        |            10
+ (-10,0)           | ((3,1),(3,3),(1,0))        |            11
+ (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | 11.1803398875
+ (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | 11.1803398875
+ (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | 11.1803398875
+ (-10,0)           | ((0,0))                    |            10
+ (-10,0)           | ((0,1),(0,1))              | 10.0498756211
+ (-3,4)            | ((2,0),(2,4),(0,0))        |   4.472135955
+ (-3,4)            | ((3,1),(3,3),(1,0))        | 5.54700196225
+ (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  |   4.472135955
+ (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  |   4.472135955
+ (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) |   4.472135955
+ (-3,4)            | ((0,0))                    |             5
+ (-3,4)            | ((0,1),(0,1))              | 4.24264068712
+ (5.1,34.5)        | ((2,0),(2,4),(0,0))        | 30.6571362002
+ (5.1,34.5)        | ((3,1),(3,3),(1,0))        | 31.5699223946
+ (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | 26.5680258958
+ (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | 26.5680258958
+ (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | 26.5680258958
+ (5.1,34.5)        | ((0,0))                    | 34.8749193547
+ (5.1,34.5)        | ((0,1),(0,1))              | 33.8859853037
+ (-5,-12)          | ((2,0),(2,4),(0,0))        |            13
+ (-5,-12)          | ((3,1),(3,3),(1,0))        |  13.416407865
+ (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | 15.2315462117
+ (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | 15.2315462117
+ (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) |  11.313708499
+ (-5,-12)          | ((0,0))                    |            13
+ (-5,-12)          | ((0,1),(0,1))              | 13.9283882772
+ (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        |             0
+ (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        |             1
+ (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  |  2.2360679775
+ (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  |  2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | 1.58113883008
+ (1e-300,-1e-300)  | ((0,0))                    |             0
+ (1e-300,-1e-300)  | ((0,1),(0,1))              |             1
+ (1e+300,Infinity) | ((2,0),(2,4),(0,0))        |      Infinity
+ (1e+300,Infinity) | ((3,1),(3,3),(1,0))        |      Infinity
+ (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  |      Infinity
+ (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  |      Infinity
+ (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) |      Infinity
+ (1e+300,Infinity) | ((0,0))                    |      Infinity
+ (1e+300,Infinity) | ((0,1),(0,1))              |      Infinity
+ (NaN,NaN)         | ((2,0),(2,4),(0,0))        |             0
+ (NaN,NaN)         | ((3,1),(3,3),(1,0))        |             0
+ (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  |             0
+ (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  |             0
+ (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) |             0
+ (NaN,NaN)         | ((0,0))                    |             0
+ (NaN,NaN)         | ((0,1),(0,1))              |             0
+ (10,10)           | ((2,0),(2,4),(0,0))        |            10
+ (10,10)           | ((3,1),(3,3),(1,0))        | 9.89949493661
+ (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | 3.60555127546
+ (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | 3.60555127546
+ (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | 3.60555127546
+ (10,10)           | ((0,0))                    | 14.1421356237
+ (10,10)           | ((0,1),(0,1))              | 13.4536240471
+(63 rows)
+
+-- Closest point to line
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LINE_TBL l;
+        f1         |                   s                   |             ?column?             
+-------------------+---------------------------------------+----------------------------------
+ (0,0)             | {0,-1,5}                              | (0,5)
+ (0,0)             | {1,0,5}                               | (-5,0)
+ (0,0)             | {0,3,0}                               | (0,0)
+ (0,0)             | {1,-1,0}                              | (0,0)
+ (0,0)             | {-0.4,-1,-6}                          | (-2.06896551724,-5.1724137931)
+ (0,0)             | {-0.000184615384615,-1,15.3846153846} | (0.00284023658959,15.3846148603)
+ (0,0)             | {NaN,-1,NaN}                          | 
+ (0,0)             | {3,NaN,5}                             | 
+ (0,0)             | {NaN,NaN,NaN}                         | 
+ (0,0)             | {0,-1,3}                              | (0,3)
+ (0,0)             | {-1,0,3}                              | (3,0)
+ (-10,0)           | {0,-1,5}                              | (-10,5)
+ (-10,0)           | {1,0,5}                               | (-5,0)
+ (-10,0)           | {0,3,0}                               | (-10,0)
+ (-10,0)           | {1,-1,0}                              | (-5,-5)
+ (-10,0)           | {-0.4,-1,-6}                          | (-10.6896551724,-1.72413793103)
+ (-10,0)           | {-0.000184615384615,-1,15.3846153846} | (-9.99715942258,15.386461014)
+ (-10,0)           | {NaN,-1,NaN}                          | 
+ (-10,0)           | {3,NaN,5}                             | 
+ (-10,0)           | {NaN,NaN,NaN}                         | 
+ (-10,0)           | {0,-1,3}                              | (-10,3)
+ (-10,0)           | {-1,0,3}                              | (3,0)
+ (-3,4)            | {0,-1,5}                              | (-3,5)
+ (-3,4)            | {1,0,5}                               | (-5,4)
+ (-3,4)            | {0,3,0}                               | (-3,0)
+ (-3,4)            | {1,-1,0}                              | (0.5,0.5)
+ (-3,4)            | {-0.4,-1,-6}                          | (-6.03448275862,-3.58620689655)
+ (-3,4)            | {-0.000184615384615,-1,15.3846153846} | (-2.99789812268,15.3851688427)
+ (-3,4)            | {NaN,-1,NaN}                          | 
+ (-3,4)            | {3,NaN,5}                             | 
+ (-3,4)            | {NaN,NaN,NaN}                         | 
+ (-3,4)            | {0,-1,3}                              | (-3,3)
+ (-3,4)            | {-1,0,3}                              | (3,4)
+ (5.1,34.5)        | {0,-1,5}                              | (5.1,5)
+ (5.1,34.5)        | {1,0,5}                               | (-5,34.5)
+ (5.1,34.5)        | {0,3,0}                               | (5.1,0)
+ (5.1,34.5)        | {1,-1,0}                              | (19.8,19.8)
+ (5.1,34.5)        | {-0.4,-1,-6}                          | (-9.56896551724,-2.1724137931)
+ (5.1,34.5)        | {-0.000184615384615,-1,15.3846153846} | (5.09647083221,15.3836744977)
+ (5.1,34.5)        | {NaN,-1,NaN}                          | 
+ (5.1,34.5)        | {3,NaN,5}                             | 
+ (5.1,34.5)        | {NaN,NaN,NaN}                         | 
+ (5.1,34.5)        | {0,-1,3}                              | (5.1,3)
+ (5.1,34.5)        | {-1,0,3}                              | (3,34.5)
+ (-5,-12)          | {0,-1,5}                              | (-5,5)
+ (-5,-12)          | {1,0,5}                               | (-5,-12)
+ (-5,-12)          | {0,3,0}                               | (-5,0)
+ (-5,-12)          | {1,-1,0}                              | (-8.5,-8.5)
+ (-5,-12)          | {-0.4,-1,-6}                          | (-2.24137931034,-5.10344827586)
+ (-5,-12)          | {-0.000184615384615,-1,15.3846153846} | (-4.99494420846,15.3855375282)
+ (-5,-12)          | {NaN,-1,NaN}                          | 
+ (-5,-12)          | {3,NaN,5}                             | 
+ (-5,-12)          | {NaN,NaN,NaN}                         | 
+ (-5,-12)          | {0,-1,3}                              | (-5,3)
+ (-5,-12)          | {-1,0,3}                              | (3,-12)
+ (1e-300,-1e-300)  | {0,-1,5}                              | (1e-300,5)
+ (1e-300,-1e-300)  | {1,0,5}                               | (-5,-1e-300)
+ (1e-300,-1e-300)  | {0,3,0}                               | (1e-300,0)
+ (1e-300,-1e-300)  | {1,-1,0}                              | (0,0)
+ (1e-300,-1e-300)  | {-0.4,-1,-6}                          | (-2.06896551724,-5.1724137931)
+ (1e-300,-1e-300)  | {-0.000184615384615,-1,15.3846153846} | (0.00284023658959,15.3846148603)
+ (1e-300,-1e-300)  | {NaN,-1,NaN}                          | 
+ (1e-300,-1e-300)  | {3,NaN,5}                             | 
+ (1e-300,-1e-300)  | {NaN,NaN,NaN}                         | 
+ (1e-300,-1e-300)  | {0,-1,3}                              | (1e-300,3)
+ (1e-300,-1e-300)  | {-1,0,3}                              | (3,-1e-300)
+ (1e+300,Infinity) | {0,-1,5}                              | (1e+300,5)
+ (1e+300,Infinity) | {1,0,5}                               | 
+ (1e+300,Infinity) | {0,3,0}                               | (1e+300,0)
+ (1e+300,Infinity) | {1,-1,0}                              | (Infinity,NaN)
+ (1e+300,Infinity) | {-0.4,-1,-6}                          | (-Infinity,NaN)
+ (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} | (-Infinity,NaN)
+ (1e+300,Infinity) | {NaN,-1,NaN}                          | 
+ (1e+300,Infinity) | {3,NaN,5}                             | 
+ (1e+300,Infinity) | {NaN,NaN,NaN}                         | 
+ (1e+300,Infinity) | {0,-1,3}                              | (1e+300,3)
+ (1e+300,Infinity) | {-1,0,3}                              | 
+ (NaN,NaN)         | {0,-1,5}                              | 
+ (NaN,NaN)         | {1,0,5}                               | 
+ (NaN,NaN)         | {0,3,0}                               | 
+ (NaN,NaN)         | {1,-1,0}                              | 
+ (NaN,NaN)         | {-0.4,-1,-6}                          | 
+ (NaN,NaN)         | {-0.000184615384615,-1,15.3846153846} | 
+ (NaN,NaN)         | {NaN,-1,NaN}                          | 
+ (NaN,NaN)         | {3,NaN,5}                             | 
+ (NaN,NaN)         | {NaN,NaN,NaN}                         | 
+ (NaN,NaN)         | {0,-1,3}                              | 
+ (NaN,NaN)         | {-1,0,3}                              | 
+ (10,10)           | {0,-1,5}                              | (10,5)
+ (10,10)           | {1,0,5}                               | (-5,10)
+ (10,10)           | {0,3,0}                               | (10,0)
+ (10,10)           | {1,-1,0}                              | (10,10)
+ (10,10)           | {-0.4,-1,-6}                          | (3.10344827586,-7.24137931034)
+ (10,10)           | {-0.000184615384615,-1,15.3846153846} | (10.000993742,15.3827690473)
+ (10,10)           | {NaN,-1,NaN}                          | 
+ (10,10)           | {3,NaN,5}                             | 
+ (10,10)           | {NaN,NaN,NaN}                         | 
+ (10,10)           | {0,-1,3}                              | (10,3)
+ (10,10)           | {-1,0,3}                              | (3,10)
+(99 rows)
+
+-- Closest point to line segment
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LSEG_TBL l;
+        f1         |               s               |             ?column?             
+-------------------+-------------------------------+----------------------------------
+ (0,0)             | [(1,2),(3,4)]                 | (1,2)
+ (0,0)             | [(0,0),(6,6)]                 | (0,0)
+ (0,0)             | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ (0,0)             | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
+ (0,0)             | [(11,22),(33,44)]             | (11,22)
+ (0,0)             | [(-10,2),(-10,3)]             | (-10,2)
+ (0,0)             | [(0,-20),(30,-20)]            | (0,-20)
+ (0,0)             | [(NaN,1),(NaN,90)]            | 
+ (-10,0)           | [(1,2),(3,4)]                 | (1,2)
+ (-10,0)           | [(0,0),(6,6)]                 | (0,0)
+ (-10,0)           | [(10,-10),(-3,-4)]            | (-3,-4)
+ (-10,0)           | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
+ (-10,0)           | [(11,22),(33,44)]             | (11,22)
+ (-10,0)           | [(-10,2),(-10,3)]             | (-10,2)
+ (-10,0)           | [(0,-20),(30,-20)]            | (0,-20)
+ (-10,0)           | [(NaN,1),(NaN,90)]            | 
+ (-3,4)            | [(1,2),(3,4)]                 | (1,2)
+ (-3,4)            | [(0,0),(6,6)]                 | (0.5,0.5)
+ (-3,4)            | [(10,-10),(-3,-4)]            | (-3,-4)
+ (-3,4)            | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
+ (-3,4)            | [(11,22),(33,44)]             | (11,22)
+ (-3,4)            | [(-10,2),(-10,3)]             | (-10,3)
+ (-3,4)            | [(0,-20),(30,-20)]            | (0,-20)
+ (-3,4)            | [(NaN,1),(NaN,90)]            | 
+ (5.1,34.5)        | [(1,2),(3,4)]                 | (3,4)
+ (5.1,34.5)        | [(0,0),(6,6)]                 | (6,6)
+ (5.1,34.5)        | [(10,-10),(-3,-4)]            | (-3,-4)
+ (5.1,34.5)        | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
+ (5.1,34.5)        | [(11,22),(33,44)]             | (14.3,25.3)
+ (5.1,34.5)        | [(-10,2),(-10,3)]             | (-10,3)
+ (5.1,34.5)        | [(0,-20),(30,-20)]            | (5.1,-20)
+ (5.1,34.5)        | [(NaN,1),(NaN,90)]            | 
+ (-5,-12)          | [(1,2),(3,4)]                 | (1,2)
+ (-5,-12)          | [(0,0),(6,6)]                 | (0,0)
+ (-5,-12)          | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
+ (-5,-12)          | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
+ (-5,-12)          | [(11,22),(33,44)]             | (11,22)
+ (-5,-12)          | [(-10,2),(-10,3)]             | (-10,2)
+ (-5,-12)          | [(0,-20),(30,-20)]            | (0,-20)
+ (-5,-12)          | [(NaN,1),(NaN,90)]            | 
+ (1e-300,-1e-300)  | [(1,2),(3,4)]                 | (1,2)
+ (1e-300,-1e-300)  | [(0,0),(6,6)]                 | (0,0)
+ (1e-300,-1e-300)  | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ (1e-300,-1e-300)  | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
+ (1e-300,-1e-300)  | [(11,22),(33,44)]             | (11,22)
+ (1e-300,-1e-300)  | [(-10,2),(-10,3)]             | (-10,2)
+ (1e-300,-1e-300)  | [(0,-20),(30,-20)]            | (0,-20)
+ (1e-300,-1e-300)  | [(NaN,1),(NaN,90)]            | 
+ (1e+300,Infinity) | [(1,2),(3,4)]                 | (3,4)
+ (1e+300,Infinity) | [(0,0),(6,6)]                 | (6,6)
+ (1e+300,Infinity) | [(10,-10),(-3,-4)]            | (-3,-4)
+ (1e+300,Infinity) | [(-1000000,200),(300000,-40)] | (300000,-40)
+ (1e+300,Infinity) | [(11,22),(33,44)]             | (33,44)
+ (1e+300,Infinity) | [(-10,2),(-10,3)]             | (-10,3)
+ (1e+300,Infinity) | [(0,-20),(30,-20)]            | (30,-20)
+ (1e+300,Infinity) | [(NaN,1),(NaN,90)]            | (NaN,90)
+ (NaN,NaN)         | [(1,2),(3,4)]                 | 
+ (NaN,NaN)         | [(0,0),(6,6)]                 | 
+ (NaN,NaN)         | [(10,-10),(-3,-4)]            | 
+ (NaN,NaN)         | [(-1000000,200),(300000,-40)] | 
+ (NaN,NaN)         | [(11,22),(33,44)]             | 
+ (NaN,NaN)         | [(-10,2),(-10,3)]             | 
+ (NaN,NaN)         | [(0,-20),(30,-20)]            | 
+ (NaN,NaN)         | [(NaN,1),(NaN,90)]            | 
+ (10,10)           | [(1,2),(3,4)]                 | (3,4)
+ (10,10)           | [(0,0),(6,6)]                 | (6,6)
+ (10,10)           | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
+ (10,10)           | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
+ (10,10)           | [(11,22),(33,44)]             | (11,22)
+ (10,10)           | [(-10,2),(-10,3)]             | (-10,3)
+ (10,10)           | [(0,-20),(30,-20)]            | (10,-20)
+ (10,10)           | [(NaN,1),(NaN,90)]            | 
+(72 rows)
+
+-- Closest point to box
+SELECT p.f1, b.f1, p.f1 ## b.f1 FROM POINT_TBL p, BOX_TBL b;
+        f1         |         f1          |   ?column?   
+-------------------+---------------------+--------------
+ (0,0)             | (2,2),(0,0)         | (0,0)
+ (0,0)             | (3,3),(1,1)         | (1,1)
+ (0,0)             | (-2,2),(-8,-10)     | (-2,0)
+ (0,0)             | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (0,0)             | (3,3),(3,3)         | (3,3)
+ (-10,0)           | (2,2),(0,0)         | (0,0)
+ (-10,0)           | (3,3),(1,1)         | (1,1)
+ (-10,0)           | (-2,2),(-8,-10)     | (-8,0)
+ (-10,0)           | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (-10,0)           | (3,3),(3,3)         | (3,3)
+ (-3,4)            | (2,2),(0,0)         | (0,2)
+ (-3,4)            | (3,3),(1,1)         | (1,3)
+ (-3,4)            | (-2,2),(-8,-10)     | (-3,2)
+ (-3,4)            | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (-3,4)            | (3,3),(3,3)         | (3,3)
+ (5.1,34.5)        | (2,2),(0,0)         | (2,2)
+ (5.1,34.5)        | (3,3),(1,1)         | (3,3)
+ (5.1,34.5)        | (-2,2),(-8,-10)     | (-2,2)
+ (5.1,34.5)        | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (5.1,34.5)        | (3,3),(3,3)         | (3,3)
+ (-5,-12)          | (2,2),(0,0)         | (0,0)
+ (-5,-12)          | (3,3),(1,1)         | (1,1)
+ (-5,-12)          | (-2,2),(-8,-10)     | (-5,-10)
+ (-5,-12)          | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (-5,-12)          | (3,3),(3,3)         | (3,3)
+ (1e-300,-1e-300)  | (2,2),(0,0)         | (0,0)
+ (1e-300,-1e-300)  | (3,3),(1,1)         | (1,1)
+ (1e-300,-1e-300)  | (-2,2),(-8,-10)     | (-2,-1e-300)
+ (1e-300,-1e-300)  | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (1e-300,-1e-300)  | (3,3),(3,3)         | (3,3)
+ (1e+300,Infinity) | (2,2),(0,0)         | (0,2)
+ (1e+300,Infinity) | (3,3),(1,1)         | (1,3)
+ (1e+300,Infinity) | (-2,2),(-8,-10)     | (-8,2)
+ (1e+300,Infinity) | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (1e+300,Infinity) | (3,3),(3,3)         | (3,3)
+ (NaN,NaN)         | (2,2),(0,0)         | 
+ (NaN,NaN)         | (3,3),(1,1)         | 
+ (NaN,NaN)         | (-2,2),(-8,-10)     | 
+ (NaN,NaN)         | (2.5,3.5),(2.5,2.5) | 
+ (NaN,NaN)         | (3,3),(3,3)         | 
+ (10,10)           | (2,2),(0,0)         | (2,2)
+ (10,10)           | (3,3),(1,1)         | (3,3)
+ (10,10)           | (-2,2),(-8,-10)     | (-2,2)
+ (10,10)           | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (10,10)           | (3,3),(3,3)         | (3,3)
+(45 rows)
+
+-- On line
+SELECT p.f1, l.s FROM POINT_TBL p, LINE_TBL l WHERE p.f1 <@ l.s;
+        f1        |    s     
+------------------+----------
+ (0,0)            | {0,3,0}
+ (0,0)            | {1,-1,0}
+ (-10,0)          | {0,3,0}
+ (-5,-12)         | {1,0,5}
+ (1e-300,-1e-300) | {0,3,0}
+ (1e-300,-1e-300) | {1,-1,0}
+ (10,10)          | {1,-1,0}
+(7 rows)
+
+-- On line segment
+SELECT p.f1, l.s FROM POINT_TBL p, LSEG_TBL l WHERE p.f1 <@ l.s;
+        f1        |       s       
+------------------+---------------
+ (0,0)            | [(0,0),(6,6)]
+ (1e-300,-1e-300) | [(0,0),(6,6)]
+(2 rows)
+
+-- On path
+SELECT p.f1, p1.f1 FROM POINT_TBL p, PATH_TBL p1 WHERE p.f1 <@ p1.f1;
+        f1        |            f1             
+------------------+---------------------------
+ (0,0)            | [(0,0),(3,0),(4,5),(1,6)]
+ (1e-300,-1e-300) | [(0,0),(3,0),(4,5),(1,6)]
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((10,20))
+ (NaN,NaN)        | ((11,12),(13,14))
+(7 rows)
+
+--
+-- Lines
+--
+-- Vertical
+SELECT s FROM LINE_TBL WHERE ?| s;
+    s     
+----------
+ {1,0,5}
+ {-1,0,3}
+(2 rows)
+
+-- Horizontal
+SELECT s FROM LINE_TBL WHERE ?- s;
+    s     
+----------
+ {0,-1,5}
+ {0,3,0}
+ {0,-1,3}
+(3 rows)
+
+-- Same as line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s = l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {0,-1,5}
+ {1,0,5}                               | {1,0,5}
+ {0,3,0}                               | {0,3,0}
+ {1,-1,0}                              | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846}
+ {NaN,-1,NaN}                          | {NaN,-1,NaN}
+ {3,NaN,5}                             | {3,NaN,5}
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}
+ {0,-1,3}                              | {0,-1,3}
+ {-1,0,3}                              | {-1,0,3}
+(11 rows)
+
+-- Parallel to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?|| l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {0,-1,5}
+ {0,-1,5}                              | {0,3,0}
+ {0,-1,5}                              | {0,-1,3}
+ {1,0,5}                               | {1,0,5}
+ {1,0,5}                               | {-1,0,3}
+ {0,3,0}                               | {0,-1,5}
+ {0,3,0}                               | {0,3,0}
+ {0,3,0}                               | {0,-1,3}
+ {1,-1,0}                              | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,3}                              | {0,-1,5}
+ {0,-1,3}                              | {0,3,0}
+ {0,-1,3}                              | {0,-1,3}
+ {-1,0,3}                              | {1,0,5}
+ {-1,0,3}                              | {-1,0,3}
+(16 rows)
+
+-- Perpendicular to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?-| l2.s;
+    s     |    s     
+----------+----------
+ {0,-1,5} | {1,0,5}
+ {0,-1,5} | {-1,0,3}
+ {1,0,5}  | {0,-1,5}
+ {1,0,5}  | {0,3,0}
+ {1,0,5}  | {0,-1,3}
+ {0,3,0}  | {1,0,5}
+ {0,3,0}  | {-1,0,3}
+ {0,-1,3} | {1,0,5}
+ {0,-1,3} | {-1,0,3}
+ {-1,0,3} | {0,-1,5}
+ {-1,0,3} | {0,3,0}
+ {-1,0,3} | {0,-1,3}
+(12 rows)
+
+-- Distance to line
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2;
+                   s                   |                   s                   | ?column? 
+---------------------------------------+---------------------------------------+----------
+ {0,-1,5}                              | {0,-1,5}                              |        0
+ {0,-1,5}                              | {1,0,5}                               |        0
+ {0,-1,5}                              | {0,3,0}                               |        5
+ {0,-1,5}                              | {1,-1,0}                              |        0
+ {0,-1,5}                              | {-0.4,-1,-6}                          |        0
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,-1,5}                              | {NaN,-1,NaN}                          |        0
+ {0,-1,5}                              | {3,NaN,5}                             |        0
+ {0,-1,5}                              | {NaN,NaN,NaN}                         |        0
+ {0,-1,5}                              | {0,-1,3}                              |        2
+ {0,-1,5}                              | {-1,0,3}                              |        0
+ {1,0,5}                               | {0,-1,5}                              |        0
+ {1,0,5}                               | {1,0,5}                               |        0
+ {1,0,5}                               | {0,3,0}                               |        0
+ {1,0,5}                               | {1,-1,0}                              |        0
+ {1,0,5}                               | {-0.4,-1,-6}                          |        0
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846} |        0
+ {1,0,5}                               | {NaN,-1,NaN}                          |        0
+ {1,0,5}                               | {3,NaN,5}                             |        0
+ {1,0,5}                               | {NaN,NaN,NaN}                         |        0
+ {1,0,5}                               | {0,-1,3}                              |        0
+ {1,0,5}                               | {-1,0,3}                              |        8
+ {0,3,0}                               | {0,-1,5}                              |        5
+ {0,3,0}                               | {1,0,5}                               |        0
+ {0,3,0}                               | {0,3,0}                               |        0
+ {0,3,0}                               | {1,-1,0}                              |        0
+ {0,3,0}                               | {-0.4,-1,-6}                          |        0
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,3,0}                               | {NaN,-1,NaN}                          |        0
+ {0,3,0}                               | {3,NaN,5}                             |        0
+ {0,3,0}                               | {NaN,NaN,NaN}                         |        0
+ {0,3,0}                               | {0,-1,3}                              |        3
+ {0,3,0}                               | {-1,0,3}                              |        0
+ {1,-1,0}                              | {0,-1,5}                              |        0
+ {1,-1,0}                              | {1,0,5}                               |        0
+ {1,-1,0}                              | {0,3,0}                               |        0
+ {1,-1,0}                              | {1,-1,0}                              |        0
+ {1,-1,0}                              | {-0.4,-1,-6}                          |        0
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {1,-1,0}                              | {NaN,-1,NaN}                          |        0
+ {1,-1,0}                              | {3,NaN,5}                             |        0
+ {1,-1,0}                              | {NaN,NaN,NaN}                         |        0
+ {1,-1,0}                              | {0,-1,3}                              |        0
+ {1,-1,0}                              | {-1,0,3}                              |        0
+ {-0.4,-1,-6}                          | {0,-1,5}                              |        0
+ {-0.4,-1,-6}                          | {1,0,5}                               |        0
+ {-0.4,-1,-6}                          | {0,3,0}                               |        0
+ {-0.4,-1,-6}                          | {1,-1,0}                              |        0
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}                          |        0
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846} |        0
+ {-0.4,-1,-6}                          | {NaN,-1,NaN}                          |        0
+ {-0.4,-1,-6}                          | {3,NaN,5}                             |        0
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}                         |        0
+ {-0.4,-1,-6}                          | {0,-1,3}                              |        0
+ {-0.4,-1,-6}                          | {-1,0,3}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}                               |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}                               |        0
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}                          |        0
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} |        0
+ {-0.000184615384615,-1,15.3846153846} | {NaN,-1,NaN}                          |        0
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}                             |        0
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}                         |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}                              |        0
+ {NaN,-1,NaN}                          | {0,-1,5}                              |        0
+ {NaN,-1,NaN}                          | {1,0,5}                               |        0
+ {NaN,-1,NaN}                          | {0,3,0}                               |        0
+ {NaN,-1,NaN}                          | {1,-1,0}                              |        0
+ {NaN,-1,NaN}                          | {-0.4,-1,-6}                          |        0
+ {NaN,-1,NaN}                          | {-0.000184615384615,-1,15.3846153846} |        0
+ {NaN,-1,NaN}                          | {NaN,-1,NaN}                          |        0
+ {NaN,-1,NaN}                          | {3,NaN,5}                             |        0
+ {NaN,-1,NaN}                          | {NaN,NaN,NaN}                         |        0
+ {NaN,-1,NaN}                          | {0,-1,3}                              |        0
+ {NaN,-1,NaN}                          | {-1,0,3}                              |        0
+ {3,NaN,5}                             | {0,-1,5}                              |        0
+ {3,NaN,5}                             | {1,0,5}                               |        0
+ {3,NaN,5}                             | {0,3,0}                               |        0
+ {3,NaN,5}                             | {1,-1,0}                              |        0
+ {3,NaN,5}                             | {-0.4,-1,-6}                          |        0
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846} |        0
+ {3,NaN,5}                             | {NaN,-1,NaN}                          |        0
+ {3,NaN,5}                             | {3,NaN,5}                             |        0
+ {3,NaN,5}                             | {NaN,NaN,NaN}                         |        0
+ {3,NaN,5}                             | {0,-1,3}                              |        0
+ {3,NaN,5}                             | {-1,0,3}                              |        0
+ {NaN,NaN,NaN}                         | {0,-1,5}                              |        0
+ {NaN,NaN,NaN}                         | {1,0,5}                               |        0
+ {NaN,NaN,NaN}                         | {0,3,0}                               |        0
+ {NaN,NaN,NaN}                         | {1,-1,0}                              |        0
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}                          |        0
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846} |        0
+ {NaN,NaN,NaN}                         | {NaN,-1,NaN}                          |        0
+ {NaN,NaN,NaN}                         | {3,NaN,5}                             |        0
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}                         |        0
+ {NaN,NaN,NaN}                         | {0,-1,3}                              |        0
+ {NaN,NaN,NaN}                         | {-1,0,3}                              |        0
+ {0,-1,3}                              | {0,-1,5}                              |        2
+ {0,-1,3}                              | {1,0,5}                               |        0
+ {0,-1,3}                              | {0,3,0}                               |        3
+ {0,-1,3}                              | {1,-1,0}                              |        0
+ {0,-1,3}                              | {-0.4,-1,-6}                          |        0
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,-1,3}                              | {NaN,-1,NaN}                          |        0
+ {0,-1,3}                              | {3,NaN,5}                             |        0
+ {0,-1,3}                              | {NaN,NaN,NaN}                         |        0
+ {0,-1,3}                              | {0,-1,3}                              |        0
+ {0,-1,3}                              | {-1,0,3}                              |        0
+ {-1,0,3}                              | {0,-1,5}                              |        0
+ {-1,0,3}                              | {1,0,5}                               |        8
+ {-1,0,3}                              | {0,3,0}                               |        0
+ {-1,0,3}                              | {1,-1,0}                              |        0
+ {-1,0,3}                              | {-0.4,-1,-6}                          |        0
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {-1,0,3}                              | {NaN,-1,NaN}                          |        0
+ {-1,0,3}                              | {3,NaN,5}                             |        0
+ {-1,0,3}                              | {NaN,NaN,NaN}                         |        0
+ {-1,0,3}                              | {0,-1,3}                              |        0
+ {-1,0,3}                              | {-1,0,3}                              |        0
+(121 rows)
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LINE_TBL l, BOX_TBL b;
+ERROR:  function "dist_lb" not implemented
+-- Intersect with line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?# l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {1,0,5}
+ {0,-1,5}                              | {1,-1,0}
+ {0,-1,5}                              | {-0.4,-1,-6}
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,5}                              | {NaN,-1,NaN}
+ {0,-1,5}                              | {3,NaN,5}
+ {0,-1,5}                              | {NaN,NaN,NaN}
+ {0,-1,5}                              | {-1,0,3}
+ {1,0,5}                               | {0,-1,5}
+ {1,0,5}                               | {0,3,0}
+ {1,0,5}                               | {1,-1,0}
+ {1,0,5}                               | {-0.4,-1,-6}
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846}
+ {1,0,5}                               | {NaN,-1,NaN}
+ {1,0,5}                               | {3,NaN,5}
+ {1,0,5}                               | {NaN,NaN,NaN}
+ {1,0,5}                               | {0,-1,3}
+ {0,3,0}                               | {1,0,5}
+ {0,3,0}                               | {1,-1,0}
+ {0,3,0}                               | {-0.4,-1,-6}
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846}
+ {0,3,0}                               | {NaN,-1,NaN}
+ {0,3,0}                               | {3,NaN,5}
+ {0,3,0}                               | {NaN,NaN,NaN}
+ {0,3,0}                               | {-1,0,3}
+ {1,-1,0}                              | {0,-1,5}
+ {1,-1,0}                              | {1,0,5}
+ {1,-1,0}                              | {0,3,0}
+ {1,-1,0}                              | {-0.4,-1,-6}
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846}
+ {1,-1,0}                              | {NaN,-1,NaN}
+ {1,-1,0}                              | {3,NaN,5}
+ {1,-1,0}                              | {NaN,NaN,NaN}
+ {1,-1,0}                              | {0,-1,3}
+ {1,-1,0}                              | {-1,0,3}
+ {-0.4,-1,-6}                          | {0,-1,5}
+ {-0.4,-1,-6}                          | {1,0,5}
+ {-0.4,-1,-6}                          | {0,3,0}
+ {-0.4,-1,-6}                          | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846}
+ {-0.4,-1,-6}                          | {NaN,-1,NaN}
+ {-0.4,-1,-6}                          | {3,NaN,5}
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}
+ {-0.4,-1,-6}                          | {0,-1,3}
+ {-0.4,-1,-6}                          | {-1,0,3}
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {NaN,-1,NaN}
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}
+ {NaN,-1,NaN}                          | {0,-1,5}
+ {NaN,-1,NaN}                          | {1,0,5}
+ {NaN,-1,NaN}                          | {0,3,0}
+ {NaN,-1,NaN}                          | {1,-1,0}
+ {NaN,-1,NaN}                          | {-0.4,-1,-6}
+ {NaN,-1,NaN}                          | {-0.000184615384615,-1,15.3846153846}
+ {NaN,-1,NaN}                          | {NaN,-1,NaN}
+ {NaN,-1,NaN}                          | {3,NaN,5}
+ {NaN,-1,NaN}                          | {NaN,NaN,NaN}
+ {NaN,-1,NaN}                          | {0,-1,3}
+ {NaN,-1,NaN}                          | {-1,0,3}
+ {3,NaN,5}                             | {0,-1,5}
+ {3,NaN,5}                             | {1,0,5}
+ {3,NaN,5}                             | {0,3,0}
+ {3,NaN,5}                             | {1,-1,0}
+ {3,NaN,5}                             | {-0.4,-1,-6}
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846}
+ {3,NaN,5}                             | {NaN,-1,NaN}
+ {3,NaN,5}                             | {3,NaN,5}
+ {3,NaN,5}                             | {NaN,NaN,NaN}
+ {3,NaN,5}                             | {0,-1,3}
+ {3,NaN,5}                             | {-1,0,3}
+ {NaN,NaN,NaN}                         | {0,-1,5}
+ {NaN,NaN,NaN}                         | {1,0,5}
+ {NaN,NaN,NaN}                         | {0,3,0}
+ {NaN,NaN,NaN}                         | {1,-1,0}
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846}
+ {NaN,NaN,NaN}                         | {NaN,-1,NaN}
+ {NaN,NaN,NaN}                         | {3,NaN,5}
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}
+ {NaN,NaN,NaN}                         | {0,-1,3}
+ {NaN,NaN,NaN}                         | {-1,0,3}
+ {0,-1,3}                              | {1,0,5}
+ {0,-1,3}                              | {1,-1,0}
+ {0,-1,3}                              | {-0.4,-1,-6}
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,3}                              | {NaN,-1,NaN}
+ {0,-1,3}                              | {3,NaN,5}
+ {0,-1,3}                              | {NaN,NaN,NaN}
+ {0,-1,3}                              | {-1,0,3}
+ {-1,0,3}                              | {0,-1,5}
+ {-1,0,3}                              | {0,3,0}
+ {-1,0,3}                              | {1,-1,0}
+ {-1,0,3}                              | {-0.4,-1,-6}
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846}
+ {-1,0,3}                              | {NaN,-1,NaN}
+ {-1,0,3}                              | {3,NaN,5}
+ {-1,0,3}                              | {NaN,NaN,NaN}
+ {-1,0,3}                              | {0,-1,3}
+(105 rows)
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LINE_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+      s       |         f1          
+--------------+---------------------
+ {1,0,5}      | (-2,2),(-8,-10)
+ {0,3,0}      | (2,2),(0,0)
+ {0,3,0}      | (-2,2),(-8,-10)
+ {1,-1,0}     | (2,2),(0,0)
+ {1,-1,0}     | (3,3),(1,1)
+ {1,-1,0}     | (-2,2),(-8,-10)
+ {1,-1,0}     | (2.5,3.5),(2.5,2.5)
+ {-0.4,-1,-6} | (-2,2),(-8,-10)
+ {0,-1,3}     | (3,3),(1,1)
+ {0,-1,3}     | (2.5,3.5),(2.5,2.5)
+ {-1,0,3}     | (3,3),(1,1)
+(11 rows)
+
+-- Intersection point with line
+SELECT l1.s, l2.s, l1.s # l2.s FROM LINE_TBL l1, LINE_TBL l2;
+                   s                   |                   s                   |            ?column?             
+---------------------------------------+---------------------------------------+---------------------------------
+ {0,-1,5}                              | {0,-1,5}                              | 
+ {0,-1,5}                              | {1,0,5}                               | (-5,5)
+ {0,-1,5}                              | {0,3,0}                               | 
+ {0,-1,5}                              | {1,-1,0}                              | (5,5)
+ {0,-1,5}                              | {-0.4,-1,-6}                          | (-27.5,5)
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846} | (56250,5)
+ {0,-1,5}                              | {NaN,-1,NaN}                          | (NaN,5)
+ {0,-1,5}                              | {3,NaN,5}                             | (NaN,5)
+ {0,-1,5}                              | {NaN,NaN,NaN}                         | (NaN,5)
+ {0,-1,5}                              | {0,-1,3}                              | 
+ {0,-1,5}                              | {-1,0,3}                              | (3,5)
+ {1,0,5}                               | {0,-1,5}                              | (-5,5)
+ {1,0,5}                               | {1,0,5}                               | 
+ {1,0,5}                               | {0,3,0}                               | (-5,0)
+ {1,0,5}                               | {1,-1,0}                              | (-5,-5)
+ {1,0,5}                               | {-0.4,-1,-6}                          | (-5,-4)
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846} | (-5,15.3855384615)
+ {1,0,5}                               | {NaN,-1,NaN}                          | (-5,NaN)
+ {1,0,5}                               | {3,NaN,5}                             | (-5,NaN)
+ {1,0,5}                               | {NaN,NaN,NaN}                         | (-5,NaN)
+ {1,0,5}                               | {0,-1,3}                              | (-5,3)
+ {1,0,5}                               | {-1,0,3}                              | 
+ {0,3,0}                               | {0,-1,5}                              | 
+ {0,3,0}                               | {1,0,5}                               | (-5,0)
+ {0,3,0}                               | {0,3,0}                               | 
+ {0,3,0}                               | {1,-1,0}                              | (0,0)
+ {0,3,0}                               | {-0.4,-1,-6}                          | (-15,0)
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846} | (83333.3333333,0)
+ {0,3,0}                               | {NaN,-1,NaN}                          | (NaN,0)
+ {0,3,0}                               | {3,NaN,5}                             | (NaN,0)
+ {0,3,0}                               | {NaN,NaN,NaN}                         | (NaN,0)
+ {0,3,0}                               | {0,-1,3}                              | 
+ {0,3,0}                               | {-1,0,3}                              | (3,0)
+ {1,-1,0}                              | {0,-1,5}                              | (5,5)
+ {1,-1,0}                              | {1,0,5}                               | (-5,-5)
+ {1,-1,0}                              | {0,3,0}                               | (0,0)
+ {1,-1,0}                              | {1,-1,0}                              | 
+ {1,-1,0}                              | {-0.4,-1,-6}                          | (-4.28571428571,-4.28571428571)
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846} | (15.3817756722,15.3817756722)
+ {1,-1,0}                              | {NaN,-1,NaN}                          | (NaN,NaN)
+ {1,-1,0}                              | {3,NaN,5}                             | (NaN,NaN)
+ {1,-1,0}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {1,-1,0}                              | {0,-1,3}                              | (3,3)
+ {1,-1,0}                              | {-1,0,3}                              | (3,3)
+ {-0.4,-1,-6}                          | {0,-1,5}                              | (-27.5,5)
+ {-0.4,-1,-6}                          | {1,0,5}                               | (-5,-4)
+ {-0.4,-1,-6}                          | {0,3,0}                               | (-15,0)
+ {-0.4,-1,-6}                          | {1,-1,0}                              | (-4.28571428571,-4.28571428571)
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}                          | 
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846} | (-53.4862244113,15.3944897645)
+ {-0.4,-1,-6}                          | {NaN,-1,NaN}                          | (NaN,NaN)
+ {-0.4,-1,-6}                          | {3,NaN,5}                             | (NaN,NaN)
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-0.4,-1,-6}                          | {0,-1,3}                              | (-22.5,3)
+ {-0.4,-1,-6}                          | {-1,0,3}                              | (3,-7.2)
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}                              | (56250,5)
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}                               | (-5,15.3855384615)
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}                               | (83333.3333333,0)
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}                              | (15.3817756722,15.3817756722)
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}                          | (-53.4862244113,15.3944897645)
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} | 
+ {-0.000184615384615,-1,15.3846153846} | {NaN,-1,NaN}                          | (NaN,NaN)
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}                             | (NaN,NaN)
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}                              | (67083.3333333,3)
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}                              | (3,15.3840615385)
+ {NaN,-1,NaN}                          | {0,-1,5}                              | (NaN,5)
+ {NaN,-1,NaN}                          | {1,0,5}                               | (-5,NaN)
+ {NaN,-1,NaN}                          | {0,3,0}                               | (NaN,0)
+ {NaN,-1,NaN}                          | {1,-1,0}                              | (NaN,NaN)
+ {NaN,-1,NaN}                          | {-0.4,-1,-6}                          | (NaN,NaN)
+ {NaN,-1,NaN}                          | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ {NaN,-1,NaN}                          | {NaN,-1,NaN}                          | (NaN,NaN)
+ {NaN,-1,NaN}                          | {3,NaN,5}                             | (NaN,NaN)
+ {NaN,-1,NaN}                          | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {NaN,-1,NaN}                          | {0,-1,3}                              | (NaN,3)
+ {NaN,-1,NaN}                          | {-1,0,3}                              | (3,NaN)
+ {3,NaN,5}                             | {0,-1,5}                              | (NaN,5)
+ {3,NaN,5}                             | {1,0,5}                               | (-5,NaN)
+ {3,NaN,5}                             | {0,3,0}                               | (NaN,0)
+ {3,NaN,5}                             | {1,-1,0}                              | (NaN,NaN)
+ {3,NaN,5}                             | {-0.4,-1,-6}                          | (NaN,NaN)
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ {3,NaN,5}                             | {NaN,-1,NaN}                          | (NaN,NaN)
+ {3,NaN,5}                             | {3,NaN,5}                             | (NaN,NaN)
+ {3,NaN,5}                             | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {3,NaN,5}                             | {0,-1,3}                              | (NaN,3)
+ {3,NaN,5}                             | {-1,0,3}                              | (3,NaN)
+ {NaN,NaN,NaN}                         | {0,-1,5}                              | (NaN,5)
+ {NaN,NaN,NaN}                         | {1,0,5}                               | (-5,NaN)
+ {NaN,NaN,NaN}                         | {0,3,0}                               | (NaN,0)
+ {NaN,NaN,NaN}                         | {1,-1,0}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}                          | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {NaN,-1,NaN}                          | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {3,NaN,5}                             | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,-1,3}                              | (NaN,3)
+ {NaN,NaN,NaN}                         | {-1,0,3}                              | (3,NaN)
+ {0,-1,3}                              | {0,-1,5}                              | 
+ {0,-1,3}                              | {1,0,5}                               | (-5,3)
+ {0,-1,3}                              | {0,3,0}                               | 
+ {0,-1,3}                              | {1,-1,0}                              | (3,3)
+ {0,-1,3}                              | {-0.4,-1,-6}                          | (-22.5,3)
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846} | (67083.3333333,3)
+ {0,-1,3}                              | {NaN,-1,NaN}                          | (NaN,3)
+ {0,-1,3}                              | {3,NaN,5}                             | (NaN,3)
+ {0,-1,3}                              | {NaN,NaN,NaN}                         | (NaN,3)
+ {0,-1,3}                              | {0,-1,3}                              | 
+ {0,-1,3}                              | {-1,0,3}                              | (3,3)
+ {-1,0,3}                              | {0,-1,5}                              | (3,5)
+ {-1,0,3}                              | {1,0,5}                               | 
+ {-1,0,3}                              | {0,3,0}                               | (3,0)
+ {-1,0,3}                              | {1,-1,0}                              | (3,3)
+ {-1,0,3}                              | {-0.4,-1,-6}                          | (3,-7.2)
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846} | (3,15.3840615385)
+ {-1,0,3}                              | {NaN,-1,NaN}                          | (3,NaN)
+ {-1,0,3}                              | {3,NaN,5}                             | (3,NaN)
+ {-1,0,3}                              | {NaN,NaN,NaN}                         | (3,NaN)
+ {-1,0,3}                              | {0,-1,3}                              | (3,3)
+ {-1,0,3}                              | {-1,0,3}                              | 
+(121 rows)
+
+-- Closest point to line segment
+SELECT l.s, l1.s, l.s ## l1.s FROM LINE_TBL l, LSEG_TBL l1;
+                   s                   |               s               |            ?column?            
+---------------------------------------+-------------------------------+--------------------------------
+ {0,-1,5}                              | [(1,2),(3,4)]                 | (3,4)
+ {0,-1,5}                              | [(0,0),(6,6)]                 | (5,5)
+ {0,-1,5}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,-1,5}                              | [(-1000000,200),(300000,-40)] | (56250,5)
+ {0,-1,5}                              | [(11,22),(33,44)]             | (11,22)
+ {0,-1,5}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {0,-1,5}                              | [(0,-20),(30,-20)]            | 
+ {0,-1,5}                              | [(NaN,1),(NaN,90)]            | 
+ {1,0,5}                               | [(1,2),(3,4)]                 | (1,2)
+ {1,0,5}                               | [(0,0),(6,6)]                 | (0,0)
+ {1,0,5}                               | [(10,-10),(-3,-4)]            | (-3,-4)
+ {1,0,5}                               | [(-1000000,200),(300000,-40)] | (-5,15.3855384615)
+ {1,0,5}                               | [(11,22),(33,44)]             | (11,22)
+ {1,0,5}                               | [(-10,2),(-10,3)]             | 
+ {1,0,5}                               | [(0,-20),(30,-20)]            | (0,-20)
+ {1,0,5}                               | [(NaN,1),(NaN,90)]            | 
+ {0,3,0}                               | [(1,2),(3,4)]                 | (1,2)
+ {0,3,0}                               | [(0,0),(6,6)]                 | (0,0)
+ {0,3,0}                               | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,3,0}                               | [(-1000000,200),(300000,-40)] | (83333.3333333,0)
+ {0,3,0}                               | [(11,22),(33,44)]             | (11,22)
+ {0,3,0}                               | [(-10,2),(-10,3)]             | (-10,2)
+ {0,3,0}                               | [(0,-20),(30,-20)]            | 
+ {0,3,0}                               | [(NaN,1),(NaN,90)]            | 
+ {1,-1,0}                              | [(1,2),(3,4)]                 | 
+ {1,-1,0}                              | [(0,0),(6,6)]                 | 
+ {1,-1,0}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {1,-1,0}                              | [(-1000000,200),(300000,-40)] | (15.3817756722,15.3817756722)
+ {1,-1,0}                              | [(11,22),(33,44)]             | 
+ {1,-1,0}                              | [(-10,2),(-10,3)]             | (-10,2)
+ {1,-1,0}                              | [(0,-20),(30,-20)]            | (0,-20)
+ {1,-1,0}                              | [(NaN,1),(NaN,90)]            | 
+ {-0.4,-1,-6}                          | [(1,2),(3,4)]                 | (1,2)
+ {-0.4,-1,-6}                          | [(0,0),(6,6)]                 | (0,0)
+ {-0.4,-1,-6}                          | [(10,-10),(-3,-4)]            | (10,-10)
+ {-0.4,-1,-6}                          | [(-1000000,200),(300000,-40)] | (-53.4862244113,15.3944897645)
+ {-0.4,-1,-6}                          | [(11,22),(33,44)]             | (11,22)
+ {-0.4,-1,-6}                          | [(-10,2),(-10,3)]             | (-10,2)
+ {-0.4,-1,-6}                          | [(0,-20),(30,-20)]            | (30,-20)
+ {-0.4,-1,-6}                          | [(NaN,1),(NaN,90)]            | 
+ {-0.000184615384615,-1,15.3846153846} | [(1,2),(3,4)]                 | (3,4)
+ {-0.000184615384615,-1,15.3846153846} | [(0,0),(6,6)]                 | (6,6)
+ {-0.000184615384615,-1,15.3846153846} | [(10,-10),(-3,-4)]            | (-3,-4)
+ {-0.000184615384615,-1,15.3846153846} | [(-1000000,200),(300000,-40)] | 
+ {-0.000184615384615,-1,15.3846153846} | [(11,22),(33,44)]             | (11,22)
+ {-0.000184615384615,-1,15.3846153846} | [(-10,2),(-10,3)]             | (-10,3)
+ {-0.000184615384615,-1,15.3846153846} | [(0,-20),(30,-20)]            | (30,-20)
+ {-0.000184615384615,-1,15.3846153846} | [(NaN,1),(NaN,90)]            | 
+ {NaN,-1,NaN}                          | [(1,2),(3,4)]                 | 
+ {NaN,-1,NaN}                          | [(0,0),(6,6)]                 | 
+ {NaN,-1,NaN}                          | [(10,-10),(-3,-4)]            | 
+ {NaN,-1,NaN}                          | [(-1000000,200),(300000,-40)] | 
+ {NaN,-1,NaN}                          | [(11,22),(33,44)]             | 
+ {NaN,-1,NaN}                          | [(-10,2),(-10,3)]             | 
+ {NaN,-1,NaN}                          | [(0,-20),(30,-20)]            | 
+ {NaN,-1,NaN}                          | [(NaN,1),(NaN,90)]            | 
+ {3,NaN,5}                             | [(1,2),(3,4)]                 | 
+ {3,NaN,5}                             | [(0,0),(6,6)]                 | 
+ {3,NaN,5}                             | [(10,-10),(-3,-4)]            | 
+ {3,NaN,5}                             | [(-1000000,200),(300000,-40)] | 
+ {3,NaN,5}                             | [(11,22),(33,44)]             | 
+ {3,NaN,5}                             | [(-10,2),(-10,3)]             | 
+ {3,NaN,5}                             | [(0,-20),(30,-20)]            | 
+ {3,NaN,5}                             | [(NaN,1),(NaN,90)]            | 
+ {NaN,NaN,NaN}                         | [(1,2),(3,4)]                 | 
+ {NaN,NaN,NaN}                         | [(0,0),(6,6)]                 | 
+ {NaN,NaN,NaN}                         | [(10,-10),(-3,-4)]            | 
+ {NaN,NaN,NaN}                         | [(-1000000,200),(300000,-40)] | 
+ {NaN,NaN,NaN}                         | [(11,22),(33,44)]             | 
+ {NaN,NaN,NaN}                         | [(-10,2),(-10,3)]             | 
+ {NaN,NaN,NaN}                         | [(0,-20),(30,-20)]            | 
+ {NaN,NaN,NaN}                         | [(NaN,1),(NaN,90)]            | 
+ {0,-1,3}                              | [(1,2),(3,4)]                 | (2,3)
+ {0,-1,3}                              | [(0,0),(6,6)]                 | (3,3)
+ {0,-1,3}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,-1,3}                              | [(-1000000,200),(300000,-40)] | (67083.3333333,3)
+ {0,-1,3}                              | [(11,22),(33,44)]             | (11,22)
+ {0,-1,3}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {0,-1,3}                              | [(0,-20),(30,-20)]            | 
+ {0,-1,3}                              | [(NaN,1),(NaN,90)]            | 
+ {-1,0,3}                              | [(1,2),(3,4)]                 | (3,4)
+ {-1,0,3}                              | [(0,0),(6,6)]                 | (3,3)
+ {-1,0,3}                              | [(10,-10),(-3,-4)]            | (3,-6.76923076923)
+ {-1,0,3}                              | [(-1000000,200),(300000,-40)] | (3,15.3840615385)
+ {-1,0,3}                              | [(11,22),(33,44)]             | (11,22)
+ {-1,0,3}                              | [(-10,2),(-10,3)]             | 
+ {-1,0,3}                              | [(0,-20),(30,-20)]            | (3,-20)
+ {-1,0,3}                              | [(NaN,1),(NaN,90)]            | 
+(88 rows)
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LINE_TBL l, BOX_TBL b;
+ERROR:  function "close_lb" not implemented
 --
 -- Line segments
 --
 -- intersection
 SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
    FROM LSEG_TBL l, POINT_TBL p;
 ERROR:  operator does not exist: lseg # point
 LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
                                            ^
 HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (-0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
+-- Length
+SELECT s, @-@ s FROM LSEG_TBL;
+               s               |   ?column?    
+-------------------------------+---------------
+ [(1,2),(3,4)]                 | 2.82842712475
+ [(0,0),(6,6)]                 | 8.48528137424
+ [(10,-10),(-3,-4)]            | 14.3178210633
+ [(-1000000,200),(300000,-40)] | 1300000.02215
+ [(11,22),(33,44)]             | 31.1126983722
+ [(-10,2),(-10,3)]             |             1
+ [(0,-20),(30,-20)]            |            30
+ [(NaN,1),(NaN,90)]            |           NaN
+(8 rows)
+
+-- Vertical
+SELECT s FROM LSEG_TBL WHERE ?| s;
+         s         
+-------------------
+ [(-10,2),(-10,3)]
+(1 row)
+
+-- Horizontal
+SELECT s FROM LSEG_TBL WHERE ?- s;
+         s          
+--------------------
+ [(0,-20),(30,-20)]
+(1 row)
+
+-- Center
+SELECT s, @@ s FROM LSEG_TBL;
+               s               |   ?column?   
+-------------------------------+--------------
+ [(1,2),(3,4)]                 | (2,3)
+ [(0,0),(6,6)]                 | (3,3)
+ [(10,-10),(-3,-4)]            | (3.5,-7)
+ [(-1000000,200),(300000,-40)] | (-350000,80)
+ [(11,22),(33,44)]             | (22,33)
+ [(-10,2),(-10,3)]             | (-10,2.5)
+ [(0,-20),(30,-20)]            | (15,-20)
+ [(NaN,1),(NaN,90)]            | (NaN,45.5)
+(8 rows)
+
+-- To point
+SELECT s, s::point FROM LSEG_TBL;
+               s               |      s       
+-------------------------------+--------------
+ [(1,2),(3,4)]                 | (2,3)
+ [(0,0),(6,6)]                 | (3,3)
+ [(10,-10),(-3,-4)]            | (3.5,-7)
+ [(-1000000,200),(300000,-40)] | (-350000,80)
+ [(11,22),(33,44)]             | (22,33)
+ [(-10,2),(-10,3)]             | (-10,2.5)
+ [(0,-20),(30,-20)]            | (15,-20)
+ [(NaN,1),(NaN,90)]            | (NaN,45.5)
+(8 rows)
+
+-- Has points less than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s < l2.s;
+         s          |               s               
+--------------------+-------------------------------
+ [(1,2),(3,4)]      | [(0,0),(6,6)]
+ [(1,2),(3,4)]      | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]      | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]      | [(11,22),(33,44)]
+ [(1,2),(3,4)]      | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]      | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]      | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]      | [(11,22),(33,44)]
+ [(0,0),(6,6)]      | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)] | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)] | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]  | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]  | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]  | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]  | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]  | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]  | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]  | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)] | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)] | [(11,22),(33,44)]
+(21 rows)
+
+-- Has points less than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s <= l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(28 rows)
+
+-- Has points equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s = l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]
+(8 rows)
+
+-- Has points greater than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s >= l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(28 rows)
+
+-- Has points greater than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s > l2.s;
+               s               |         s          
+-------------------------------+--------------------
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+(21 rows)
+
+-- Has points not equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s != l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)]
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]
+(56 rows)
+
+-- Parallel with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?|| l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(13 rows)
+
+-- Perpendicular with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?-| l2.s;
+         s          |         s          
+--------------------+--------------------
+ [(-10,2),(-10,3)]  | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)] | [(-10,2),(-10,3)]
+(2 rows)
+
+-- Distance to line
+SELECT l.s, l1.s, l.s <-> l1.s FROM LSEG_TBL l, LINE_TBL l1;
+               s               |                   s                   |    ?column?    
+-------------------------------+---------------------------------------+----------------
+ [(1,2),(3,4)]                 | {0,-1,5}                              |              1
+ [(0,0),(6,6)]                 | {0,-1,5}                              |              0
+ [(10,-10),(-3,-4)]            | {0,-1,5}                              |              9
+ [(-1000000,200),(300000,-40)] | {0,-1,5}                              |              0
+ [(11,22),(33,44)]             | {0,-1,5}                              |             17
+ [(-10,2),(-10,3)]             | {0,-1,5}                              |              2
+ [(0,-20),(30,-20)]            | {0,-1,5}                              |             25
+ [(NaN,1),(NaN,90)]            | {0,-1,5}                              |            NaN
+ [(1,2),(3,4)]                 | {1,0,5}                               |              6
+ [(0,0),(6,6)]                 | {1,0,5}                               |              5
+ [(10,-10),(-3,-4)]            | {1,0,5}                               |              2
+ [(-1000000,200),(300000,-40)] | {1,0,5}                               |              0
+ [(11,22),(33,44)]             | {1,0,5}                               |             16
+ [(-10,2),(-10,3)]             | {1,0,5}                               |              5
+ [(0,-20),(30,-20)]            | {1,0,5}                               |              5
+ [(NaN,1),(NaN,90)]            | {1,0,5}                               |            NaN
+ [(1,2),(3,4)]                 | {0,3,0}                               |              2
+ [(0,0),(6,6)]                 | {0,3,0}                               |              0
+ [(10,-10),(-3,-4)]            | {0,3,0}                               |              4
+ [(-1000000,200),(300000,-40)] | {0,3,0}                               |              0
+ [(11,22),(33,44)]             | {0,3,0}                               |             22
+ [(-10,2),(-10,3)]             | {0,3,0}                               |              2
+ [(0,-20),(30,-20)]            | {0,3,0}                               |             20
+ [(NaN,1),(NaN,90)]            | {0,3,0}                               |            NaN
+ [(1,2),(3,4)]                 | {1,-1,0}                              | 0.707106781187
+ [(0,0),(6,6)]                 | {1,-1,0}                              |              0
+ [(10,-10),(-3,-4)]            | {1,-1,0}                              | 0.707106781187
+ [(-1000000,200),(300000,-40)] | {1,-1,0}                              |              0
+ [(11,22),(33,44)]             | {1,-1,0}                              |  7.77817459305
+ [(-10,2),(-10,3)]             | {1,-1,0}                              |  8.48528137424
+ [(0,-20),(30,-20)]            | {1,-1,0}                              |  14.1421356237
+ [(NaN,1),(NaN,90)]            | {1,-1,0}                              |            NaN
+ [(1,2),(3,4)]                 | {-0.4,-1,-6}                          |  7.79920420344
+ [(0,0),(6,6)]                 | {-0.4,-1,-6}                          |  5.57086014531
+ [(10,-10),(-3,-4)]            | {-0.4,-1,-6}                          |              0
+ [(-1000000,200),(300000,-40)] | {-0.4,-1,-6}                          |              0
+ [(11,22),(33,44)]             | {-0.4,-1,-6}                          |  30.0826447847
+ [(-10,2),(-10,3)]             | {-0.4,-1,-6}                          |  3.71390676354
+ [(0,-20),(30,-20)]            | {-0.4,-1,-6}                          |  1.85695338177
+ [(NaN,1),(NaN,90)]            | {-0.4,-1,-6}                          |            NaN
+ [(1,2),(3,4)]                 | {-0.000184615384615,-1,15.3846153846} |  11.3840613445
+ [(0,0),(6,6)]                 | {-0.000184615384615,-1,15.3846153846} |   9.3835075324
+ [(10,-10),(-3,-4)]            | {-0.000184615384615,-1,15.3846153846} |  19.3851689004
+ [(-1000000,200),(300000,-40)] | {-0.000184615384615,-1,15.3846153846} |              0
+ [(11,22),(33,44)]             | {-0.000184615384615,-1,15.3846153846} |  6.61741527185
+ [(-10,2),(-10,3)]             | {-0.000184615384615,-1,15.3846153846} |  12.3864613274
+ [(0,-20),(30,-20)]            | {-0.000184615384615,-1,15.3846153846} |  35.3790763202
+ [(NaN,1),(NaN,90)]            | {-0.000184615384615,-1,15.3846153846} |            NaN
+ [(1,2),(3,4)]                 | {NaN,-1,NaN}                          |            NaN
+ [(0,0),(6,6)]                 | {NaN,-1,NaN}                          |            NaN
+ [(10,-10),(-3,-4)]            | {NaN,-1,NaN}                          |            NaN
+ [(-1000000,200),(300000,-40)] | {NaN,-1,NaN}                          |            NaN
+ [(11,22),(33,44)]             | {NaN,-1,NaN}                          |            NaN
+ [(-10,2),(-10,3)]             | {NaN,-1,NaN}                          |            NaN
+ [(0,-20),(30,-20)]            | {NaN,-1,NaN}                          |            NaN
+ [(NaN,1),(NaN,90)]            | {NaN,-1,NaN}                          |            NaN
+ [(1,2),(3,4)]                 | {3,NaN,5}                             |            NaN
+ [(0,0),(6,6)]                 | {3,NaN,5}                             |            NaN
+ [(10,-10),(-3,-4)]            | {3,NaN,5}                             |            NaN
+ [(-1000000,200),(300000,-40)] | {3,NaN,5}                             |            NaN
+ [(11,22),(33,44)]             | {3,NaN,5}                             |            NaN
+ [(-10,2),(-10,3)]             | {3,NaN,5}                             |            NaN
+ [(0,-20),(30,-20)]            | {3,NaN,5}                             |            NaN
+ [(NaN,1),(NaN,90)]            | {3,NaN,5}                             |            NaN
+ [(1,2),(3,4)]                 | {NaN,NaN,NaN}                         |            NaN
+ [(0,0),(6,6)]                 | {NaN,NaN,NaN}                         |            NaN
+ [(10,-10),(-3,-4)]            | {NaN,NaN,NaN}                         |            NaN
+ [(-1000000,200),(300000,-40)] | {NaN,NaN,NaN}                         |            NaN
+ [(11,22),(33,44)]             | {NaN,NaN,NaN}                         |            NaN
+ [(-10,2),(-10,3)]             | {NaN,NaN,NaN}                         |            NaN
+ [(0,-20),(30,-20)]            | {NaN,NaN,NaN}                         |            NaN
+ [(NaN,1),(NaN,90)]            | {NaN,NaN,NaN}                         |            NaN
+ [(1,2),(3,4)]                 | {0,-1,3}                              |              0
+ [(0,0),(6,6)]                 | {0,-1,3}                              |              0
+ [(10,-10),(-3,-4)]            | {0,-1,3}                              |              7
+ [(-1000000,200),(300000,-40)] | {0,-1,3}                              |              0
+ [(11,22),(33,44)]             | {0,-1,3}                              |             19
+ [(-10,2),(-10,3)]             | {0,-1,3}                              |              0
+ [(0,-20),(30,-20)]            | {0,-1,3}                              |             23
+ [(NaN,1),(NaN,90)]            | {0,-1,3}                              |            NaN
+ [(1,2),(3,4)]                 | {-1,0,3}                              |              0
+ [(0,0),(6,6)]                 | {-1,0,3}                              |              0
+ [(10,-10),(-3,-4)]            | {-1,0,3}                              |              0
+ [(-1000000,200),(300000,-40)] | {-1,0,3}                              |              0
+ [(11,22),(33,44)]             | {-1,0,3}                              |              8
+ [(-10,2),(-10,3)]             | {-1,0,3}                              |             13
+ [(0,-20),(30,-20)]            | {-1,0,3}                              |              0
+ [(NaN,1),(NaN,90)]            | {-1,0,3}                              |            NaN
+(88 rows)
+
+-- Distance to line segment
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               |    ?column?    
+-------------------------------+-------------------------------+----------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 |              0
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 0.707106781187
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            |  7.12398901685
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] |  11.3840613445
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             |  19.6977156036
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             |             11
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            |             22
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            |            NaN
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 0.707106781187
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 |              0
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            |  4.88901207039
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] |   9.3835075324
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             |  16.7630546142
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             |  10.1980390272
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            |             20
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            |            NaN
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 |  7.12398901685
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 |  4.88901207039
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            |              0
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] |  19.3851689004
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             |  29.4737584815
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             |  9.21954445729
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            |             10
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            |            NaN
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 |  11.3840613445
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 |   9.3835075324
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            |  19.3851689004
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] |              0
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             |  6.61741527185
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             |  12.3864613274
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            |  35.3790763202
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            |            NaN
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 |  19.6977156036
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 |  16.7630546142
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            |  29.4737584815
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] |  6.61741527185
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             |              0
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             |   28.319604517
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            |             42
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            |            NaN
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 |             11
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 |  10.1980390272
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            |  9.21954445729
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] |  12.3864613274
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             |   28.319604517
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             |              0
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            |  24.1660919472
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            |            NaN
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 |             22
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 |             20
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            |             10
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] |  35.3790763202
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             |             42
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             |  24.1660919472
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            |              0
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 |            NaN
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 |            NaN
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] |            NaN
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             |            NaN
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             |            NaN
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            |            NaN
+(64 rows)
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LSEG_TBL l, BOX_TBL b;
+               s               |         f1          |    ?column?    
+-------------------------------+---------------------+----------------
+ [(1,2),(3,4)]                 | (2,2),(0,0)         |              0
+ [(1,2),(3,4)]                 | (3,3),(1,1)         |              0
+ [(1,2),(3,4)]                 | (-2,2),(-8,-10)     |              3
+ [(1,2),(3,4)]                 | (2.5,3.5),(2.5,2.5) |              0
+ [(1,2),(3,4)]                 | (3,3),(3,3)         | 0.707106781187
+ [(0,0),(6,6)]                 | (2,2),(0,0)         |              0
+ [(0,0),(6,6)]                 | (3,3),(1,1)         |              0
+ [(0,0),(6,6)]                 | (-2,2),(-8,-10)     |              2
+ [(0,0),(6,6)]                 | (2.5,3.5),(2.5,2.5) |              0
+ [(0,0),(6,6)]                 | (3,3),(3,3)         |              0
+ [(10,-10),(-3,-4)]            | (2,2),(0,0)         |  4.88901207039
+ [(10,-10),(-3,-4)]            | (3,3),(1,1)         |  6.21602963235
+ [(10,-10),(-3,-4)]            | (-2,2),(-8,-10)     |              0
+ [(10,-10),(-3,-4)]            | (2.5,3.5),(2.5,2.5) |  8.20655597529
+ [(10,-10),(-3,-4)]            | (3,3),(3,3)         |  8.87006475627
+ [(-1000000,200),(300000,-40)] | (2,2),(0,0)         |  13.3842459258
+ [(-1000000,200),(300000,-40)] | (3,3),(1,1)         |  12.3840613274
+ [(-1000000,200),(300000,-40)] | (-2,2),(-8,-10)     |  13.3849843873
+ [(-1000000,200),(300000,-40)] | (2.5,3.5),(2.5,2.5) |  11.8841536436
+ [(-1000000,200),(300000,-40)] | (3,3),(3,3)         |  12.3840613274
+ [(11,22),(33,44)]             | (2,2),(0,0)         |  21.9317121995
+ [(11,22),(33,44)]             | (3,3),(1,1)         |  20.6155281281
+ [(11,22),(33,44)]             | (-2,2),(-8,-10)     |  23.8537208838
+ [(11,22),(33,44)]             | (2.5,3.5),(2.5,2.5) |  20.3592730715
+ [(11,22),(33,44)]             | (3,3),(3,3)         |  20.6155281281
+ [(-10,2),(-10,3)]             | (2,2),(0,0)         |             10
+ [(-10,2),(-10,3)]             | (3,3),(1,1)         |             11
+ [(-10,2),(-10,3)]             | (-2,2),(-8,-10)     |              2
+ [(-10,2),(-10,3)]             | (2.5,3.5),(2.5,2.5) |           12.5
+ [(-10,2),(-10,3)]             | (3,3),(3,3)         |             13
+ [(0,-20),(30,-20)]            | (2,2),(0,0)         |             20
+ [(0,-20),(30,-20)]            | (3,3),(1,1)         |             21
+ [(0,-20),(30,-20)]            | (-2,2),(-8,-10)     |  10.1980390272
+ [(0,-20),(30,-20)]            | (2.5,3.5),(2.5,2.5) |           22.5
+ [(0,-20),(30,-20)]            | (3,3),(3,3)         |             23
+ [(NaN,1),(NaN,90)]            | (2,2),(0,0)         |            NaN
+ [(NaN,1),(NaN,90)]            | (3,3),(1,1)         |            NaN
+ [(NaN,1),(NaN,90)]            | (-2,2),(-8,-10)     |            NaN
+ [(NaN,1),(NaN,90)]            | (2.5,3.5),(2.5,2.5) |            NaN
+ [(NaN,1),(NaN,90)]            | (3,3),(3,3)         |            NaN
+(40 rows)
+
+-- Intersect with line segment
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s ?# l1.s;
+               s               |      s       
+-------------------------------+--------------
+ [(0,0),(6,6)]                 | {0,-1,5}
+ [(-1000000,200),(300000,-40)] | {0,-1,5}
+ [(-1000000,200),(300000,-40)] | {1,0,5}
+ [(0,0),(6,6)]                 | {0,3,0}
+ [(-1000000,200),(300000,-40)] | {0,3,0}
+ [(-1000000,200),(300000,-40)] | {1,-1,0}
+ [(10,-10),(-3,-4)]            | {-0.4,-1,-6}
+ [(-1000000,200),(300000,-40)] | {-0.4,-1,-6}
+ [(1,2),(3,4)]                 | {0,-1,3}
+ [(0,0),(6,6)]                 | {0,-1,3}
+ [(-1000000,200),(300000,-40)] | {0,-1,3}
+ [(-10,2),(-10,3)]             | {0,-1,3}
+ [(1,2),(3,4)]                 | {-1,0,3}
+ [(0,0),(6,6)]                 | {-1,0,3}
+ [(10,-10),(-3,-4)]            | {-1,0,3}
+ [(-1000000,200),(300000,-40)] | {-1,0,3}
+ [(0,-20),(30,-20)]            | {-1,0,3}
+(17 rows)
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+         s          |         f1          
+--------------------+---------------------
+ [(1,2),(3,4)]      | (2,2),(0,0)
+ [(1,2),(3,4)]      | (3,3),(1,1)
+ [(1,2),(3,4)]      | (2.5,3.5),(2.5,2.5)
+ [(0,0),(6,6)]      | (2,2),(0,0)
+ [(0,0),(6,6)]      | (3,3),(1,1)
+ [(0,0),(6,6)]      | (2.5,3.5),(2.5,2.5)
+ [(10,-10),(-3,-4)] | (-2,2),(-8,-10)
+(7 rows)
+
+-- Intersection point with line segment
+SELECT l1.s, l2.s, l1.s # l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               | ?column? 
+-------------------------------+-------------------------------+----------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 | 
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            | 
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] | 
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             | 
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             | 
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            | 
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            | 
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 | 
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            | 
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] | 
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             | 
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             | 
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            | 
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            | 
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 | 
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 | 
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            | 
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] | 
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             | 
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             | 
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            | 
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            | 
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 | 
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 | 
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            | 
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] | 
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             | 
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             | 
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            | 
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            | 
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 | 
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 | 
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            | 
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] | 
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             | 
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             | 
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            | 
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            | 
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 | 
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 | 
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            | 
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] | 
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             | 
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             | 
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            | 
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            | 
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 | 
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 | 
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            | 
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] | 
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             | 
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             | 
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            | 
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            | 
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 | 
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 | 
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            | 
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] | 
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             | 
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             | 
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            | 
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            | 
+(64 rows)
+
+-- Closest point to line
+SELECT l.s, l1.s, l.s ## l1.s FROM LSEG_TBL l, LINE_TBL l1;
+ERROR:  function "close_sl" not implemented
+-- Closest point to line segment
+SELECT l1.s, l2.s, l1.s ## l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               |            ?column?             
+-------------------------------+-------------------------------+---------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 | 
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            | (-1.98536585366,-4.46829268293)
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] | (3.00210167283,15.3840611505)
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             | 
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             | (-10,2)
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            | (1,-20)
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            | 
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 | 
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] | (6.00173233982,15.3835073725)
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             | 
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             | (-10,2)
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            | (0,-20)
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            | 
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 | (1,2)
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 | (0,0)
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            | 
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] | (-2.99642119965,15.3851685701)
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             | (11,22)
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             | (-10,2)
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            | (10,-20)
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            | 
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 | (3,4)
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 | (6,6)
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            | (-3,-4)
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] | 
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             | (11,22)
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             | (-10,3)
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            | (30,-20)
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            | 
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 | 
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 | 
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            | (-1.3512195122,-4.76097560976)
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] | (10.9987783234,15.3825848409)
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             | 
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             | (-10,3)
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            | (11,-20)
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            | 
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 | (1,2)
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 | (0,0)
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            | (-3,-4)
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] | (-9.99771326872,15.3864611163)
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             | (11,22)
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             | 
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            | (0,-20)
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            | 
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 | (1,2)
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 | (0,0)
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            | (10,-10)
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] | (30.0065315217,15.3790757173)
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             | (11,22)
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             | (-10,2)
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            | 
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            | 
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 | 
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 | 
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            | 
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] | 
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             | 
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             | 
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            | 
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            | 
+(64 rows)
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LSEG_TBL l, BOX_TBL b;
+               s               |         f1          |  ?column?   
+-------------------------------+---------------------+-------------
+ [(1,2),(3,4)]                 | (2,2),(0,0)         | (1,2)
+ [(1,2),(3,4)]                 | (3,3),(1,1)         | (1.5,2.5)
+ [(1,2),(3,4)]                 | (-2,2),(-8,-10)     | (-2,2)
+ [(1,2),(3,4)]                 | (2.5,3.5),(2.5,2.5) | (2.25,3.25)
+ [(1,2),(3,4)]                 | (3,3),(3,3)         | (3,3)
+ [(0,0),(6,6)]                 | (2,2),(0,0)         | (1,1)
+ [(0,0),(6,6)]                 | (3,3),(1,1)         | (2,2)
+ [(0,0),(6,6)]                 | (-2,2),(-8,-10)     | (-2,0)
+ [(0,0),(6,6)]                 | (2.5,3.5),(2.5,2.5) | (2.75,2.75)
+ [(0,0),(6,6)]                 | (3,3),(3,3)         | (3,3)
+ [(10,-10),(-3,-4)]            | (2,2),(0,0)         | (0,0)
+ [(10,-10),(-3,-4)]            | (3,3),(1,1)         | (1,1)
+ [(10,-10),(-3,-4)]            | (-2,2),(-8,-10)     | (-3,-4)
+ [(10,-10),(-3,-4)]            | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ [(10,-10),(-3,-4)]            | (3,3),(3,3)         | (3,3)
+ [(-1000000,200),(300000,-40)] | (2,2),(0,0)         | (2,2)
+ [(-1000000,200),(300000,-40)] | (3,3),(1,1)         | (3,3)
+ [(-1000000,200),(300000,-40)] | (-2,2),(-8,-10)     | (-2,2)
+ [(-1000000,200),(300000,-40)] | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ [(-1000000,200),(300000,-40)] | (3,3),(3,3)         | (3,3)
+ [(11,22),(33,44)]             | (2,2),(0,0)         | (2,2)
+ [(11,22),(33,44)]             | (3,3),(1,1)         | (3,3)
+ [(11,22),(33,44)]             | (-2,2),(-8,-10)     | (-2,2)
+ [(11,22),(33,44)]             | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ [(11,22),(33,44)]             | (3,3),(3,3)         | (3,3)
+ [(-10,2),(-10,3)]             | (2,2),(0,0)         | (0,2)
+ [(-10,2),(-10,3)]             | (3,3),(1,1)         | (1,2)
+ [(-10,2),(-10,3)]             | (-2,2),(-8,-10)     | (-8,2)
+ [(-10,2),(-10,3)]             | (2.5,3.5),(2.5,2.5) | (2.5,3)
+ [(-10,2),(-10,3)]             | (3,3),(3,3)         | (3,3)
+ [(0,-20),(30,-20)]            | (2,2),(0,0)         | (0,0)
+ [(0,-20),(30,-20)]            | (3,3),(1,1)         | (1,1)
+ [(0,-20),(30,-20)]            | (-2,2),(-8,-10)     | (-2,-10)
+ [(0,-20),(30,-20)]            | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ [(0,-20),(30,-20)]            | (3,3),(3,3)         | (3,3)
+ [(NaN,1),(NaN,90)]            | (2,2),(0,0)         | 
+ [(NaN,1),(NaN,90)]            | (3,3),(1,1)         | 
+ [(NaN,1),(NaN,90)]            | (-2,2),(-8,-10)     | 
+ [(NaN,1),(NaN,90)]            | (2.5,3.5),(2.5,2.5) | 
+ [(NaN,1),(NaN,90)]            | (3,3),(3,3)         | 
+(40 rows)
+
+-- On line
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s <@ l1.s;
+               s               |                   s                   
+-------------------------------+---------------------------------------
+ [(0,0),(6,6)]                 | {1,-1,0}
+ [(-1000000,200),(300000,-40)] | {-0.000184615384615,-1,15.3846153846}
+(2 rows)
+
+-- On box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s <@ b.f1;
+ s | f1 
+---+----
+(0 rows)
 
 --
 -- Boxes
 --
 SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
  six |                              box                               
 -----+----------------------------------------------------------------
      | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
      | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
      | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
      | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
      | (107.071067812,207.071067812),(92.9289321881,192.928932188)
      | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
+     | (3,5),(3,5)
+     | (NaN,NaN),(NaN,NaN)
+(8 rows)
 
 -- translation
 SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
+ twentyfour |             translation             
+------------+-------------------------------------
             | (2,2),(0,0)
             | (3,3),(1,1)
+            | (-2,2),(-8,-10)
             | (2.5,3.5),(2.5,2.5)
             | (3,3),(3,3)
             | (-8,2),(-10,0)
             | (-7,3),(-9,1)
+            | (-12,2),(-18,-10)
             | (-7.5,3.5),(-7.5,2.5)
             | (-7,3),(-7,3)
             | (-1,6),(-3,4)
             | (0,7),(-2,5)
+            | (-5,6),(-11,-6)
             | (-0.5,7.5),(-0.5,6.5)
             | (0,7),(0,7)
             | (7.1,36.5),(5.1,34.5)
             | (8.1,37.5),(6.1,35.5)
+            | (3.1,36.5),(-2.9,24.5)
             | (7.6,38),(7.6,37)
             | (8.1,37.5),(8.1,37.5)
             | (-3,-10),(-5,-12)
             | (-2,-9),(-4,-11)
+            | (-7,-10),(-13,-22)
             | (-2.5,-8.5),(-2.5,-9.5)
             | (-2,-9),(-2,-9)
+            | (2,2),(1e-300,-1e-300)
+            | (3,3),(1,1)
+            | (-2,2),(-8,-10)
+            | (2.5,3.5),(2.5,2.5)
+            | (3,3),(3,3)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
             | (12,12),(10,10)
             | (13,13),(11,11)
+            | (8,12),(2,0)
             | (12.5,13.5),(12.5,12.5)
             | (13,13),(13,13)
-(24 rows)
+(45 rows)
 
 SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
+ twentyfour |               translation               
+------------+-----------------------------------------
             | (2,2),(0,0)
             | (3,3),(1,1)
+            | (-2,2),(-8,-10)
             | (2.5,3.5),(2.5,2.5)
             | (3,3),(3,3)
             | (12,2),(10,0)
             | (13,3),(11,1)
+            | (8,2),(2,-10)
             | (12.5,3.5),(12.5,2.5)
             | (13,3),(13,3)
             | (5,-2),(3,-4)
             | (6,-1),(4,-3)
+            | (1,-2),(-5,-14)
             | (5.5,-0.5),(5.5,-1.5)
             | (6,-1),(6,-1)
             | (-3.1,-32.5),(-5.1,-34.5)
             | (-2.1,-31.5),(-4.1,-33.5)
+            | (-7.1,-32.5),(-13.1,-44.5)
             | (-2.6,-31),(-2.6,-32)
             | (-2.1,-31.5),(-2.1,-31.5)
             | (7,14),(5,12)
             | (8,15),(6,13)
+            | (3,14),(-3,2)
             | (7.5,15.5),(7.5,14.5)
             | (8,15),(8,15)
+            | (2,2),(-1e-300,1e-300)
+            | (3,3),(1,1)
+            | (-2,2),(-8,-10)
+            | (2.5,3.5),(2.5,2.5)
+            | (3,3),(3,3)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
             | (-8,-8),(-10,-10)
             | (-7,-7),(-9,-9)
+            | (-12,-8),(-18,-20)
             | (-7.5,-6.5),(-7.5,-7.5)
             | (-7,-7),(-7,-7)
-(24 rows)
+(45 rows)
 
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (-0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (-0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,-0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
+-- Multiply with point
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+         f1          |     f1     |          ?column?           
+---------------------+------------+-----------------------------
+ (2,2),(0,0)         | (5.1,34.5) | (0,79.2),(-58.8,0)
+ (2,2),(0,0)         | (10,10)    | (0,40),(0,0)
+ (3,3),(1,1)         | (5.1,34.5) | (-29.4,118.8),(-88.2,39.6)
+ (3,3),(1,1)         | (10,10)    | (0,60),(0,20)
+ (-2,2),(-8,-10)     | (5.1,34.5) | (304.2,-58.8),(-79.2,-327)
+ (-2,2),(-8,-10)     | (10,10)    | (20,0),(-40,-180)
+ (2.5,3.5),(2.5,2.5) | (5.1,34.5) | (-73.5,104.1),(-108,99)
+ (2.5,3.5),(2.5,2.5) | (10,10)    | (0,60),(-10,50)
+ (3,3),(3,3)         | (5.1,34.5) | (-88.2,118.8),(-88.2,118.8)
+ (3,3),(3,3)         | (10,10)    | (0,60),(0,60)
+(10 rows)
 
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,-0),(-0.2,-0.2)
-        | (0.08,-0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (-0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
+-- Overflow error
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] > 1000;
+         f1          |        f1         |                  ?column?                  
+---------------------+-------------------+--------------------------------------------
+ (2,2),(0,0)         | (1e+300,Infinity) | (NaN,NaN),(-Infinity,Infinity)
+ (2,2),(0,0)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (3,3),(1,1)         | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (3,3),(1,1)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (-2,2),(-8,-10)     | (1e+300,Infinity) | (Infinity,-Infinity),(-Infinity,-Infinity)
+ (-2,2),(-8,-10)     | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (2.5,3.5),(2.5,2.5) | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (2.5,3.5),(2.5,2.5) | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (3,3),(3,3)         | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (3,3),(3,3)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+(10 rows)
 
+-- Divide by point
+SELECT b.f1, p.f1, b.f1 / p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+         f1          |     f1     |                               ?column?                               
+---------------------+------------+----------------------------------------------------------------------
+ (2,2),(0,0)         | (5.1,34.5) | (0.0651176557644,0),(0,-0.0483449262493)
+ (2,2),(0,0)         | (10,10)    | (0.2,0),(0,0)
+ (3,3),(1,1)         | (5.1,34.5) | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
+ (3,3),(1,1)         | (10,10)    | (0.3,0),(0.1,0)
+ (-2,2),(-8,-10)     | (5.1,34.5) | (0.0483449262493,0.18499334024),(-0.317201914064,0.0651176557644)
+ (-2,2),(-8,-10)     | (10,10)    | (0,0.2),(-0.9,-0.1)
+ (2.5,3.5),(2.5,2.5) | (5.1,34.5) | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
+ (2.5,3.5),(2.5,2.5) | (10,10)    | (0.3,0.05),(0.25,0)
+ (3,3),(3,3)         | (5.1,34.5) | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
+ (3,3),(3,3)         | (10,10)    | (0.3,0),(0.3,0)
+(10 rows)
+
+-- To box
 SELECT f1::box
 	FROM POINT_TBL;
-          f1           
------------------------
+                 f1                  
+-------------------------------------
  (0,0),(0,0)
  (-10,0),(-10,0)
  (-3,4),(-3,4)
  (5.1,34.5),(5.1,34.5)
  (-5,-12),(-5,-12)
+ (1e-300,-1e-300),(1e-300,-1e-300)
+ (1e+300,Infinity),(1e+300,Infinity)
+ (NaN,NaN),(NaN,NaN)
  (10,10),(10,10)
-(6 rows)
+(9 rows)
 
 SELECT bound_box(a.f1, b.f1)
 	FROM BOX_TBL a, BOX_TBL b;
       bound_box      
 ---------------------
  (2,2),(0,0)
  (3,3),(0,0)
+ (2,2),(-8,-10)
  (2.5,3.5),(0,0)
  (3,3),(0,0)
  (3,3),(0,0)
  (3,3),(1,1)
+ (3,3),(-8,-10)
  (3,3.5),(1,1)
  (3,3),(1,1)
+ (2,2),(-8,-10)
+ (3,3),(-8,-10)
+ (-2,2),(-8,-10)
+ (2.5,3.5),(-8,-10)
+ (3,3),(-8,-10)
  (2.5,3.5),(0,0)
  (3,3.5),(1,1)
+ (2.5,3.5),(-8,-10)
  (2.5,3.5),(2.5,2.5)
  (3,3.5),(2.5,2.5)
  (3,3),(0,0)
  (3,3),(1,1)
+ (3,3),(-8,-10)
  (3,3.5),(2.5,2.5)
  (3,3),(3,3)
-(16 rows)
+(25 rows)
+
+-- Below box
+SELECT b1.f1, b2.f1, b1.f1 <^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          | ?column? 
+---------------------+---------------------+----------
+ (2,2),(0,0)         | (2,2),(0,0)         | f
+ (2,2),(0,0)         | (3,3),(1,1)         | f
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | f
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | t
+ (2,2),(0,0)         | (3,3),(3,3)         | t
+ (3,3),(1,1)         | (2,2),(0,0)         | f
+ (3,3),(1,1)         | (3,3),(1,1)         | f
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | f
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(1,1)         | (3,3),(3,3)         | t
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | f
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | f
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | f
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | t
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | t
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | f
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | f
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | f
+ (3,3),(3,3)         | (2,2),(0,0)         | f
+ (3,3),(3,3)         | (3,3),(1,1)         | f
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | f
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(3,3)         | (3,3),(3,3)         | t
+(25 rows)
+
+-- Above box
+SELECT b1.f1, b2.f1, b1.f1 >^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          | ?column? 
+---------------------+---------------------+----------
+ (2,2),(0,0)         | (2,2),(0,0)         | f
+ (2,2),(0,0)         | (3,3),(1,1)         | f
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | f
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | f
+ (2,2),(0,0)         | (3,3),(3,3)         | f
+ (3,3),(1,1)         | (2,2),(0,0)         | f
+ (3,3),(1,1)         | (3,3),(1,1)         | f
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | f
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(1,1)         | (3,3),(3,3)         | f
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | f
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | f
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | f
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | f
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | f
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | t
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | f
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | t
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | f
+ (3,3),(3,3)         | (2,2),(0,0)         | t
+ (3,3),(3,3)         | (3,3),(1,1)         | t
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | t
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(3,3)         | (3,3),(3,3)         | t
+(25 rows)
+
+-- Intersection point with box
+SELECT b1.f1, b2.f1, b1.f1 # b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          |      ?column?       
+---------------------+---------------------+---------------------
+ (2,2),(0,0)         | (2,2),(0,0)         | (2,2),(0,0)
+ (2,2),(0,0)         | (3,3),(1,1)         | (2,2),(1,1)
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | 
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | 
+ (2,2),(0,0)         | (3,3),(3,3)         | 
+ (3,3),(1,1)         | (2,2),(0,0)         | (2,2),(1,1)
+ (3,3),(1,1)         | (3,3),(1,1)         | (3,3),(1,1)
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | 
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | (2.5,3),(2.5,2.5)
+ (3,3),(1,1)         | (3,3),(3,3)         | (3,3),(3,3)
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | 
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | 
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | (-2,2),(-8,-10)
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | 
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | 
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | 
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | (2.5,3),(2.5,2.5)
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | 
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5)
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | 
+ (3,3),(3,3)         | (2,2),(0,0)         | 
+ (3,3),(3,3)         | (3,3),(1,1)         | (3,3),(3,3)
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | 
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | 
+ (3,3),(3,3)         | (3,3),(3,3)         | (3,3),(3,3)
+(25 rows)
+
+-- Diagonal
+SELECT f1, diagonal(f1) FROM BOX_TBL;
+         f1          |       diagonal        
+---------------------+-----------------------
+ (2,2),(0,0)         | [(2,2),(0,0)]
+ (3,3),(1,1)         | [(3,3),(1,1)]
+ (-2,2),(-8,-10)     | [(-2,2),(-8,-10)]
+ (2.5,3.5),(2.5,2.5) | [(2.5,3.5),(2.5,2.5)]
+ (3,3),(3,3)         | [(3,3),(3,3)]
+(5 rows)
+
+-- Distance to box
+SELECT b1.f1, b2.f1, b1.f1 <-> b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          |   ?column?    
+---------------------+---------------------+---------------
+ (2,2),(0,0)         | (2,2),(0,0)         |             0
+ (2,2),(0,0)         | (3,3),(1,1)         | 1.41421356237
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | 7.81024967591
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) |           2.5
+ (2,2),(0,0)         | (3,3),(3,3)         | 2.82842712475
+ (3,3),(1,1)         | (2,2),(0,0)         | 1.41421356237
+ (3,3),(1,1)         | (3,3),(1,1)         |             0
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | 9.21954445729
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | 1.11803398875
+ (3,3),(1,1)         | (3,3),(3,3)         | 1.41421356237
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | 7.81024967591
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | 9.21954445729
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     |             0
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | 10.2591422643
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | 10.6301458127
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         |           2.5
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | 1.11803398875
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | 10.2591422643
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) |             0
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         |           0.5
+ (3,3),(3,3)         | (2,2),(0,0)         | 2.82842712475
+ (3,3),(3,3)         | (3,3),(1,1)         | 1.41421356237
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | 10.6301458127
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) |           0.5
+ (3,3),(3,3)         | (3,3),(3,3)         |             0
+(25 rows)
 
 --
 -- Paths
 --
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
+-- Points
+SELECT f1, npoints(f1) FROM PATH_TBL;
+            f1             | npoints 
+---------------------------+---------
+ [(1,2),(3,4)]             |       2
+ ((1,2),(3,4))             |       2
+ [(0,0),(3,0),(4,5),(1,6)] |       4
+ ((1,2),(3,4))             |       2
+ ((1,2),(3,4))             |       2
+ [(1,2),(3,4)]             |       2
+ ((10,20))                 |       1
+ [(11,12),(13,14)]         |       2
+ ((11,12),(13,14))         |       2
+(9 rows)
 
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
+-- Area
+SELECT f1, area(f1) FROM PATH_TBL;
+            f1             | area 
+---------------------------+------
+ [(1,2),(3,4)]             |     
+ ((1,2),(3,4))             |    0
+ [(0,0),(3,0),(4,5),(1,6)] |     
+ ((1,2),(3,4))             |    0
+ ((1,2),(3,4))             |    0
+ [(1,2),(3,4)]             |     
+ ((10,20))                 |    0
+ [(11,12),(13,14)]         |     
+ ((11,12),(13,14))         |    0
+(9 rows)
 
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
+-- Length
+SELECT f1, @-@ f1 FROM PATH_TBL;
+            f1             |   ?column?    
+---------------------------+---------------
+ [(1,2),(3,4)]             | 2.82842712475
+ ((1,2),(3,4))             | 5.65685424949
+ [(0,0),(3,0),(4,5),(1,6)] | 11.2612971738
+ ((1,2),(3,4))             | 5.65685424949
+ ((1,2),(3,4))             | 5.65685424949
+ [(1,2),(3,4)]             | 2.82842712475
+ ((10,20))                 |             0
+ [(11,12),(13,14)]         | 2.82842712475
+ ((11,12),(13,14))         | 5.65685424949
+(9 rows)
 
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
+-- Center
+SELECT f1, @@ f1 FROM PATH_TBL;
+ERROR:  function "path_center" not implemented
+-- To polygon
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isclosed(f1);
+        f1         |        f1         
+-------------------+-------------------
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((10,20))         | ((10,20))
+ ((11,12),(13,14)) | ((11,12),(13,14))
+(5 rows)
+
+-- Open path cannot be converted to polygon error
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isopen(f1);
+ERROR:  open path cannot be converted to polygon
+-- Has points less than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 < p2.f1;
+        f1         |            f1             
+-------------------+---------------------------
+ [(1,2),(3,4)]     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]     | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))         | [(1,2),(3,4)]
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | [(1,2),(3,4)]
+ ((10,20))         | [(11,12),(13,14)]
+ ((10,20))         | ((11,12),(13,14))
+ [(11,12),(13,14)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((11,12),(13,14)) | [(0,0),(3,0),(4,5),(1,6)]
+(15 rows)
+
+-- Has points less than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 <= p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | [(1,2),(3,4)]
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | [(1,2),(3,4)]
+ ((10,20))                 | ((10,20))
+ ((10,20))                 | [(11,12),(13,14)]
+ ((10,20))                 | ((11,12),(13,14))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(66 rows)
+
+-- Has points equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 = p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | ((10,20))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(51 rows)
+
+-- Has points greater than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 >= p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | ((10,20))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((10,20))
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((10,20))
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(66 rows)
+
+-- Has points greater than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 > p2.f1;
+            f1             |        f1         
+---------------------------+-------------------
+ [(1,2),(3,4)]             | ((10,20))
+ ((1,2),(3,4))             | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | ((10,20))
+ [(1,2),(3,4)]             | ((10,20))
+ [(11,12),(13,14)]         | ((10,20))
+ ((11,12),(13,14))         | ((10,20))
+(15 rows)
+
+-- Add path
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+            f1             |            f1             |                     ?column?                      
+---------------------------+---------------------------+---------------------------------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4),(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))                 | 
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         | [(1,2),(3,4),(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6),(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6),(0,0),(3,0),(4,5),(1,6)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6),(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))                 | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6),(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4),(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))                 | 
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         | [(1,2),(3,4),(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))         | 
+ ((10,20))                 | [(1,2),(3,4)]             | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | [(1,2),(3,4)]             | 
+ ((10,20))                 | ((10,20))                 | 
+ ((10,20))                 | [(11,12),(13,14)]         | 
+ ((10,20))                 | ((11,12),(13,14))         | 
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             | [(11,12),(13,14),(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14),(0,0),(3,0),(4,5),(1,6)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             | [(11,12),(13,14),(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((10,20))                 | 
+ [(11,12),(13,14)]         | [(11,12),(13,14)]         | [(11,12),(13,14),(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))         | 
+ ((11,12),(13,14))         | [(1,2),(3,4)]             | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | [(1,2),(3,4)]             | 
+ ((11,12),(13,14))         | ((10,20))                 | 
+ ((11,12),(13,14))         | [(11,12),(13,14)]         | 
+ ((11,12),(13,14))         | ((11,12),(13,14))         | 
+(81 rows)
+
+-- Add point
+SELECT p.f1, p1.f1, p.f1 + p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                                 ?column?                                  
+---------------------------+-------------------+---------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((10,20))                 | (0,0)             | ((10,20))
+ [(11,12),(13,14)]         | (0,0)             | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (0,0)             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (-10,0)           | [(-9,2),(-7,4)]
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(-10,0),(-7,0),(-6,5),(-9,6)]
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ [(1,2),(3,4)]             | (-10,0)           | [(-9,2),(-7,4)]
+ ((10,20))                 | (-10,0)           | ((0,20))
+ [(11,12),(13,14)]         | (-10,0)           | [(1,12),(3,14)]
+ ((11,12),(13,14))         | (-10,0)           | ((1,12),(3,14))
+ [(1,2),(3,4)]             | (-3,4)            | [(-2,6),(0,8)]
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(-3,4),(0,4),(1,9),(-2,10)]
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ [(1,2),(3,4)]             | (-3,4)            | [(-2,6),(0,8)]
+ ((10,20))                 | (-3,4)            | ((7,24))
+ [(11,12),(13,14)]         | (-3,4)            | [(8,16),(10,18)]
+ ((11,12),(13,14))         | (-3,4)            | ((8,16),(10,18))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(6.1,36.5),(8.1,38.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(5.1,34.5),(8.1,34.5),(9.1,39.5),(6.1,40.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(6.1,36.5),(8.1,38.5)]
+ ((10,20))                 | (5.1,34.5)        | ((15.1,54.5))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(16.1,46.5),(18.1,48.5)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((16.1,46.5),(18.1,48.5))
+ [(1,2),(3,4)]             | (-5,-12)          | [(-4,-10),(-2,-8)]
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(-5,-12),(-2,-12),(-1,-7),(-4,-6)]
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ [(1,2),(3,4)]             | (-5,-12)          | [(-4,-10),(-2,-8)]
+ ((10,20))                 | (-5,-12)          | ((5,8))
+ [(11,12),(13,14)]         | (-5,-12)          | [(6,0),(8,2)]
+ ((11,12),(13,14))         | (-5,-12)          | ((6,0),(8,2))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(1e-300,-1e-300),(3,-1e-300),(4,5),(1,6)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((10,20))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity),(1e+300,Infinity),(1e+300,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((1e+300,Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(11,12),(13,14)]
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(10,10),(13,10),(14,15),(11,16)]
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (10,10)           | [(11,12),(13,14)]
+ ((10,20))                 | (10,10)           | ((20,30))
+ [(11,12),(13,14)]         | (10,10)           | [(21,22),(23,24)]
+ ((11,12),(13,14))         | (10,10)           | ((21,22),(23,24))
+(81 rows)
+
+-- Subtract point
+SELECT p.f1, p1.f1, p.f1 - p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                                     ?column?                                      
+---------------------------+-------------------+-----------------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((10,20))                 | (0,0)             | ((10,20))
+ [(11,12),(13,14)]         | (0,0)             | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (0,0)             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (-10,0)           | [(11,2),(13,4)]
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(10,0),(13,0),(14,5),(11,6)]
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ [(1,2),(3,4)]             | (-10,0)           | [(11,2),(13,4)]
+ ((10,20))                 | (-10,0)           | ((20,20))
+ [(11,12),(13,14)]         | (-10,0)           | [(21,12),(23,14)]
+ ((11,12),(13,14))         | (-10,0)           | ((21,12),(23,14))
+ [(1,2),(3,4)]             | (-3,4)            | [(4,-2),(6,0)]
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(3,-4),(6,-4),(7,1),(4,2)]
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ [(1,2),(3,4)]             | (-3,4)            | [(4,-2),(6,0)]
+ ((10,20))                 | (-3,4)            | ((13,16))
+ [(11,12),(13,14)]         | (-3,4)            | [(14,8),(16,10)]
+ ((11,12),(13,14))         | (-3,4)            | ((14,8),(16,10))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-4.1,-32.5),(-2.1,-30.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(-5.1,-34.5),(-2.1,-34.5),(-1.1,-29.5),(-4.1,-28.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-4.1,-32.5),(-2.1,-30.5)]
+ ((10,20))                 | (5.1,34.5)        | ((4.9,-14.5))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(5.9,-22.5),(7.9,-20.5)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((5.9,-22.5),(7.9,-20.5))
+ [(1,2),(3,4)]             | (-5,-12)          | [(6,14),(8,16)]
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(5,12),(8,12),(9,17),(6,18)]
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ [(1,2),(3,4)]             | (-5,-12)          | [(6,14),(8,16)]
+ ((10,20))                 | (-5,-12)          | ((15,32))
+ [(11,12),(13,14)]         | (-5,-12)          | [(16,24),(18,26)]
+ ((11,12),(13,14))         | (-5,-12)          | ((16,24),(18,26))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(-1e-300,1e-300),(3,1e-300),(4,5),(1,6)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((10,20))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity),(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((-1e+300,-Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(-9,-8),(-7,-6)]
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(-10,-10),(-7,-10),(-6,-5),(-9,-4)]
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ [(1,2),(3,4)]             | (10,10)           | [(-9,-8),(-7,-6)]
+ ((10,20))                 | (10,10)           | ((0,10))
+ [(11,12),(13,14)]         | (10,10)           | [(1,2),(3,4)]
+ ((11,12),(13,14))         | (10,10)           | ((1,2),(3,4))
+(81 rows)
+
+-- Multiply with point
+SELECT p.f1, p1.f1, p.f1 * p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                               ?column?                               
+---------------------------+-------------------+----------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(0,0),(0,0)]
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(0,0),(0,0),(0,0)]
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ [(1,2),(3,4)]             | (0,0)             | [(0,0),(0,0)]
+ ((10,20))                 | (0,0)             | ((0,0))
+ [(11,12),(13,14)]         | (0,0)             | [(0,0),(0,0)]
+ ((11,12),(13,14))         | (0,0)             | ((0,0),(0,0))
+ [(1,2),(3,4)]             | (-10,0)           | [(-10,-20),(-30,-40)]
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(0,0),(-30,0),(-40,-50),(-10,-60)]
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ [(1,2),(3,4)]             | (-10,0)           | [(-10,-20),(-30,-40)]
+ ((10,20))                 | (-10,0)           | ((-100,-200))
+ [(11,12),(13,14)]         | (-10,0)           | [(-110,-120),(-130,-140)]
+ ((11,12),(13,14))         | (-10,0)           | ((-110,-120),(-130,-140))
+ [(1,2),(3,4)]             | (-3,4)            | [(-11,-2),(-25,0)]
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(0,0),(-9,12),(-32,1),(-27,-14)]
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ [(1,2),(3,4)]             | (-3,4)            | [(-11,-2),(-25,0)]
+ ((10,20))                 | (-3,4)            | ((-110,-20))
+ [(11,12),(13,14)]         | (-3,4)            | [(-81,8),(-95,10)]
+ ((11,12),(13,14))         | (-3,4)            | ((-81,8),(-95,10))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-63.9,44.7),(-122.7,123.9)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(0,0),(15.3,103.5),(-152.1,163.5),(-201.9,65.1)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-63.9,44.7),(-122.7,123.9)]
+ ((10,20))                 | (5.1,34.5)        | ((-639,447))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(-357.9,440.7),(-416.7,519.9)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((-357.9,440.7),(-416.7,519.9))
+ [(1,2),(3,4)]             | (-5,-12)          | [(19,-22),(33,-56)]
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(0,0),(-15,-36),(40,-73),(67,-42)]
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ [(1,2),(3,4)]             | (-5,-12)          | [(19,-22),(33,-56)]
+ ((10,20))                 | (-5,-12)          | ((190,-220))
+ [(11,12),(13,14)]         | (-5,-12)          | [(89,-192),(103,-226)]
+ ((11,12),(13,14))         | (-5,-12)          | ((89,-192),(103,-226))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(3e-300,1e-300),(7e-300,1e-300)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(0,0),(3e-300,-3e-300),(9e-300,1e-300),(7e-300,5e-300)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(3e-300,1e-300),(7e-300,1e-300)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((3e-299,1e-299))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(2.3e-299,1e-300),(2.7e-299,1e-300)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((2.3e-299,1e-300),(2.7e-299,1e-300))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(NaN,NaN),(NaN,Infinity),(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((-Infinity,Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(-10,30),(-10,70)]
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(0,0),(30,30),(-10,90),(-50,70)]
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ [(1,2),(3,4)]             | (10,10)           | [(-10,30),(-10,70)]
+ ((10,20))                 | (10,10)           | ((-100,300))
+ [(11,12),(13,14)]         | (10,10)           | [(-10,230),(-10,270)]
+ ((11,12),(13,14))         | (10,10)           | ((-10,230),(-10,270))
+(81 rows)
+
+-- Divide by point
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+            f1             |     f1     |                                                    ?column?                                                     
+---------------------------+------------+-----------------------------------------------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (5.1,34.5) | [(0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952)]
+ [(1,2),(3,4)]             | (10,10)    | [(0.15,0.05),(0.35,0.05)]
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5) | [(0,0),(0.0125795471363,-0.0850969365103),(0.158600957032,-0.0924966701199),(0.174387055399,-0.00320655123082)]
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)    | [(0,0),(0.15,-0.15),(0.45,0.05),(0.35,0.25)]
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ [(1,2),(3,4)]             | (5.1,34.5) | [(0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952)]
+ [(1,2),(3,4)]             | (10,10)    | [(0.15,0.05),(0.35,0.05)]
+ ((10,20))                 | (5.1,34.5) | ((0.609244733856,-0.199792807459))
+ ((10,20))                 | (10,10)    | ((1.5,0.5))
+ [(11,12),(13,14)]         | (5.1,34.5) | [(0.386512752208,-0.261703911993),(0.451630407972,-0.310048838242)]
+ [(11,12),(13,14)]         | (10,10)    | [(1.15,0.05),(1.35,0.05)]
+ ((11,12),(13,14))         | (5.1,34.5) | ((0.386512752208,-0.261703911993),(0.451630407972,-0.310048838242))
+ ((11,12),(13,14))         | (10,10)    | ((1.15,0.05),(1.35,0.05))
+(18 rows)
+
+-- Division by 0 error
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to path
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+            f1             |            f1             |    ?column?    
+---------------------------+---------------------------+----------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((10,20))                 |  17.4642491966
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         |   11.313708499
+ [(1,2),(3,4)]             | ((11,12),(13,14))         |   11.313708499
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)] |              0
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))                 |  16.1554944214
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]         |  9.89949493661
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))         |  9.89949493661
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((10,20))                 |  17.4642491966
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         |   11.313708499
+ [(1,2),(3,4)]             | ((11,12),(13,14))         |   11.313708499
+ ((10,20))                 | [(1,2),(3,4)]             |  17.4642491966
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)] |  16.1554944214
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | [(1,2),(3,4)]             |  17.4642491966
+ ((10,20))                 | ((10,20))                 |              0
+ ((10,20))                 | [(11,12),(13,14)]         |   6.7082039325
+ ((10,20))                 | ((11,12),(13,14))         |   6.7082039325
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             |   11.313708499
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)] |  9.89949493661
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             |   11.313708499
+ [(11,12),(13,14)]         | ((10,20))                 |   6.7082039325
+ [(11,12),(13,14)]         | [(11,12),(13,14)]         |              0
+ [(11,12),(13,14)]         | ((11,12),(13,14))         |              0
+ ((11,12),(13,14))         | [(1,2),(3,4)]             |   11.313708499
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)] |  9.89949493661
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | [(1,2),(3,4)]             |   11.313708499
+ ((11,12),(13,14))         | ((10,20))                 |   6.7082039325
+ ((11,12),(13,14))         | [(11,12),(13,14)]         |              0
+ ((11,12),(13,14))         | ((11,12),(13,14))         |              0
+(81 rows)
 
 --
 -- Polygons
 --
 -- containment
 SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
    FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
+ twentyfour |        f1         |             f1             | contains 
+------------+-------------------+----------------------------+----------
+            | (0,0)             | ((2,0),(2,4),(0,0))        | t
+            | (0,0)             | ((3,1),(3,3),(1,0))        | f
+            | (0,0)             | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (0,0)             | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (0,0)             | ((0,0))                    | t
+            | (0,0)             | ((0,1),(0,1))              | f
+            | (-10,0)           | ((2,0),(2,4),(0,0))        | f
+            | (-10,0)           | ((3,1),(3,3),(1,0))        | f
+            | (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-10,0)           | ((0,0))                    | f
+            | (-10,0)           | ((0,1),(0,1))              | f
+            | (-3,4)            | ((2,0),(2,4),(0,0))        | f
+            | (-3,4)            | ((3,1),(3,3),(1,0))        | f
+            | (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-3,4)            | ((0,0))                    | f
+            | (-3,4)            | ((0,1),(0,1))              | f
+            | (5.1,34.5)        | ((2,0),(2,4),(0,0))        | f
+            | (5.1,34.5)        | ((3,1),(3,3),(1,0))        | f
+            | (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (5.1,34.5)        | ((0,0))                    | f
+            | (5.1,34.5)        | ((0,1),(0,1))              | f
+            | (-5,-12)          | ((2,0),(2,4),(0,0))        | f
+            | (-5,-12)          | ((3,1),(3,3),(1,0))        | f
+            | (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-5,-12)          | ((0,0))                    | f
+            | (-5,-12)          | ((0,1),(0,1))              | f
+            | (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        | t
+            | (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        | f
+            | (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e-300,-1e-300)  | ((0,0))                    | t
+            | (1e-300,-1e-300)  | ((0,1),(0,1))              | f
+            | (1e+300,Infinity) | ((2,0),(2,4),(0,0))        | f
+            | (1e+300,Infinity) | ((3,1),(3,3),(1,0))        | f
+            | (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e+300,Infinity) | ((0,0))                    | f
+            | (1e+300,Infinity) | ((0,1),(0,1))              | f
+            | (NaN,NaN)         | ((2,0),(2,4),(0,0))        | t
+            | (NaN,NaN)         | ((3,1),(3,3),(1,0))        | t
+            | (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  | t
+            | (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  | t
+            | (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) | t
+            | (NaN,NaN)         | ((0,0))                    | t
+            | (NaN,NaN)         | ((0,1),(0,1))              | t
+            | (10,10)           | ((2,0),(2,4),(0,0))        | f
+            | (10,10)           | ((3,1),(3,3),(1,0))        | f
+            | (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (10,10)           | ((0,0))                    | f
+            | (10,10)           | ((0,1),(0,1))              | f
+(63 rows)
 
 SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
    FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
+ twentyfour |        f1         |             f1             | contained 
+------------+-------------------+----------------------------+-----------
+            | (0,0)             | ((2,0),(2,4),(0,0))        | t
+            | (0,0)             | ((3,1),(3,3),(1,0))        | f
+            | (0,0)             | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (0,0)             | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (0,0)             | ((0,0))                    | t
+            | (0,0)             | ((0,1),(0,1))              | f
+            | (-10,0)           | ((2,0),(2,4),(0,0))        | f
+            | (-10,0)           | ((3,1),(3,3),(1,0))        | f
+            | (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-10,0)           | ((0,0))                    | f
+            | (-10,0)           | ((0,1),(0,1))              | f
+            | (-3,4)            | ((2,0),(2,4),(0,0))        | f
+            | (-3,4)            | ((3,1),(3,3),(1,0))        | f
+            | (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-3,4)            | ((0,0))                    | f
+            | (-3,4)            | ((0,1),(0,1))              | f
+            | (5.1,34.5)        | ((2,0),(2,4),(0,0))        | f
+            | (5.1,34.5)        | ((3,1),(3,3),(1,0))        | f
+            | (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (5.1,34.5)        | ((0,0))                    | f
+            | (5.1,34.5)        | ((0,1),(0,1))              | f
+            | (-5,-12)          | ((2,0),(2,4),(0,0))        | f
+            | (-5,-12)          | ((3,1),(3,3),(1,0))        | f
+            | (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-5,-12)          | ((0,0))                    | f
+            | (-5,-12)          | ((0,1),(0,1))              | f
+            | (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        | t
+            | (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        | f
+            | (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e-300,-1e-300)  | ((0,0))                    | t
+            | (1e-300,-1e-300)  | ((0,1),(0,1))              | f
+            | (1e+300,Infinity) | ((2,0),(2,4),(0,0))        | f
+            | (1e+300,Infinity) | ((3,1),(3,3),(1,0))        | f
+            | (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e+300,Infinity) | ((0,0))                    | f
+            | (1e+300,Infinity) | ((0,1),(0,1))              | f
+            | (NaN,NaN)         | ((2,0),(2,4),(0,0))        | t
+            | (NaN,NaN)         | ((3,1),(3,3),(1,0))        | t
+            | (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  | t
+            | (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  | t
+            | (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) | t
+            | (NaN,NaN)         | ((0,0))                    | t
+            | (NaN,NaN)         | ((0,1),(0,1))              | t
+            | (10,10)           | ((2,0),(2,4),(0,0))        | f
+            | (10,10)           | ((3,1),(3,3),(1,0))        | f
+            | (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (10,10)           | ((0,0))                    | f
+            | (10,10)           | ((0,1),(0,1))              | f
+(63 rows)
 
 SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
    FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
+ four | npoints |          polygon           
+------+---------+----------------------------
       |       3 | ((2,0),(2,4),(0,0))
       |       3 | ((3,1),(3,3),(1,0))
+      |       4 | ((1,2),(3,4),(5,6),(7,8))
+      |       4 | ((7,8),(5,6),(3,4),(1,2))
+      |       4 | ((1,2),(7,8),(5,6),(3,-4))
       |       1 | ((0,0))
       |       2 | ((0,1),(0,1))
-(4 rows)
+(7 rows)
 
 SELECT '' AS four, polygon(f1)
    FROM BOX_TBL;
  four |                  polygon                  
 ------+-------------------------------------------
       | ((0,0),(0,2),(2,2),(2,0))
       | ((1,1),(1,3),(3,3),(3,1))
+      | ((-8,-10),(-8,2),(-2,2),(-2,-10))
       | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
       | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, polygon(f1)
    FROM PATH_TBL WHERE isclosed(f1);
  four |      polygon      
 ------+-------------------
       | ((1,2),(3,4))
       | ((1,2),(3,4))
       | ((1,2),(3,4))
+      | ((10,20))
       | ((11,12),(13,14))
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
    FROM PATH_TBL
    WHERE isopen(f1);
  four |         open_path         |          polygon          
 ------+---------------------------+---------------------------
       | [(1,2),(3,4)]             | ((1,2),(3,4))
       | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
       | [(1,2),(3,4)]             | ((1,2),(3,4))
       | [(11,12),(13,14)]         | ((11,12),(13,14))
 (4 rows)
 
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
+-- To box
+SELECT f1, f1::box FROM POLYGON_TBL;
+             f1             |      f1      
+----------------------------+--------------
+ ((2,0),(2,4),(0,0))        | (2,4),(0,0)
+ ((3,1),(3,3),(1,0))        | (3,3),(1,0)
+ ((1,2),(3,4),(5,6),(7,8))  | (7,8),(1,2)
+ ((7,8),(5,6),(3,4),(1,2))  | (7,8),(1,2)
+ ((1,2),(7,8),(5,6),(3,-4)) | (7,8),(1,-4)
+ ((0,0))                    | (0,0),(0,0)
+ ((0,1),(0,1))              | (0,1),(0,1)
+(7 rows)
 
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
+-- To path
+SELECT f1, f1::path FROM POLYGON_TBL;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(7 rows)
 
+-- Same as polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 ~= p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(9 rows)
+
+-- Contained by polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <@ p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(12 rows)
+
+-- Contains polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 @> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(12 rows)
+
+-- Overlap with polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 && p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(25 rows)
+
+-- Left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 << p2.f1;
+      f1       |             f1             
+---------------+----------------------------
+ ((0,0))       | ((3,1),(3,3),(1,0))
+ ((0,0))       | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))       | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))       | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1)) | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1)) | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1)) | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1)) | ((1,2),(7,8),(5,6),(3,-4))
+(8 rows)
+
+-- Overlap of left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &< p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))                    | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1))              | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(32 rows)
+
+-- Right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 >> p2.f1;
+             f1             |      f1       
+----------------------------+---------------
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((0,1),(0,1))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1))
+(8 rows)
+
+-- Overlap of right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((2,0),(2,4),(0,0))        | ((0,1),(0,1))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((0,1),(0,1))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((3,1),(3,3),(1,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(37 rows)
+
+-- Below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <<| p2.f1;
+      f1       |            f1             
+---------------+---------------------------
+ ((0,0))       | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))       | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))       | ((0,1),(0,1))
+ ((0,1),(0,1)) | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1)) | ((7,8),(5,6),(3,4),(1,2))
+(5 rows)
+
+-- Overlap or below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &<| p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))                    | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1))              | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(31 rows)
+
+-- Above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |>> p2.f1;
+            f1             |      f1       
+---------------------------+---------------
+ ((1,2),(3,4),(5,6),(7,8)) | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8)) | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2)) | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2)) | ((0,1),(0,1))
+ ((0,1),(0,1))             | ((0,0))
+(5 rows)
+
+-- Overlap or above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |&> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((3,1),(3,3),(1,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(32 rows)
+
+-- Distance to polygon
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2;
+ERROR:  function "poly_distance" not implemented
 --
 -- Circles
 --
 SELECT '' AS six, circle(f1, 50.0)
    FROM POINT_TBL;
- six |     circle      
------+-----------------
+ six |         circle         
+-----+------------------------
      | <(0,0),50>
      | <(-10,0),50>
      | <(-3,4),50>
      | <(5.1,34.5),50>
      | <(-5,-12),50>
+     | <(1e-300,-1e-300),50>
+     | <(1e+300,Infinity),50>
+     | <(NaN,NaN),50>
      | <(10,10),50>
-(6 rows)
+(9 rows)
 
 SELECT '' AS four, circle(f1)
    FROM BOX_TBL;
- four |        circle         
-------+-----------------------
+ four |         circle         
+------+------------------------
       | <(1,1),1.41421356237>
       | <(2,2),1.41421356237>
+      | <(-5,-4),6.7082039325>
       | <(2.5,3),0.5>
       | <(3,3),0>
-(4 rows)
+(5 rows)
 
 SELECT '' AS two, circle(f1)
    FROM POLYGON_TBL
    WHERE (# f1) >= 3;
  two |                    circle                     
 -----+-----------------------------------------------
      | <(1.33333333333,1.33333333333),2.04168905064>
      | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
+     | <(4,5),2.82842712475>
+     | <(4,5),2.82842712475>
+     | <(4,3),4.80664375676>
+(5 rows)
 
 SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
    FROM CIRCLE_TBL c1, POINT_TBL p1
    WHERE (p1.f1 <-> c1.f1) > 0
    ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
+ twentyfour |     circle     |       point       |   distance    
+------------+----------------+-------------------+---------------
+            | <(1,2),3>      | (-3,4)            |   1.472135955
+            | <(5,1),3>      | (0,0)             | 2.09901951359
+            | <(5,1),3>      | (1e-300,-1e-300)  | 2.09901951359
+            | <(5,1),3>      | (-3,4)            | 5.54400374532
+            | <(3,5),0>      | (0,0)             | 5.83095189485
+            | <(3,5),0>      | (1e-300,-1e-300)  | 5.83095189485
+            | <(3,5),0>      | (-3,4)            |  6.0827625303
+            | <(1,3),5>      | (-10,0)           | 6.40175425099
+            | <(1,3),5>      | (10,10)           | 6.40175425099
+            | <(5,1),3>      | (10,10)           | 7.29563014099
+            | <(1,2),3>      | (-10,0)           |  8.1803398875
+            | <(3,5),0>      | (10,10)           | 8.60232526704
+            | <(1,2),3>      | (10,10)           | 9.04159457879
+            | <(1,3),5>      | (-5,-12)          | 11.1554944214
+            | <(5,1),3>      | (-10,0)           | 12.0332963784
+            | <(1,2),3>      | (-5,-12)          | 12.2315462117
+            | <(5,1),3>      | (-5,-12)          | 13.4012194669
+            | <(3,5),0>      | (-10,0)           | 13.9283882772
+            | <(3,5),0>      | (-5,-12)          | 18.7882942281
+            | <(1,3),5>      | (5.1,34.5)        | 26.7657047773
+            | <(3,5),0>      | (5.1,34.5)        | 29.5746513082
+            | <(1,2),3>      | (5.1,34.5)        | 29.7575945393
+            | <(5,1),3>      | (5.1,34.5)        | 30.5001492534
+            | <(100,200),10> | (5.1,34.5)        | 180.778038568
+            | <(100,200),10> | (10,10)           | 200.237960416
+            | <(100,200),10> | (-3,4)            | 211.415898255
+            | <(100,200),10> | (0,0)             |  213.60679775
+            | <(100,200),10> | (1e-300,-1e-300)  |  213.60679775
+            | <(100,200),10> | (-10,0)           |  218.25424421
+            | <(100,200),10> | (-5,-12)          | 226.577682802
+            | <(3,5),0>      | (1e+300,Infinity) |      Infinity
+            | <(1,2),3>      | (1e+300,Infinity) |      Infinity
+            | <(5,1),3>      | (1e+300,Infinity) |      Infinity
+            | <(1,3),5>      | (1e+300,Infinity) |      Infinity
+            | <(100,200),10> | (1e+300,Infinity) |      Infinity
+            | <(1,2),100>    | (1e+300,Infinity) |      Infinity
+            | <(100,1),115>  | (1e+300,Infinity) |      Infinity
+            | <(3,5),0>      | (NaN,NaN)         |           NaN
+            | <(1,2),3>      | (NaN,NaN)         |           NaN
+            | <(5,1),3>      | (NaN,NaN)         |           NaN
+            | <(1,3),5>      | (NaN,NaN)         |           NaN
+            | <(100,200),10> | (NaN,NaN)         |           NaN
+            | <(1,2),100>    | (NaN,NaN)         |           NaN
+            | <(100,1),115>  | (NaN,NaN)         |           NaN
+            | <(3,5),NaN>    | (-10,0)           |           NaN
+            | <(3,5),NaN>    | (-5,-12)          |           NaN
+            | <(3,5),NaN>    | (-3,4)            |           NaN
+            | <(3,5),NaN>    | (0,0)             |           NaN
+            | <(3,5),NaN>    | (1e-300,-1e-300)  |           NaN
+            | <(3,5),NaN>    | (5.1,34.5)        |           NaN
+            | <(3,5),NaN>    | (10,10)           |           NaN
+            | <(3,5),NaN>    | (1e+300,Infinity) |           NaN
+            | <(3,5),NaN>    | (NaN,NaN)         |           NaN
+(53 rows)
+
+-- To polygon
+SELECT f1, f1::polygon FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+       f1       |                                                                                                          f1                                                                                                          
+----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ <(5,1),3>      | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
+ <(1,2),100>    | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
+ <(1,3),5>      | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
+ <(1,2),3>      | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
+ <(100,200),10> | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
+ <(100,1),115>  | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
+(6 rows)
+
+-- To polygon with less points
+SELECT f1, polygon(8, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+       f1       |                                                                             polygon                                                                              
+----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ <(5,1),3>      | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
+ <(1,2),100>    | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
+ <(1,3),5>      | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
+ <(1,2),3>      | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
+ <(100,200),10> | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
+ <(100,1),115>  | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
+(6 rows)
+
+-- Too less points error
+SELECT f1, polygon(1, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+ERROR:  must request at least 2 points
+-- Zero radius error
+SELECT f1, polygon(10, f1) FROM CIRCLE_TBL WHERE f1 < '<(0,0),1>';
+ERROR:  cannot convert circle with radius zero to polygon
+-- Same as circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 ~= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+ <(3,5),NaN>    | <(3,5),0>
+ <(3,5),NaN>    | <(3,5),NaN>
+(9 rows)
+
+-- Overlap with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 && c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,1),115>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(100,1),115>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(33 rows)
+
+-- Overlap or left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &< c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(28 rows)
+
+-- Left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 << c2.f1;
+    f1     |       f1       
+-----------+----------------
+ <(5,1),3> | <(100,200),10>
+ <(1,3),5> | <(100,200),10>
+ <(1,2),3> | <(100,200),10>
+ <(3,5),0> | <(100,200),10>
+(4 rows)
+
+-- Right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >> c2.f1;
+       f1       |    f1     
+----------------+-----------
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(3,5),0>
+(4 rows)
+
+-- Overlap or right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(28 rows)
+
+-- Contained by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <@ c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(17 rows)
+
+-- Contain by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 @> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(3,5),0>
+(17 rows)
+
+-- Below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <<| c2.f1;
+      f1       |       f1       
+---------------+----------------
+ <(5,1),3>     | <(100,200),10>
+ <(5,1),3>     | <(3,5),0>
+ <(1,2),100>   | <(100,200),10>
+ <(1,3),5>     | <(100,200),10>
+ <(1,2),3>     | <(100,200),10>
+ <(100,1),115> | <(100,200),10>
+ <(3,5),0>     | <(100,200),10>
+(7 rows)
+
+-- Above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |>> c2.f1;
+       f1       |      f1       
+----------------+---------------
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(3,5),0>      | <(5,1),3>
+(7 rows)
+
+-- Overlap or below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &<| c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Overlap or above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |&> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 = c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(9 rows)
+
+-- Area not equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 != c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(40 rows)
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 > c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(3,5),0>
+(20 rows)
+
+-- Area less than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area greater than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Add point
+SELECT c.f1, p.f1, c.f1 + p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |        ?column?         
+----------------+-------------------+-------------------------
+ <(5,1),3>      | (0,0)             | <(5,1),3>
+ <(1,2),100>    | (0,0)             | <(1,2),100>
+ <(1,3),5>      | (0,0)             | <(1,3),5>
+ <(1,2),3>      | (0,0)             | <(1,2),3>
+ <(100,200),10> | (0,0)             | <(100,200),10>
+ <(100,1),115>  | (0,0)             | <(100,1),115>
+ <(3,5),0>      | (0,0)             | <(3,5),0>
+ <(3,5),NaN>    | (0,0)             | <(3,5),NaN>
+ <(5,1),3>      | (-10,0)           | <(-5,1),3>
+ <(1,2),100>    | (-10,0)           | <(-9,2),100>
+ <(1,3),5>      | (-10,0)           | <(-9,3),5>
+ <(1,2),3>      | (-10,0)           | <(-9,2),3>
+ <(100,200),10> | (-10,0)           | <(90,200),10>
+ <(100,1),115>  | (-10,0)           | <(90,1),115>
+ <(3,5),0>      | (-10,0)           | <(-7,5),0>
+ <(3,5),NaN>    | (-10,0)           | <(-7,5),NaN>
+ <(5,1),3>      | (-3,4)            | <(2,5),3>
+ <(1,2),100>    | (-3,4)            | <(-2,6),100>
+ <(1,3),5>      | (-3,4)            | <(-2,7),5>
+ <(1,2),3>      | (-3,4)            | <(-2,6),3>
+ <(100,200),10> | (-3,4)            | <(97,204),10>
+ <(100,1),115>  | (-3,4)            | <(97,5),115>
+ <(3,5),0>      | (-3,4)            | <(0,9),0>
+ <(3,5),NaN>    | (-3,4)            | <(0,9),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(10.1,35.5),3>
+ <(1,2),100>    | (5.1,34.5)        | <(6.1,36.5),100>
+ <(1,3),5>      | (5.1,34.5)        | <(6.1,37.5),5>
+ <(1,2),3>      | (5.1,34.5)        | <(6.1,36.5),3>
+ <(100,200),10> | (5.1,34.5)        | <(105.1,234.5),10>
+ <(100,1),115>  | (5.1,34.5)        | <(105.1,35.5),115>
+ <(3,5),0>      | (5.1,34.5)        | <(8.1,39.5),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(8.1,39.5),NaN>
+ <(5,1),3>      | (-5,-12)          | <(0,-11),3>
+ <(1,2),100>    | (-5,-12)          | <(-4,-10),100>
+ <(1,3),5>      | (-5,-12)          | <(-4,-9),5>
+ <(1,2),3>      | (-5,-12)          | <(-4,-10),3>
+ <(100,200),10> | (-5,-12)          | <(95,188),10>
+ <(100,1),115>  | (-5,-12)          | <(95,-11),115>
+ <(3,5),0>      | (-5,-12)          | <(-2,-7),0>
+ <(3,5),NaN>    | (-5,-12)          | <(-2,-7),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(5,1),3>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(1,2),100>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(1,3),5>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(1,2),3>
+ <(100,200),10> | (1e-300,-1e-300)  | <(100,200),10>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(100,1),115>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(3,5),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(3,5),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(1e+300,Infinity),3>
+ <(1,2),100>    | (1e+300,Infinity) | <(1e+300,Infinity),100>
+ <(1,3),5>      | (1e+300,Infinity) | <(1e+300,Infinity),5>
+ <(1,2),3>      | (1e+300,Infinity) | <(1e+300,Infinity),3>
+ <(100,200),10> | (1e+300,Infinity) | <(1e+300,Infinity),10>
+ <(100,1),115>  | (1e+300,Infinity) | <(1e+300,Infinity),115>
+ <(3,5),0>      | (1e+300,Infinity) | <(1e+300,Infinity),0>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(1e+300,Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),100>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),5>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),10>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),115>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),0>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(15,11),3>
+ <(1,2),100>    | (10,10)           | <(11,12),100>
+ <(1,3),5>      | (10,10)           | <(11,13),5>
+ <(1,2),3>      | (10,10)           | <(11,12),3>
+ <(100,200),10> | (10,10)           | <(110,210),10>
+ <(100,1),115>  | (10,10)           | <(110,11),115>
+ <(3,5),0>      | (10,10)           | <(13,15),0>
+ <(3,5),NaN>    | (10,10)           | <(13,15),NaN>
+(72 rows)
+
+-- Subtract point
+SELECT c.f1, p.f1, c.f1 - p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |         ?column?          
+----------------+-------------------+---------------------------
+ <(5,1),3>      | (0,0)             | <(5,1),3>
+ <(1,2),100>    | (0,0)             | <(1,2),100>
+ <(1,3),5>      | (0,0)             | <(1,3),5>
+ <(1,2),3>      | (0,0)             | <(1,2),3>
+ <(100,200),10> | (0,0)             | <(100,200),10>
+ <(100,1),115>  | (0,0)             | <(100,1),115>
+ <(3,5),0>      | (0,0)             | <(3,5),0>
+ <(3,5),NaN>    | (0,0)             | <(3,5),NaN>
+ <(5,1),3>      | (-10,0)           | <(15,1),3>
+ <(1,2),100>    | (-10,0)           | <(11,2),100>
+ <(1,3),5>      | (-10,0)           | <(11,3),5>
+ <(1,2),3>      | (-10,0)           | <(11,2),3>
+ <(100,200),10> | (-10,0)           | <(110,200),10>
+ <(100,1),115>  | (-10,0)           | <(110,1),115>
+ <(3,5),0>      | (-10,0)           | <(13,5),0>
+ <(3,5),NaN>    | (-10,0)           | <(13,5),NaN>
+ <(5,1),3>      | (-3,4)            | <(8,-3),3>
+ <(1,2),100>    | (-3,4)            | <(4,-2),100>
+ <(1,3),5>      | (-3,4)            | <(4,-1),5>
+ <(1,2),3>      | (-3,4)            | <(4,-2),3>
+ <(100,200),10> | (-3,4)            | <(103,196),10>
+ <(100,1),115>  | (-3,4)            | <(103,-3),115>
+ <(3,5),0>      | (-3,4)            | <(6,1),0>
+ <(3,5),NaN>    | (-3,4)            | <(6,1),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(-0.1,-33.5),3>
+ <(1,2),100>    | (5.1,34.5)        | <(-4.1,-32.5),100>
+ <(1,3),5>      | (5.1,34.5)        | <(-4.1,-31.5),5>
+ <(1,2),3>      | (5.1,34.5)        | <(-4.1,-32.5),3>
+ <(100,200),10> | (5.1,34.5)        | <(94.9,165.5),10>
+ <(100,1),115>  | (5.1,34.5)        | <(94.9,-33.5),115>
+ <(3,5),0>      | (5.1,34.5)        | <(-2.1,-29.5),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(-2.1,-29.5),NaN>
+ <(5,1),3>      | (-5,-12)          | <(10,13),3>
+ <(1,2),100>    | (-5,-12)          | <(6,14),100>
+ <(1,3),5>      | (-5,-12)          | <(6,15),5>
+ <(1,2),3>      | (-5,-12)          | <(6,14),3>
+ <(100,200),10> | (-5,-12)          | <(105,212),10>
+ <(100,1),115>  | (-5,-12)          | <(105,13),115>
+ <(3,5),0>      | (-5,-12)          | <(8,17),0>
+ <(3,5),NaN>    | (-5,-12)          | <(8,17),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(5,1),3>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(1,2),100>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(1,3),5>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(1,2),3>
+ <(100,200),10> | (1e-300,-1e-300)  | <(100,200),10>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(100,1),115>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(3,5),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(3,5),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(-1e+300,-Infinity),3>
+ <(1,2),100>    | (1e+300,Infinity) | <(-1e+300,-Infinity),100>
+ <(1,3),5>      | (1e+300,Infinity) | <(-1e+300,-Infinity),5>
+ <(1,2),3>      | (1e+300,Infinity) | <(-1e+300,-Infinity),3>
+ <(100,200),10> | (1e+300,Infinity) | <(-1e+300,-Infinity),10>
+ <(100,1),115>  | (1e+300,Infinity) | <(-1e+300,-Infinity),115>
+ <(3,5),0>      | (1e+300,Infinity) | <(-1e+300,-Infinity),0>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(-1e+300,-Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),100>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),5>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),10>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),115>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),0>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(-5,-9),3>
+ <(1,2),100>    | (10,10)           | <(-9,-8),100>
+ <(1,3),5>      | (10,10)           | <(-9,-7),5>
+ <(1,2),3>      | (10,10)           | <(-9,-8),3>
+ <(100,200),10> | (10,10)           | <(90,190),10>
+ <(100,1),115>  | (10,10)           | <(90,-9),115>
+ <(3,5),0>      | (10,10)           | <(-7,-5),0>
+ <(3,5),NaN>    | (10,10)           | <(-7,-5),NaN>
+(72 rows)
+
+-- Multiply with point
+SELECT c.f1, p.f1, c.f1 * p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |                  ?column?                  
+----------------+-------------------+--------------------------------------------
+ <(5,1),3>      | (0,0)             | <(0,0),0>
+ <(1,2),100>    | (0,0)             | <(0,0),0>
+ <(1,3),5>      | (0,0)             | <(0,0),0>
+ <(1,2),3>      | (0,0)             | <(0,0),0>
+ <(100,200),10> | (0,0)             | <(0,0),0>
+ <(100,1),115>  | (0,0)             | <(0,0),0>
+ <(3,5),0>      | (0,0)             | <(0,0),0>
+ <(3,5),NaN>    | (0,0)             | <(0,0),NaN>
+ <(5,1),3>      | (-10,0)           | <(-50,-10),30>
+ <(1,2),100>    | (-10,0)           | <(-10,-20),1000>
+ <(1,3),5>      | (-10,0)           | <(-10,-30),50>
+ <(1,2),3>      | (-10,0)           | <(-10,-20),30>
+ <(100,200),10> | (-10,0)           | <(-1000,-2000),100>
+ <(100,1),115>  | (-10,0)           | <(-1000,-10),1150>
+ <(3,5),0>      | (-10,0)           | <(-30,-50),0>
+ <(3,5),NaN>    | (-10,0)           | <(-30,-50),NaN>
+ <(5,1),3>      | (-3,4)            | <(-19,17),15>
+ <(1,2),100>    | (-3,4)            | <(-11,-2),500>
+ <(1,3),5>      | (-3,4)            | <(-15,-5),25>
+ <(1,2),3>      | (-3,4)            | <(-11,-2),15>
+ <(100,200),10> | (-3,4)            | <(-1100,-200),50>
+ <(100,1),115>  | (-3,4)            | <(-304,397),575>
+ <(3,5),0>      | (-3,4)            | <(-29,-3),0>
+ <(3,5),NaN>    | (-3,4)            | <(-29,-3),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(-9,177.6),104.624758064>
+ <(1,2),100>    | (5.1,34.5)        | <(-63.9,44.7),3487.49193547>
+ <(1,3),5>      | (5.1,34.5)        | <(-98.4,49.8),174.374596774>
+ <(1,2),3>      | (5.1,34.5)        | <(-63.9,44.7),104.624758064>
+ <(100,200),10> | (5.1,34.5)        | <(-6390,4470),348.749193547>
+ <(100,1),115>  | (5.1,34.5)        | <(475.5,3455.1),4010.6157258>
+ <(3,5),0>      | (5.1,34.5)        | <(-157.2,129),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(-157.2,129),NaN>
+ <(5,1),3>      | (-5,-12)          | <(-13,-65),39>
+ <(1,2),100>    | (-5,-12)          | <(19,-22),1300>
+ <(1,3),5>      | (-5,-12)          | <(31,-27),65>
+ <(1,2),3>      | (-5,-12)          | <(19,-22),39>
+ <(100,200),10> | (-5,-12)          | <(1900,-2200),130>
+ <(100,1),115>  | (-5,-12)          | <(-488,-1205),1495>
+ <(3,5),0>      | (-5,-12)          | <(45,-61),0>
+ <(3,5),NaN>    | (-5,-12)          | <(45,-61),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(6e-300,-4e-300),4.24264068712e-300>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(3e-300,1e-300),1.41421356237e-298>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(4e-300,2e-300),7.07106781187e-300>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(3e-300,1e-300),4.24264068712e-300>
+ <(100,200),10> | (1e-300,-1e-300)  | <(3e-298,1e-298),1.41421356237e-299>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(1.01e-298,-9.9e-299),1.62634559673e-298>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(8e-300,2e-300),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(8e-300,2e-300),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,2),100>    | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,3),5>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,2),3>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(100,200),10> | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(100,1),115>  | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(3,5),0>      | (1e+300,Infinity) | <(-Infinity,Infinity),NaN>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(-Infinity,Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(40,60),42.4264068712>
+ <(1,2),100>    | (10,10)           | <(-10,30),1414.21356237>
+ <(1,3),5>      | (10,10)           | <(-20,40),70.7106781187>
+ <(1,2),3>      | (10,10)           | <(-10,30),42.4264068712>
+ <(100,200),10> | (10,10)           | <(-1000,3000),141.421356237>
+ <(100,1),115>  | (10,10)           | <(990,1010),1626.34559673>
+ <(3,5),0>      | (10,10)           | <(-20,80),0>
+ <(3,5),NaN>    | (10,10)           | <(-20,80),NaN>
+(72 rows)
+
+-- Divide by point
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+       f1       |     f1     |                       ?column?                       
+----------------+------------+------------------------------------------------------
+ <(5,1),3>      | (5.1,34.5) | <(0.0493315573973,-0.137635045138),0.0860217042937>
+ <(5,1),3>      | (10,10)    | <(0.3,-0.2),0.212132034356>
+ <(1,2),100>    | (5.1,34.5) | <(0.0609244733856,-0.0199792807459),2.86739014312>
+ <(1,2),100>    | (10,10)    | <(0.15,0.05),7.07106781187>
+ <(1,3),5>      | (5.1,34.5) | <(0.0892901188891,-0.0157860983671),0.143369507156>
+ <(1,3),5>      | (10,10)    | <(0.2,0.1),0.353553390593>
+ <(1,2),3>      | (5.1,34.5) | <(0.0609244733856,-0.0199792807459),0.0860217042937>
+ <(1,2),3>      | (10,10)    | <(0.15,0.05),0.212132034356>
+ <(100,200),10> | (5.1,34.5) | <(6.09244733856,-1.99792807459),0.286739014312>
+ <(100,200),10> | (10,10)    | <(15,5),0.707106781187>
+ <(100,1),115>  | (5.1,34.5) | <(0.44768388338,-2.83237136796),3.29749866459>
+ <(100,1),115>  | (10,10)    | <(5.05,-4.95),8.13172798365>
+ <(3,5),0>      | (5.1,34.5) | <(0.154407774653,-0.0641310246164),0>
+ <(3,5),0>      | (10,10)    | <(0.4,0.1),0>
+ <(3,5),NaN>    | (5.1,34.5) | <(0.154407774653,-0.0641310246164),NaN>
+ <(3,5),NaN>    | (10,10)    | <(0.4,0.1),NaN>
+(16 rows)
+
+-- Overflow error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] > 1000;
+ERROR:  value out of range: overflow
+-- Division by 0 error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to polygon
+SELECT c.f1, p.f1, c.f1 <-> p.f1 FROM CIRCLE_TBL c, POLYGON_TBL p;
+       f1       |             f1             |    ?column?    
+----------------+----------------------------+----------------
+ <(5,1),3>      | ((2,0),(2,4),(0,0))        |              0
+ <(5,1),3>      | ((3,1),(3,3),(1,0))        |              0
+ <(5,1),3>      | ((1,2),(3,4),(5,6),(7,8))  | 0.535533905933
+ <(5,1),3>      | ((7,8),(5,6),(3,4),(1,2))  | 0.535533905933
+ <(5,1),3>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(5,1),3>      | ((0,0))                    |  2.09901951359
+ <(5,1),3>      | ((0,1),(0,1))              |              2
+ <(1,2),100>    | ((2,0),(2,4),(0,0))        |              0
+ <(1,2),100>    | ((3,1),(3,3),(1,0))        |              0
+ <(1,2),100>    | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,2),100>    | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,2),100>    | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,2),100>    | ((0,0))                    |              0
+ <(1,2),100>    | ((0,1),(0,1))              |              0
+ <(1,3),5>      | ((2,0),(2,4),(0,0))        |              0
+ <(1,3),5>      | ((3,1),(3,3),(1,0))        |              0
+ <(1,3),5>      | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,3),5>      | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,3),5>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,3),5>      | ((0,0))                    |              0
+ <(1,3),5>      | ((0,1),(0,1))              |              0
+ <(1,2),3>      | ((2,0),(2,4),(0,0))        |              0
+ <(1,2),3>      | ((3,1),(3,3),(1,0))        |              0
+ <(1,2),3>      | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,2),3>      | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,2),3>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,2),3>      | ((0,0))                    |              0
+ <(1,2),3>      | ((0,1),(0,1))              |              0
+ <(100,200),10> | ((2,0),(2,4),(0,0))        |  209.134661795
+ <(100,200),10> | ((3,1),(3,3),(1,0))        |  209.585974051
+ <(100,200),10> | ((1,2),(3,4),(5,6),(7,8))  |  203.337760371
+ <(100,200),10> | ((7,8),(5,6),(3,4),(1,2))  |  203.337760371
+ <(100,200),10> | ((1,2),(7,8),(5,6),(3,-4)) |  203.337760371
+ <(100,200),10> | ((0,0))                    |   213.60679775
+ <(100,200),10> | ((0,1),(0,1))              |  212.712819568
+ <(100,1),115>  | ((2,0),(2,4),(0,0))        |              0
+ <(100,1),115>  | ((3,1),(3,3),(1,0))        |              0
+ <(100,1),115>  | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(100,1),115>  | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(100,1),115>  | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(100,1),115>  | ((0,0))                    |              0
+ <(100,1),115>  | ((0,1),(0,1))              |              0
+ <(3,5),0>      | ((2,0),(2,4),(0,0))        |  1.41421356237
+ <(3,5),0>      | ((3,1),(3,3),(1,0))        |              2
+ <(3,5),0>      | ((1,2),(3,4),(5,6),(7,8))  | 0.707106781187
+ <(3,5),0>      | ((7,8),(5,6),(3,4),(1,2))  | 0.707106781187
+ <(3,5),0>      | ((1,2),(7,8),(5,6),(3,-4)) | 0.707106781187
+ <(3,5),0>      | ((0,0))                    |  5.83095189485
+ <(3,5),0>      | ((0,1),(0,1))              |              5
+ <(3,5),NaN>    | ((2,0),(2,4),(0,0))        |            NaN
+ <(3,5),NaN>    | ((3,1),(3,3),(1,0))        |            NaN
+ <(3,5),NaN>    | ((1,2),(3,4),(5,6),(7,8))  |            NaN
+ <(3,5),NaN>    | ((7,8),(5,6),(3,4),(1,2))  |            NaN
+ <(3,5),NaN>    | ((1,2),(7,8),(5,6),(3,-4)) |            NaN
+ <(3,5),NaN>    | ((0,0))                    |            NaN
+ <(3,5),NaN>    | ((0,1),(0,1))              |            NaN
+(56 rows)
 
diff --git a/src/test/regress/expected/geometry_1.out b/src/test/regress/expected/geometry_1.out
deleted file mode 100644
index 3b92e23059..0000000000
--- a/src/test/regress/expected/geometry_1.out
+++ /dev/null
@@ -1,563 +0,0 @@
---
--- GEOMETRY
---
--- Back off displayed precision a little bit to reduce platform-to-platform
--- variation in results.
-SET extra_float_digits TO -3;
---
--- Points
---
-SELECT '' AS four, center(f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS four, (@@ f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS six, point(f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS six, (@@ f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS two, (@@ f1) AS center
-   FROM POLYGON_TBL
-   WHERE (# f1) > 2;
- two |            center             
------+-------------------------------
-     | (1.33333333333,1.33333333333)
-     | (2.33333333333,1.33333333333)
-(2 rows)
-
--- "is horizontal" function
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is horizontal" operator
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is vertical" function
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE isvertical(p1.f1, point '(5.1,34.5)');
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
--- "is vertical" operator
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?| point '(5.1,34.5)';
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
---
--- Line segments
---
--- intersection
-SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-   FROM LSEG_TBL l, POINT_TBL p;
-ERROR:  operator does not exist: lseg # point
-LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-                                           ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
-
---
--- Boxes
---
-SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
- six |                              box                               
------+----------------------------------------------------------------
-     | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
-     | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
-     | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
-     | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
-     | (107.071067812,207.071067812),(92.9289321881,192.928932188)
-     | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
-
--- translation
-SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (-8,2),(-10,0)
-            | (-7,3),(-9,1)
-            | (-7.5,3.5),(-7.5,2.5)
-            | (-7,3),(-7,3)
-            | (-1,6),(-3,4)
-            | (0,7),(-2,5)
-            | (-0.5,7.5),(-0.5,6.5)
-            | (0,7),(0,7)
-            | (7.1,36.5),(5.1,34.5)
-            | (8.1,37.5),(6.1,35.5)
-            | (7.6,38),(7.6,37)
-            | (8.1,37.5),(8.1,37.5)
-            | (-3,-10),(-5,-12)
-            | (-2,-9),(-4,-11)
-            | (-2.5,-8.5),(-2.5,-9.5)
-            | (-2,-9),(-2,-9)
-            | (12,12),(10,10)
-            | (13,13),(11,11)
-            | (12.5,13.5),(12.5,12.5)
-            | (13,13),(13,13)
-(24 rows)
-
-SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (12,2),(10,0)
-            | (13,3),(11,1)
-            | (12.5,3.5),(12.5,2.5)
-            | (13,3),(13,3)
-            | (5,-2),(3,-4)
-            | (6,-1),(4,-3)
-            | (5.5,-0.5),(5.5,-1.5)
-            | (6,-1),(6,-1)
-            | (-3.1,-32.5),(-5.1,-34.5)
-            | (-2.1,-31.5),(-4.1,-33.5)
-            | (-2.6,-31),(-2.6,-32)
-            | (-2.1,-31.5),(-2.1,-31.5)
-            | (7,14),(5,12)
-            | (8,15),(6,13)
-            | (7.5,15.5),(7.5,14.5)
-            | (8,15),(8,15)
-            | (-8,-8),(-10,-10)
-            | (-7,-7),(-9,-9)
-            | (-7.5,-6.5),(-7.5,-7.5)
-            | (-7,-7),(-7,-7)
-(24 rows)
-
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
-
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,0),(-0.2,-0.2)
-        | (0.08,0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
-
-SELECT f1::box
-	FROM POINT_TBL;
-          f1           
------------------------
- (0,0),(0,0)
- (-10,0),(-10,0)
- (-3,4),(-3,4)
- (5.1,34.5),(5.1,34.5)
- (-5,-12),(-5,-12)
- (10,10),(10,10)
-(6 rows)
-
-SELECT bound_box(a.f1, b.f1)
-	FROM BOX_TBL a, BOX_TBL b;
-      bound_box      
----------------------
- (2,2),(0,0)
- (3,3),(0,0)
- (2.5,3.5),(0,0)
- (3,3),(0,0)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(1,1)
- (3,3),(1,1)
- (2.5,3.5),(0,0)
- (3,3.5),(1,1)
- (2.5,3.5),(2.5,2.5)
- (3,3.5),(2.5,2.5)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(2.5,2.5)
- (3,3),(3,3)
-(16 rows)
-
---
--- Paths
---
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
-
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
-
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
-
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
-
---
--- Polygons
---
--- containment
-SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
-   FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
-      |       3 | ((2,0),(2,4),(0,0))
-      |       3 | ((3,1),(3,3),(1,0))
-      |       1 | ((0,0))
-      |       2 | ((0,1),(0,1))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM BOX_TBL;
- four |                  polygon                  
-------+-------------------------------------------
-      | ((0,0),(0,2),(2,2),(2,0))
-      | ((1,1),(1,3),(3,3),(3,1))
-      | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
-      | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM PATH_TBL WHERE isclosed(f1);
- four |      polygon      
-------+-------------------
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((11,12),(13,14))
-(4 rows)
-
-SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
-   FROM PATH_TBL
-   WHERE isopen(f1);
- four |         open_path         |          polygon          
-------+---------------------------+---------------------------
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(11,12),(13,14)]         | ((11,12),(13,14))
-(4 rows)
-
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
-
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
-
---
--- Circles
---
-SELECT '' AS six, circle(f1, 50.0)
-   FROM POINT_TBL;
- six |     circle      
------+-----------------
-     | <(0,0),50>
-     | <(-10,0),50>
-     | <(-3,4),50>
-     | <(5.1,34.5),50>
-     | <(-5,-12),50>
-     | <(10,10),50>
-(6 rows)
-
-SELECT '' AS four, circle(f1)
-   FROM BOX_TBL;
- four |        circle         
-------+-----------------------
-      | <(1,1),1.41421356237>
-      | <(2,2),1.41421356237>
-      | <(2.5,3),0.5>
-      | <(3,3),0>
-(4 rows)
-
-SELECT '' AS two, circle(f1)
-   FROM POLYGON_TBL
-   WHERE (# f1) >= 3;
- two |                    circle                     
------+-----------------------------------------------
-     | <(1.33333333333,1.33333333333),2.04168905064>
-     | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
-
-SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
-   FROM CIRCLE_TBL c1, POINT_TBL p1
-   WHERE (p1.f1 <-> c1.f1) > 0
-   ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
-
diff --git a/src/test/regress/expected/geometry_2.out b/src/test/regress/expected/geometry_2.out
deleted file mode 100644
index 5a922bcd3f..0000000000
--- a/src/test/regress/expected/geometry_2.out
+++ /dev/null
@@ -1,563 +0,0 @@
---
--- GEOMETRY
---
--- Back off displayed precision a little bit to reduce platform-to-platform
--- variation in results.
-SET extra_float_digits TO -3;
---
--- Points
---
-SELECT '' AS four, center(f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS four, (@@ f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS six, point(f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS six, (@@ f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS two, (@@ f1) AS center
-   FROM POLYGON_TBL
-   WHERE (# f1) > 2;
- two |            center             
------+-------------------------------
-     | (1.33333333333,1.33333333333)
-     | (2.33333333333,1.33333333333)
-(2 rows)
-
--- "is horizontal" function
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is horizontal" operator
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is vertical" function
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE isvertical(p1.f1, point '(5.1,34.5)');
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
--- "is vertical" operator
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?| point '(5.1,34.5)';
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
---
--- Line segments
---
--- intersection
-SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-   FROM LSEG_TBL l, POINT_TBL p;
-ERROR:  operator does not exist: lseg # point
-LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-                                           ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
-
---
--- Boxes
---
-SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
- six |                              box                               
------+----------------------------------------------------------------
-     | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
-     | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
-     | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
-     | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
-     | (107.071067812,207.071067812),(92.9289321881,192.928932188)
-     | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
-
--- translation
-SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (-8,2),(-10,0)
-            | (-7,3),(-9,1)
-            | (-7.5,3.5),(-7.5,2.5)
-            | (-7,3),(-7,3)
-            | (-1,6),(-3,4)
-            | (0,7),(-2,5)
-            | (-0.5,7.5),(-0.5,6.5)
-            | (0,7),(0,7)
-            | (7.1,36.5),(5.1,34.5)
-            | (8.1,37.5),(6.1,35.5)
-            | (7.6,38),(7.6,37)
-            | (8.1,37.5),(8.1,37.5)
-            | (-3,-10),(-5,-12)
-            | (-2,-9),(-4,-11)
-            | (-2.5,-8.5),(-2.5,-9.5)
-            | (-2,-9),(-2,-9)
-            | (12,12),(10,10)
-            | (13,13),(11,11)
-            | (12.5,13.5),(12.5,12.5)
-            | (13,13),(13,13)
-(24 rows)
-
-SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (12,2),(10,0)
-            | (13,3),(11,1)
-            | (12.5,3.5),(12.5,2.5)
-            | (13,3),(13,3)
-            | (5,-2),(3,-4)
-            | (6,-1),(4,-3)
-            | (5.5,-0.5),(5.5,-1.5)
-            | (6,-1),(6,-1)
-            | (-3.1,-32.5),(-5.1,-34.5)
-            | (-2.1,-31.5),(-4.1,-33.5)
-            | (-2.6,-31),(-2.6,-32)
-            | (-2.1,-31.5),(-2.1,-31.5)
-            | (7,14),(5,12)
-            | (8,15),(6,13)
-            | (7.5,15.5),(7.5,14.5)
-            | (8,15),(8,15)
-            | (-8,-8),(-10,-10)
-            | (-7,-7),(-9,-9)
-            | (-7.5,-6.5),(-7.5,-7.5)
-            | (-7,-7),(-7,-7)
-(24 rows)
-
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (-0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (-0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,-0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
-
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,-0),(-0.2,-0.2)
-        | (0.08,-0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (-0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
-
-SELECT f1::box
-	FROM POINT_TBL;
-          f1           
------------------------
- (0,0),(0,0)
- (-10,0),(-10,0)
- (-3,4),(-3,4)
- (5.1,34.5),(5.1,34.5)
- (-5,-12),(-5,-12)
- (10,10),(10,10)
-(6 rows)
-
-SELECT bound_box(a.f1, b.f1)
-	FROM BOX_TBL a, BOX_TBL b;
-      bound_box      
----------------------
- (2,2),(0,0)
- (3,3),(0,0)
- (2.5,3.5),(0,0)
- (3,3),(0,0)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(1,1)
- (3,3),(1,1)
- (2.5,3.5),(0,0)
- (3,3.5),(1,1)
- (2.5,3.5),(2.5,2.5)
- (3,3.5),(2.5,2.5)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(2.5,2.5)
- (3,3),(3,3)
-(16 rows)
-
---
--- Paths
---
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
-
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
-
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
-
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
-
---
--- Polygons
---
--- containment
-SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
-   FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
-      |       3 | ((2,0),(2,4),(0,0))
-      |       3 | ((3,1),(3,3),(1,0))
-      |       1 | ((0,0))
-      |       2 | ((0,1),(0,1))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM BOX_TBL;
- four |                  polygon                  
-------+-------------------------------------------
-      | ((0,0),(0,2),(2,2),(2,0))
-      | ((1,1),(1,3),(3,3),(3,1))
-      | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
-      | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM PATH_TBL WHERE isclosed(f1);
- four |      polygon      
-------+-------------------
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((11,12),(13,14))
-(4 rows)
-
-SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
-   FROM PATH_TBL
-   WHERE isopen(f1);
- four |         open_path         |          polygon          
-------+---------------------------+---------------------------
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(11,12),(13,14)]         | ((11,12),(13,14))
-(4 rows)
-
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
-
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
-
---
--- Circles
---
-SELECT '' AS six, circle(f1, 50.0)
-   FROM POINT_TBL;
- six |     circle      
------+-----------------
-     | <(0,0),50>
-     | <(-10,0),50>
-     | <(-3,4),50>
-     | <(5.1,34.5),50>
-     | <(-5,-12),50>
-     | <(10,10),50>
-(6 rows)
-
-SELECT '' AS four, circle(f1)
-   FROM BOX_TBL;
- four |        circle         
-------+-----------------------
-      | <(1,1),1.41421356237>
-      | <(2,2),1.41421356237>
-      | <(2.5,3),0.5>
-      | <(3,3),0>
-(4 rows)
-
-SELECT '' AS two, circle(f1)
-   FROM POLYGON_TBL
-   WHERE (# f1) >= 3;
- two |                    circle                     
------+-----------------------------------------------
-     | <(1.33333333333,1.33333333333),2.04168905064>
-     | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
-
-SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
-   FROM CIRCLE_TBL c1, POINT_TBL p1
-   WHERE (p1.f1 <-> c1.f1) > 0
-   ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
-
diff --git a/src/test/regress/expected/line.out b/src/test/regress/expected/line.out
index f20abdc430..34d0659519 100644
--- a/src/test/regress/expected/line.out
+++ b/src/test/regress/expected/line.out
@@ -1,271 +1,80 @@
 --
 -- LINE
 -- Infinite lines
 --
 --DROP TABLE LINE_TBL;
 CREATE TABLE LINE_TBL (s line);
-INSERT INTO LINE_TBL VALUES ('{1,-1,1}');
-INSERT INTO LINE_TBL VALUES ('(0,0),(6,6)');
+INSERT INTO LINE_TBL VALUES ('{0,-1,5}');	-- A == 0
+INSERT INTO LINE_TBL VALUES ('{1,0,5}');	-- B == 0
+INSERT INTO LINE_TBL VALUES ('{0,3,0}');	-- A == C == 0
+INSERT INTO LINE_TBL VALUES (' (0,0), (6,6)');
 INSERT INTO LINE_TBL VALUES ('10,-10 ,-5,-4');
 INSERT INTO LINE_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LINE_TBL VALUES ('(11,22,33,44)');
-INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
-ERROR:  invalid line specification: must be two distinct points
-LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
-                                     ^
+INSERT INTO LINE_TBL VALUES (line(point '(1,0)', point '(1,0)'));
+INSERT INTO LINE_TBL VALUES ('{3,NaN,5}');
+INSERT INTO LINE_TBL VALUES ('{NaN,NaN,NaN}');
 -- horizontal
 INSERT INTO LINE_TBL VALUES ('[(1,3),(2,3)]');
 -- vertical
 INSERT INTO LINE_TBL VALUES ('[(3,1),(3,2)]');
 -- bad values for parser testing
+INSERT INTO LINE_TBL VALUES ('{}');
+ERROR:  invalid input syntax for type line: "{}"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{}');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0');
+ERROR:  invalid input syntax for type line: "{0"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0,0}');
+ERROR:  invalid input syntax for type line: "{0,0}"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0}');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0,0,1');
+ERROR:  invalid input syntax for type line: "{0,0,1"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1');
+                                     ^
 INSERT INTO LINE_TBL VALUES ('{0,0,1}');
 ERROR:  invalid line specification: A and B cannot both be zero
 LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1}');
                                      ^
+INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
+ERROR:  invalid input syntax for type line: "{0,0,1} x"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
+                                     ^
 INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
 ERROR:  invalid input syntax for type line: "(3asdf,2 ,3,4r2)"
 LINE 1: INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
                                      ^
 INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
 ERROR:  invalid input syntax for type line: "[1,2,3, 4"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
                                      ^
 INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
 ERROR:  invalid input syntax for type line: "[(,2),(3,4)]"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
                                      ^
 INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
 ERROR:  invalid input syntax for type line: "[(1,2),(3,4)"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
                                      ^
+INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
+ERROR:  invalid line specification: must be two distinct points
+LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
+                                     ^
 select * from LINE_TBL;
                       s                      
 ---------------------------------------------
- {1,-1,1}
+ {0,-1,5}
+ {1,0,5}
+ {0,3,0}
  {1,-1,0}
  {-0.4,-1,-6}
  {-0.000184615384615385,-1,15.3846153846154}
- {1,-1,11}
+ {NaN,-1,NaN}
+ {3,NaN,5}
+ {NaN,NaN,NaN}
  {0,-1,3}
  {-1,0,3}
-(7 rows)
-
--- functions and operators
-SELECT * FROM LINE_TBL WHERE (s <-> line '[(1,2),(3,4)]') < 10;
-                      s                      
----------------------------------------------
- {1,-1,1}
- {1,-1,0}
- {-0.4,-1,-6}
- {-0.000184615384615385,-1,15.3846153846154}
- {1,-1,11}
- {0,-1,3}
- {-1,0,3}
-(7 rows)
-
-SELECT * FROM LINE_TBL WHERE (point '(0.1,0.1)' <-> s) < 1;
-    s     
-----------
- {1,-1,1}
- {1,-1,0}
-(2 rows)
-
-SELECT * FROM LINE_TBL WHERE (lseg '[(0.1,0.1),(0.2,0.2)]' <-> s) < 1;
-    s     
-----------
- {1,-1,1}
- {1,-1,0}
-(2 rows)
-
-SELECT line '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
- ?column? 
-----------
-        2
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
- ?column? 
-----------
-        2
-(1 row)
-
-SELECT point '(-1,1)' <-> line '[(-3,0),(-4,0)]';
- ?column? 
-----------
-        1
-(1 row)
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(2,0),(0,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# box '(0,0,2,2)';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(3,0),(4,1)]' ?# box '(0,0,2,2)';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(1,1)' <@ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT point '(1,1)' <@ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(1,1)' @ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT point '(1,1)' @ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT lseg '[(1,1),(2,2)]' <@ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' <@ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT lseg '[(1,1),(2,2)]' @ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' @ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(0,1)' ## line '[(0,0),(1,1)]';
- ?column?  
------------
- (0.5,0.5)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ## lseg '[(1,0),(2,0)]';
- ?column? 
-----------
- (1,0)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(2,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(1,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(2,1)]';
- ?column? 
-----------
- 
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(1,1)]';
- ?column? 
-----------
- (1,1)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(2,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,0)]' ?-| line '[(0,0),(0,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?-| line '[(1,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT ?- line '[(0,0),(1,0)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT ?- line '[(0,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT ?| line '[(0,0),(0,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT ?| line '[(0,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line(point '(1,2)', point '(3,4)');
-   line   
-----------
- {1,-1,1}
-(1 row)
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,5)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,4)]';  -- false
- ?column? 
-----------
- f
-(1 row)
+(11 rows)
 
diff --git a/src/test/regress/expected/lseg.out b/src/test/regress/expected/lseg.out
index bba1f3ee80..7e878b5577 100644
--- a/src/test/regress/expected/lseg.out
+++ b/src/test/regress/expected/lseg.out
@@ -1,21 +1,24 @@
 --
 -- LSEG
 -- Line segments
 --
 --DROP TABLE LSEG_TBL;
 CREATE TABLE LSEG_TBL (s lseg);
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('(0,0),(6,6)');
 INSERT INTO LSEG_TBL VALUES ('10,-10 ,-3,-4');
 INSERT INTO LSEG_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LSEG_TBL VALUES ('(11,22,33,44)');
+INSERT INTO LSEG_TBL VALUES (lseg(point(11, 22), point(33,44)));
+INSERT INTO LSEG_TBL VALUES ('[(-10,2),(-10,3)]');	-- vertical
+INSERT INTO LSEG_TBL VALUES ('[(0,-20),(30,-20)]');	-- horizontal
+INSERT INTO LSEG_TBL VALUES ('[(NaN,1),(NaN,90)]');	-- NaN
 -- bad values for parser testing
 INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
 ERROR:  invalid input syntax for type lseg: "(3asdf,2 ,3,4r2)"
 LINE 1: INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
                                      ^
 INSERT INTO LSEG_TBL VALUES ('[1,2,3, 4');
 ERROR:  invalid input syntax for type lseg: "[1,2,3, 4"
 LINE 1: INSERT INTO LSEG_TBL VALUES ('[1,2,3, 4');
                                      ^
 INSERT INTO LSEG_TBL VALUES ('[(,2),(3,4)]');
@@ -27,26 +30,15 @@ ERROR:  invalid input syntax for type lseg: "[(1,2),(3,4)"
 LINE 1: INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)');
                                      ^
 select * from LSEG_TBL;
                s               
 -------------------------------
  [(1,2),(3,4)]
  [(0,0),(6,6)]
  [(10,-10),(-3,-4)]
  [(-1000000,200),(300000,-40)]
  [(11,22),(33,44)]
-(5 rows)
-
-SELECT * FROM LSEG_TBL WHERE s <= lseg '[(1,2),(3,4)]';
-       s       
----------------
- [(1,2),(3,4)]
-(1 row)
-
-SELECT * FROM LSEG_TBL WHERE (s <-> lseg '[(1,2),(3,4)]') < 10;
-         s          
---------------------
- [(1,2),(3,4)]
- [(0,0),(6,6)]
- [(10,-10),(-3,-4)]
-(3 rows)
+ [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]
+ [(NaN,1),(NaN,90)]
+(8 rows)
 
diff --git a/src/test/regress/expected/path.out b/src/test/regress/expected/path.out
index 08d6d61dda..bd6e467752 100644
--- a/src/test/regress/expected/path.out
+++ b/src/test/regress/expected/path.out
@@ -1,79 +1,82 @@
 --
 -- PATH
 --
 --DROP TABLE PATH_TBL;
 CREATE TABLE PATH_TBL (f1 path);
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)]');
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
-INSERT INTO PATH_TBL VALUES ('[(0,0),(3,0),(4,5),(1,6)]');
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
-INSERT INTO PATH_TBL VALUES ('1,2 ,3,4');
-INSERT INTO PATH_TBL VALUES ('[1,2,3, 4]');
-INSERT INTO PATH_TBL VALUES ('[11,12,13,14]');
-INSERT INTO PATH_TBL VALUES ('(11,12,13,14)');
+INSERT INTO PATH_TBL VALUES (' ( ( 1 , 2 ) , ( 3 , 4 ) ) ');
+INSERT INTO PATH_TBL VALUES ('[ (0,0),(3,0),(4,5),(1,6) ]');
+INSERT INTO PATH_TBL VALUES ('((1,2) ,(3,4 ))');
+INSERT INTO PATH_TBL VALUES ('1,2 ,3,4 ');
+INSERT INTO PATH_TBL VALUES (' [1,2,3, 4] ');
+INSERT INTO PATH_TBL VALUES ('((10,20))');	-- Only one point
+INSERT INTO PATH_TBL VALUES ('[ 11,12,13,14 ]');
+INSERT INTO PATH_TBL VALUES ('( 11,12,13,14) ');
 -- bad values for parser testing
+INSERT INTO PATH_TBL VALUES ('[]');
+ERROR:  invalid input syntax for type path: "[]"
+LINE 1: INSERT INTO PATH_TBL VALUES ('[]');
+                                     ^
 INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
 ERROR:  invalid input syntax for type path: "[(,2),(3,4)]"
 LINE 1: INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
                                      ^
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
 ERROR:  invalid input syntax for type path: "[(1,2),(3,4)"
 LINE 1: INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
                                      ^
-SELECT f1 FROM PATH_TBL;
-            f1             
----------------------------
- [(1,2),(3,4)]
- ((1,2),(3,4))
- [(0,0),(3,0),(4,5),(1,6)]
- ((1,2),(3,4))
- ((1,2),(3,4))
- [(1,2),(3,4)]
- [(11,12),(13,14)]
- ((11,12),(13,14))
-(8 rows)
-
+INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+ERROR:  invalid input syntax for type path: "(1,2,3,4"
+LINE 1: INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+                                     ^
+INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
+ERROR:  invalid input syntax for type path: "(1,2),(3,4)]"
+LINE 1: INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
+                                     ^
 SELECT '' AS count, f1 AS open_path FROM PATH_TBL WHERE isopen(f1);
  count |         open_path         
 -------+---------------------------
        | [(1,2),(3,4)]
        | [(0,0),(3,0),(4,5),(1,6)]
        | [(1,2),(3,4)]
        | [(11,12),(13,14)]
 (4 rows)
 
 SELECT '' AS count, f1 AS closed_path FROM PATH_TBL WHERE isclosed(f1);
  count |    closed_path    
 -------+-------------------
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
+       | ((10,20))
        | ((11,12),(13,14))
-(4 rows)
+(5 rows)
 
 SELECT '' AS count, pclose(f1) AS closed_path FROM PATH_TBL;
  count |        closed_path        
 -------+---------------------------
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((0,0),(3,0),(4,5),(1,6))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
+       | ((10,20))
        | ((11,12),(13,14))
        | ((11,12),(13,14))
-(8 rows)
+(9 rows)
 
 SELECT '' AS count, popen(f1) AS open_path FROM PATH_TBL;
  count |         open_path         
 -------+---------------------------
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
        | [(0,0),(3,0),(4,5),(1,6)]
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
+       | [(10,20)]
        | [(11,12),(13,14)]
        | [(11,12),(13,14)]
-(8 rows)
+(9 rows)
 
diff --git a/src/test/regress/expected/point.out b/src/test/regress/expected/point.out
index bfc0962749..c18e865370 100644
--- a/src/test/regress/expected/point.out
+++ b/src/test/regress/expected/point.out
@@ -1,43 +1,57 @@
 --
 -- POINT
 --
 CREATE TABLE POINT_TBL(f1 point);
 INSERT INTO POINT_TBL(f1) VALUES ('(0.0,0.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-10.0,0.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-3.0,4.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(5.1, 34.5)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-5.0,-12.0)');
+INSERT INTO POINT_TBL(f1) VALUES ('(1e-300,-1e-300)');	-- To underflow
+INSERT INTO POINT_TBL(f1) VALUES ('(1e+300,Inf)');		-- To overflow
+INSERT INTO POINT_TBL(f1) VALUES (' ( Nan , NaN ) ');
 -- bad format points
 INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
 ERROR:  invalid input syntax for type point: "asdfasdf"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
                                           ^
 INSERT INTO POINT_TBL(f1) VALUES ('10.0,10.0');
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
 ERROR:  invalid input syntax for type point: "(10.0 10.0)"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
                                           ^
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+ERROR:  invalid input syntax for type point: "(10.0, 10.0) x"
+LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+                                          ^
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
 ERROR:  invalid input syntax for type point: "(10.0,10.0"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
                                           ^
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');	-- Out of range
+ERROR:  "1e+500" is out of range for type double precision
+LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');
+                                          ^
 SELECT '' AS six, * FROM POINT_TBL;
- six |     f1     
------+------------
+ six |        f1         
+-----+-------------------
      | (0,0)
      | (-10,0)
      | (-3,4)
      | (5.1,34.5)
      | (-5,-12)
+     | (1e-300,-1e-300)
+     | (1e+300,Infinity)
+     | (NaN,NaN)
      | (10,10)
-(6 rows)
+(9 rows)
 
 -- left of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE p.f1 << '(0.0, 0.0)';
  three |    f1    
 -------+----------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
 (3 rows)
 
@@ -85,172 +99,282 @@ 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    
--------+----------
+ three |        f1         
+-------+-------------------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
-(3 rows)
+       | (1e-300,-1e-300)
+       | (1e+300,Infinity)
+       | (NaN,NaN)
+(6 rows)
 
 SELECT '' AS two, p.* FROM POINT_TBL p
    WHERE p.f1 <@ path '[(0,0),(-10,0),(-10,10)]';
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 SELECT '' AS three, p.* FROM POINT_TBL p
    WHERE not box '(0,0,100,100)' @> p.f1;
- three |    f1    
--------+----------
+ three |        f1         
+-------+-------------------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
-(3 rows)
+       | (1e-300,-1e-300)
+       | (1e+300,Infinity)
+       | (NaN,NaN)
+(6 rows)
 
 SELECT '' AS six, p.f1, p.f1 <-> point '(0,0)' AS dist
    FROM POINT_TBL p
    ORDER BY dist;
- six |     f1     |       dist       
------+------------+------------------
-     | (0,0)      |                0
-     | (-3,4)     |                5
-     | (-10,0)    |               10
-     | (-5,-12)   |               13
-     | (10,10)    |  14.142135623731
-     | (5.1,34.5) | 34.8749193547455
-(6 rows)
+ six |        f1         |         dist         
+-----+-------------------+----------------------
+     | (0,0)             |                    0
+     | (1e-300,-1e-300)  | 1.4142135623731e-300
+     | (-3,4)            |                    5
+     | (-10,0)           |                   10
+     | (-5,-12)          |                   13
+     | (10,10)           |      14.142135623731
+     | (5.1,34.5)        |     34.8749193547455
+     | (1e+300,Infinity) |             Infinity
+     | (NaN,NaN)         |                  NaN
+(9 rows)
 
 SELECT '' AS thirtysix, p1.f1 AS point1, p2.f1 AS point2, p1.f1 <-> p2.f1 AS dist
    FROM POINT_TBL p1, POINT_TBL p2
    ORDER BY dist, p1.f1[0], p2.f1[0];
- thirtysix |   point1   |   point2   |       dist       
------------+------------+------------+------------------
-           | (-10,0)    | (-10,0)    |                0
-           | (-5,-12)   | (-5,-12)   |                0
-           | (-3,4)     | (-3,4)     |                0
-           | (0,0)      | (0,0)      |                0
-           | (5.1,34.5) | (5.1,34.5) |                0
-           | (10,10)    | (10,10)    |                0
-           | (-3,4)     | (0,0)      |                5
-           | (0,0)      | (-3,4)     |                5
-           | (-10,0)    | (-3,4)     | 8.06225774829855
-           | (-3,4)     | (-10,0)    | 8.06225774829855
-           | (-10,0)    | (0,0)      |               10
-           | (0,0)      | (-10,0)    |               10
-           | (-10,0)    | (-5,-12)   |               13
-           | (-5,-12)   | (-10,0)    |               13
-           | (-5,-12)   | (0,0)      |               13
-           | (0,0)      | (-5,-12)   |               13
-           | (0,0)      | (10,10)    |  14.142135623731
-           | (10,10)    | (0,0)      |  14.142135623731
-           | (-3,4)     | (10,10)    | 14.3178210632764
-           | (10,10)    | (-3,4)     | 14.3178210632764
-           | (-5,-12)   | (-3,4)     | 16.1245154965971
-           | (-3,4)     | (-5,-12)   | 16.1245154965971
-           | (-10,0)    | (10,10)    | 22.3606797749979
-           | (10,10)    | (-10,0)    | 22.3606797749979
-           | (5.1,34.5) | (10,10)    | 24.9851956166046
-           | (10,10)    | (5.1,34.5) | 24.9851956166046
-           | (-5,-12)   | (10,10)    | 26.6270539113887
-           | (10,10)    | (-5,-12)   | 26.6270539113887
-           | (-3,4)     | (5.1,34.5) | 31.5572495632937
-           | (5.1,34.5) | (-3,4)     | 31.5572495632937
-           | (0,0)      | (5.1,34.5) | 34.8749193547455
-           | (5.1,34.5) | (0,0)      | 34.8749193547455
-           | (-10,0)    | (5.1,34.5) | 37.6597928831267
-           | (5.1,34.5) | (-10,0)    | 37.6597928831267
-           | (-5,-12)   | (5.1,34.5) | 47.5842410888311
-           | (5.1,34.5) | (-5,-12)   | 47.5842410888311
-(36 rows)
+ thirtysix |      point1       |      point2       |         dist         
+-----------+-------------------+-------------------+----------------------
+           | (-10,0)           | (-10,0)           |                    0
+           | (-5,-12)          | (-5,-12)          |                    0
+           | (-3,4)            | (-3,4)            |                    0
+           | (0,0)             | (0,0)             |                    0
+           | (1e-300,-1e-300)  | (1e-300,-1e-300)  |                    0
+           | (5.1,34.5)        | (5.1,34.5)        |                    0
+           | (10,10)           | (10,10)           |                    0
+           | (0,0)             | (1e-300,-1e-300)  | 1.4142135623731e-300
+           | (1e-300,-1e-300)  | (0,0)             | 1.4142135623731e-300
+           | (-3,4)            | (0,0)             |                    5
+           | (-3,4)            | (1e-300,-1e-300)  |                    5
+           | (0,0)             | (-3,4)            |                    5
+           | (1e-300,-1e-300)  | (-3,4)            |                    5
+           | (-10,0)           | (-3,4)            |     8.06225774829855
+           | (-3,4)            | (-10,0)           |     8.06225774829855
+           | (-10,0)           | (0,0)             |                   10
+           | (-10,0)           | (1e-300,-1e-300)  |                   10
+           | (0,0)             | (-10,0)           |                   10
+           | (1e-300,-1e-300)  | (-10,0)           |                   10
+           | (-10,0)           | (-5,-12)          |                   13
+           | (-5,-12)          | (-10,0)           |                   13
+           | (-5,-12)          | (0,0)             |                   13
+           | (-5,-12)          | (1e-300,-1e-300)  |                   13
+           | (0,0)             | (-5,-12)          |                   13
+           | (1e-300,-1e-300)  | (-5,-12)          |                   13
+           | (0,0)             | (10,10)           |      14.142135623731
+           | (1e-300,-1e-300)  | (10,10)           |      14.142135623731
+           | (10,10)           | (0,0)             |      14.142135623731
+           | (10,10)           | (1e-300,-1e-300)  |      14.142135623731
+           | (-3,4)            | (10,10)           |     14.3178210632764
+           | (10,10)           | (-3,4)            |     14.3178210632764
+           | (-5,-12)          | (-3,4)            |     16.1245154965971
+           | (-3,4)            | (-5,-12)          |     16.1245154965971
+           | (-10,0)           | (10,10)           |     22.3606797749979
+           | (10,10)           | (-10,0)           |     22.3606797749979
+           | (5.1,34.5)        | (10,10)           |     24.9851956166046
+           | (10,10)           | (5.1,34.5)        |     24.9851956166046
+           | (-5,-12)          | (10,10)           |     26.6270539113887
+           | (10,10)           | (-5,-12)          |     26.6270539113887
+           | (-3,4)            | (5.1,34.5)        |     31.5572495632937
+           | (5.1,34.5)        | (-3,4)            |     31.5572495632937
+           | (0,0)             | (5.1,34.5)        |     34.8749193547455
+           | (1e-300,-1e-300)  | (5.1,34.5)        |     34.8749193547455
+           | (5.1,34.5)        | (0,0)             |     34.8749193547455
+           | (5.1,34.5)        | (1e-300,-1e-300)  |     34.8749193547455
+           | (-10,0)           | (5.1,34.5)        |     37.6597928831267
+           | (5.1,34.5)        | (-10,0)           |     37.6597928831267
+           | (-5,-12)          | (5.1,34.5)        |     47.5842410888311
+           | (5.1,34.5)        | (-5,-12)          |     47.5842410888311
+           | (-10,0)           | (1e+300,Infinity) |             Infinity
+           | (-5,-12)          | (1e+300,Infinity) |             Infinity
+           | (-3,4)            | (1e+300,Infinity) |             Infinity
+           | (0,0)             | (1e+300,Infinity) |             Infinity
+           | (1e-300,-1e-300)  | (1e+300,Infinity) |             Infinity
+           | (5.1,34.5)        | (1e+300,Infinity) |             Infinity
+           | (10,10)           | (1e+300,Infinity) |             Infinity
+           | (1e+300,Infinity) | (-10,0)           |             Infinity
+           | (1e+300,Infinity) | (-5,-12)          |             Infinity
+           | (1e+300,Infinity) | (-3,4)            |             Infinity
+           | (1e+300,Infinity) | (0,0)             |             Infinity
+           | (1e+300,Infinity) | (1e-300,-1e-300)  |             Infinity
+           | (1e+300,Infinity) | (5.1,34.5)        |             Infinity
+           | (1e+300,Infinity) | (10,10)           |             Infinity
+           | (-10,0)           | (NaN,NaN)         |                  NaN
+           | (-5,-12)          | (NaN,NaN)         |                  NaN
+           | (-3,4)            | (NaN,NaN)         |                  NaN
+           | (0,0)             | (NaN,NaN)         |                  NaN
+           | (1e-300,-1e-300)  | (NaN,NaN)         |                  NaN
+           | (5.1,34.5)        | (NaN,NaN)         |                  NaN
+           | (10,10)           | (NaN,NaN)         |                  NaN
+           | (1e+300,Infinity) | (1e+300,Infinity) |                  NaN
+           | (1e+300,Infinity) | (NaN,NaN)         |                  NaN
+           | (NaN,NaN)         | (-10,0)           |                  NaN
+           | (NaN,NaN)         | (-5,-12)          |                  NaN
+           | (NaN,NaN)         | (-3,4)            |                  NaN
+           | (NaN,NaN)         | (0,0)             |                  NaN
+           | (NaN,NaN)         | (1e-300,-1e-300)  |                  NaN
+           | (NaN,NaN)         | (5.1,34.5)        |                  NaN
+           | (NaN,NaN)         | (10,10)           |                  NaN
+           | (NaN,NaN)         | (1e+300,Infinity) |                  NaN
+           | (NaN,NaN)         | (NaN,NaN)         |                  NaN
+(81 rows)
 
 SELECT '' AS thirty, p1.f1 AS point1, p2.f1 AS point2
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3;
- thirty |   point1   |   point2   
---------+------------+------------
-        | (0,0)      | (-10,0)
-        | (0,0)      | (-3,4)
-        | (0,0)      | (5.1,34.5)
-        | (0,0)      | (-5,-12)
-        | (0,0)      | (10,10)
-        | (-10,0)    | (0,0)
-        | (-10,0)    | (-3,4)
-        | (-10,0)    | (5.1,34.5)
-        | (-10,0)    | (-5,-12)
-        | (-10,0)    | (10,10)
-        | (-3,4)     | (0,0)
-        | (-3,4)     | (-10,0)
-        | (-3,4)     | (5.1,34.5)
-        | (-3,4)     | (-5,-12)
-        | (-3,4)     | (10,10)
-        | (5.1,34.5) | (0,0)
-        | (5.1,34.5) | (-10,0)
-        | (5.1,34.5) | (-3,4)
-        | (5.1,34.5) | (-5,-12)
-        | (5.1,34.5) | (10,10)
-        | (-5,-12)   | (0,0)
-        | (-5,-12)   | (-10,0)
-        | (-5,-12)   | (-3,4)
-        | (-5,-12)   | (5.1,34.5)
-        | (-5,-12)   | (10,10)
-        | (10,10)    | (0,0)
-        | (10,10)    | (-10,0)
-        | (10,10)    | (-3,4)
-        | (10,10)    | (5.1,34.5)
-        | (10,10)    | (-5,-12)
-(30 rows)
+ thirty |      point1       |      point2       
+--------+-------------------+-------------------
+        | (0,0)             | (-10,0)
+        | (0,0)             | (-3,4)
+        | (0,0)             | (5.1,34.5)
+        | (0,0)             | (-5,-12)
+        | (0,0)             | (1e+300,Infinity)
+        | (0,0)             | (NaN,NaN)
+        | (0,0)             | (10,10)
+        | (-10,0)           | (0,0)
+        | (-10,0)           | (-3,4)
+        | (-10,0)           | (5.1,34.5)
+        | (-10,0)           | (-5,-12)
+        | (-10,0)           | (1e-300,-1e-300)
+        | (-10,0)           | (1e+300,Infinity)
+        | (-10,0)           | (NaN,NaN)
+        | (-10,0)           | (10,10)
+        | (-3,4)            | (0,0)
+        | (-3,4)            | (-10,0)
+        | (-3,4)            | (5.1,34.5)
+        | (-3,4)            | (-5,-12)
+        | (-3,4)            | (1e-300,-1e-300)
+        | (-3,4)            | (1e+300,Infinity)
+        | (-3,4)            | (NaN,NaN)
+        | (-3,4)            | (10,10)
+        | (5.1,34.5)        | (0,0)
+        | (5.1,34.5)        | (-10,0)
+        | (5.1,34.5)        | (-3,4)
+        | (5.1,34.5)        | (-5,-12)
+        | (5.1,34.5)        | (1e-300,-1e-300)
+        | (5.1,34.5)        | (1e+300,Infinity)
+        | (5.1,34.5)        | (NaN,NaN)
+        | (5.1,34.5)        | (10,10)
+        | (-5,-12)          | (0,0)
+        | (-5,-12)          | (-10,0)
+        | (-5,-12)          | (-3,4)
+        | (-5,-12)          | (5.1,34.5)
+        | (-5,-12)          | (1e-300,-1e-300)
+        | (-5,-12)          | (1e+300,Infinity)
+        | (-5,-12)          | (NaN,NaN)
+        | (-5,-12)          | (10,10)
+        | (1e-300,-1e-300)  | (-10,0)
+        | (1e-300,-1e-300)  | (-3,4)
+        | (1e-300,-1e-300)  | (5.1,34.5)
+        | (1e-300,-1e-300)  | (-5,-12)
+        | (1e-300,-1e-300)  | (1e+300,Infinity)
+        | (1e-300,-1e-300)  | (NaN,NaN)
+        | (1e-300,-1e-300)  | (10,10)
+        | (1e+300,Infinity) | (0,0)
+        | (1e+300,Infinity) | (-10,0)
+        | (1e+300,Infinity) | (-3,4)
+        | (1e+300,Infinity) | (5.1,34.5)
+        | (1e+300,Infinity) | (-5,-12)
+        | (1e+300,Infinity) | (1e-300,-1e-300)
+        | (1e+300,Infinity) | (1e+300,Infinity)
+        | (1e+300,Infinity) | (NaN,NaN)
+        | (1e+300,Infinity) | (10,10)
+        | (NaN,NaN)         | (0,0)
+        | (NaN,NaN)         | (-10,0)
+        | (NaN,NaN)         | (-3,4)
+        | (NaN,NaN)         | (5.1,34.5)
+        | (NaN,NaN)         | (-5,-12)
+        | (NaN,NaN)         | (1e-300,-1e-300)
+        | (NaN,NaN)         | (1e+300,Infinity)
+        | (NaN,NaN)         | (NaN,NaN)
+        | (NaN,NaN)         | (10,10)
+        | (10,10)           | (0,0)
+        | (10,10)           | (-10,0)
+        | (10,10)           | (-3,4)
+        | (10,10)           | (5.1,34.5)
+        | (10,10)           | (-5,-12)
+        | (10,10)           | (1e-300,-1e-300)
+        | (10,10)           | (1e+300,Infinity)
+        | (10,10)           | (NaN,NaN)
+(72 rows)
 
 -- put distance result into output to allow sorting with GEQ optimizer - tgl 97/05/10
 SELECT '' AS fifteen, p1.f1 AS point1, p2.f1 AS point2, (p1.f1 <-> p2.f1) AS distance
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3 and p1.f1 << p2.f1
    ORDER BY distance, p1.f1[0], p2.f1[0];
- fifteen |   point1   |   point2   |     distance     
----------+------------+------------+------------------
-         | (-3,4)     | (0,0)      |                5
-         | (-10,0)    | (-3,4)     | 8.06225774829855
-         | (-10,0)    | (0,0)      |               10
-         | (-10,0)    | (-5,-12)   |               13
-         | (-5,-12)   | (0,0)      |               13
-         | (0,0)      | (10,10)    |  14.142135623731
-         | (-3,4)     | (10,10)    | 14.3178210632764
-         | (-5,-12)   | (-3,4)     | 16.1245154965971
-         | (-10,0)    | (10,10)    | 22.3606797749979
-         | (5.1,34.5) | (10,10)    | 24.9851956166046
-         | (-5,-12)   | (10,10)    | 26.6270539113887
-         | (-3,4)     | (5.1,34.5) | 31.5572495632937
-         | (0,0)      | (5.1,34.5) | 34.8749193547455
-         | (-10,0)    | (5.1,34.5) | 37.6597928831267
-         | (-5,-12)   | (5.1,34.5) | 47.5842410888311
-(15 rows)
+ fifteen |      point1      |      point2       |     distance     
+---------+------------------+-------------------+------------------
+         | (-3,4)           | (0,0)             |                5
+         | (-3,4)           | (1e-300,-1e-300)  |                5
+         | (-10,0)          | (-3,4)            | 8.06225774829855
+         | (-10,0)          | (0,0)             |               10
+         | (-10,0)          | (1e-300,-1e-300)  |               10
+         | (-10,0)          | (-5,-12)          |               13
+         | (-5,-12)         | (0,0)             |               13
+         | (-5,-12)         | (1e-300,-1e-300)  |               13
+         | (0,0)            | (10,10)           |  14.142135623731
+         | (1e-300,-1e-300) | (10,10)           |  14.142135623731
+         | (-3,4)           | (10,10)           | 14.3178210632764
+         | (-5,-12)         | (-3,4)            | 16.1245154965971
+         | (-10,0)          | (10,10)           | 22.3606797749979
+         | (5.1,34.5)       | (10,10)           | 24.9851956166046
+         | (-5,-12)         | (10,10)           | 26.6270539113887
+         | (-3,4)           | (5.1,34.5)        | 31.5572495632937
+         | (0,0)            | (5.1,34.5)        | 34.8749193547455
+         | (1e-300,-1e-300) | (5.1,34.5)        | 34.8749193547455
+         | (-10,0)          | (5.1,34.5)        | 37.6597928831267
+         | (-5,-12)         | (5.1,34.5)        | 47.5842410888311
+         | (-10,0)          | (1e+300,Infinity) |         Infinity
+         | (-5,-12)         | (1e+300,Infinity) |         Infinity
+         | (-3,4)           | (1e+300,Infinity) |         Infinity
+         | (0,0)            | (1e+300,Infinity) |         Infinity
+         | (1e-300,-1e-300) | (1e+300,Infinity) |         Infinity
+         | (5.1,34.5)       | (1e+300,Infinity) |         Infinity
+         | (10,10)          | (1e+300,Infinity) |         Infinity
+(27 rows)
 
 -- put distance result into output to allow sorting with GEQ optimizer - tgl 97/05/10
 SELECT '' AS three, p1.f1 AS point1, p2.f1 AS point2, (p1.f1 <-> p2.f1) AS distance
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3 and p1.f1 << p2.f1 and p1.f1 >^ p2.f1
    ORDER BY distance;
- three |   point1   |  point2  |     distance     
--------+------------+----------+------------------
-       | (-3,4)     | (0,0)    |                5
-       | (-10,0)    | (-5,-12) |               13
-       | (5.1,34.5) | (10,10)  | 24.9851956166046
-(3 rows)
+ three |   point1   |      point2      |     distance     
+-------+------------+------------------+------------------
+       | (-3,4)     | (0,0)            |                5
+       | (-3,4)     | (1e-300,-1e-300) |                5
+       | (-10,0)    | (-5,-12)         |               13
+       | (5.1,34.5) | (10,10)          | 24.9851956166046
+(4 rows)
 
 -- Test that GiST indexes provide same behavior as sequential scan
 CREATE TEMP TABLE point_gist_tbl(f1 point);
 INSERT INTO point_gist_tbl SELECT '(0,0)' FROM generate_series(0,1000);
 CREATE INDEX point_gist_tbl_index ON point_gist_tbl USING gist (f1);
 INSERT INTO point_gist_tbl VALUES ('(0.0000009,0.0000009)');
 SET enable_seqscan TO true;
 SET enable_indexscan TO false;
 SET enable_bitmapscan TO false;
 SELECT COUNT(*) FROM point_gist_tbl WHERE f1 ~= '(0.0000009,0.0000009)'::point;
diff --git a/src/test/regress/expected/polygon.out b/src/test/regress/expected/polygon.out
index 4a1f60427a..be5f76bf9d 100644
--- a/src/test/regress/expected/polygon.out
+++ b/src/test/regress/expected/polygon.out
@@ -1,18 +1,21 @@
 --
 -- POLYGON
 --
 -- polygon logic
 --
 CREATE TABLE POLYGON_TBL(f1 polygon);
 INSERT INTO POLYGON_TBL(f1) VALUES ('(2.0,0.0),(2.0,4.0),(0.0,0.0)');
 INSERT INTO POLYGON_TBL(f1) VALUES ('(3.0,1.0),(3.0,3.0),(1.0,0.0)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(3,4),(5,6),(7,8)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(7,8),(5,6),(3,4),(1,2)'); -- Reverse
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(7,8),(5,6),(3,-4)');
 -- degenerate polygons
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,0.0)');
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,1.0),(0.0,1.0)');
 -- bad polygon input strings
 INSERT INTO POLYGON_TBL(f1) VALUES ('0.0');
 ERROR:  invalid input syntax for type polygon: "0.0"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('0.0');
                                             ^
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0 0.0');
 ERROR:  invalid input syntax for type polygon: "(0.0 0.0"
@@ -24,215 +27,30 @@ LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2)');
                                             ^
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2,3');
 ERROR:  invalid input syntax for type polygon: "(0,1,2,3"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2,3');
                                             ^
 INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
 ERROR:  invalid input syntax for type polygon: "asdf"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
                                             ^
 SELECT '' AS four, * FROM POLYGON_TBL;
- four |         f1          
-------+---------------------
+ four |             f1             
+------+----------------------------
       | ((2,0),(2,4),(0,0))
       | ((3,1),(3,3),(1,0))
+      | ((1,2),(3,4),(5,6),(7,8))
+      | ((7,8),(5,6),(3,4),(1,2))
+      | ((1,2),(7,8),(5,6),(3,-4))
       | ((0,0))
       | ((0,1),(0,1))
-(4 rows)
-
--- overlap
-SELECT '' AS three, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 && '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- three |         f1          
--------+---------------------
-       | ((2,0),(2,4),(0,0))
-       | ((3,1),(3,3),(1,0))
-(2 rows)
-
--- left overlap
-SELECT '' AS four, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &< '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- four |         f1          
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
-
--- right overlap
-SELECT '' AS two, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- two |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- left of
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 << '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |      f1       
------+---------------
-     | ((0,0))
-     | ((0,1),(0,1))
-(2 rows)
-
--- right of
-SELECT '' AS zero, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 >> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- zero | f1 
-------+----
-(0 rows)
-
--- contained
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- same
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- contains
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
---
--- polygon logic
---
--- left of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- left overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
- true 
-------
- f
-(1 row)
-
--- right overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' &> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- right of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' >> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- contained in
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- contains
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((0,4),(6,4),(3,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
-SELECT '((1,1),(1,4),(5,4),(5,3),(2,3),(2,2),(5,2),(5,1))'::polygon @> '((3,2),(3,3),(4,3),(4,2))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((0,0),(0,3),(3,3),(3,0))'::polygon @> '((2,1),(2,2),(3,2),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
--- same
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' && polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
- true 
-------
- t
-(1 row)
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon && '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
-SELECT '((1,4),(1,1),(4,1),(4,2),(2,2),(2,4),(1,4))'::polygon && '((3,3),(4,3),(4,4),(3,4),(3,3))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((200,800),(800,800),(800,200),(200,200))' &&  '(1000,1000,0,0)'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
--- distance from a point
-SELECT	'(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
-	'(1,1)'::point <-> '((0,0),(2,2),(1,3))'::polygon as on_segment,
-	'(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;
- on_corner | on_segment | inside |   near_corner   | near_segment 
------------+------------+--------+-----------------+--------------
-         0 |          0 |      0 | 1.4142135623731 |          3.2
-(1 row)
+(7 rows)
 
 --
 -- 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
diff --git a/src/test/regress/sql/box.sql b/src/test/regress/sql/box.sql
index 135ac108eb..6710fc90f5 100644
--- a/src/test/regress/sql/box.sql
+++ b/src/test/regress/sql/box.sql
@@ -18,29 +18,38 @@
 
 -- boxes are specified by two points, given by four floats x1,y1,x2,y2
 
 
 CREATE TABLE BOX_TBL (f1 box);
 
 INSERT INTO BOX_TBL (f1) VALUES ('(2.0,2.0,0.0,0.0)');
 
 INSERT INTO BOX_TBL (f1) VALUES ('(1.0,1.0,3.0,3.0)');
 
+INSERT INTO BOX_TBL (f1) VALUES ('((-8, 2), (-2, -10))');
+
+
 -- degenerate cases where the box is a line or a point
 -- note that lines and points boxes all have zero area
 INSERT INTO BOX_TBL (f1) VALUES ('(2.5, 2.5, 2.5,3.5)');
 
 INSERT INTO BOX_TBL (f1) VALUES ('(3.0, 3.0,3.0,3.0)');
 
 -- badly formatted box inputs
 INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
 
+INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+
 INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
 
 
 SELECT '' AS four, * FROM BOX_TBL;
 
 SELECT '' AS four, b.*, area(b.f1) as barea
    FROM BOX_TBL b;
 
 -- overlap
 SELECT '' AS three, b.f1
diff --git a/src/test/regress/sql/circle.sql b/src/test/regress/sql/circle.sql
index c0284b2b59..46c96e1400 100644
--- a/src/test/regress/sql/circle.sql
+++ b/src/test/regress/sql/circle.sql
@@ -7,26 +7,34 @@ CREATE TABLE CIRCLE_TBL (f1 circle);
 INSERT INTO CIRCLE_TBL VALUES ('<(5,1),3>');
 
 INSERT INTO CIRCLE_TBL VALUES ('<(1,2),100>');
 
 INSERT INTO CIRCLE_TBL VALUES ('1,3,5');
 
 INSERT INTO CIRCLE_TBL VALUES ('((1,2),3)');
 
 INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10>');
 
-INSERT INTO CIRCLE_TBL VALUES ('<(100,1),115>');
+INSERT INTO CIRCLE_TBL VALUES (' < ( 100 , 1 ) , 115 > ');
+
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),0>');	-- Zero radius
+
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),NaN>');	-- NaN radius
 
 -- bad values
 
 INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
 
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+
 INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
 
 INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
 
 SELECT * FROM CIRCLE_TBL;
 
 SELECT '' AS six, center(f1) AS center
   FROM CIRCLE_TBL;
 
 SELECT '' AS six, radius(f1) AS radius
diff --git a/src/test/regress/sql/geometry.sql b/src/test/regress/sql/geometry.sql
index 1429ee772a..ce98b3e90c 100644
--- a/src/test/regress/sql/geometry.sql
+++ b/src/test/regress/sql/geometry.sql
@@ -39,74 +39,298 @@ SELECT '' AS two, p1.f1
 -- "is vertical" function
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE isvertical(p1.f1, point '(5.1,34.5)');
 
 -- "is vertical" operator
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?| point '(5.1,34.5)';
 
+-- Slope
+SELECT p1.f1, p2.f1, slope(p1.f1, p2.f1) FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Add point
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Subtract point
+SELECT p1.f1, p2.f1, p1.f1 - p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Multiply with point
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+
+-- Underflow error
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] < 1;
+
+-- Divide by point
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] BETWEEN 1 AND 1000;
+
+-- Overflow error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] > 1000;
+
+-- Division by 0 error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1 ~= '(0,0)'::point;
+
+-- Distance to line
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LINE_TBL l;
+
+-- Distance to line segment
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LSEG_TBL l;
+
+-- Distance to box
+SELECT p.f1, b.f1, p.f1 <-> b.f1 FROM POINT_TBL p, BOX_TBL b;
+
+-- Distance to path
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, PATH_TBL p1;
+
+-- Distance to polygon
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, POLYGON_TBL p1;
+
+-- Closest point to line
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LINE_TBL l;
+
+-- Closest point to line segment
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LSEG_TBL l;
+
+-- Closest point to box
+SELECT p.f1, b.f1, p.f1 ## b.f1 FROM POINT_TBL p, BOX_TBL b;
+
+-- On line
+SELECT p.f1, l.s FROM POINT_TBL p, LINE_TBL l WHERE p.f1 <@ l.s;
+
+-- On line segment
+SELECT p.f1, l.s FROM POINT_TBL p, LSEG_TBL l WHERE p.f1 <@ l.s;
+
+-- On path
+SELECT p.f1, p1.f1 FROM POINT_TBL p, PATH_TBL p1 WHERE p.f1 <@ p1.f1;
+
+--
+-- Lines
+--
+
+-- Vertical
+SELECT s FROM LINE_TBL WHERE ?| s;
+
+-- Horizontal
+SELECT s FROM LINE_TBL WHERE ?- s;
+
+-- Same as line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s = l2.s;
+
+-- Parallel to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?|| l2.s;
+
+-- Perpendicular to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?-| l2.s;
+
+-- Distance to line
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2;
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LINE_TBL l, BOX_TBL b;
+
+-- Intersect with line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?# l2.s;
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LINE_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+
+-- Intersection point with line
+SELECT l1.s, l2.s, l1.s # l2.s FROM LINE_TBL l1, LINE_TBL l2;
+
+-- Closest point to line segment
+SELECT l.s, l1.s, l.s ## l1.s FROM LINE_TBL l, LSEG_TBL l1;
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LINE_TBL l, BOX_TBL b;
+
 --
 -- Line segments
 --
 
 -- intersection
 SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
    FROM LSEG_TBL l, POINT_TBL p;
 
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
+-- Length
+SELECT s, @-@ s FROM LSEG_TBL;
+
+-- Vertical
+SELECT s FROM LSEG_TBL WHERE ?| s;
+
+-- Horizontal
+SELECT s FROM LSEG_TBL WHERE ?- s;
+
+-- Center
+SELECT s, @@ s FROM LSEG_TBL;
+
+-- To point
+SELECT s, s::point FROM LSEG_TBL;
+
+-- Has points less than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s < l2.s;
+
+-- Has points less than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s <= l2.s;
+
+-- Has points equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s = l2.s;
+
+-- Has points greater than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s >= l2.s;
+
+-- Has points greater than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s > l2.s;
+
+-- Has points not equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s != l2.s;
+
+-- Parallel with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?|| l2.s;
+
+-- Perpendicular with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?-| l2.s;
+
+-- Distance to line
+SELECT l.s, l1.s, l.s <-> l1.s FROM LSEG_TBL l, LINE_TBL l1;
+
+-- Distance to line segment
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LSEG_TBL l, BOX_TBL b;
+
+-- Intersect with line segment
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s ?# l1.s;
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+
+-- Intersection point with line segment
+SELECT l1.s, l2.s, l1.s # l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Closest point to line
+SELECT l.s, l1.s, l.s ## l1.s FROM LSEG_TBL l, LINE_TBL l1;
+
+-- Closest point to line segment
+SELECT l1.s, l2.s, l1.s ## l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LSEG_TBL l, BOX_TBL b;
+
+-- On line
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s <@ l1.s;
+
+-- On box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s <@ b.f1;
 
 --
 -- Boxes
 --
 
 SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
 
 -- translation
 SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
 
 SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
 
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
+-- Multiply with point
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
 
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
+-- Overflow error
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] > 1000;
 
+-- Divide by point
+SELECT b.f1, p.f1, b.f1 / p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+
+-- To box
 SELECT f1::box
 	FROM POINT_TBL;
 
 SELECT bound_box(a.f1, b.f1)
 	FROM BOX_TBL a, BOX_TBL b;
 
+-- Below box
+SELECT b1.f1, b2.f1, b1.f1 <^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Above box
+SELECT b1.f1, b2.f1, b1.f1 >^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Intersection point with box
+SELECT b1.f1, b2.f1, b1.f1 # b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Diagonal
+SELECT f1, diagonal(f1) FROM BOX_TBL;
+
+-- Distance to box
+SELECT b1.f1, b2.f1, b1.f1 <-> b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
 --
 -- Paths
 --
 
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
+-- Points
+SELECT f1, npoints(f1) FROM PATH_TBL;
 
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
+-- Area
+SELECT f1, area(f1) FROM PATH_TBL;
 
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
+-- Length
+SELECT f1, @-@ f1 FROM PATH_TBL;
 
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
+-- Center
+SELECT f1, @@ f1 FROM PATH_TBL;
+
+-- To polygon
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isclosed(f1);
+
+-- Open path cannot be converted to polygon error
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isopen(f1);
+
+-- Has points less than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 < p2.f1;
+
+-- Has points less than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 <= p2.f1;
+
+-- Has points equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 = p2.f1;
+
+-- Has points greater than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 >= p2.f1;
+
+-- Has points greater than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 > p2.f1;
+
+-- Add path
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+
+-- Add point
+SELECT p.f1, p1.f1, p.f1 + p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+
+-- Subtract point
+SELECT p.f1, p1.f1, p.f1 - p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+
+-- Multiply with point
+SELECT p.f1, p1.f1, p.f1 * p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+
+-- Divide by point
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+
+-- Division by 0 error
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1 ~= '(0,0)'::point;
+
+-- Distance to path
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
 
 --
 -- Polygons
 --
 
 -- containment
 SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
    FROM POLYGON_TBL poly, POINT_TBL p;
 
 SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
@@ -118,36 +342,166 @@ SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
 SELECT '' AS four, polygon(f1)
    FROM BOX_TBL;
 
 SELECT '' AS four, polygon(f1)
    FROM PATH_TBL WHERE isclosed(f1);
 
 SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
    FROM PATH_TBL
    WHERE isopen(f1);
 
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
+-- To box
+SELECT f1, f1::box FROM POLYGON_TBL;
 
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
+-- To path
+SELECT f1, f1::path FROM POLYGON_TBL;
+
+-- Same as polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 ~= p2.f1;
+
+-- Contained by polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <@ p2.f1;
+
+-- Contains polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 @> p2.f1;
+
+-- Overlap with polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 && p2.f1;
+
+-- Left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 << p2.f1;
+
+-- Overlap of left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &< p2.f1;
+
+-- Right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 >> p2.f1;
+
+-- Overlap of right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &> p2.f1;
+
+-- Below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <<| p2.f1;
+
+-- Overlap or below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &<| p2.f1;
+
+-- Above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |>> p2.f1;
+
+-- Overlap or above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |&> p2.f1;
+
+-- Distance to polygon
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2;
 
 --
 -- Circles
 --
 
 SELECT '' AS six, circle(f1, 50.0)
    FROM POINT_TBL;
 
 SELECT '' AS four, circle(f1)
    FROM BOX_TBL;
 
 SELECT '' AS two, circle(f1)
    FROM POLYGON_TBL
    WHERE (# f1) >= 3;
 
 SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
    FROM CIRCLE_TBL c1, POINT_TBL p1
    WHERE (p1.f1 <-> c1.f1) > 0
    ORDER BY distance, area(c1.f1), p1.f1[0];
+
+-- To polygon
+SELECT f1, f1::polygon FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+
+-- To polygon with less points
+SELECT f1, polygon(8, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+
+-- Too less points error
+SELECT f1, polygon(1, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+
+-- Zero radius error
+SELECT f1, polygon(10, f1) FROM CIRCLE_TBL WHERE f1 < '<(0,0),1>';
+
+-- Same as circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 ~= c2.f1;
+
+-- Overlap with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 && c2.f1;
+
+-- Overlap or left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &< c2.f1;
+
+-- Left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 << c2.f1;
+
+-- Right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >> c2.f1;
+
+-- Overlap or right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &> c2.f1;
+
+-- Contained by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <@ c2.f1;
+
+-- Contain by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 @> c2.f1;
+
+-- Below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <<| c2.f1;
+
+-- Above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |>> c2.f1;
+
+-- Overlap or below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &<| c2.f1;
+
+-- Overlap or above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |&> c2.f1;
+
+-- Area equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 = c2.f1;
+
+-- Area not equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 != c2.f1;
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 > c2.f1;
+
+-- Area less than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <= c2.f1;
+
+-- Area greater than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >= c2.f1;
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+
+-- Add point
+SELECT c.f1, p.f1, c.f1 + p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Subtract point
+SELECT c.f1, p.f1, c.f1 - p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Multiply with point
+SELECT c.f1, p.f1, c.f1 * p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Divide by point
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+
+-- Overflow error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] > 1000;
+
+-- Division by 0 error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1 ~= '(0,0)'::point;
+
+-- Distance to polygon
+SELECT c.f1, p.f1, c.f1 <-> p.f1 FROM CIRCLE_TBL c, POLYGON_TBL p;
diff --git a/src/test/regress/sql/line.sql b/src/test/regress/sql/line.sql
index 94067b0cee..4a985020d7 100644
--- a/src/test/regress/sql/line.sql
+++ b/src/test/regress/sql/line.sql
@@ -1,87 +1,39 @@
 --
 -- LINE
 -- Infinite lines
 --
 
 --DROP TABLE LINE_TBL;
 CREATE TABLE LINE_TBL (s line);
 
-INSERT INTO LINE_TBL VALUES ('{1,-1,1}');
-INSERT INTO LINE_TBL VALUES ('(0,0),(6,6)');
+INSERT INTO LINE_TBL VALUES ('{0,-1,5}');	-- A == 0
+INSERT INTO LINE_TBL VALUES ('{1,0,5}');	-- B == 0
+INSERT INTO LINE_TBL VALUES ('{0,3,0}');	-- A == C == 0
+INSERT INTO LINE_TBL VALUES (' (0,0), (6,6)');
 INSERT INTO LINE_TBL VALUES ('10,-10 ,-5,-4');
 INSERT INTO LINE_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LINE_TBL VALUES ('(11,22,33,44)');
 
-INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
+INSERT INTO LINE_TBL VALUES (line(point '(1,0)', point '(1,0)'));
+
+INSERT INTO LINE_TBL VALUES ('{3,NaN,5}');
+INSERT INTO LINE_TBL VALUES ('{NaN,NaN,NaN}');
 
 -- horizontal
 INSERT INTO LINE_TBL VALUES ('[(1,3),(2,3)]');
 -- vertical
 INSERT INTO LINE_TBL VALUES ('[(3,1),(3,2)]');
 
 -- bad values for parser testing
+INSERT INTO LINE_TBL VALUES ('{}');
+INSERT INTO LINE_TBL VALUES ('{0');
+INSERT INTO LINE_TBL VALUES ('{0,0}');
+INSERT INTO LINE_TBL VALUES ('{0,0,1');
 INSERT INTO LINE_TBL VALUES ('{0,0,1}');
+INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
 INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
 INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
 INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
 INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
+INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
 
 select * from LINE_TBL;
-
-
--- functions and operators
-
-SELECT * FROM LINE_TBL WHERE (s <-> line '[(1,2),(3,4)]') < 10;
-
-SELECT * FROM LINE_TBL WHERE (point '(0.1,0.1)' <-> s) < 1;
-
-SELECT * FROM LINE_TBL WHERE (lseg '[(0.1,0.1),(0.2,0.2)]' <-> s) < 1;
-
-SELECT line '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
-SELECT lseg '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
-SELECT point '(-1,1)' <-> line '[(-3,0),(-4,0)]';
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(2,0),(0,2)]';  -- true
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(0,0),(1,0)]';  -- false
-
-SELECT line '[(0,0),(1,1)]' ?# box '(0,0,2,2)';  -- true
-SELECT line '[(3,0),(4,1)]' ?# box '(0,0,2,2)';  -- false
-
-SELECT point '(1,1)' <@ line '[(0,0),(2,2)]';  -- true
-SELECT point '(1,1)' <@ line '[(0,0),(1,0)]';  -- false
-
-SELECT point '(1,1)' @ line '[(0,0),(2,2)]';  -- true
-SELECT point '(1,1)' @ line '[(0,0),(1,0)]';  -- false
-
-SELECT lseg '[(1,1),(2,2)]' <@ line '[(0,0),(2,2)]';  -- true
-SELECT lseg '[(1,1),(2,1)]' <@ line '[(0,0),(1,0)]';  -- false
-
-SELECT lseg '[(1,1),(2,2)]' @ line '[(0,0),(2,2)]';  -- true
-SELECT lseg '[(1,1),(2,1)]' @ line '[(0,0),(1,0)]';  -- false
-
-SELECT point '(0,1)' ## line '[(0,0),(1,1)]';
-
-SELECT line '[(0,0),(1,1)]' ## lseg '[(1,0),(2,0)]';
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(2,1)]';  -- false
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(1,1)]';  -- true
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(2,1)]';
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(1,1)]';
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(2,1)]';  -- true
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(1,1)]';  -- false
-
-SELECT line '[(0,0),(1,0)]' ?-| line '[(0,0),(0,1)]';  -- true
-SELECT line '[(0,0),(1,1)]' ?-| line '[(1,0),(1,1)]';  -- false
-
-SELECT ?- line '[(0,0),(1,0)]';  -- true
-SELECT ?- line '[(0,0),(1,1)]';  -- false
-
-SELECT ?| line '[(0,0),(0,1)]';  -- true
-SELECT ?| line '[(0,0),(1,1)]';  -- false
-
-SELECT line(point '(1,2)', point '(3,4)');
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,5)]';  -- true
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,4)]';  -- false
diff --git a/src/test/regress/sql/lseg.sql b/src/test/regress/sql/lseg.sql
index 07c5a29e0a..f266ca3e09 100644
--- a/src/test/regress/sql/lseg.sql
+++ b/src/test/regress/sql/lseg.sql
@@ -3,23 +3,22 @@
 -- Line segments
 --
 
 --DROP TABLE LSEG_TBL;
 CREATE TABLE LSEG_TBL (s lseg);
 
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('(0,0),(6,6)');
 INSERT INTO LSEG_TBL VALUES ('10,-10 ,-3,-4');
 INSERT INTO LSEG_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LSEG_TBL VALUES ('(11,22,33,44)');
+INSERT INTO LSEG_TBL VALUES (lseg(point(11, 22), point(33,44)));
+INSERT INTO LSEG_TBL VALUES ('[(-10,2),(-10,3)]');	-- vertical
+INSERT INTO LSEG_TBL VALUES ('[(0,-20),(30,-20)]');	-- horizontal
+INSERT INTO LSEG_TBL VALUES ('[(NaN,1),(NaN,90)]');	-- NaN
 
 -- bad values for parser testing
 INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
 INSERT INTO LSEG_TBL VALUES ('[1,2,3, 4');
 INSERT INTO LSEG_TBL VALUES ('[(,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)');
 
 select * from LSEG_TBL;
-
-SELECT * FROM LSEG_TBL WHERE s <= lseg '[(1,2),(3,4)]';
-
-SELECT * FROM LSEG_TBL WHERE (s <-> lseg '[(1,2),(3,4)]') < 10;
diff --git a/src/test/regress/sql/path.sql b/src/test/regress/sql/path.sql
index 7e69b539ad..318decf974 100644
--- a/src/test/regress/sql/path.sql
+++ b/src/test/regress/sql/path.sql
@@ -1,38 +1,44 @@
 --
 -- PATH
 --
 
 --DROP TABLE PATH_TBL;
 
 CREATE TABLE PATH_TBL (f1 path);
 
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)]');
 
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
+INSERT INTO PATH_TBL VALUES (' ( ( 1 , 2 ) , ( 3 , 4 ) ) ');
 
-INSERT INTO PATH_TBL VALUES ('[(0,0),(3,0),(4,5),(1,6)]');
+INSERT INTO PATH_TBL VALUES ('[ (0,0),(3,0),(4,5),(1,6) ]');
 
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
+INSERT INTO PATH_TBL VALUES ('((1,2) ,(3,4 ))');
 
-INSERT INTO PATH_TBL VALUES ('1,2 ,3,4');
+INSERT INTO PATH_TBL VALUES ('1,2 ,3,4 ');
 
-INSERT INTO PATH_TBL VALUES ('[1,2,3, 4]');
+INSERT INTO PATH_TBL VALUES (' [1,2,3, 4] ');
 
-INSERT INTO PATH_TBL VALUES ('[11,12,13,14]');
+INSERT INTO PATH_TBL VALUES ('((10,20))');	-- Only one point
 
-INSERT INTO PATH_TBL VALUES ('(11,12,13,14)');
+INSERT INTO PATH_TBL VALUES ('[ 11,12,13,14 ]');
+
+INSERT INTO PATH_TBL VALUES ('( 11,12,13,14) ');
 
 -- bad values for parser testing
+INSERT INTO PATH_TBL VALUES ('[]');
+
 INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
 
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
 
-SELECT f1 FROM PATH_TBL;
+INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+
+INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
 
 SELECT '' AS count, f1 AS open_path FROM PATH_TBL WHERE isopen(f1);
 
 SELECT '' AS count, f1 AS closed_path FROM PATH_TBL WHERE isclosed(f1);
 
 SELECT '' AS count, pclose(f1) AS closed_path FROM PATH_TBL;
 
 SELECT '' AS count, popen(f1) AS open_path FROM PATH_TBL;
diff --git a/src/test/regress/sql/point.sql b/src/test/regress/sql/point.sql
index 63a803a809..a209f3bfeb 100644
--- a/src/test/regress/sql/point.sql
+++ b/src/test/regress/sql/point.sql
@@ -7,29 +7,39 @@ CREATE TABLE POINT_TBL(f1 point);
 INSERT INTO POINT_TBL(f1) VALUES ('(0.0,0.0)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-10.0,0.0)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-3.0,4.0)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(5.1, 34.5)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-5.0,-12.0)');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(1e-300,-1e-300)');	-- To underflow
+
+INSERT INTO POINT_TBL(f1) VALUES ('(1e+300,Inf)');		-- To overflow
+
+INSERT INTO POINT_TBL(f1) VALUES (' ( Nan , NaN ) ');
+
 -- bad format points
 INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
 
 INSERT INTO POINT_TBL(f1) VALUES ('10.0,10.0');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');	-- Out of range
+
 
 SELECT '' AS six, * FROM POINT_TBL;
 
 -- left of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE p.f1 << '(0.0, 0.0)';
 
 -- right of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE '(0.0,0.0)' >> p.f1;
 
 -- above
diff --git a/src/test/regress/sql/polygon.sql b/src/test/regress/sql/polygon.sql
index 7e8cb08cd8..d3d2fe3457 100644
--- a/src/test/regress/sql/polygon.sql
+++ b/src/test/regress/sql/polygon.sql
@@ -4,126 +4,43 @@
 -- polygon logic
 --
 
 CREATE TABLE POLYGON_TBL(f1 polygon);
 
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(2.0,0.0),(2.0,4.0),(0.0,0.0)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(3.0,1.0),(3.0,3.0),(1.0,0.0)');
 
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(3,4),(5,6),(7,8)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(7,8),(5,6),(3,4),(1,2)'); -- Reverse
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(7,8),(5,6),(3,-4)');
+
 -- degenerate polygons
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,0.0)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,1.0),(0.0,1.0)');
 
 -- bad polygon input strings
 INSERT INTO POLYGON_TBL(f1) VALUES ('0.0');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0 0.0');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2,3');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
 
 
 SELECT '' AS four, * FROM POLYGON_TBL;
 
--- overlap
-SELECT '' AS three, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 && '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- left overlap
-SELECT '' AS four, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &< '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- right overlap
-SELECT '' AS two, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- left of
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 << '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- right of
-SELECT '' AS zero, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 >> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- contained
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- same
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- contains
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
---
--- polygon logic
---
--- left of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- left overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
-
--- right overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' &> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- right of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' >> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- contained in
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- contains
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "false";
-
-SELECT '((0,4),(6,4),(3,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
-
-SELECT '((1,1),(1,4),(5,4),(5,3),(2,3),(2,2),(5,2),(5,1))'::polygon @> '((3,2),(3,3),(4,3),(4,2))'::polygon AS "false";
-
-SELECT '((0,0),(0,3),(3,3),(3,0))'::polygon @> '((2,1),(2,2),(3,2),(3,1))'::polygon AS "true";
-
--- same
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' && polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon && '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
-
-SELECT '((1,4),(1,1),(4,1),(4,2),(2,2),(2,4),(1,4))'::polygon && '((3,3),(4,3),(4,4),(3,4),(3,3))'::polygon AS "false";
-SELECT '((200,800),(800,800),(800,200),(200,200))' &&  '(1000,1000,0,0)'::polygon AS "true";
-
--- distance from a point
-SELECT	'(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
-	'(1,1)'::point <-> '((0,0),(2,2),(1,3))'::polygon as on_segment,
-	'(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;
-- 
2.14.3 (Apple Git-98)

#38Kyotaro HORIGUCHI
horiguchi.kyotaro@lab.ntt.co.jp
In reply to: Emre Hasegeli (#37)
Re: [HACKERS] [PATCH] Improve geometric types

Hello, sorry for the absense.

(Sorry for the long but should be hard-to-read article..)

At Thu, 4 Jan 2018 14:53:47 +0100, Emre Hasegeli <emre@hasegeli.com> wrote in <CAE2gYzz0hRfC-M8KDV4Aytj+6k6cvoiGqVvEjVyHTbtraf=YBQ@mail.gmail.com>

Rebased versions are attached.

Thank you for the new patch.

I'm looking 0001 patch. This does many things at once but seems
hard to split into step-by-step patches. So I reviewed this from
the viewpoint that how each of the external function is
changed. (Attatchment 1).

I think that this patch is not intending to change any behaviors
of the external functions, but intending make it mathematically
reasonable. So some behavioral changes are ineviablly
requried. The problem here is what is the most reasonable (and
acceptable) behavior.

The comments below are just the starting of a discussion about
some aspects of design. I'm sorry that this discussion might be
changing the way to go largily, but I'd like to hear what you
think about two topics.

I found seemingly inconsistent handling of NaN.

- Old box_same assumed NaN != NaN, but new assumes NaN ==
NaN. I'm not sure how the difference is significant out of the
context of sorting, though...

- box_overlap()'s behavior has not been changed. As the result
box_same and box_overlap now behaves differently concerning
NaN handling.

- line_construct_pts has been changed so that generates
{NaN,-1,NaN} for two identical points (old code generated
{-1,0,0}) but I think the right behavior here is erroring out.
(as line_in behaves.)

I feel that it'd better to define how to handle non-numbers
before refactoring. I prefer to just denying NaN as a part of
the geometric types, or any input containing NaN just yields a
result filled with NaNs.

The next point is reasonability of the algorithm and consistency
among related functions.

- line_parallel considers the EPSILON(ugaa) with different scale
from the old code, but both don't seem reasonable.. It might
not be the time to touch it, but if we changed the behavior,
I'd like to choose reasonable one. At least the tolerance of
parallelity should be taken by rotation, not by slope.

I think that one reasonable way to do this is taking the distance
between the far ends of two direction (unit) vectors.

Assuming Ax + By + C = 0, the direction vecotr dv(x, y) for the
line is:

n = sqrt(A^2 + B^2), dv = (B / n, -A / n).

(and the normal vector nv = (A / n, B / n))

The vector needs to be restricted within upper or any two
successive quadrants so that it is usable for this objective. So
let's restrict A to be negative value for now. Something like the
follwoing would be an answer.

void line_direction_vector(Point *result, LINE *l)
{
float8 A = l->A;
float8 B = l->B;
float8 n;

n = HYPOT(A, B);

/* keep the result vector within the 1st-2nd quadrants */
if (A > 0)
{
A = -A;
B = -B;
}
point_construct(result, B / n, -A / n);
}

bool line_parallel(LINE *l1, LINE *l2)
{
Point d1, d2;

line_direction_vector(&d1, l1);
line_direction_vector(&d2, l2);
return FPzero(point_dt(&d1, &d2));
}

Also perpendicularity is detected by comparing the direction
vector of one line and the normal vector of another in the same
manner.

void line_normal_vector(Point *result, LINE *l)
{
float8 A = l->A;
float8 B = l->B;
float8 n;

/* keep the result vector within the 1st-2nd quadrants */
n = HYPOT(A, B);
if (B < 0)
{
A = -A;
B = -B;
}
point_construct(result, A / n, B / n);
}

bool line_perp(LINE *l1, LINE *l2)
{
Point d1, d2;

line_direction_vector(&d1, l1);
line_normal_vector(&d2, l2);
return FPzero(point_dt(&d1, &d2));
}

In relation to this, equality of two lines is also nuisance.
From the definitions, two equal lines are parallel. In
contraposition, two nonparallel lines cannot be equal. This
relationship is represented by the following expression:

is_equal =: line_parallel(l1, l2) && FPzero(line_distance(l1, l2))

But the line_distance returns zero in most cases even if it is
considered "parallel" with considering tolerance. This means that
There's almost no two lines that are parallel but not equal (that
is, the truely parallel lines)... sigh.

So we might should calculate the distance in different (not
purely mathematical/geometrical) way. For example, if we can
assume the geometric objects are placed mainly around the origin,
we could take the distance between the points nearest to origin
on both lines. (In other words, between the foots of
perpendicular lines from the origin onto the both lines). Of
couse this is not ideal but...

The same discussion also affects line_interpt_line or other
similar functions.

At last, just a simple comment.

- point_eq_point() assumes that NaN == NaN. This is an inherited
behavior from old float[48]_cmp_internal() but it's not a
common treat. point_eq_point() needs any comment about the
special definition as float[48]_cmp_internal has.

regards,

--
Kyotaro Horiguchi
NTT Open Source Software Center

#39Emre Hasegeli
emre@hasegeli.com
In reply to: Kyotaro HORIGUCHI (#38)
Re: [HACKERS] [PATCH] Improve geometric types

I found seemingly inconsistent handling of NaN.

- Old box_same assumed NaN != NaN, but new assumes NaN ==
NaN. I'm not sure how the difference is significant out of the
context of sorting, though...

There is no box != box operator. If there was one, previous code
would return false for every input including NaN, because it was
ignorant about NaNs other than a few bandaids to avoid crashes.

My idea is to make the equality (same) operators behave like the float
datatypes treating NaNs as equals. The float datatypes also treat
NaNs as greater than any non-NAN. We don't need to worry about this
part now, because there are no basic comparison operators defined for
the geometric types.

- box_overlap()'s behavior has not been changed. As the result
box_same and box_overlap now behaves differently concerning
NaN handling.

After your previous email, I though this would be the right thing to
do. I made the containment and placement operators return false for
NaN input unless we can find the result using non-NaN coordinates. Do
you find this behaviour reasonable?

- line_construct_pts has been changed so that generates
{NaN,-1,NaN} for two identical points (old code generated
{-1,0,0}) but I think the right behavior here is erroring out.
(as line_in behaves.)

I agree. We should also check for the endpoints being the same on
lseg_interpt functions. I will make the changes on the next version.

I feel that it'd better to define how to handle non-numbers
before refactoring. I prefer to just denying NaN as a part of
the geometric types, or any input containing NaN just yields a
result filled with NaNs.

It would be nice to deny NaNs altogether, but I don't think it is
feasible. People cannot restore their existing data if we start doing
that. It would also require us to check any result we emit being NaN
and error out in more cases.

The next point is reasonability of the algorithm and consistency
among related functions.

- line_parallel considers the EPSILON(ugaa) with different scale
from the old code, but both don't seem reasonable.. It might
not be the time to touch it, but if we changed the behavior,
I'd like to choose reasonable one. At least the tolerance of
parallelity should be taken by rotation, not by slope.

I think you are right. Vector based algorithms would be good for many
other operations as well. This would be more changes, though. I am
try to reduce the amount of changes to increase my chances to get this
committed. I just used slope() there to increase the code reuse and
to make the operation symmetrical. I can revert it back to its
previous state, if you thing it is better.

So we might should calculate the distance in different (not
purely mathematical/geometrical) way. For example, if we can
assume the geometric objects are placed mainly around the origin,
we could take the distance between the points nearest to origin
on both lines. (In other words, between the foots of
perpendicular lines from the origin onto the both lines). Of
couse this is not ideal but...

The EPSILON is unfair to coordinates closer to the origin. I am not
sure what it the best way to improve this. I am trying to avoid
dealing with EPSILON related issues in the scope of these changes.

At last, just a simple comment.

- point_eq_point() assumes that NaN == NaN. This is an inherited
behavior from old float[48]_cmp_internal() but it's not a
common treat. point_eq_point() needs any comment about the
special definition as float[48]_cmp_internal has.

I hope I answered this on the previous questions. I will incorporate
the decision to threat NaNs as equals into the comments and the commit
messages on the next version, if we agree on it.

#40Kyotaro HORIGUCHI
horiguchi.kyotaro@lab.ntt.co.jp
In reply to: Emre Hasegeli (#39)
Re: [HACKERS] [PATCH] Improve geometric types

Hello,

I'm still wandering on the way and confused. Sorry for
inconsistent comments in advanceX-(

At Sun, 14 Jan 2018 13:20:57 +0100, Emre Hasegeli <emre@hasegeli.com> wrote in <CAE2gYzyY3U4n1Zn48qG6dL=FWgv29yag5PdGV2Gc17w9Toeaog@mail.gmail.com>

I found seemingly inconsistent handling of NaN.

- Old box_same assumed NaN != NaN, but new assumes NaN ==
NaN. I'm not sure how the difference is significant out of the
context of sorting, though...

There is no box != box operator. If there was one, previous code
would return false for every input including NaN, because it was
ignorant about NaNs other than a few bandaids to avoid crashes.

My idea is to make the equality (same) operators behave like the float
datatypes treating NaNs as equals. The float datatypes also treat
NaNs as greater than any non-NAN. We don't need to worry about this
part now, because there are no basic comparison operators defined for
the geometric types.

I'm not sure what you mean by the "basic comparison ops" but I'm
fine with the policy, handling each component values in the same
way with float. So point_eq_point() is right and other functions
should follow the same policy.

- box_overlap()'s behavior has not been changed. As the result
box_same and box_overlap now behaves differently concerning
NaN handling.

After your previous email, I though this would be the right thing to
do. I made the containment and placement operators return false for
NaN input unless we can find the result using non-NaN coordinates. Do
you find this behaviour reasonable?

Sorry for going back and force, but I don't see a difference
between it and the original behavior from the point of view of
reasonability. Isn't is enough to let each component comparison
follow float by redefining FPxx() functions?

For example, define FPle as the follwoing:

static inline bool FP8le(float8 a, float8 b)
{
return float8_le(a, float8_pl(b, EPSILON));
}

Then define box_ov using this function:

static bool box_ov(BOX *box1, BOX *box2)
{
return (FP8le(box1->low.x, box2->high.x) &&....);
}

Another example, define FPeq as:

static inline bool FP8eq(float8 a, float8 b)
{
if (isnan(a))
{
if (isnan(b))
return true;
return false;
}
else if (isnan(b))
return false;

if (isinf(a) && isinf(b))
return true;

return abs(a - b) <= EPSILON;
}

Then redefine point_eq_point as:

statinc inline bool
point_eq_point(Point *pt1, Point *pt2)
{
return FP8eq(pt1->x, pt2->x) && FP8eq(pt1->y, pt2->y);
}

...

At least this is in a kind of consistency and the behavior is
inferable (in a certain sense).

- line_construct_pts has been changed so that generates
{NaN,-1,NaN} for two identical points (old code generated
{-1,0,0}) but I think the right behavior here is erroring out.
(as line_in behaves.)

I agree. We should also check for the endpoints being the same on
lseg_interpt functions. I will make the changes on the next version.

I feel that it'd better to define how to handle non-numbers
before refactoring. I prefer to just denying NaN as a part of
the geometric types, or any input containing NaN just yields a
result filled with NaNs.

It would be nice to deny NaNs altogether, but I don't think it is
feasible. People cannot restore their existing data if we start doing
that. It would also require us to check any result we emit being NaN
and error out in more cases.

It sounds right.

The next point is reasonability of the algorithm and consistency
among related functions.

- line_parallel considers the EPSILON(ugaa) with different scale
from the old code, but both don't seem reasonable.. It might
not be the time to touch it, but if we changed the behavior,
I'd like to choose reasonable one. At least the tolerance of
parallelity should be taken by rotation, not by slope.

I think you are right. Vector based algorithms would be good for many
other operations as well. This would be more changes, though. I am
try to reduce the amount of changes to increase my chances to get this
committed. I just used slope() there to increase the code reuse and
to make the operation symmetrical. I can revert it back to its
previous state, if you thing it is better.

I'm fine with both using slope with the same scale (that is,
keeping the previous behavior) or going into vector based. But
the latter raises a problem as below:(

So we might should calculate the distance in different (not
purely mathematical/geometrical) way. For example, if we can
assume the geometric objects are placed mainly around the origin,
we could take the distance between the points nearest to origin
on both lines. (In other words, between the foots of
perpendicular lines from the origin onto the both lines). Of
couse this is not ideal but...

The EPSILON is unfair to coordinates closer to the origin. I am not
sure what it the best way to improve this. I am trying to avoid
dealing with EPSILON related issues in the scope of these changes.

Right. And I don't have a good idea here..

At last, just a simple comment.

- point_eq_point() assumes that NaN == NaN. This is an inherited
behavior from old float[48]_cmp_internal() but it's not a
common treat. point_eq_point() needs any comment about the
special definition as float[48]_cmp_internal has.

I hope I answered this on the previous questions. I will incorporate
the decision to threat NaNs as equals into the comments and the commit
messages on the next version, if we agree on it.

Perhas it's fine for me.

regards,

--
Kyotaro Horiguchi
NTT Open Source Software Center

#41Emre Hasegeli
emre@hasegeli.com
In reply to: Kyotaro HORIGUCHI (#40)
Re: [HACKERS] [PATCH] Improve geometric types

I'm not sure what you mean by the "basic comparison ops" but I'm
fine with the policy, handling each component values in the same
way with float. So point_eq_point() is right and other functions
should follow the same policy.

I mean <, >, <= and >= by basic comparison operators. Operators with
those symbols are available for some geometric types, but they are
comparing the sizes of the objects. Currently only the equality
operators follow the same policy with point_eq_point (), others never
return true when NaNs are involved.

Sorry for going back and force, but I don't see a difference
between it and the original behavior from the point of view of
reasonability. Isn't is enough to let each component comparison
follow float by redefining FPxx() functions?

My previous patch was doing exactly that. I though that is not what
we want to do. Do we want box_overlap() to return true when NaNs are
involved?

#42Kyotaro HORIGUCHI
horiguchi.kyotaro@lab.ntt.co.jp
In reply to: Emre Hasegeli (#41)
Re: [HACKERS] [PATCH] Improve geometric types

Hello,

I played more around geometric types and recalled that geometric
types don't have orderings. Also have corrected some other
misunderstanding. Sorry for my confusion and I think I returned
on the way.

At Wed, 17 Jan 2018 18:59:30 +0100, Emre Hasegeli <emre@hasegeli.com> wrote in <CAE2gYzzgJ7B-HdmxuSDoqu-_x1nEeoEA45is2hP8ex4r3KNH8Q@mail.gmail.com>

I'm not sure what you mean by the "basic comparison ops" but I'm
fine with the policy, handling each component values in the same
way with float. So point_eq_point() is right and other functions
should follow the same policy.

I mean <, >, <= and >= by basic comparison operators. Operators with
those symbols are available for some geometric types, but they are
comparing the sizes of the objects. Currently only the equality
operators follow the same policy with point_eq_point (), others never
return true when NaNs are involved.

Sorry for going back and force, but I don't see a difference
between it and the original behavior from the point of view of
reasonability. Isn't is enough to let each component comparison
follow float by redefining FPxx() functions?

My previous patch was doing exactly that. I though that is not what
we want to do. Do we want box_overlap() to return true when NaNs are
involved?

All comparison operators don't need consideration on
ordering. And the existing comparison operators behaves
diferrently from float and already behaves in the way of bare
float. There's no behavior as the whole of an object. I have
fixed my understanding as this. (And I saw all patches altoghter
by mistake..) As the result most my concern was pointless.

0001:

- You removed the check of parallelity check of
line_interpt_line(old line_interpt_internal) but line_parallel
is not changed so the consistency between the two functions are
lost. It is better to be another patch file (maybe 0004?).

- + Assert(p1->npts > 0 && p2->npts > 0);

Other path_ functions are allowing path with no points so just
returning false if (p1->npts == 0 || p2->npts == 0) seems
enough. Assertion should be used only for something server
cannot continue working. (division by zero doesn't crash
server) I saw other similar assertions in the patch.

0002: I have no comment so far on this patch.

0003:

close_pl/ps/lseg/pb/ls/sb have changed to return null when
lseg_closept_line returns NAN, but they are defined as strict
and that is reasonable. Anyway pg_hypot returns NaN only when
parameters contain INF or NAN so we should error out when it
returns nan.

circle_in rejects negative radius and circle_recv modived to
reject zero and negative. What is the reason for the change?

I understand that we don't need to consider NAN is equal to NAN.
circle_same, point_eq_point, line_eq no longer needs such
change?

Assertion is added in pg_hypot but it is impossible for result
to be negative there. Why do you added it?

0004:

Looking line_recv's change, I became to think that FPxx macros
is provided for coordinate values. I don't think it is applied
to non-coordinate values like coefficients. If some kind of
tolerance is needed here, it is not the same with the EPSILON.

 +    if (FPzero(line->A) && FPzero(line->B))
 +        ereport(ERROR,

So, the above should be exact comparison with 0.0 and line_in
also should be the same. And maybe the same thing should be done
at many places..

But the following line of line_parallel still requires some kind
of tolerance to work properly. Since this patch is an
imoprovement patch, I think we can change it to the vector method.

The problem of line_distance is an existing one so we can leave
it alone. It returns 0.0 for the most cases but it is a
long-standing behavior.. (Anyway I don't find a reasonable
definition of the distance between very-nearly parallel lines..)

-- Sorry time's up today.

regards,

--
Kyotaro Horiguchi
NTT Open Source Software Center

#43Emre Hasegeli
emre@hasegeli.com
In reply to: Kyotaro HORIGUCHI (#42)
Re: [HACKERS] [PATCH] Improve geometric types

0001:

- You removed the check of parallelity check of
line_interpt_line(old line_interpt_internal) but line_parallel
is not changed so the consistency between the two functions are
lost. It is better to be another patch file (maybe 0004?).

I am making line_parallel() use line_interpt_line(). What they do is
exactly the same.

- + Assert(p1->npts > 0 && p2->npts > 0);

Other path_ functions are allowing path with no points so just
returning false if (p1->npts == 0 || p2->npts == 0) seems
enough. Assertion should be used only for something server
cannot continue working. (division by zero doesn't crash
server) I saw other similar assertions in the patch.

path_in() and path_recv() reject paths with no points. I thought we
shouldn't spend cycles for things that cannot happen. I can revert
this part if you find previous practice better.

0003:

close_pl/ps/lseg/pb/ls/sb have changed to return null when
lseg_closept_line returns NAN, but they are defined as strict
and that is reasonable. Anyway pg_hypot returns NaN only when
parameters contain INF or NAN so we should error out when it
returns nan.

I though strict is only related to the input being NULL. Tom Lane
made close_ps() return NULL with commit
278148907a971ec7fa4ffb24248103d8012155d2. The other functions
currently fail with elog()s from DirectFunctionCalls. I don't have
strong preference for NULL or an error. Could you please suggest an
errcode and errmsg, if you have?

circle_in rejects negative radius and circle_recv modived to
reject zero and negative. What is the reason for the change?

Overlooking. Thank you for noticing. I am fixing it.

I understand that we don't need to consider NAN is equal to NAN.
circle_same, point_eq_point, line_eq no longer needs such
change?

I though it would be better to consider NaNs equal only on the
equality operators. That is why only they are changed that way.

Assertion is added in pg_hypot but it is impossible for result
to be negative there. Why do you added it?

True. I am removing it.

0004:

Looking line_recv's change, I became to think that FPxx macros
is provided for coordinate values. I don't think it is applied
to non-coordinate values like coefficients. If some kind of
tolerance is needed here, it is not the same with the EPSILON.

+    if (FPzero(line->A) && FPzero(line->B))
+        ereport(ERROR,

So, the above should be exact comparison with 0.0 and line_in
also should be the same. And maybe the same thing should be done
at many places..

I agree you. EPSILON is currently applied prematurely. I am trying
to stay away from EPSION related issues to improve the chances to get
this part committed.

But the following line of line_parallel still requires some kind
of tolerance to work properly. Since this patch is an
imoprovement patch, I think we can change it to the vector method.

I am making line_parallel() use line_interpt_line() in response to
your first remark. Vector based algorithm is probably better for
every use of line_interpt_line(), but it is a bigger change with more
user visible effects.

The problem of line_distance is an existing one so we can leave
it alone. It returns 0.0 for the most cases but it is a
long-standing behavior.. (Anyway I don't find a reasonable
definition of the distance between very-nearly parallel lines..)

Exact comparison with 0.0 instead of FPzero() would also be an
improvement for line_distance(), but I am not doing it now.

-- Sorry time's up today.

I am waiting for the rest of your review to post the new versions.

#44Kyotaro HORIGUCHI
horiguchi.kyotaro@lab.ntt.co.jp
In reply to: Emre Hasegeli (#43)
Re: [HACKERS] [PATCH] Improve geometric types

Hello,

At Thu, 18 Jan 2018 16:01:01 +0100, Emre Hasegeli <emre@hasegeli.com> wrote in <CAE2gYzwgcan3w3=-3oHa4Efif=0yvoErn-e_V5KJLUi9pd8ivQ@mail.gmail.com>

0001:

- You removed the check of parallelity check of
line_interpt_line(old line_interpt_internal) but line_parallel
is not changed so the consistency between the two functions are
lost. It is better to be another patch file (maybe 0004?).

I am making line_parallel() use line_interpt_line(). What they do is
exactly the same.

Thanks.

- + Assert(p1->npts > 0 && p2->npts > 0);

Other path_ functions are allowing path with no points so just
returning false if (p1->npts == 0 || p2->npts == 0) seems
enough. Assertion should be used only for something server
cannot continue working. (division by zero doesn't crash
server) I saw other similar assertions in the patch.

path_in() and path_recv() reject paths with no points. I thought we
shouldn't spend cycles for things that cannot happen. I can revert
this part if you find previous practice better.

I'm fine with the current shape. Thanks. Maybe the same
discussion applies to polygons. (cf. poly_overlap)

0003:

close_pl/ps/lseg/pb/ls/sb have changed to return null when
lseg_closept_line returns NAN, but they are defined as strict
and that is reasonable. Anyway pg_hypot returns NaN only when
parameters contain INF or NAN so we should error out when it
returns nan.

I though strict is only related to the input being NULL. Tom Lane

Oops. Yes. you're rigtht.

made close_ps() return NULL with commit
278148907a971ec7fa4ffb24248103d8012155d2. The other functions

Thank you for the pointer. By the way,

/messages/by-id/1919.1468269494@sss.pgh.pa.us

| > Is it reasonable to disallow NaN coordinates on the next major
| > release. Are there any reason to deal with them?
|
| I don't see how we can do that; what would you do about tables already
| containing NaNs? Even without that consideration, assuming that there's
| no way a NaN could creep in seems a pretty fragile assumption, considering
| that operations like Infinity/Infinity will produce one.

Ok, it is convicing. The policy is don't do anything that is not
harmful to server. Currently close_* are *strict* so what we
should do is avoid returning '(anything *)NULL' as a result.

currently fail with elog()s from DirectFunctionCalls. I don't have
strong preference for NULL or an error. Could you please suggest an
errcode and errmsg, if you have?

=# select close_sb('((nan,0),(1,1))'::lseg, '((-1,-1),(2,2))'::box);
ERROR: function 0x8fe61c returned NULL

Recosdering on it and I came to think that such usage of SQL null
is the same to "invalid" objects I mentioned upthread. But we
don't actively check component NaNs but if we happen to see an
invalid result, return SQL null instead.

In this criteria close_* functions looks good that return SQL
null.

0003:

line_closept_point asserts line_interpt_line returns true but it
is hazardous. It is safer if line_closept_point returns NaN if
line_interpt_line returns false.

All other functions looks good in the criteria.

I understand that we don't need to consider NAN is equal to NAN.
circle_same, point_eq_point, line_eq no longer needs such
change?

I though it would be better to consider NaNs equal only on the
equality operators. That is why only they are changed that way.

I'm convinced by that.

0004:

Looking line_recv's change, I became to think that FPxx macros
is provided for coordinate values. I don't think it is applied
to non-coordinate values like coefficients. If some kind of
tolerance is needed here, it is not the same with the EPSILON.

+    if (FPzero(line->A) && FPzero(line->B))
+        ereport(ERROR,

So, the above should be exact comparison with 0.0 and line_in
also should be the same. And maybe the same thing should be done
at many places..

I agree you. EPSILON is currently applied prematurely. I am trying
to stay away from EPSION related issues to improve the chances to get
this part committed.

Agreed.

But the following line of line_parallel still requires some kind
of tolerance to work properly. Since this patch is an
imoprovement patch, I think we can change it to the vector method.

I am making line_parallel() use line_interpt_line() in response to
your first remark. Vector based algorithm is probably better for
every use of line_interpt_line(), but it is a bigger change with more
user visible effects.

I'm fine with that.

The problem of line_distance is an existing one so we can leave
it alone. It returns 0.0 for the most cases but it is a
long-standing behavior.. (Anyway I don't find a reasonable
definition of the distance between very-nearly parallel lines..)

Exact comparison with 0.0 instead of FPzero() would also be an
improvement for line_distance(), but I am not doing it now.

reagrds,

--
Kyotaro Horiguchi
NTT Open Source Software Center

#45Emre Hasegeli
emre@hasegeli.com
In reply to: Kyotaro HORIGUCHI (#44)
Re: [HACKERS] [PATCH] Improve geometric types

I'm fine with the current shape. Thanks. Maybe the same
discussion applies to polygons. (cf. poly_overlap)

It indeed does. I am incorporating.

line_closept_point asserts line_interpt_line returns true but it
is hazardous. It is safer if line_closept_point returns NaN if
line_interpt_line returns false.

Yes, it makes more sense. I am changing it.

I understand that we don't need to consider NAN is equal to NAN.
circle_same, point_eq_point, line_eq no longer needs such
change?

I though it would be better to consider NaNs equal only on the
equality operators. That is why only they are changed that way.

I'm convinced by that.

Great. I am documenting this decision better on the patches.

#46Emre Hasegeli
emre@hasegeli.com
In reply to: Emre Hasegeli (#45)
6 attachment(s)
Re: [HACKERS] [PATCH] Improve geometric types

New versions are attached including all changes we discussed.

Attachments:

0002-float-header-v11.patchapplication/octet-stream; name=0002-float-header-v11.patchDownload
From 078cbf6b60c488f987d62b3c6a10eb0e05a05e99 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 28 May 2016 18:16:05 +0200
Subject: [PATCH 2/6] float-header-v11

Provide header file for built-in float datatypes

Even though, some datatypes under adt/ have separate header files,
most of the simple ones do not.  Their public functions were on
the builtins.h.  We would need to make more functions of floats public
to let the geometric types built on top of them.  This is a good
opportunity to make a separate header file for floats.

1acf7572554515b99ef6e783750aaea8777524ec made _cmp functions public
to solve NaN problem locally for GiST indexes.  This patch reworks it
in favour of a more extensive API.  The API uses inline functions
instead of macros, as they are easier to use compared to macros,
and avoid double-evaluation hazards.
---
 contrib/btree_gin/btree_gin.c                 |   1 +
 contrib/btree_gist/btree_ts.c                 |   1 +
 contrib/cube/cube.c                           |   2 +-
 contrib/cube/cubeparse.y                      |   2 +-
 contrib/postgres_fdw/postgres_fdw.c           |   1 +
 src/backend/access/gist/gistget.c             |   2 +-
 src/backend/access/gist/gistproc.c            |  55 +--
 src/backend/access/gist/gistutil.c            |   2 +-
 src/backend/utils/adt/float.c                 | 589 ++++++--------------------
 src/backend/utils/adt/formatting.c            |   1 +
 src/backend/utils/adt/geo_ops.c               |   6 +-
 src/backend/utils/adt/geo_spgist.c            |   2 +-
 src/backend/utils/adt/numeric.c               |   1 +
 src/backend/utils/adt/rangetypes_gist.c       |   3 +-
 src/backend/utils/adt/rangetypes_selfuncs.c   |   3 +-
 src/backend/utils/adt/rangetypes_typanalyze.c |   3 +-
 src/backend/utils/adt/timestamp.c             |   1 +
 src/backend/utils/misc/guc.c                  |   1 +
 src/include/utils/builtins.h                  |  14 -
 src/include/utils/float.h                     | 374 ++++++++++++++++
 src/include/utils/geo_decls.h                 |   1 +
 21 files changed, 552 insertions(+), 513 deletions(-)
 create mode 100644 src/include/utils/float.h

diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index 2473f79ca1..301caefd47 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -3,20 +3,21 @@
  */
 #include "postgres.h"
 
 #include <limits.h>
 
 #include "access/stratnum.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/cash.h"
 #include "utils/date.h"
+#include "utils/float.h"
 #include "utils/inet.h"
 #include "utils/numeric.h"
 #include "utils/timestamp.h"
 #include "utils/varbit.h"
 
 PG_MODULE_MAGIC;
 
 typedef struct QueryInfo
 {
 	StrategyNumber strategy;
diff --git a/contrib/btree_gist/btree_ts.c b/contrib/btree_gist/btree_ts.c
index 18740cad38..49d1849d88 100644
--- a/contrib/btree_gist/btree_ts.c
+++ b/contrib/btree_gist/btree_ts.c
@@ -2,20 +2,21 @@
  * contrib/btree_gist/btree_ts.c
  */
 #include "postgres.h"
 
 #include <limits.h>
 
 #include "btree_gist.h"
 #include "btree_utils_num.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 typedef struct
 {
 	Timestamp	lower;
 	Timestamp	upper;
 } tsKEY;
 
 /*
 ** timestamp ops
 */
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c
index d96ca1ec1f..79476ed0df 100644
--- a/contrib/cube/cube.c
+++ b/contrib/cube/cube.c
@@ -7,21 +7,21 @@
 ******************************************************************************/
 
 #include "postgres.h"
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 
 #include "cubedata.h"
 
 PG_MODULE_MAGIC;
 
 /*
  * Taken from the intarray contrib header
  */
 #define ARRPTR(x)  ( (double *) ARR_DATA_PTR(x) )
 #define ARRNELEMS(x)  ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x))
diff --git a/contrib/cube/cubeparse.y b/contrib/cube/cubeparse.y
index 1b65fa967c..deb2efdc0d 100644
--- a/contrib/cube/cubeparse.y
+++ b/contrib/cube/cubeparse.y
@@ -1,20 +1,20 @@
 %{
 /* contrib/cube/cubeparse.y */
 
 /* NdBox = [(lowerleft),(upperright)] */
 /* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */
 
 #include "postgres.h"
 
 #include "cubedata.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 
 /* All grammar constructs return strings */
 #define YYSTYPE char *
 
 /*
  * Bison doesn't allocate anything that needs to live across parser calls,
  * so we can easily have it use palloc instead of malloc.  This prevents
  * memory leaks if we error out during parsing.  Note this only works with
  * bison >= 2.0.  However, in bison 1.875 the default is to use alloca()
  * if possible, so there's not really much problem anyhow, at least if
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 7ff43337a9..2603a7f072 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -28,20 +28,21 @@
 #include "optimizer/cost.h"
 #include "optimizer/clauses.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
 #include "optimizer/planmain.h"
 #include "optimizer/restrictinfo.h"
 #include "optimizer/var.h"
 #include "optimizer/tlist.h"
 #include "parser/parsetree.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 #include "utils/sampling.h"
 #include "utils/selfuncs.h"
 
 PG_MODULE_MAGIC;
 
 /* Default CPU cost to start up a foreign query. */
diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c
index b30b931c3b..ea992287eb 100644
--- a/src/backend/access/gist/gistget.c
+++ b/src/backend/access/gist/gistget.c
@@ -13,21 +13,21 @@
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/gist_private.h"
 #include "access/relscan.h"
 #include "catalog/pg_type.h"
 #include "miscadmin.h"
 #include "pgstat.h"
 #include "lib/pairingheap.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 
 /*
  * gistkillitems() -- set LP_DEAD state for items an indexscan caller has
  * told us were killed.
  *
  * We re-read page here, so it's important to check page LSN. If the page
  * has been modified since the last read (as determined by LSN), we cannot
  * flag any entries because it is possible that the old entry was vacuumed
diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index 97e6dc9910..4bbfdadf9f 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -27,62 +27,53 @@
 
 
 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
 						 StrategyNumber strategy);
 static bool rtree_internal_consistent(BOX *key, BOX *query,
 						  StrategyNumber strategy);
 
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
 
-/* Convenience macros for NaN-aware comparisons */
-#define FLOAT8_EQ(a,b)	(float8_cmp_internal(a, b) == 0)
-#define FLOAT8_LT(a,b)	(float8_cmp_internal(a, b) < 0)
-#define FLOAT8_LE(a,b)	(float8_cmp_internal(a, b) <= 0)
-#define FLOAT8_GT(a,b)	(float8_cmp_internal(a, b) > 0)
-#define FLOAT8_GE(a,b)	(float8_cmp_internal(a, b) >= 0)
-#define FLOAT8_MAX(a,b)  (FLOAT8_GT(a, b) ? (a) : (b))
-#define FLOAT8_MIN(a,b)  (FLOAT8_LT(a, b) ? (a) : (b))
-
 
 /**************************************************
  * Box ops
  **************************************************/
 
 /*
  * Calculates union of two boxes, a and b. The result is stored in *n.
  */
 static void
 rt_box_union(BOX *n, const BOX *a, const BOX *b)
 {
-	n->high.x = FLOAT8_MAX(a->high.x, b->high.x);
-	n->high.y = FLOAT8_MAX(a->high.y, b->high.y);
-	n->low.x = FLOAT8_MIN(a->low.x, b->low.x);
-	n->low.y = FLOAT8_MIN(a->low.y, b->low.y);
+	n->high.x = float8_max(a->high.x, b->high.x);
+	n->high.y = float8_max(a->high.y, b->high.y);
+	n->low.x = float8_min(a->low.x, b->low.x);
+	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
 static double
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
-	if (FLOAT8_LE(box->high.x, box->low.x) ||
-		FLOAT8_LE(box->high.y, box->low.y))
+	if (float8_le(box->high.x, box->low.x) ||
+		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
 	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
@@ -137,27 +128,27 @@ gist_box_consistent(PG_FUNCTION_ARGS)
 												 query,
 												 strategy));
 }
 
 /*
  * Increase BOX b to include addon.
  */
 static void
 adjustBox(BOX *b, const BOX *addon)
 {
-	if (FLOAT8_LT(b->high.x, addon->high.x))
+	if (float8_lt(b->high.x, addon->high.x))
 		b->high.x = addon->high.x;
-	if (FLOAT8_GT(b->low.x, addon->low.x))
+	if (float8_gt(b->low.x, addon->low.x))
 		b->low.x = addon->low.x;
-	if (FLOAT8_LT(b->high.y, addon->high.y))
+	if (float8_lt(b->high.y, addon->high.y))
 		b->high.y = addon->high.y;
-	if (FLOAT8_GT(b->low.y, addon->low.y))
+	if (float8_gt(b->low.y, addon->low.y))
 		b->low.y = addon->low.y;
 }
 
 /*
  * The GiST Union method for boxes
  *
  * returns the minimal bounding box that encloses all the entries in entryvec
  */
 Datum
 gist_box_union(PG_FUNCTION_ARGS)
@@ -609,36 +600,36 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		i1 = 0;
 		i2 = 0;
 		rightLower = intervalsLower[i1].lower;
 		leftUpper = intervalsUpper[i2].lower;
 		while (true)
 		{
 			/*
 			 * Find next lower bound of right group.
 			 */
 			while (i1 < nentries &&
-				   FLOAT8_EQ(rightLower, intervalsLower[i1].lower))
+				   float8_eq(rightLower, intervalsLower[i1].lower))
 			{
-				if (FLOAT8_LT(leftUpper, intervalsLower[i1].upper))
+				if (float8_lt(leftUpper, intervalsLower[i1].upper))
 					leftUpper = intervalsLower[i1].upper;
 				i1++;
 			}
 			if (i1 >= nentries)
 				break;
 			rightLower = intervalsLower[i1].lower;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * left group.
 			 */
 			while (i2 < nentries &&
-				   FLOAT8_LE(intervalsUpper[i2].upper, leftUpper))
+				   float8_le(intervalsUpper[i2].upper, leftUpper))
 				i2++;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim, rightLower, i1, leftUpper, i2);
 		}
 
 		/*
 		 * Iterate over upper bound of left group finding greatest possible
@@ -646,35 +637,35 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		 */
 		i1 = nentries - 1;
 		i2 = nentries - 1;
 		rightLower = intervalsLower[i1].upper;
 		leftUpper = intervalsUpper[i2].upper;
 		while (true)
 		{
 			/*
 			 * Find next upper bound of left group.
 			 */
-			while (i2 >= 0 && FLOAT8_EQ(leftUpper, intervalsUpper[i2].upper))
+			while (i2 >= 0 && float8_eq(leftUpper, intervalsUpper[i2].upper))
 			{
-				if (FLOAT8_GT(rightLower, intervalsUpper[i2].lower))
+				if (float8_gt(rightLower, intervalsUpper[i2].lower))
 					rightLower = intervalsUpper[i2].lower;
 				i2--;
 			}
 			if (i2 < 0)
 				break;
 			leftUpper = intervalsUpper[i2].upper;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * right group.
 			 */
-			while (i1 >= 0 && FLOAT8_GE(intervalsLower[i1].lower, rightLower))
+			while (i1 >= 0 && float8_ge(intervalsLower[i1].lower, rightLower))
 				i1--;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim,
 								 rightLower, i1 + 1, leftUpper, i2 + 1);
 		}
 	}
 
@@ -748,42 +739,42 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
 		}
 		else
 		{
 			lower = box->low.y;
 			upper = box->high.y;
 		}
 
-		if (FLOAT8_LE(upper, context.leftUpper))
+		if (float8_le(upper, context.leftUpper))
 		{
 			/* Fits to the left group */
-			if (FLOAT8_GE(lower, context.rightLower))
+			if (float8_ge(lower, context.rightLower))
 			{
 				/* Fits also to the right group, so "common entry" */
 				commonEntries[commonEntriesCount++].index = i;
 			}
 			else
 			{
 				/* Doesn't fit to the right group, so join to the left group */
 				PLACE_LEFT(box, i);
 			}
 		}
 		else
 		{
 			/*
 			 * Each entry should fit on either left or right group. Since this
 			 * entry didn't fit on the left group, it better fit in the right
 			 * group.
 			 */
-			Assert(FLOAT8_GE(lower, context.rightLower));
+			Assert(float8_ge(lower, context.rightLower));
 
 			/* Doesn't fit to the left group, so join to the right group */
 			PLACE_RIGHT(box, i);
 		}
 	}
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
@@ -853,24 +844,24 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
  * equivalent to box_same().
  */
 Datum
 gist_box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *b1 = PG_GETARG_BOX_P(0);
 	BOX		   *b2 = PG_GETARG_BOX_P(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
 	if (b1 && b2)
-		*result = (FLOAT8_EQ(b1->low.x, b2->low.x) &&
-				   FLOAT8_EQ(b1->low.y, b2->low.y) &&
-				   FLOAT8_EQ(b1->high.x, b2->high.x) &&
-				   FLOAT8_EQ(b1->high.y, b2->high.y));
+		*result = (float8_eq(b1->low.x, b2->low.x) &&
+				   float8_eq(b1->low.y, b2->low.y) &&
+				   float8_eq(b1->high.x, b2->high.x) &&
+				   float8_eq(b1->high.y, b2->high.y));
 	else
 		*result = (b1 == NULL && b2 == NULL);
 	PG_RETURN_POINTER(result);
 }
 
 /*
  * Leaf-level consistency for boxes: just apply the query operator
  */
 static bool
 gist_box_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy)
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 55cccd247a..7e43b8fc87 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -15,21 +15,21 @@
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist_private.h"
 #include "access/htup_details.h"
 #include "access/reloptions.h"
 #include "catalog/pg_opclass.h"
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/syscache.h"
 
 
 /*
  * Write itup vector to page, has no control of free space.
  */
 void
 gistfillbuffer(Page page, IndexTuple *itup, int len, OffsetNumber off)
 {
 	OffsetNumber l = InvalidOffsetNumber;
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index bc6a3e09b5..e4d097c6a0 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -16,62 +16,29 @@
 
 #include <ctype.h>
 #include <float.h>
 #include <math.h>
 #include <limits.h>
 
 #include "catalog/pg_type.h"
 #include "common/int.h"
 #include "libpq/pqformat.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/sortsupport.h"
 
 
-#ifndef M_PI
-/* from my RH5.2 gcc math.h file - thomas 2000-04-03 */
-#define M_PI 3.14159265358979323846
-#endif
-
-/* Radians per degree, a.k.a. PI / 180 */
-#define RADIANS_PER_DEGREE 0.0174532925199432957692
-
-/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0.  NAN definition from
- * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfNotNumberNANItems.asp
- */
-#if defined(WIN32) && !defined(NAN)
-static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
-
-#define NAN (*(const double *) nan)
-#endif
-
 /* not sure what the following should be, but better to make it over-sufficient */
 #define MAXFLOATWIDTH	64
 #define MAXDOUBLEWIDTH	128
 
-/*
- * check to see if a float4/8 val has underflowed or overflowed
- */
-#define CHECKFLOATVAL(val, inf_is_valid, zero_is_valid)			\
-do {															\
-	if (isinf(val) && !(inf_is_valid))							\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		  errmsg("value out of range: overflow")));				\
-																\
-	if ((val) == 0.0 && !(zero_is_valid))						\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		 errmsg("value out of range: underflow")));				\
-} while(0)
-
-
 /* Configurable GUC parameter */
 int			extra_float_digits = 0; /* Added to DBL_DIG or FLT_DIG */
 
 /* Cached constants for degree-based trig functions */
 static bool degree_consts_set = false;
 static float8 sin_30 = 0;
 static float8 one_minus_cos_60 = 0;
 static float8 asin_0_5 = 0;
 static float8 acos_0_5 = 0;
 static float8 atan_1_0 = 0;
@@ -102,100 +69,20 @@ static void init_degree_constants(void);
  * function, which causes configure to not set HAVE_CBRT.  Furthermore,
  * their compilers spit up at the mismatch between extern declaration
  * and static definition.  We work around that here by the expedient
  * of a #define to make the actual name of the static function different.
  */
 #define cbrt my_cbrt
 static double cbrt(double x);
 #endif							/* HAVE_CBRT */
 
 
-/*
- * Routines to provide reasonably platform-independent handling of
- * infinity and NaN.  We assume that isinf() and isnan() are available
- * and work per spec.  (On some platforms, we have to supply our own;
- * see src/port.)  However, generating an Infinity or NaN in the first
- * place is less well standardized; pre-C99 systems tend not to have C99's
- * INFINITY and NAN macros.  We centralize our workarounds for this here.
- */
-
-double
-get_float8_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (double) INFINITY;
-#else
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (double) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-/*
-* The funny placements of the two #pragmas is necessary because of a
-* long lived bug in the Microsoft compilers.
-* See http://support.microsoft.com/kb/120968/en-us for details
-*/
-#if (_MSC_VER >= 1800)
-#pragma warning(disable:4756)
-#endif
-float
-get_float4_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (float) INFINITY;
-#else
-#if (_MSC_VER >= 1800)
-#pragma warning(default:4756)
-#endif
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (float) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-double
-get_float8_nan(void)
-{
-	/* (double) NAN doesn't work on some NetBSD/MIPS releases */
-#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
-	/* C99 standard way */
-	return (double) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (double) (0.0 / 0.0);
-#endif
-}
-
-float
-get_float4_nan(void)
-{
-#ifdef NAN
-	/* C99 standard way */
-	return (float) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (float) (0.0 / 0.0);
-#endif
-}
-
-
 /*
  * Returns -1 if 'val' represents negative infinity, 1 if 'val'
  * represents (positive) infinity, and 0 otherwise. On some platforms,
  * this is equivalent to the isinf() macro, but not everywhere: C99
  * does not specify that isinf() needs to distinguish between positive
  * and negative infinity.
  */
 int
 is_infinite(double val)
 {
@@ -340,21 +227,21 @@ float4in(PG_FUNCTION_ARGS)
 	if (*endptr != '\0')
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"real", orig_num)));
 
 	/*
 	 * if we get here, we have a legal double, still need to check to see if
 	 * it's a legal float4
 	 */
-	CHECKFLOATVAL((float4) val, isinf(val), val == 0);
+	check_float4_val((float4) val, isinf(val), val == 0);
 
 	PG_RETURN_FLOAT4((float4) val);
 }
 
 /*
  *		float4out		- converts a float4 number to a string
  *						  using a standard output format
  */
 Datum
 float4out(PG_FUNCTION_ARGS)
@@ -690,35 +577,35 @@ float4up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT4(arg);
 }
 
 Datum
 float4larger(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) > 0)
+	if (float4_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 Datum
 float4smaller(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) < 0)
+	if (float4_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 /*
  *		======================
  *		FLOAT8 BASE OPERATIONS
  *		======================
@@ -757,35 +644,35 @@ float8up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT8(arg);
 }
 
 Datum
 float8larger(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) > 0)
+	if (float8_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 Datum
 float8smaller(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) < 0)
+	if (float8_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		====================
  *		ARITHMETIC OPERATORS
@@ -796,234 +683,165 @@ float8smaller(PG_FUNCTION_ARGS)
  *		float4pl		- returns arg1 + arg2
  *		float4mi		- returns arg1 - arg2
  *		float4mul		- returns arg1 * arg2
  *		float4div		- returns arg1 / arg2
  */
 Datum
 float4pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 + arg2;
-
-	/*
-	 * There isn't any way to check for underflow of addition/subtraction
-	 * because numbers near the underflow value have already been rounded to
-	 * the point where we can't detect that the two values were originally
-	 * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
-	 * 1.4013e-45.
-	 */
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_pl(arg1, arg2));
 }
 
 Datum
 float4mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mi(arg1, arg2));
 }
 
 Datum
 float4mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mul(arg1, arg2));
 }
 
 Datum
 float4div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_div(arg1, arg2));
 }
 
 /*
  *		float8pl		- returns arg1 + arg2
  *		float8mi		- returns arg1 - arg2
  *		float8mul		- returns arg1 * arg2
  *		float8div		- returns arg1 / arg2
  */
 Datum
 float8pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 + arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, arg2));
 }
 
 Datum
 float8mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 - arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, arg2));
 }
 
 Datum
 float8mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 * arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, arg2));
 }
 
 Datum
 float8div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, arg2));
 }
 
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float4{eq,ne,lt,le,gt,ge}		- float4/float4 comparison operations
  */
 int
 float4_cmp_internal(float4 a, float4 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float4_gt(a, b))
+		return 1;
+	if (float4_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
 float4eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float4_eq(arg1, arg2));
 }
 
 Datum
 float4ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float4_ne(arg1, arg2));
 }
 
 Datum
 float4lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float4_lt(arg1, arg2));
 }
 
 Datum
 float4le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float4_le(arg1, arg2));
 }
 
 Datum
 float4gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float4_gt(arg1, arg2));
 }
 
 Datum
 float4ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float4_ge(arg1, arg2));
 }
 
 Datum
 btfloat4cmp(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
 	PG_RETURN_INT32(float4_cmp_internal(arg1, arg2));
 }
@@ -1045,99 +863,79 @@ btfloat4sortsupport(PG_FUNCTION_ARGS)
 	ssup->comparator = btfloat4fastcmp;
 	PG_RETURN_VOID();
 }
 
 /*
  *		float8{eq,ne,lt,le,gt,ge}		- float8/float8 comparison operations
  */
 int
 float8_cmp_internal(float8 a, float8 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float8_gt(a, b))
+		return 1;
+	if (float8_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
 float8eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, arg2));
 }
 
 Datum
 float8ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, arg2));
 }
 
 Datum
 float8lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, arg2));
 }
 
 Datum
 float8le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, arg2));
 }
 
 Datum
 float8gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, arg2));
 }
 
 Datum
 float8ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, arg2));
 }
 
 Datum
 btfloat8cmp(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
 	PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
 }
@@ -1200,21 +998,21 @@ ftod(PG_FUNCTION_ARGS)
 
 
 /*
  *		dtof			- converts a float8 number to a float4 number
  */
 Datum
 dtof(PG_FUNCTION_ARGS)
 {
 	float8		num = PG_GETARG_FLOAT8(0);
 
-	CHECKFLOATVAL((float4) num, isinf(num), num == 0);
+	check_float4_val((float4) num, isinf(num), num == 0);
 
 	PG_RETURN_FLOAT4((float4) num);
 }
 
 
 /*
  *		dtoi4			- converts a float8 number to an int4 number
  */
 Datum
 dtoi4(PG_FUNCTION_ARGS)
@@ -1425,36 +1223,36 @@ dsqrt(PG_FUNCTION_ARGS)
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
 				 errmsg("cannot take square root of a negative number")));
 
 	result = sqrt(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcbrt			- returns cube root of arg1
  */
 Datum
 dcbrt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	result = cbrt(arg1);
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dpow			- returns pow(arg1,arg2)
  */
 Datum
 dpow(PG_FUNCTION_ARGS)
 {
@@ -1493,40 +1291,40 @@ dpow(PG_FUNCTION_ARGS)
 			/* The sign of Inf is not significant in this case. */
 			result = get_float8_infinity();
 		else if (fabs(arg1) != 1)
 			result = 0;
 		else
 			result = 1;
 	}
 	else if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
+	check_float8_val(result, isinf(arg1) || isinf(arg2), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dexp			- returns the exponential function of arg1
  */
 Datum
 dexp(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	errno = 0;
 	result = exp(arg1);
 	if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1), false);
+	check_float8_val(result, isinf(arg1), false);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dlog1			- returns the natural logarithm of arg1
  */
 Datum
 dlog1(PG_FUNCTION_ARGS)
 {
@@ -1541,21 +1339,21 @@ dlog1(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of zero")));
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of a negative number")));
 
 	result = log(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dlog10			- returns the base 10 logarithm of arg1
  */
 Datum
 dlog10(PG_FUNCTION_ARGS)
 {
@@ -1571,21 +1369,21 @@ dlog10(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of zero")));
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of a negative number")));
 
 	result = log10(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dacos			- returns the arccos of arg1 (radians)
  */
 Datum
 dacos(PG_FUNCTION_ARGS)
 {
@@ -1601,21 +1399,21 @@ dacos(PG_FUNCTION_ARGS)
 	 * range [-1, 1] to values in the range [0, Pi], so we should reject any
 	 * inputs outside that range and the result will always be finite.
 	 */
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = acos(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dasin			- returns the arcsin of arg1 (radians)
  */
 Datum
 dasin(PG_FUNCTION_ARGS)
 {
@@ -1631,21 +1429,21 @@ dasin(PG_FUNCTION_ARGS)
 	 * range [-1, 1] to values in the range [-Pi/2, Pi/2], so we should reject
 	 * any inputs outside that range and the result will always be finite.
 	 */
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = asin(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		datan			- returns the arctan of arg1 (radians)
  */
 Datum
 datan(PG_FUNCTION_ARGS)
 {
@@ -1656,21 +1454,21 @@ datan(PG_FUNCTION_ARGS)
 	if (isnan(arg1))
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/*
 	 * The principal branch of the inverse tangent function maps all inputs to
 	 * values in the range [-Pi/2, Pi/2], so the result should always be
 	 * finite, even if the input is infinite.
 	 */
 	result = atan(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		atan2			- returns the arctan of arg1/arg2 (radians)
  */
 Datum
 datan2(PG_FUNCTION_ARGS)
 {
@@ -1681,21 +1479,21 @@ datan2(PG_FUNCTION_ARGS)
 	/* Per the POSIX spec, return NaN if either input is NaN */
 	if (isnan(arg1) || isnan(arg2))
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/*
 	 * atan2 maps all inputs to values in the range [-Pi, Pi], so the result
 	 * should always be finite, even if the inputs are infinite.
 	 */
 	result = atan2(arg1, arg2);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcos			- returns the cosine of arg1 (radians)
  */
 Datum
 dcos(PG_FUNCTION_ARGS)
 {
@@ -1721,21 +1519,21 @@ dcos(PG_FUNCTION_ARGS)
 	 * platform reports via errno, so also explicitly test for infinite
 	 * inputs.
 	 */
 	errno = 0;
 	result = cos(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcot			- returns the cotangent of arg1 (radians)
  */
 Datum
 dcot(PG_FUNCTION_ARGS)
 {
@@ -1748,21 +1546,21 @@ dcot(PG_FUNCTION_ARGS)
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = tan(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = 1.0 / result;
-	CHECKFLOATVAL(result, true /* cot(0) == Inf */ , true);
+	check_float8_val(result, true /* cot(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dsin			- returns the sine of arg1 (radians)
  */
 Datum
 dsin(PG_FUNCTION_ARGS)
 {
@@ -1774,21 +1572,21 @@ dsin(PG_FUNCTION_ARGS)
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = sin(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dtan			- returns the tangent of arg1 (radians)
  */
 Datum
 dtan(PG_FUNCTION_ARGS)
 {
@@ -1800,21 +1598,21 @@ dtan(PG_FUNCTION_ARGS)
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = tan(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, true /* tan(pi/2) == Inf */ , true);
+	check_float8_val(result, true /* tan(pi/2) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /* ========== DEGREE-BASED TRIGONOMETRIC FUNCTIONS ========== */
 
 
 /*
  * Initialize the cached constants declared at the head of this file
  * (sin_30 etc).  The fact that we need those at all, let alone need this
@@ -1952,21 +1750,21 @@ dacosd(PG_FUNCTION_ARGS)
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	if (arg1 >= 0.0)
 		result = acosd_q1(arg1);
 	else
 		result = 90.0 + asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dasind			- returns the arcsin of arg1 (degrees)
  */
 Datum
 dasind(PG_FUNCTION_ARGS)
 {
@@ -1987,21 +1785,21 @@ dasind(PG_FUNCTION_ARGS)
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	if (arg1 >= 0.0)
 		result = asind_q1(arg1);
 	else
 		result = -asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		datand			- returns the arctan of arg1 (degrees)
  */
 Datum
 datand(PG_FUNCTION_ARGS)
 {
@@ -2017,21 +1815,21 @@ datand(PG_FUNCTION_ARGS)
 
 	/*
 	 * The principal branch of the inverse tangent function maps all inputs to
 	 * values in the range [-90, 90], so the result should always be finite,
 	 * even if the input is infinite.  Additionally, we take care to ensure
 	 * than when arg1 is 1, the result is exactly 45.
 	 */
 	atan_arg1 = atan(arg1);
 	result = (atan_arg1 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		atan2d			- returns the arctan of arg1/arg2 (degrees)
  */
 Datum
 datan2d(PG_FUNCTION_ARGS)
 {
@@ -2051,21 +1849,21 @@ datan2d(PG_FUNCTION_ARGS)
 	 * result should always be finite, even if the inputs are infinite.
 	 *
 	 * Note: this coding assumes that atan(1.0) is a suitable scaling constant
 	 * to get an exact result from atan2().  This might well fail on us at
 	 * some point, requiring us to decide exactly what inputs we think we're
 	 * going to guarantee an exact result for.
 	 */
 	atan2_arg1_arg2 = atan2(arg1, arg2);
 	result = (atan2_arg1_arg2 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		sind_0_to_30	- returns the sine of an angle that lies between 0 and
  *						  30 degrees.  This will return exactly 0 when x is 0,
  *						  and exactly 0.5 when x is 30 degrees.
  */
 static double
@@ -2172,21 +1970,21 @@ dcosd(PG_FUNCTION_ARGS)
 
 	if (arg1 > 90.0)
 	{
 		/* cosd(180-x) = -cosd(x) */
 		arg1 = 180.0 - arg1;
 		sign = -sign;
 	}
 
 	result = sign * cosd_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcotd			- returns the cotangent of arg1 (degrees)
  */
 Datum
 dcotd(PG_FUNCTION_ARGS)
 {
@@ -2237,21 +2035,21 @@ dcotd(PG_FUNCTION_ARGS)
 	result = sign * (cot_arg1 / cot_45);
 
 	/*
 	 * On some machines we get cotd(270) = minus zero, but this isn't always
 	 * true.  For portability, and because the user constituency for this
 	 * function probably doesn't want minus zero, force it to plain zero.
 	 */
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* cotd(0) == Inf */ , true);
+	check_float8_val(result, true /* cotd(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dsind			- returns the sine of arg1 (degrees)
  */
 Datum
 dsind(PG_FUNCTION_ARGS)
 {
@@ -2291,21 +2089,21 @@ dsind(PG_FUNCTION_ARGS)
 	}
 
 	if (arg1 > 90.0)
 	{
 		/* sind(180-x) = sind(x) */
 		arg1 = 180.0 - arg1;
 	}
 
 	result = sign * sind_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dtand			- returns the tangent of arg1 (degrees)
  */
 Datum
 dtand(PG_FUNCTION_ARGS)
 {
@@ -2356,64 +2154,56 @@ dtand(PG_FUNCTION_ARGS)
 	result = sign * (tan_arg1 / tan_45);
 
 	/*
 	 * On some machines we get tand(180) = minus zero, but this isn't always
 	 * true.  For portability, and because the user constituency for this
 	 * function probably doesn't want minus zero, force it to plain zero.
 	 */
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* tand(90) == Inf */ , true);
+	check_float8_val(result, true /* tand(90) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		degrees		- returns degrees converted from radians
  */
 Datum
 degrees(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
 
-	result = arg1 / RADIANS_PER_DEGREE;
-
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, RADIANS_PER_DEGREE));
 }
 
 
 /*
  *		dpi				- returns the constant PI
  */
 Datum
 dpi(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_FLOAT8(M_PI);
 }
 
 
 /*
  *		radians		- returns radians converted from degrees
  */
 Datum
 radians(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
 
-	result = arg1 * RADIANS_PER_DEGREE;
-
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, RADIANS_PER_DEGREE));
 }
 
 
 /*
  *		drandom		- returns a random number
  */
 Datum
 drandom(PG_FUNCTION_ARGS)
 {
 	float8		result;
@@ -2491,144 +2281,105 @@ check_float8_array(ArrayType *transarray, const char *caller, int n)
  * This function is used only in two stage aggregation and
  * shouldn't be called outside aggregate context.
  */
 Datum
 float8_combine(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_combine", 3);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-
 	transvalues2 = check_float8_array(transarray2, "float8_combine", 3);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
 
 Datum
 float8_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8		newval = PG_GETARG_FLOAT8(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float8_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
 	else
 	{
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
 								 sizeof(float8), FLOAT8PASSBYVAL, 'd');
 
 		PG_RETURN_ARRAYTYPE_P(result);
 	}
 }
 
 Datum
 float4_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 
 	/* do computations as float8 */
 	float8		newval = PG_GETARG_FLOAT4(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float4_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
 	else
 	{
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
 								 sizeof(float8), FLOAT8PASSBYVAL, 'd');
 
 		PG_RETURN_ARRAYTYPE_P(result);
 	}
 }
 
 Datum
@@ -2664,21 +2415,21 @@ float8_var_pop(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_var_pop", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Population variance is undefined when N is 0, so return NULL */
 	if (N == 0.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / (N * N));
 }
 
 Datum
 float8_var_samp(PG_FUNCTION_ARGS)
@@ -2693,21 +2444,21 @@ float8_var_samp(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_var_samp", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Sample variance is undefined when N is 0 or 1, so return NULL */
 	if (N <= 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
 }
 
 Datum
 float8_stddev_pop(PG_FUNCTION_ARGS)
@@ -2722,21 +2473,21 @@ float8_stddev_pop(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_stddev_pop", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Population stddev is undefined when N is 0, so return NULL */
 	if (N == 0.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(sqrt(numerator / (N * N)));
 }
 
 Datum
 float8_stddev_samp(PG_FUNCTION_ARGS)
@@ -2751,21 +2502,21 @@ float8_stddev_samp(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_stddev_samp", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Sample stddev is undefined when N is 0 or 1, so return NULL */
 	if (N <= 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(sqrt(numerator / (N * (N - 1.0))));
 }
 
 /*
  *		=========================
@@ -2800,30 +2551,30 @@ float8_regr_accum(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_accum", 6);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	N += 1.0;
 	sumX += newvalX;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
+	check_float8_val(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
 	sumX2 += newvalX * newvalX;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
+	check_float8_val(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
 	sumY += newvalY;
-	CHECKFLOATVAL(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
+	check_float8_val(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
 	sumY2 += newvalY * newvalY;
-	CHECKFLOATVAL(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
+	check_float8_val(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
 	sumXY += newvalX * newvalY;
-	CHECKFLOATVAL(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
-				  isinf(newvalY), true);
+	check_float8_val(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
+					 isinf(newvalY), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
 		transvalues[0] = N;
 		transvalues[1] = sumX;
@@ -2862,63 +2613,33 @@ float8_regr_accum(PG_FUNCTION_ARGS)
  * This function is used only in two stage aggregation and
  * shouldn't be called outside aggregate context.
  */
 Datum
 float8_regr_combine(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2,
-				sumY,
-				sumY2,
-				sumXY;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_regr_combine", 6);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-	sumY = transvalues1[3];
-	sumY2 = transvalues1[4];
-	sumXY = transvalues1[5];
-
 	transvalues2 = check_float8_array(transarray2, "float8_regr_combine", 6);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-	sumY += transvalues2[3];
-	CHECKFLOATVAL(sumY, isinf(transvalues1[3]) || isinf(transvalues2[3]),
-				  true);
-	sumY2 += transvalues2[4];
-	CHECKFLOATVAL(sumY2, isinf(transvalues1[4]) || isinf(transvalues2[4]),
-				  true);
-	sumXY += transvalues2[5];
-	CHECKFLOATVAL(sumXY, isinf(transvalues1[5]) || isinf(transvalues2[5]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
-	transvalues1[3] = sumY;
-	transvalues1[4] = sumY2;
-	transvalues1[5] = sumXY;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
+	transvalues1[3] = float8_pl(transvalues1[3], transvalues2[3]);
+	transvalues1[4] = float8_pl(transvalues1[4], transvalues2[4]);
+	transvalues1[5] = float8_pl(transvalues1[5], transvalues2[5]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
 
 
 Datum
 float8_regr_sxx(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
@@ -2930,21 +2651,21 @@ float8_regr_sxx(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_sxx", 6);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_syy(PG_FUNCTION_ARGS)
@@ -2959,21 +2680,21 @@ float8_regr_syy(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_syy", 6);
 	N = transvalues[0];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumY2) || isinf(sumY), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_sxy(PG_FUNCTION_ARGS)
@@ -2990,22 +2711,22 @@ float8_regr_sxy(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	/* A negative result is valid here */
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_avgx(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3058,22 +2779,22 @@ float8_covar_pop(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * N));
 }
 
 Datum
 float8_covar_samp(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
 	float8		N,
@@ -3086,22 +2807,22 @@ float8_covar_samp(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is <= 1 we should return NULL */
 	if (N < 2.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
 }
 
 Datum
 float8_corr(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
 	float8		N,
@@ -3120,26 +2841,26 @@ float8_corr(PG_FUNCTION_ARGS)
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0 || numeratorY <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXY / sqrt(numeratorX * numeratorY));
 }
 
 Datum
 float8_regr_r2(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3160,26 +2881,26 @@ float8_regr_r2(PG_FUNCTION_ARGS)
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 	/* per spec, horizontal line produces 1.0 */
 	if (numeratorY <= 0)
 		PG_RETURN_FLOAT8(1.0);
 
 	PG_RETURN_FLOAT8((numeratorXY * numeratorXY) /
 					 (numeratorX * numeratorY));
 }
 
@@ -3201,24 +2922,24 @@ float8_regr_slope(PG_FUNCTION_ARGS)
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXY / numeratorX);
 }
 
 Datum
 float8_regr_intercept(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3236,24 +2957,24 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXXY = sumY * sumX2 - sumX * sumXY;
-	CHECKFLOATVAL(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
-				  isinf(sumX) || isinf(sumXY), true);
+	check_float8_val(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
+					 isinf(sumX) || isinf(sumXY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXXY / numeratorX);
 }
 
 
 /*
  *		====================================
  *		MIXED-PRECISION ARITHMETIC OPERATORS
@@ -3264,251 +2985,211 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
  *		float48pl		- returns arg1 + arg2
  *		float48mi		- returns arg1 - arg2
  *		float48mul		- returns arg1 * arg2
  *		float48div		- returns arg1 / arg2
  */
 Datum
 float48pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 + arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl((float8) arg1, arg2));
 }
 
 Datum
 float48mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi((float8) arg1, arg2));
 }
 
 Datum
 float48mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul((float8) arg1, arg2));
 }
 
 Datum
 float48div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div((float8) arg1, arg2));
 }
 
 /*
  *		float84pl		- returns arg1 + arg2
  *		float84mi		- returns arg1 - arg2
  *		float84mul		- returns arg1 * arg2
  *		float84div		- returns arg1 / arg2
  */
 Datum
 float84pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 + arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, (float8) arg2));
 }
 
 Datum
 float84mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 - arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, (float8) arg2));
 }
 
 Datum
 float84mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 * arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, (float8) arg2));
 }
 
 Datum
 float84div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, (float8) arg2));
 }
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float48{eq,ne,lt,le,gt,ge}		- float4/float8 comparison operations
  */
 Datum
 float48eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq((float8) arg1, arg2));
 }
 
 Datum
 float48ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne((float8) arg1, arg2));
 }
 
 Datum
 float48lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt((float8) arg1, arg2));
 }
 
 Datum
 float48le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le((float8) arg1, arg2));
 }
 
 Datum
 float48gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt((float8) arg1, arg2));
 }
 
 Datum
 float48ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge((float8) arg1, arg2));
 }
 
 /*
  *		float84{eq,ne,lt,le,gt,ge}		- float8/float4 comparison operations
  */
 Datum
 float84eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, (float8) arg2));
 }
 
 Datum
 float84ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, (float8) arg2));
 }
 
 Datum
 float84lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, (float8) arg2));
 }
 
 Datum
 float84le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, (float8) arg2));
 }
 
 Datum
 float84gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, (float8) arg2));
 }
 
 Datum
 float84ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, (float8) arg2));
 }
 
 /*
  * Implements the float8 version of the width_bucket() function
  * defined by SQL2003. See also width_bucket_numeric().
  *
  * 'bound1' and 'bound2' are the lower and upper bounds of the
  * histogram's range, respectively. 'count' is the number of buckets
  * in the histogram. width_bucket() returns an integer indicating the
  * bucket number that 'operand' belongs to in an equiwidth histogram
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c
index b8bd4caa3e..7ecbc0b455 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -84,20 +84,21 @@
 
 #ifdef USE_ICU
 #include <unicode/ustring.h>
 #endif
 
 #include "catalog/pg_collation.h"
 #include "mb/pg_wchar.h"
 #include "utils/builtins.h"
 #include "utils/date.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 #include "utils/formatting.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/pg_locale.h"
 
 /* ----------
  * Routines type
  * ----------
  */
 #define DCH_TYPE		1		/* DATE-TIME version	*/
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index e3119efea0..d5b25e6bb9 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -14,27 +14,23 @@
  */
 #include "postgres.h"
 
 #include <math.h>
 #include <limits.h>
 #include <float.h>
 #include <ctype.h>
 
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
-#include "utils/builtins.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index 0fe40499e0..096e59f817 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -69,21 +69,21 @@
  *			src/backend/utils/adt/geo_spgist.c
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
 
 #include "access/spgist.h"
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
  * is going only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 5b34badd5b..77a2613a50 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -29,20 +29,21 @@
 #include "access/hash.h"
 #include "catalog/pg_type.h"
 #include "common/int.h"
 #include "funcapi.h"
 #include "lib/hyperloglog.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/sortsupport.h"
 
 /* ----------
  * Uncomment the following to enable compilation of dump_numeric()
  * and dump_var() and to get a dump of any result produced by make_result().
  * ----------
 #define NUMERIC_DEBUG
diff --git a/src/backend/utils/adt/rangetypes_gist.c b/src/backend/utils/adt/rangetypes_gist.c
index 2fe61043d9..450479e31c 100644
--- a/src/backend/utils/adt/rangetypes_gist.c
+++ b/src/backend/utils/adt/rangetypes_gist.c
@@ -9,21 +9,22 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_gist.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/gist.h"
 #include "access/stratnum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/datum.h"
 #include "utils/rangetypes.h"
 
 
 /*
  * Range class properties used to segregate different classes of ranges in
  * GiST.  Each unique combination of properties is a class.  CLS_EMPTY cannot
  * be combined with anything else.
  */
 #define CLS_NORMAL			0	/* Ordinary finite range (no bits set) */
diff --git a/src/backend/utils/adt/rangetypes_selfuncs.c b/src/backend/utils/adt/rangetypes_selfuncs.c
index 59761ecf34..f9a5117492 100644
--- a/src/backend/utils/adt/rangetypes_selfuncs.c
+++ b/src/backend/utils/adt/rangetypes_selfuncs.c
@@ -14,21 +14,22 @@
  *	  src/backend/utils/adt/rangetypes_selfuncs.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/htup_details.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 #include "utils/selfuncs.h"
 #include "utils/typcache.h"
 
 static double calc_rangesel(TypeCacheEntry *typcache, VariableStatData *vardata,
 			  RangeType *constval, Oid operator);
 static double default_range_selectivity(Oid operator);
 static double calc_hist_selectivity(TypeCacheEntry *typcache,
 					  VariableStatData *vardata, RangeType *constval,
diff --git a/src/backend/utils/adt/rangetypes_typanalyze.c b/src/backend/utils/adt/rangetypes_typanalyze.c
index f2c11f54bc..9c50e4c1be 100644
--- a/src/backend/utils/adt/rangetypes_typanalyze.c
+++ b/src/backend/utils/adt/rangetypes_typanalyze.c
@@ -19,21 +19,22 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_typanalyze.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "catalog/pg_operator.h"
 #include "commands/vacuum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 
 static int	float8_qsort_cmp(const void *a1, const void *a2);
 static int	range_bound_qsort_cmp(const void *a1, const void *a2, void *arg);
 static void compute_range_stats(VacAttrStats *stats,
 					AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows);
 
 /*
  * range_typanalyze -- typanalyze function for range columns
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index e6a1eed191..f8ffa8aa4f 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -27,20 +27,21 @@
 #include "common/int128.h"
 #include "funcapi.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
 #include "parser/scansup.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 /*
  * gcc's -ffast-math switch breaks routines that expect exact results from
  * expressions like timeval / SECS_PER_HOUR, where timeval is double.
  */
 #ifdef __FAST_MATH__
 #error -ffast-math is known to break this code
 #endif
 
 #define SAMESIGN(a,b)	(((a) < 0) == ((b) < 0))
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 72f6be329e..9530a53ecb 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -72,20 +72,21 @@
 #include "storage/fd.h"
 #include "storage/large_object.h"
 #include "storage/pg_shmem.h"
 #include "storage/proc.h"
 #include "storage/predicate.h"
 #include "tcop/tcopprot.h"
 #include "tsearch/ts_cache.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/guc_tables.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/pg_locale.h"
 #include "utils/plancache.h"
 #include "utils/portal.h"
 #include "utils/ps_status.h"
 #include "utils/rls.h"
 #include "utils/snapmgr.h"
 #include "utils/tzparser.h"
 #include "utils/varlena.h"
 #include "utils/xml.h"
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 8bb57c5829..6432222a76 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -43,34 +43,20 @@ extern int	namestrcmp(Name name, const char *str);
 
 /* numutils.c */
 extern int32 pg_atoi(const char *s, int size, int c);
 extern void pg_itoa(int16 i, char *a);
 extern void pg_ltoa(int32 l, char *a);
 extern void pg_lltoa(int64 ll, char *a);
 extern char *pg_ltostr_zeropad(char *str, int32 value, int32 minwidth);
 extern char *pg_ltostr(char *str, int32 value);
 extern uint64 pg_strtouint64(const char *str, char **endptr, int base);
 
-/* float.c */
-extern PGDLLIMPORT int extra_float_digits;
-
-extern double get_float8_infinity(void);
-extern float get_float4_infinity(void);
-extern double get_float8_nan(void);
-extern float get_float4_nan(void);
-extern int	is_infinite(double val);
-extern double float8in_internal(char *num, char **endptr_p,
-				  const char *type_name, const char *orig_string);
-extern char *float8out_internal(double num);
-extern int	float4_cmp_internal(float4 a, float4 b);
-extern int	float8_cmp_internal(float8 a, float8 b);
-
 /* oid.c */
 extern oidvector *buildoidvector(const Oid *oids, int n);
 extern Oid	oidparse(Node *node);
 extern int	oid_cmp(const void *p1, const void *p2);
 
 /* regexp.c */
 extern char *regexp_fixed_prefix(text *text_re, bool case_insensitive,
 					Oid collation, bool *exact);
 
 /* ruleutils.c */
diff --git a/src/include/utils/float.h b/src/include/utils/float.h
new file mode 100644
index 0000000000..b1f34183de
--- /dev/null
+++ b/src/include/utils/float.h
@@ -0,0 +1,374 @@
+/*-------------------------------------------------------------------------
+ *
+ * float.h
+ *	  Definitions for the built-in floating-point types
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/include/utils/float.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef FLOAT_H
+#define FLOAT_H
+
+#include <math.h>
+
+#ifndef M_PI
+/* From my RH5.2 gcc math.h file - thomas 2000-04-03 */
+#define M_PI 3.14159265358979323846
+#endif
+
+/* Radians per degree, a.k.a. PI / 180 */
+#define RADIANS_PER_DEGREE 0.0174532925199432957692
+
+/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0. */
+#if defined(WIN32) && !defined(NAN)
+static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
+
+#define NAN (*(const float8 *) nan)
+#endif
+
+extern PGDLLIMPORT int extra_float_digits;
+
+/*
+ * Utility functions in float.c
+ */
+extern int	is_infinite(float8 val);
+extern float8 float8in_internal(char *num, char **endptr_p,
+				  const char *type_name, const char *orig_string);
+extern char *float8out_internal(float8 num);
+extern int	float4_cmp_internal(float4 a, float4 b);
+extern int	float8_cmp_internal(float8 a, float8 b);
+
+/*
+ * Routines to provide reasonably platform-independent handling of
+ * infinity and NaN
+ *
+ * We assume that isinf() and isnan() are available and work per spec.
+ * (On some platforms, we have to supply our own; see src/port.)  However,
+ * generating an Infinity or NaN in the first place is less well standardized;
+ * pre-C99 systems tend not to have C99's INFINITY and NaN macros.  We
+ * centralize our workarounds for this here.
+ */
+
+/*
+ * The funny placements of the two #pragmas is necessary because of a
+ * long lived bug in the Microsoft compilers.
+ * See http://support.microsoft.com/kb/120968/en-us for details
+ */
+#if (_MSC_VER >= 1800)
+#pragma warning(disable:4756)
+#endif
+static inline float
+get_float4_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float) INFINITY;
+#else
+#if (_MSC_VER >= 1800)
+#pragma warning(default:4756)
+#endif
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float8
+get_float8_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float8) INFINITY;
+#else
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float8) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float4
+get_float4_nan(void)
+{
+#ifdef NAN
+	/* C99 standard way */
+	return (float) NAN;
+#else
+	/* Assume we can get a NAN via zero divide */
+	return (float) (0.0 / 0.0);
+#endif
+}
+
+static inline float8
+get_float8_nan(void)
+{
+	/* (float8) NAN doesn't work on some NetBSD/MIPS releases */
+#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
+	/* C99 standard way */
+	return (float8) NAN;
+#else
+	/* Assume we can get a NaN via zero divide */
+	return (float8) (0.0 / 0.0);
+#endif
+}
+
+/*
+ * Checks to see if a float4/8 val has underflowed or overflowed
+ */
+
+static inline void
+check_float4_val(float4 val, bool inf_is_valid, bool zero_is_valid)
+{
+	if (isinf(val) && !inf_is_valid)
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if (val == 0.0 && !zero_is_valid)
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+static inline void
+check_float8_val(float8 val, bool inf_is_valid, bool zero_is_valid)
+{
+	if (isinf(val) && !inf_is_valid)
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if (val == 0.0 && !zero_is_valid)
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+/*
+ * Routines for operations with the checks above
+ *
+ * There isn't any way to check for underflow of addition/subtraction
+ * because numbers near the underflow value have already been rounded to
+ * the point where we can't detect that the two values were originally
+ * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
+ * 1.4013e-45.
+ */
+
+static inline float4
+float4_pl(float4 val1, float4 val2)
+{
+	float4		result;
+
+	result = val1 + val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_pl(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = val1 + val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mi(float4 val1, float4 val2)
+{
+	float4		result;
+
+	result = val1 - val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_mi(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = val1 - val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mul(float4 val1, float4 val2)
+{
+	float4		result;
+
+	result = val1 * val2;
+	check_float4_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0f || val2 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_mul(float8 val1, float8 val2)
+{
+	float8		result;
+
+	result = val1 * val2;
+	check_float8_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0 || val2 == 0.0);
+
+	return result;
+}
+
+static inline float4
+float4_div(float4 val1, float4 val2)
+{
+	float4		result;
+
+	if (val2 == 0.0f)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), val1 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_div(float8 val1, float8 val2)
+{
+	float8		result;
+
+	if (val2 == 0.0)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
+
+	return result;
+}
+
+/*
+ * Routines for NaN-aware comparisons
+ *
+ * We consider all NaNs to be equal and larger than any non-NaN. This is
+ * somewhat arbitrary; the important thing is to have a consistent sort
+ * order.
+ */
+
+static inline bool
+float4_eq(float4 val1, float4 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float8_eq(float8 val1, float8 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float4_ne(float4 val1, float4 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float8_ne(float8 val1, float8 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float4_lt(float4 val1, float4 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float8_lt(float8 val1, float8 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float4_le(float4 val1, float4 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float8_le(float8 val1, float8 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float4_gt(float4 val1, float4 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float8_gt(float8 val1, float8 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float4_ge(float4 val1, float4 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline bool
+float8_ge(float8 val1, float8 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline float4
+float4_min(float4 val1, float4 val2)
+{
+	return float4_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_min(float8 val1, float8 val2)
+{
+	return float8_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float4
+float4_max(float4 val1, float4 val2)
+{
+	return float4_gt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_max(float8 val1, float8 val2)
+{
+	return float8_gt(val1, val2) ? val1 : val2;
+}
+
+#endif							/* FLOAT_H */
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 0e066894cd..aeb31515e4 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -17,20 +17,21 @@
  *		and data types. There are still some more to do. - tgl 97/04/19
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEO_DECLS_H
 #define GEO_DECLS_H
 
 #include <math.h>
 
 #include "fmgr.h"
+#include "utils/float.h"
 
 /*--------------------------------------------------------------------
  * Useful floating point utilities and constants.
  *-------------------------------------------------------------------*/
 
 
 #define EPSILON					1.0E-06
 
 #ifdef EPSILON
 #define FPzero(A)				(fabs(A) <= EPSILON)
-- 
2.14.3 (Apple Git-98)

0003-geo-float-v08.patchapplication/octet-stream; name=0003-geo-float-v08.patchDownload
From 16624f362a48c1ff93539b67f9d62a14d3f461f5 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 27 May 2017 16:17:42 -0400
Subject: [PATCH 3/6] geo-float-v08

Use the built-in float datatype to implement geometric types

This patch makes the geometric operators and functions use the exported
function of the float datatype.  The main reason of doing so is to check
for underflow and overflow, and to handle NaNs consciously.

The float datatypes consider NaNs to be equal and greater than any
non-NaN.  This change considers NaNs equal only for the equality
operators.  The placement operators, contains, overlaps, left/right of
etc. continues to return false when NaNs are involved.  We don't need
to worry about them being considered greater than any-NaN because there
aren't any basic comparison operators like less/greater than for the
geometric datatypes.

All changes can be summarised as:

* Check for underflow and overflow
* Check for division by zero
* Let the objects with NaN values to be the same
* Return NULL when the distance is NaN for all closest point operators
* Don't round the slope to DBL_MAX
* Favour not-NaN over NaN where it makes sense

The patch also replaces all occurrences of "double" as "float8".  They
are the same, but were randomly spread on the same file.
---
 src/backend/access/gist/gistproc.c |  91 +++----
 src/backend/utils/adt/geo_ops.c    | 496 ++++++++++++++++++++-----------------
 src/backend/utils/adt/geo_spgist.c |  28 +--
 src/include/utils/geo_decls.h      |  17 +-
 4 files changed, 339 insertions(+), 293 deletions(-)

diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index 4bbfdadf9f..4b6233f212 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -16,20 +16,21 @@
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/geo_decls.h"
 
 
 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
 						 StrategyNumber strategy);
 static bool rtree_internal_consistent(BOX *key, BOX *query,
 						  StrategyNumber strategy);
 
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
@@ -48,55 +49,56 @@ rt_box_union(BOX *n, const BOX *a, const BOX *b)
 	n->high.x = float8_max(a->high.x, b->high.x);
 	n->high.y = float8_max(a->high.y, b->high.y);
 	n->low.x = float8_min(a->low.x, b->low.x);
 	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
 	if (float8_le(box->high.x, box->low.x) ||
 		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
-	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
+	return float8_mul(float8_mi(box->high.x, box->low.x),
+					  float8_mi(box->high.y, box->low.y));
 }
 
 /*
  * Return amount by which the union of the two boxes is larger than
  * the original BOX's area.  The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 box_penalty(const BOX *original, const BOX *new)
 {
 	BOX			unionbox;
 
 	rt_box_union(&unionbox, original, new);
-	return size_box(&unionbox) - size_box(original);
+	return float8_mi(size_box(&unionbox), size_box(original));
 }
 
 /*
  * The GiST Consistent method for boxes
  *
  * Should return false if for all data items x below entry,
  * the predicate x op query must be false, where op is the oper
  * corresponding to strategy in the pg_amop table.
  */
 Datum
@@ -256,74 +258,74 @@ fallbackSplit(GistEntryVector *entryvec, GIST_SPLITVEC *v)
 
 /*
  * Represents information about an entry that can be placed to either group
  * without affecting overlap over selected axis ("common entry").
  */
 typedef struct
 {
 	/* Index of entry in the initial array */
 	int			index;
 	/* Delta between penalties of entry insertion into different groups */
-	double		delta;
+	float8		delta;
 } CommonEntry;
 
 /*
  * Context for g_box_consider_split. Contains information about currently
  * selected split and some general information.
  */
 typedef struct
 {
 	int			entriesCount;	/* total number of entries being split */
 	BOX			boundingBox;	/* minimum bounding box across all entries */
 
 	/* Information about currently selected split follows */
 
 	bool		first;			/* true if no split was selected yet */
 
-	double		leftUpper;		/* upper bound of left interval */
-	double		rightLower;		/* lower bound of right interval */
+	float8		leftUpper;		/* upper bound of left interval */
+	float8		rightLower;		/* lower bound of right interval */
 
 	float4		ratio;
 	float4		overlap;
 	int			dim;			/* axis of this split */
-	double		range;			/* width of general MBR projection to the
+	float8		range;			/* width of general MBR projection to the
 								 * selected axis */
 } ConsiderSplitContext;
 
 /*
  * Interval represents projection of box to axis.
  */
 typedef struct
 {
-	double		lower,
+	float8		lower,
 				upper;
 } SplitInterval;
 
 /*
  * Interval comparison function by lower bound of the interval;
  */
 static int
 interval_cmp_lower(const void *i1, const void *i2)
 {
-	double		lower1 = ((const SplitInterval *) i1)->lower,
+	float8		lower1 = ((const SplitInterval *) i1)->lower,
 				lower2 = ((const SplitInterval *) i2)->lower;
 
 	return float8_cmp_internal(lower1, lower2);
 }
 
 /*
  * Interval comparison function by upper bound of the interval;
  */
 static int
 interval_cmp_upper(const void *i1, const void *i2)
 {
-	double		upper1 = ((const SplitInterval *) i1)->upper,
+	float8		upper1 = ((const SplitInterval *) i1)->upper,
 				upper2 = ((const SplitInterval *) i2)->upper;
 
 	return float8_cmp_internal(upper1, upper2);
 }
 
 /*
  * Replace negative (or NaN) value with zero.
  */
 static inline float
 non_negative(float val)
@@ -332,28 +334,28 @@ non_negative(float val)
 		return val;
 	else
 		return 0.0f;
 }
 
 /*
  * Consider replacement of currently selected split with the better one.
  */
 static inline void
 g_box_consider_split(ConsiderSplitContext *context, int dimNum,
-					 double rightLower, int minLeftCount,
-					 double leftUpper, int maxLeftCount)
+					 float8 rightLower, int minLeftCount,
+					 float8 leftUpper, int maxLeftCount)
 {
 	int			leftCount,
 				rightCount;
 	float4		ratio,
 				overlap;
-	double		range;
+	float8		range;
 
 	/*
 	 * Calculate entries distribution ratio assuming most uniform distribution
 	 * of common entries.
 	 */
 	if (minLeftCount >= (context->entriesCount + 1) / 2)
 	{
 		leftCount = minLeftCount;
 	}
 	else
@@ -362,40 +364,41 @@ g_box_consider_split(ConsiderSplitContext *context, int dimNum,
 			leftCount = maxLeftCount;
 		else
 			leftCount = context->entriesCount / 2;
 	}
 	rightCount = context->entriesCount - leftCount;
 
 	/*
 	 * Ratio of split - quotient between size of lesser group and total
 	 * entries count.
 	 */
-	ratio = ((float4) Min(leftCount, rightCount)) /
-		((float4) context->entriesCount);
+	ratio = float4_div(Min(leftCount, rightCount), context->entriesCount);
 
 	if (ratio > LIMIT_RATIO)
 	{
 		bool		selectthis = false;
 
 		/*
 		 * The ratio is acceptable, so compare current split with previously
 		 * selected one. Between splits of one dimension we search for minimal
 		 * overlap (allowing negative values) and minimal ration (between same
 		 * overlaps. We switch dimension if find less overlap (non-negative)
 		 * or less range with same overlap.
 		 */
 		if (dimNum == 0)
-			range = context->boundingBox.high.x - context->boundingBox.low.x;
+			range = float8_mi(context->boundingBox.high.x,
+							  context->boundingBox.low.x);
 		else
-			range = context->boundingBox.high.y - context->boundingBox.low.y;
+			range = float8_mi(context->boundingBox.high.y,
+							  context->boundingBox.low.y);
 
-		overlap = (leftUpper - rightLower) / range;
+		overlap = float8_div(float8_mi(leftUpper, rightLower), range);
 
 		/* If there is no previous selection, select this */
 		if (context->first)
 			selectthis = true;
 		else if (context->dim == dimNum)
 		{
 			/*
 			 * Within the same dimension, choose the new split if it has a
 			 * smaller overlap, or same overlap but better ratio.
 			 */
@@ -524,21 +527,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		else
 			adjustBox(&context.boundingBox, box);
 	}
 
 	/*
 	 * Iterate over axes for optimal split searching.
 	 */
 	context.first = true;		/* nothing selected yet */
 	for (dim = 0; dim < 2; dim++)
 	{
-		double		leftUpper,
+		float8		leftUpper,
 					rightLower;
 		int			i1,
 					i2;
 
 		/* Project each entry as an interval on the selected axis. */
 		for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 		{
 			box = DatumGetBoxP(entryvec->vector[i].key);
 			if (dim == 0)
 			{
@@ -721,21 +724,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 			*rightBox = *(box);					\
 		v->spl_right[v->spl_nright++] = off;	\
 	} while(0)
 
 	/*
 	 * Distribute entries which can be distributed unambiguously, and collect
 	 * common entries.
 	 */
 	for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 	{
-		double		lower,
+		float8		lower,
 					upper;
 
 		/*
 		 * Get upper and lower bounds along selected axis.
 		 */
 		box = DatumGetBoxP(entryvec->vector[i].key);
 		if (context.dim == 0)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
@@ -776,31 +779,31 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
 	{
 		/*
 		 * Calculate minimum number of entries that must be placed in both
 		 * groups, to reach LIMIT_RATIO.
 		 */
-		int			m = ceil(LIMIT_RATIO * (double) nentries);
+		int			m = ceil(LIMIT_RATIO * (float8) nentries);
 
 		/*
 		 * Calculate delta between penalties of join "common entries" to
 		 * different groups.
 		 */
 		for (i = 0; i < commonEntriesCount; i++)
 		{
 			box = DatumGetBoxP(entryvec->vector[commonEntries[i].index].key);
-			commonEntries[i].delta = Abs(box_penalty(leftBox, box) -
-										 box_penalty(rightBox, box));
+			commonEntries[i].delta = Abs(float8_mi(box_penalty(leftBox, box),
+												   box_penalty(rightBox, box)));
 		}
 
 		/*
 		 * Sort "common entries" by calculated deltas in order to distribute
 		 * the most ambiguous entries first.
 		 */
 		qsort(commonEntries, commonEntriesCount, sizeof(CommonEntry), common_entry_cmp);
 
 		/*
 		 * Distribute "common entries" between groups.
@@ -1100,24 +1103,24 @@ gist_circle_compress(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	GISTENTRY  *retval;
 
 	if (entry->leafkey)
 	{
 		CIRCLE	   *in = DatumGetCircleP(entry->key);
 		BOX		   *r;
 
 		r = (BOX *) palloc(sizeof(BOX));
-		r->high.x = in->center.x + in->radius;
-		r->low.x = in->center.x - in->radius;
-		r->high.y = in->center.y + in->radius;
-		r->low.y = in->center.y - in->radius;
+		r->high.x = float8_pl(in->center.x, in->radius);
+		r->low.x = float8_mi(in->center.x, in->radius);
+		r->high.y = float8_pl(in->center.y, in->radius);
+		r->low.y = float8_mi(in->center.y, in->radius);
 
 		retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
 		gistentryinit(*retval, PointerGetDatum(r),
 					  entry->rel, entry->page,
 					  entry->offset, false);
 	}
 	else
 		retval = entry;
 	PG_RETURN_POINTER(retval);
 }
@@ -1141,24 +1144,24 @@ gist_circle_consistent(PG_FUNCTION_ARGS)
 	*recheck = true;
 
 	if (DatumGetBoxP(entry->key) == NULL || query == NULL)
 		PG_RETURN_BOOL(false);
 
 	/*
 	 * Since the operators require recheck anyway, we can just use
 	 * rtree_internal_consistent even at leaf nodes.  (This works in part
 	 * because the index entries are bounding boxes not circles.)
 	 */
-	bbox.high.x = query->center.x + query->radius;
-	bbox.low.x = query->center.x - query->radius;
-	bbox.high.y = query->center.y + query->radius;
-	bbox.low.y = query->center.y - query->radius;
+	bbox.high.x = float8_pl(query->center.x, query->radius);
+	bbox.low.x = float8_mi(query->center.x, query->radius);
+	bbox.high.y = float8_pl(query->center.y, query->radius);
+	bbox.low.y = float8_mi(query->center.y, query->radius);
 
 	result = rtree_internal_consistent(DatumGetBoxP(entry->key),
 									   &bbox, strategy);
 
 	PG_RETURN_BOOL(result);
 }
 
 /**************************************************
  * Point ops
  **************************************************/
@@ -1209,63 +1212,63 @@ gist_point_fetch(PG_FUNCTION_ARGS)
 				  entry->offset, false);
 
 	PG_RETURN_POINTER(retval);
 }
 
 
 #define point_point_distance(p1,p2) \
 	DatumGetFloat8(DirectFunctionCall2(point_distance, \
 									   PointPGetDatum(p1), PointPGetDatum(p2)))
 
-static double
+static float8
 computeDistance(bool isLeaf, BOX *box, Point *point)
 {
-	double		result = 0.0;
+	float8		result = 0.0;
 
 	if (isLeaf)
 	{
 		/* simple point to point distance */
 		result = point_point_distance(point, &box->low);
 	}
 	else if (point->x <= box->high.x && point->x >= box->low.x &&
 			 point->y <= box->high.y && point->y >= box->low.y)
 	{
 		/* point inside the box */
 		result = 0.0;
 	}
 	else if (point->x <= box->high.x && point->x >= box->low.x)
 	{
 		/* point is over or below box */
 		Assert(box->low.y <= box->high.y);
 		if (point->y > box->high.y)
-			result = point->y - box->high.y;
+			result = float8_mi(point->y, box->high.y);
 		else if (point->y < box->low.y)
-			result = box->low.y - point->y;
+			result = float8_mi(box->low.y, point->y);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
 	else if (point->y <= box->high.y && point->y >= box->low.y)
 	{
 		/* point is to left or right of box */
 		Assert(box->low.x <= box->high.x);
 		if (point->x > box->high.x)
-			result = point->x - box->high.x;
+			result = float8_mi(point->x, box->high.x);
 		else if (point->x < box->low.x)
-			result = box->low.x - point->x;
+			result = float8_mi(box->low.x, point->x);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
 	else
 	{
 		/* closest point will be a vertex */
 		Point		p;
-		double		subresult;
+		float8		subresult;
 
 		result = point_point_distance(point, &box->low);
 
 		subresult = point_point_distance(point, &box->high);
 		if (result > subresult)
 			result = subresult;
 
 		p.x = box->low.x;
 		p.y = box->high.y;
 		subresult = point_point_distance(point, &p);
@@ -1442,21 +1445,21 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 	}
 
 	PG_RETURN_BOOL(result);
 }
 
 Datum
 gist_point_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(GIST_LEAF(entry),
 									   DatumGetBoxP(entry->key),
 									   PG_GETARG_POINT_P(1));
 			break;
 		default:
@@ -1471,25 +1474,25 @@ gist_point_distance(PG_FUNCTION_ARGS)
 /*
  * The inexact GiST distance method for geometric types that store bounding
  * boxes.
  *
  * Compute lossy distance from point to index entries.  The result is inexact
  * because index entries are bounding boxes, not the exact shapes of the
  * indexed geometric types.  We use distance from point to MBR of index entry.
  * This is a lower bound estimate of distance from point to indexed geometric
  * type.
  */
-static double
+static float8
 gist_bbox_distance(GISTENTRY *entry, Datum query,
 				   StrategyNumber strategy, bool *recheck)
 {
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	/* Bounding box distance is always inexact. */
 	*recheck = true;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(false,
 									   DatumGetBoxP(entry->key),
@@ -1505,32 +1508,32 @@ gist_bbox_distance(GISTENTRY *entry, Datum query,
 
 Datum
 gist_circle_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
 
 Datum
 gist_poly_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index d5b25e6bb9..c925a99876 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -51,56 +51,56 @@ static inline float8 line_invsl(LINE *line);
 static bool	line_interpt_line(Point *result, LINE *l1, LINE *l2);
 static bool line_contain_point(LINE *line, Point *point);
 static float8 line_closept_point(Point *result, LINE *line, Point *pt);
 
 /* Routines for line segments */
 static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
 static inline float8 lseg_sl(LSEG *lseg);
 static inline float8 lseg_invsl(LSEG *lseg);
 static bool	lseg_interpt_line(Point *result, LSEG *lseg, LINE *line);
 static bool	lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2);
-static int	lseg_crossing(double x, double y, double px, double py);
+static int	lseg_crossing(float8 x, float8 y, float8 px, float8 py);
 static bool	lseg_contain_point(LSEG *lseg, Point *point);
 static float8 lseg_closept_point(Point *result, LSEG *lseg, Point *pt);
 static float8 lseg_closept_line(Point *result, LSEG *lseg, LINE *line);
 static float8 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2);
 
 /* Routines for boxes */
 static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
 static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
-static double box_ar(BOX *box);
-static double box_ht(BOX *box);
-static double box_wd(BOX *box);
+static float8 box_ar(BOX *box);
+static float8 box_ht(BOX *box);
+static float8 box_wd(BOX *box);
 static bool box_contain_point(BOX *box, Point *point);
 static bool box_contain_box(BOX *box1, BOX *box2);
 static bool box_contain_lseg(BOX *box, LSEG *lseg);
 static bool box_interpt_lseg(Point *result, BOX *box, LSEG *lseg);
 static float8 box_closept_point(Point *result, BOX *box, Point *point);
 static float8 box_closept_lseg(Point *result, BOX *box, LSEG *lseg);
 
 /* Routines for circles */
-static double circle_ar(CIRCLE *circle);
+static float8 circle_ar(CIRCLE *circle);
 
 /* Routines for polygons */
 static void make_bound_box(POLYGON *poly);
 static void poly_to_circle(CIRCLE *result, POLYGON *poly);
 static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
 static bool poly_contain_poly(POLYGON *polya, POLYGON *polyb);
 static bool plist_same(int npts, Point *p1, Point *p2);
 static float8 dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 /* Routines for encoding and decoding */
-static double single_decode(char *num, char **endptr_p,
+static float8 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
-static void pair_decode(char *str, double *x, double *y, char **endptr_p,
+static void pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
 static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
 
 
 /*
@@ -138,38 +138,38 @@ static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
  *
  * For boxes, the points are opposite corners with the first point at the top right.
  * For closed paths and polygons, the points should be reordered to allow
  *	fast and correct equality comparisons.
  *
  * XXX perhaps points in complex shapes should be reordered internally
  *	to allow faster internal operations, but should keep track of input order
  *	and restore that order for text output - tgl 97/01/16
  */
 
-static double
+static float8
 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string)
 {
 	return float8in_internal(num, endptr_p, type_name, orig_string);
 }								/* single_decode() */
 
 static void
 single_encode(float8 x, StringInfo str)
 {
 	char	   *xstr = float8out_internal(x);
 
 	appendStringInfoString(str, xstr);
 	pfree(xstr);
 }								/* single_encode() */
 
 static void
-pair_decode(char *str, double *x, double *y, char **endptr_p,
+pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string)
 {
 	bool		has_delim;
 
 	while (isspace((unsigned char) *str))
 		str++;
 	if ((has_delim = (*str == LDELIM)))
 		str++;
 
 	*x = float8in_internal(str, &str, type_name, orig_string);
@@ -368,33 +368,33 @@ pair_count(char *s, char delim)
  *		External format: (two corners of box)
  *				"(f8, f8), (f8, f8)"
  *				also supports the older style "(f8, f8, f8, f8)"
  */
 Datum
 box_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	BOX		   *box = (BOX *) palloc(sizeof(BOX));
 	bool		isopen;
-	double		x,
+	float8		x,
 				y;
 
 	path_decode(str, false, 2, &(box->high), &isopen, NULL, "box", str);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*		box_out -		convert a box to external form.
@@ -408,38 +408,38 @@ box_out(PG_FUNCTION_ARGS)
 }
 
 /*
  *		box_recv			- converts external binary format to box
  */
 Datum
 box_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	BOX		   *box;
-	double		x,
+	float8		x,
 				y;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
 	box->high.x = pq_getmsgfloat8(buf);
 	box->high.y = pq_getmsgfloat8(buf);
 	box->low.x = pq_getmsgfloat8(buf);
 	box->low.y = pq_getmsgfloat8(buf);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*
@@ -458,31 +458,31 @@ box_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, box->low.y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*		box_construct	-		fill in a new box.
  */
 static inline void
 box_construct(BOX *result, Point *pt1, Point *pt2)
 {
-	if (pt1->x > pt2->x)
+	if (float8_gt(pt1->x, pt2->x))
 	{
 		result->high.x = pt1->x;
 		result->low.x = pt2->x;
 	}
 	else
 	{
 		result->high.x = pt2->x;
 		result->low.x = pt1->x;
 	}
-	if (pt1->y > pt2->y)
+	if (float8_gt(pt1->y, pt2->y))
 	{
 		result->high.y = pt1->y;
 		result->low.y = pt2->y;
 	}
 	else
 	{
 		result->high.y = pt2->y;
 		result->low.y = pt1->y;
 	}
 }
@@ -800,54 +800,54 @@ box_center(PG_FUNCTION_ARGS)
 	Point	   *result = (Point *) palloc(sizeof(Point));
 
 	box_cn(result, box);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		box_ar	-		returns the area of the box.
  */
-static double
+static float8
 box_ar(BOX *box)
 {
-	return box_wd(box) * box_ht(box);
+	return float8_mul(box_wd(box), box_ht(box));
 }
 
 
 /*		box_cn	-		stores the centerpoint of the box into *center.
  */
 static void
 box_cn(Point *center, BOX *box)
 {
-	center->x = (box->high.x + box->low.x) / 2.0;
-	center->y = (box->high.y + box->low.y) / 2.0;
+	center->x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	center->y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 }
 
 
 /*		box_wd	-		returns the width (length) of the box
  *								  (horizontal magnitude).
  */
-static double
+static float8
 box_wd(BOX *box)
 {
-	return box->high.x - box->low.x;
+	return float8_mi(box->high.x, box->low.x);
 }
 
 
 /*		box_ht	-		returns the height of the box
  *								  (vertical magnitude).
  */
-static double
+static float8
 box_ht(BOX *box)
 {
-	return box->high.y - box->low.y;
+	return float8_mi(box->high.y, box->low.y);
 }
 
 
 /*----------------------------------------------------------
  *	Funky operations.
  *---------------------------------------------------------*/
 
 /*		box_intersect	-
  *				returns the overlapping portion of two boxes,
  *				  or NULL if they do not intersect.
@@ -857,24 +857,24 @@ box_intersect(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 	BOX		   *result;
 
 	if (!box_ov(box1, box2))
 		PG_RETURN_NULL();
 
 	result = (BOX *) palloc(sizeof(BOX));
 
-	result->high.x = Min(box1->high.x, box2->high.x);
-	result->low.x = Max(box1->low.x, box2->low.x);
-	result->high.y = Min(box1->high.y, box2->high.y);
-	result->low.y = Max(box1->low.y, box2->low.y);
+	result->high.x = float8_min(box1->high.x, box2->high.x);
+	result->low.x = float8_max(box1->low.x, box2->low.x);
+	result->high.y = float8_min(box1->high.y, box2->high.y);
+	result->low.y = float8_max(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(result);
 }
 
 
 /*		box_diagonal	-
  *				returns a line segment which happens to be the
  *				  positive-slope diagonal of "box".
  */
 Datum
@@ -1006,37 +1006,37 @@ line_send(PG_FUNCTION_ARGS)
 
 /*
  * Fill already-allocated LINE struct from the point and the slope
  */
 static inline void
 line_construct(LINE *result, Point *pt, float8 m)
 {
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
-		result->A = -1;
-		result->B = 0;
+		result->A = -1.0;
+		result->B = 0.0;
 		result->C = pt->x;
 	}
 	else if (m == 0.0)
 	{
 		/* horizontal - use "y = C" */
 		result->A = 0.0;
 		result->B = -1.0;
 		result->C = pt->y;
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
-		result->C = pt->y - m * pt->x;
+		result->C = float8_mi(pt->y, float8_mul(m, pt->x));
 	}
 }
 
 /* line_construct_pp()
  * two points
  */
 Datum
 line_construct_pp(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
@@ -1075,94 +1075,105 @@ Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
 	else if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
 
-	PG_RETURN_BOOL(FPeq(((l1->A * l2->B) / (l1->B * l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
+								   float8_mul(l1->B, l2->A)), -1.0));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
 Datum
 line_horizontal(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->A));
 }
 
+
+/*
+ * Check whether the two lines are the same
+ *
+ * We consider NaNs values to be equal to each other to let those lines
+ * to be found.
+ */
 Datum
 line_eq(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	double		k;
+	float8		ratio;
 
-	if (!FPzero(l2->A))
-		k = l1->A / l2->A;
-	else if (!FPzero(l2->B))
-		k = l1->B / l2->B;
-	else if (!FPzero(l2->C))
-		k = l1->C / l2->C;
+	if (!FPzero(l2->A) && !isnan(l2->A))
+		ratio = float8_div(l1->A, l2->A);
+	else if (!FPzero(l2->B) && !isnan(l2->B))
+		ratio = float8_div(l1->B, l2->B);
+	else if (!FPzero(l2->C) && !isnan(l2->C))
+		ratio = float8_div(l1->C, l2->C);
 	else
-		k = 1.0;
+		ratio = 1.0;
 
-	PG_RETURN_BOOL(FPeq(l1->A, k * l2->A) &&
-				   FPeq(l1->B, k * l2->B) &&
-				   FPeq(l1->C, k * l2->C));
+	PG_RETURN_BOOL(((isnan(l1->A) && isnan(l2->A)) ||
+					FPeq(l1->A, float8_mul(ratio, l2->A))) &&
+				   ((isnan(l1->B) && isnan(l2->B)) ||
+					FPeq(l1->B, float8_mul(ratio, l2->B))) &&
+				   ((isnan(l1->C) && isnan(l2->C)) ||
+					FPeq(l1->C, float8_mul(ratio, l2->C))));
 }
 
 
 /*----------------------------------------------------------
  *	Line arithmetic routines.
  *---------------------------------------------------------*/
 
 /*
  * Return inverse slope of the line
  */
 static inline float8
 line_invsl(LINE *line)
 {
 	if (FPzero(line->A))
 		return DBL_MAX;
 	if (FPzero(line->B))
 		return 0.0;
-	return line->B / line->A;
+	return float8_div(line->B, line->A);
 }
 
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
 	Point		tmp;
 
 	if (line_interpt_line(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
+		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
 	point_construct(&tmp, 0.0, l1->C);
 	result = line_closept_point(NULL, l2, &tmp);
 	PG_RETURN_FLOAT8(result);
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
@@ -1181,47 +1192,51 @@ line_interpt(PG_FUNCTION_ARGS)
 /*
  * Internal version of line_interpt
  *
  * This returns true if two lines intersect (they do, if they are not
  * parallel), false if they do not.  This also sets the intersection point
  * to *result, if it is not NULL.
  *
  * NOTE If the lines are identical then we will find they are parallel
  * and report "no intersection".  This is a little weird, but since
  * there's no *unique* intersection, maybe it's appropriate behavior.
+ *
+ * If the lines have NaN constants, we will return true, and the intersection
+ * point would have NaN coordinates.  We shouldn't return false in this case
+ * because that would mean the lines are parallel.
  */
 static bool
 line_interpt_line(Point *result, LINE *l1, LINE *l2)
 {
-	double		x,
+	float8		x,
 				y;
 
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
 		if (FPzero(l2->B))		/* l2 vertical? */
 			return false;
 
 		x = l1->C;
-		y = (l2->A * x + l2->C);
+		y = float8_pl(float8_mul(l2->A, x), l2->C);
 	}
 	else if (FPzero(l2->B))		/* l2 vertical? */
 	{
 		x = l2->C;
-		y = (l1->A * x + l1->C);
+		y = float8_pl(float8_mul(l1->A, x), l1->C);
 	}
 	else
 	{
-		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
 			return false;
 
-		x = (l1->C - l2->C) / (l2->A - l1->A);
-		y = (l1->A * x + l1->C);
+		x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
+		y = float8_pl(float8_mul(l1->A, x), l1->C);
 	}
 	if (result != NULL)
 		point_construct(result, x, y);
 
 	return true;
 }
 
 
 /***********************************************************************
  **
@@ -1242,36 +1257,35 @@ line_interpt_line(Point *result, LINE *l1, LINE *l2)
  *				"(xcoord, ycoord),... "
  *				"[xcoord, ycoord,... ]"
  *		Also support older format:
  *				"(closed, npts, xcoord, ycoord,... )"
  *---------------------------------------------------------*/
 
 Datum
 path_area(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P(0);
-	double		area = 0.0;
+	float8		area = 0.0;
 	int			i,
 				j;
 
 	if (!path->closed)
 		PG_RETURN_NULL();
 
 	for (i = 0; i < path->npts; i++)
 	{
 		j = (i + 1) % path->npts;
-		area += path->p[i].x * path->p[j].y;
-		area -= path->p[i].y * path->p[j].x;
+		area = float8_pl(area, float8_mul(path->p[i].x, path->p[j].y));
+		area = float8_mi(area, float8_mul(path->p[i].y, path->p[j].x));
 	}
 
-	area *= 0.5;
-	PG_RETURN_FLOAT8(area < 0.0 ? -area : area);
+	PG_RETURN_FLOAT8(float8_div(fabs(area), 2.0));
 }
 
 
 Datum
 path_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	PATH	   *path;
 	bool		isopen;
 	char	   *s;
@@ -1527,33 +1541,33 @@ path_inter(PG_FUNCTION_ARGS)
 				j;
 	LSEG		seg1,
 				seg2;
 
 	Assert(p1->npts > 0 && p2->npts > 0);
 
 	b1.high.x = b1.low.x = p1->p[0].x;
 	b1.high.y = b1.low.y = p1->p[0].y;
 	for (i = 1; i < p1->npts; i++)
 	{
-		b1.high.x = Max(p1->p[i].x, b1.high.x);
-		b1.high.y = Max(p1->p[i].y, b1.high.y);
-		b1.low.x = Min(p1->p[i].x, b1.low.x);
-		b1.low.y = Min(p1->p[i].y, b1.low.y);
+		b1.high.x = float8_max(p1->p[i].x, b1.high.x);
+		b1.high.y = float8_max(p1->p[i].y, b1.high.y);
+		b1.low.x = float8_min(p1->p[i].x, b1.low.x);
+		b1.low.y = float8_min(p1->p[i].y, b1.low.y);
 	}
 	b2.high.x = b2.low.x = p2->p[0].x;
 	b2.high.y = b2.low.y = p2->p[0].y;
 	for (i = 1; i < p2->npts; i++)
 	{
-		b2.high.x = Max(p2->p[i].x, b2.high.x);
-		b2.high.y = Max(p2->p[i].y, b2.high.y);
-		b2.low.x = Min(p2->p[i].x, b2.low.x);
-		b2.low.y = Min(p2->p[i].y, b2.low.y);
+		b2.high.x = float8_max(p2->p[i].x, b2.high.x);
+		b2.high.y = float8_max(p2->p[i].y, b2.high.y);
+		b2.low.x = float8_min(p2->p[i].x, b2.low.x);
+		b2.low.y = float8_min(p2->p[i].y, b2.low.y);
 	}
 	if (!box_ov(&b1, &b2))
 		PG_RETURN_BOOL(false);
 
 	/* pairwise check lseg intersections */
 	for (i = 0; i < p1->npts; i++)
 	{
 		int			iprev;
 
 		if (i > 0)
@@ -1629,21 +1643,21 @@ path_distance(PG_FUNCTION_ARGS)
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
 			tmp = lseg_closept_lseg(NULL, &seg1, &seg2);
-			if (!have_min || tmp < min)
+			if (!have_min || float8_lt(tmp, min))
 			{
 				min = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	if (!have_min)
 		PG_RETURN_NULL();
 
@@ -1668,21 +1682,21 @@ path_length(PG_FUNCTION_ARGS)
 
 		if (i > 0)
 			iprev = i - 1;
 		else
 		{
 			if (!path->closed)
 				continue;
 			iprev = path->npts - 1; /* include the closure segment */
 		}
 
-		result += point_dt(&path->p[iprev], &path->p[i]);
+		result = float8_pl(result, point_dt(&path->p[iprev], &path->p[i]));
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /***********************************************************************
  **
  **		Routines for 2D points.
  **
  ***********************************************************************/
@@ -1831,44 +1845,52 @@ point_eq(PG_FUNCTION_ARGS)
 
 Datum
 point_ne(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_BOOL(!point_eq_point(pt1, pt2));
 }
 
+
+/*
+ * Check whether the two points are the same
+ *
+ * We consider NaNs coordinates to be equal to each other to let those points
+ * to be found.
+ */
 static inline bool
 point_eq_point(Point *pt1, Point *pt2)
 {
-	return FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y);
+	return ((isnan(pt1->x) && isnan(pt2->x)) || FPeq(pt1->x, pt2->x)) &&
+		   ((isnan(pt1->y) && isnan(pt2->y)) || FPeq(pt1->y, pt2->y));
 }
 
 
 /*----------------------------------------------------------
  *	"Arithmetic" operators on points.
  *---------------------------------------------------------*/
 
 Datum
 point_distance(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
 static inline float8
 point_dt(Point *pt1, Point *pt2)
 {
-	return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
+	return HYPOT(float8_mi(pt1->x, pt2->x), float8_mi(pt1->y, pt2->y));
 }
 
 Datum
 point_slope(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_sl(pt1, pt2));
 }
@@ -1879,37 +1901,37 @@ point_slope(PG_FUNCTION_ARGS)
  *
  * Note that this function returns DBL_MAX when the points are the same.
  */
 static inline float8
 point_sl(Point *pt1, Point *pt2)
 {
 	if (FPeq(pt1->x, pt2->x))
 		return DBL_MAX;
 	if (FPeq(pt1->y, pt2->y))
 		return 0.0;
-	return (pt1->y - pt2->y) / (pt1->x - pt2->x);
+	return float8_div(float8_mi(pt1->y, pt2->y), float8_mi(pt1->x, pt2->x));
 }
 
 
 /*
  * Return inverse slope of two points
  *
  * Note that this function returns 0.0 when the points are the same.
  */
 static inline float8
 point_invsl(Point *pt1, Point *pt2)
 {
 	if (FPeq(pt1->x, pt2->x))
 		return 0.0;
 	if (FPeq(pt1->y, pt2->y))
 		return DBL_MAX;
-	return (pt1->x - pt2->x) / (pt2->y - pt1->y);
+	return float8_div(float8_mi(pt1->x, pt2->x), float8_mi(pt2->y, pt1->y));
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D line segments.
  **
  ***********************************************************************/
 
 /*----------------------------------------------------------
@@ -2169,22 +2191,22 @@ lseg_distance(PG_FUNCTION_ARGS)
 
 
 Datum
 lseg_center(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
-	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
+	result->x = float8_div(float8_pl(lseg->p[0].x, lseg->p[1].x), 2.0);
+	result->y = float8_div(float8_pl(lseg->p[0].y, lseg->p[1].y), 2.0);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  *		Find the intersection point of two segments (if any).
  *
  * This returns true if two line segments intersect, false if they do not.
  * This also sets the intersection point to *result, if it is not NULL.
@@ -2293,21 +2315,21 @@ dist_ppath(PG_FUNCTION_ARGS)
 			iprev = i - 1;
 		else
 		{
 			if (!path->closed)
 				continue;
 			iprev = path->npts - 1; /* Include the closure segment */
 		}
 
 		statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
 		tmp = lseg_closept_point(NULL, &lseg, pt);
-		if (!have_min || tmp < result)
+		if (!have_min || float8_lt(tmp, result))
 		{
 			result = tmp;
 			have_min = true;
 		}
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
@@ -2323,33 +2345,28 @@ dist_pb(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
-	float8		result,
-				d2;
+	float8		result;
 
 	if (lseg_interpt_line(NULL, lseg, line))
 		result = 0.0;
 	else
-	{
-		result = line_closept_point(NULL, line, &lseg->p[0]);
-		d2 = line_closept_point(NULL, line, &lseg->p[1]);
 		/* XXX shouldn't we take the min not max? */
-		if (d2 > result)
-			result = d2;
-	}
+		result = float8_max(line_closept_point(NULL, line, &lseg->p[0]),
+							line_closept_point(NULL, line, &lseg->p[1]));
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
@@ -2382,25 +2399,24 @@ dist_lb(PG_FUNCTION_ARGS)
  * Distance from a circle to a polygon
  */
 Datum
 dist_cpoly(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	POLYGON    *poly = PG_GETARG_POLYGON_P(1);
 	float8		result;
 
 	/* calculate distance to center, and subtract radius */
-	result = dist_ppoly_internal(&circle->center, poly);
-
-	result -= circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(dist_ppoly_internal(&circle->center, poly),
+					   circle->radius);
+	if (result < 0.0)
+		result = 0.0;
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a point to a polygon
  */
 Datum
 dist_ppoly(PG_FUNCTION_ARGS)
 {
@@ -2449,21 +2465,21 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
 	for (i = 0; i < poly->npts - 1; i++)
 	{
 		seg.p[0].x = poly->p[i].x;
 		seg.p[0].y = poly->p[i].y;
 		seg.p[1].x = poly->p[i + 1].x;
 		seg.p[1].y = poly->p[i + 1].y;
 		d = lseg_closept_point(NULL, &seg, pt);
 #ifdef GEODEBUG
 		printf("dist_ppoly_internal- segment %d distance is %f\n", (i + 1), d);
 #endif
-		if (d < result)
+		if (float8_lt(d, result))
 			result = d;
 	}
 
 	return result;
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
  *				Intersection point of objects.
@@ -2542,21 +2558,22 @@ line_closept_point(Point *result, LINE *line, Point *point)
 
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	line_closept_point(result, line, pt);
+	if (isnan(line_closept_point(result, line, pt)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point on line segment to specified point.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
@@ -2602,134 +2619,136 @@ close_ps(PG_FUNCTION_ARGS)
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  *
  * XXX This function is wrong.  If must never set the *result to a point on
  * the second segment.
  */
 static float8
 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
 {
 	Point		point;
-	double		dist;
-	double		d;
+	float8		dist,
+				d;
 
 	d = lseg_closept_point(NULL, l1, &l2->p[0]);
 	dist = d;
 	if (result != NULL)
 		*result = l2->p[0];
 
 	d = lseg_closept_point(NULL, l1, &l2->p[1]);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = l2->p[1];
 	}
 
-	if (lseg_closept_point(&point, l2, &l1->p[0]) < dist)
+	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[0]), dist))
 		d = lseg_closept_point(result, l1, &point);
 
-	if (lseg_closept_point(&point, l2, &l1->p[1]) < dist)
+	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[1]), dist))
 		d = lseg_closept_point(result, l1, &point);
 
-	if (d < dist)
+	if (float8_lt(d, dist))
 		dist = d;
 
 	return dist;
 }
 
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	lseg_closept_lseg(result, l2, l1);
+	if (isnan(lseg_closept_lseg(result, l2, l1)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point on or in box to specified point.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 box_closept_point(Point *result, BOX *box, Point *pt)
 {
-	LSEG		lseg;
+	float8		dist,
+				d;
 	Point		point,
 				closept;
-	double		dist,
-				d;
+	LSEG		lseg;
 
 	if (box_contain_point(box, pt))
 	{
 		if (result != NULL)
 			*result = *pt;
 
 		return 0.0;
 	}
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&lseg, &box->low, &point);
 	dist = lseg_closept_point(result, &lseg, pt);
 
 	statlseg_construct(&lseg, &box->high, &point);
 	d = lseg_closept_point(&closept, &lseg, pt);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&lseg, &box->low, &point);
 	d = lseg_closept_point(&closept, &lseg, pt);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	statlseg_construct(&lseg, &box->high, &point);
 	d = lseg_closept_point(&closept, &lseg, pt);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	return dist;
 }
 
 Datum
 close_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	box_closept_point(result, box, pt);
+	if (isnan(box_closept_point(result, box, pt)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_sl()
  * Closest point on line to line segment.
  *
  * XXX THIS CODE IS WRONG
  * The code is actually calculating the point on the line segment
@@ -2747,21 +2766,21 @@ close_sl(PG_FUNCTION_ARGS)
 	float8		d1,
 				d2;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (lseg_interpt_line(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = line_closept_point(NULL, line, &lseg->p[0]);
 	d2 = line_closept_point(NULL, line, &lseg->p[1]);
-	if (d1 < d2)
+	if (float8_lt(d1, d2))
 		*result = lseg->p[0];
 	else
 		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
 
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_sl\" not implemented")));
@@ -2811,92 +2830,94 @@ lseg_closept_line(Point *result, LSEG *lseg, LINE *line)
 
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	lseg_closept_line(result, lseg, line);
+	if (isnan(lseg_closept_line(result, lseg, line)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point on or in box to line segment.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 box_closept_lseg(Point *result, BOX *box, LSEG *lseg)
 {
+	float8		dist,
+				d;
 	Point		point,
 				closept;
 	LSEG		bseg;
-	double		dist,
-				d;
 
 	if (box_interpt_lseg(result, box, lseg))
 		return 0.0;
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
 	dist = lseg_closept_lseg(result, &bseg, lseg);
 
 	statlseg_construct(&bseg, &box->high, &point);
 	d = lseg_closept_lseg(&closept, &bseg, lseg);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&bseg, &box->low, &point);
 	d = lseg_closept_lseg(&closept, &bseg, lseg);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	statlseg_construct(&bseg, &box->high, &point);
 	d = lseg_closept_lseg(&closept, &bseg, lseg);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	return dist;
 }
 
 Datum
 close_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	box_closept_lseg(result, box, lseg);
+	if (isnan(box_closept_lseg(result, box, lseg)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 Datum
 close_lb(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -2915,21 +2936,23 @@ close_lb(PG_FUNCTION_ARGS)
  *		on_
  *				Whether one object lies completely within another.
  *-------------------------------------------------------------------*/
 
 /*
  *		Does the point satisfy the equation?
  */
 static bool
 line_contain_point(LINE *line, Point *point)
 {
-	return FPzero(line->A * point->x + line->B * point->y + line->C);
+	return FPzero(float8_pl(float8_pl(float8_mul(line->A, point->x),
+									  float8_mul(line->B, point->y)),
+							line->C));
 }
 
 Datum
 on_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
 	PG_RETURN_BOOL(line_contain_point(line, pt));
 }
@@ -2996,33 +3019,32 @@ box_contain_pt(PG_FUNCTION_ARGS)
  *				but not cross.
  *				(we can do p-in-p in lg(n), but it takes preprocessing)
  */
 Datum
 on_ppath(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	PATH	   *path = PG_GETARG_PATH_P(1);
 	int			i,
 				n;
-	double		a,
+	float8		a,
 				b;
 
 	/*-- OPEN --*/
 	if (!path->closed)
 	{
 		n = path->npts - 1;
 		a = point_dt(pt, &path->p[0]);
 		for (i = 0; i < n; i++)
 		{
 			b = point_dt(pt, &path->p[i + 1]);
-			if (FPeq(a + b,
-					 point_dt(&path->p[i], &path->p[i + 1])))
+			if (FPeq(float8_pl(a, b), point_dt(&path->p[i], &path->p[i + 1])))
 				PG_RETURN_BOOL(true);
 			a = b;
 		}
 		PG_RETURN_BOOL(false);
 	}
 
 	/*-- CLOSED --*/
 	PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
 }
 
@@ -3094,24 +3116,24 @@ inter_sl(PG_FUNCTION_ARGS)
  * Optimize for non-intersection by checking for box intersection first.
  * - thomas 1998-01-30
  */
 static bool
 box_interpt_lseg(Point *result, BOX *box, LSEG *lseg)
 {
 	BOX			lbox;
 	LSEG		bseg;
 	Point		point;
 
-	lbox.low.x = Min(lseg->p[0].x, lseg->p[1].x);
-	lbox.low.y = Min(lseg->p[0].y, lseg->p[1].y);
-	lbox.high.x = Max(lseg->p[0].x, lseg->p[1].x);
-	lbox.high.y = Max(lseg->p[0].y, lseg->p[1].y);
+	lbox.low.x = float8_min(lseg->p[0].x, lseg->p[1].x);
+	lbox.low.y = float8_min(lseg->p[0].y, lseg->p[1].y);
+	lbox.high.x = float8_max(lseg->p[0].x, lseg->p[1].x);
+	lbox.high.y = float8_max(lseg->p[0].y, lseg->p[1].y);
 
 	/* nothing close to overlap? then not going to intersect */
 	if (!box_ov(&lbox, box))
 		return false;
 
 	if (result != NULL)
 	{
 		box_cn(&point, box);
 		lseg_closept_point(result, lseg, &point);
 	}
@@ -3204,38 +3226,38 @@ inter_lb(PG_FUNCTION_ARGS)
  * make_bound_box - create the bounding box for the input polygon
  *------------------------------------------------------------------*/
 
 /*---------------------------------------------------------------------
  * Make the smallest bounding box for the given polygon.
  *---------------------------------------------------------------------*/
 static void
 make_bound_box(POLYGON *poly)
 {
 	int			i;
-	double		x1,
+	float8		x1,
 				y1,
 				x2,
 				y2;
 
 	Assert(poly->npts > 0);
 
 	x1 = x2 = poly->p[0].x;
 	y2 = y1 = poly->p[0].y;
 	for (i = 1; i < poly->npts; i++)
 	{
-		if (poly->p[i].x < x1)
+		if (float8_lt(poly->p[i].x, x1))
 			x1 = poly->p[i].x;
-		if (poly->p[i].x > x2)
+		if (float8_gt(poly->p[i].x, x2))
 			x2 = poly->p[i].x;
-		if (poly->p[i].y < y1)
+		if (float8_lt(poly->p[i].y, y1))
 			y1 = poly->p[i].y;
-		if (poly->p[i].y > y2)
+		if (float8_gt(poly->p[i].y, y2))
 			y2 = poly->p[i].y;
 	}
 
 	poly->boundbox.low.x = x1;
 	poly->boundbox.high.x = x2;
 	poly->boundbox.low.y = y1;
 	poly->boundbox.high.y = y2;
 }
 
 /*------------------------------------------------------------------
@@ -3734,22 +3756,22 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 	}
 
 	if (res && !intersection)
 	{
 		Point		p;
 
 		/*
 		 * if X-intersection wasn't found  then check central point of tested
 		 * segment. In opposite case we already check all subsegments
 		 */
-		p.x = (t.p[0].x + t.p[1].x) / 2.0;
-		p.y = (t.p[0].y + t.p[1].y) / 2.0;
+		p.x = float8_div(float8_pl(t.p[0].x, t.p[1].x), 2.0);
+		p.y = float8_div(float8_pl(t.p[0].y, t.p[1].y), 2.0);
 
 		res = point_inside(&p, poly->npts, poly->p);
 	}
 
 	return res;
 }
 
 /*-----------------------------------------------------------------
  * Determine if polygon A contains polygon B.
  *-----------------------------------------------------------------*/
@@ -3875,22 +3897,22 @@ construct_point(PG_FUNCTION_ARGS)
 	point_construct(result, x, y);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_add_point(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x + pt2->x,
-					pt1->y + pt2->y);
+					float8_pl(pt1->x, pt2->x),
+					float8_pl(pt1->y, pt2->y));
 }
 
 Datum
 point_add(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -3898,22 +3920,22 @@ point_add(PG_FUNCTION_ARGS)
 	point_add_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_sub_point(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x - pt2->x,
-					pt1->y - pt2->y);
+					float8_mi(pt1->x, pt2->x),
+					float8_mi(pt1->y, pt2->y));
 }
 
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -3921,54 +3943,53 @@ point_sub(PG_FUNCTION_ARGS)
 	point_sub_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_mul_point(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					(pt1->x * pt2->x) - (pt1->y * pt2->y),
-					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+					float8_mi(float8_mul(pt1->x, pt2->x),
+							  float8_mul(pt1->y, pt2->y)),
+					float8_pl(float8_mul(pt1->x, pt2->y),
+							  float8_mul(pt1->y, pt2->x)));
 }
 
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	point_mul_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_div_point(Point *result, Point *pt1, Point *pt2)
 {
-	double		div;
+	float8		div;
 
-	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
-
-	if (div == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
+	div = float8_pl(float8_mul(pt2->x, pt2->x), float8_mul(pt2->y, pt2->y));
 
 	point_construct(result,
-					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
-					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+					float8_div(float8_pl(float8_mul(pt1->x, pt2->x),
+										 float8_mul(pt1->y, pt2->y)), div),
+					float8_div(float8_mi(float8_mul(pt1->y, pt2->x),
+										 float8_mul(pt1->x, pt2->y)), div));
 }
 
 Datum
 point_div(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -4091,24 +4112,24 @@ point_box(PG_FUNCTION_ARGS)
  */
 Datum
 boxes_bound_box(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0),
 			   *box2 = PG_GETARG_BOX_P(1),
 			   *container;
 
 	container = (BOX *) palloc(sizeof(BOX));
 
-	container->high.x = Max(box1->high.x, box2->high.x);
-	container->low.x = Min(box1->low.x, box2->low.x);
-	container->high.y = Max(box1->high.y, box2->high.y);
-	container->low.y = Min(box1->low.y, box2->low.y);
+	container->high.x = float8_max(box1->high.x, box2->high.x);
+	container->low.x = float8_min(box1->low.x, box2->low.x);
+	container->high.y = float8_max(box1->high.y, box2->high.y);
+	container->low.y = float8_min(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(container);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D paths.
  **
  ***********************************************************************/
@@ -4414,21 +4435,22 @@ circle_in(PG_FUNCTION_ARGS)
 		if (*cp == LDELIM)
 			s = cp;
 	}
 
 	pair_decode(s, &circle->center.x, &circle->center.y, &s, "circle", str);
 
 	if (*s == DELIM)
 		s++;
 
 	circle->radius = single_decode(s, &s, "circle", str);
-	if (circle->radius < 0)
+	/* We have to accept NaN as well. */
+	if (circle->radius < 0.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
 
 	while (depth > 0)
 	{
 		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
@@ -4481,21 +4503,21 @@ circle_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	circle->center.x = pq_getmsgfloat8(buf);
 	circle->center.y = pq_getmsgfloat8(buf);
 	circle->radius = pq_getmsgfloat8(buf);
 
-	if (circle->radius < 0)
+	if (circle->radius < 0.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
 				 errmsg("invalid radius in external \"circle\" value")));
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 /*
  *		circle_send			- converts circle to binary format
  */
@@ -4512,166 +4534,170 @@ circle_send(PG_FUNCTION_ARGS)
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for CIRCLEs.
  *		<, >, <=, >=, and == are based on circle area.
  *---------------------------------------------------------*/
 
 /*		circles identical?
+ *
+ * We consider NaNs values to be equal to each other to let those circles
+ * to be found.
  */
 Datum
 circle_same(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPeq(circle1->radius, circle2->radius) &&
+	PG_RETURN_BOOL(((isnan(circle1->radius) && isnan(circle1->radius)) ||
+					FPeq(circle1->radius, circle2->radius)) &&
 				   point_eq_point(&circle1->center, &circle2->center));
 }
 
 /*		circle_overlap	-		does circle1 overlap circle2?
  */
 Datum
 circle_overlap(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle1->radius + circle2->radius));
+						float8_pl(circle1->radius, circle2->radius)));
 }
 
 /*		circle_overleft -		is the right edge of circle1 at or left of
  *								the right edge of circle2?
  */
 Datum
 circle_overleft(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.x + circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_left		-		is circle1 strictly left of circle2?
  */
 Datum
 circle_left(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.x + circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_right	-		is circle1 strictly right of circle2?
  */
 Datum
 circle_right(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.x - circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_overright	-	is the left edge of circle1 at or right of
  *								the left edge of circle2?
  */
 Datum
 circle_overright(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.x - circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_contained		-		is circle1 contained by circle2?
  */
 Datum
 circle_contained(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle2->radius - circle1->radius));
+						float8_mi(circle2->radius, circle1->radius)));
 }
 
 /*		circle_contain	-		does circle1 contain circle2?
  */
 Datum
 circle_contain(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle1->radius - circle2->radius));
+						float8_mi(circle1->radius, circle2->radius)));
 }
 
 
 /*		circle_below		-		is circle1 strictly below circle2?
  */
 Datum
 circle_below(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.y + circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_above	-		is circle1 strictly above circle2?
  */
 Datum
 circle_above(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.y - circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overbelow -		is the upper edge of circle1 at or below
  *								the upper edge of circle2?
  */
 Datum
 circle_overbelow(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.y + circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overabove	-	is the lower edge of circle1 at or above
  *								the lower edge of circle2?
  */
 Datum
 circle_overabove(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.y - circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 
 /*		circle_relop	-		is area(circle1) relop area(circle2), within
  *								our accuracy constraint?
  */
 Datum
 circle_eq(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
@@ -4770,36 +4796,36 @@ circle_sub_pt(PG_FUNCTION_ARGS)
 Datum
 circle_mul_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_mul_point(&result->center, &circle->center, point);
-	result->radius = circle->radius * HYPOT(point->x, point->y);
+	result->radius = float8_mul(circle->radius, HYPOT(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_div_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_div_point(&result->center, &circle->center, point);
-	result->radius = circle->radius / HYPOT(point->x, point->y);
+	result->radius = float8_div(circle->radius, HYPOT(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /*		circle_area		-		returns the area of the circle.
  */
 Datum
 circle_area(PG_FUNCTION_ARGS)
 {
@@ -4809,21 +4835,21 @@ circle_area(PG_FUNCTION_ARGS)
 }
 
 
 /*		circle_diameter -		returns the diameter of the circle.
  */
 Datum
 circle_diameter(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
-	PG_RETURN_FLOAT8(2 * circle->radius);
+	PG_RETURN_FLOAT8(float8_mul(circle->radius, 2.0));
 }
 
 
 /*		circle_radius	-		returns the radius of the circle.
  */
 Datum
 circle_radius(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
@@ -4834,81 +4860,85 @@ circle_radius(PG_FUNCTION_ARGS)
 /*		circle_distance -		returns the distance between
  *								  two circles.
  */
 Datum
 circle_distance(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(&circle1->center, &circle2->center) -
-		(circle1->radius + circle2->radius);
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(&circle1->center, &circle2->center),
+					   float8_pl(circle1->radius, circle2->radius));
+	if (result < 0.0)
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 
 Datum
 circle_contain_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
 	PG_RETURN_BOOL(d <= circle->radius);
 }
 
 
 Datum
 pt_contained_circle(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
 	PG_RETURN_BOOL(d <= circle->radius);
 }
 
 
 /*		dist_pc -		returns the distance between
  *						  a point and a circle.
  */
 Datum
 dist_pc(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center),
+					   circle->radius);
+	if (result < 0.0)
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a circle to a point
  */
 Datum
 dist_cpoint(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center), circle->radius);
+	if (result < 0.0)
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*		circle_center	-		returns the center point of the circle.
  */
 Datum
 circle_center(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *result;
@@ -4916,24 +4946,24 @@ circle_center(PG_FUNCTION_ARGS)
 	result = (Point *) palloc(sizeof(Point));
 	result->x = circle->center.x;
 	result->y = circle->center.y;
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		circle_ar		-		returns the area of the circle.
  */
-static double
+static float8
 circle_ar(CIRCLE *circle)
 {
-	return M_PI * (circle->radius * circle->radius);
+	return float8_mul(float8_mul(circle->radius, circle->radius), M_PI);
 }
 
 
 /*----------------------------------------------------------
  *	Conversion operators.
  *---------------------------------------------------------*/
 
 Datum
 cr_circle(PG_FUNCTION_ARGS)
 {
@@ -4948,65 +4978,65 @@ cr_circle(PG_FUNCTION_ARGS)
 	result->radius = radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_box(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	BOX		   *box;
-	double		delta;
+	float8		delta;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
-	delta = circle->radius / sqrt(2.0);
+	delta = float8_div(circle->radius, sqrt(2.0));
 
-	box->high.x = circle->center.x + delta;
-	box->low.x = circle->center.x - delta;
-	box->high.y = circle->center.y + delta;
-	box->low.y = circle->center.y - delta;
+	box->high.x = float8_pl(circle->center.x, delta);
+	box->low.x = float8_mi(circle->center.x, delta);
+	box->high.y = float8_pl(circle->center.y, delta);
+	box->low.y = float8_mi(circle->center.y, delta);
 
 	PG_RETURN_BOX_P(box);
 }
 
 /* box_circle()
  * Convert a box to a circle.
  */
 Datum
 box_circle(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	circle->center.x = (box->high.x + box->low.x) / 2;
-	circle->center.y = (box->high.y + box->low.y) / 2;
+	circle->center.x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	circle->center.y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 
 	circle->radius = point_dt(&circle->center, &box->high);
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 
 Datum
 circle_poly(PG_FUNCTION_ARGS)
 {
 	int32		npts = PG_GETARG_INT32(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	POLYGON    *poly;
 	int			base_size,
 				size;
 	int			i;
-	double		angle;
-	double		anglestep;
+	float8		angle;
+	float8		anglestep;
 
 	if (FPzero(circle->radius))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("cannot convert circle with radius zero to polygon")));
 
 	if (npts < 2)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("must request at least 2 points")));
@@ -5017,27 +5047,30 @@ circle_poly(PG_FUNCTION_ARGS)
 	/* Check for integer overflow */
 	if (base_size / npts != sizeof(poly->p[0]) || size <= base_size)
 		ereport(ERROR,
 				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 				 errmsg("too many points requested")));
 
 	poly = (POLYGON *) palloc0(size);	/* zero any holes */
 	SET_VARSIZE(poly, size);
 	poly->npts = npts;
 
-	anglestep = (2.0 * M_PI) / npts;
+	anglestep = float8_div(2.0 * M_PI, npts);
 
 	for (i = 0; i < npts; i++)
 	{
-		angle = i * anglestep;
-		poly->p[i].x = circle->center.x - (circle->radius * cos(angle));
-		poly->p[i].y = circle->center.y + (circle->radius * sin(angle));
+		angle = float8_mul(anglestep, i);
+
+		poly->p[i].x = float8_mi(circle->center.x,
+								 float8_mul(circle->radius, cos(angle)));
+		poly->p[i].y = float8_pl(circle->center.y,
+								 float8_mul(circle->radius, sin(angle)));
 	}
 
 	make_bound_box(poly);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
 /*
  * Convert polygon to circle
  *
@@ -5052,26 +5085,27 @@ poly_to_circle(CIRCLE *result, POLYGON *poly)
 	int			i;
 
 	Assert(poly->npts > 0);
 
 	result->center.x = 0;
 	result->center.y = 0;
 	result->radius = 0;
 
 	for (i = 0; i < poly->npts; i++)
 		point_add_point(&result->center, &result->center, &poly->p[i]);
-	result->center.x /= poly->npts;
-	result->center.y /= poly->npts;
+	result->center.x = float8_div(result->center.x, poly->npts);
+	result->center.y = float8_div(result->center.y, poly->npts);
 
 	for (i = 0; i < poly->npts; i++)
-		result->radius += point_dt(&poly->p[i], &result->center);
-	result->radius /= poly->npts;
+		result->radius = float8_pl(result->radius,
+								   point_dt(&poly->p[i], &result->center));
+	result->radius = float8_div(result->radius, poly->npts);
 }
 
 Datum
 poly_circle(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
@@ -5096,44 +5130,44 @@ poly_circle(PG_FUNCTION_ARGS)
  *	http://hopf.math.northwestern.edu/index.html
  *	Description of algorithm:  http://www.linuxjournal.com/article/2197
  *							   http://www.linuxjournal.com/article/2029
  */
 
 #define POINT_ON_POLYGON INT_MAX
 
 static int
 point_inside(Point *p, int npts, Point *plist)
 {
-	double		x0,
+	float8		x0,
 				y0;
-	double		prev_x,
+	float8		prev_x,
 				prev_y;
 	int			i = 0;
-	double		x,
+	float8		x,
 				y;
 	int			cross,
 				total_cross = 0;
 
 	Assert(npts > 0);
 
 	/* compute first polygon point relative to single point */
-	x0 = plist[0].x - p->x;
-	y0 = plist[0].y - p->y;
+	x0 = float8_mi(plist[0].x, p->x);
+	y0 = float8_mi(plist[0].y, p->y);
 
 	prev_x = x0;
 	prev_y = y0;
 	/* loop over polygon points and aggregate total_cross */
 	for (i = 1; i < npts; i++)
 	{
 		/* compute next polygon point relative to single point */
-		x = plist[i].x - p->x;
-		y = plist[i].y - p->y;
+		x = float8_mi(plist[i].x, p->x);
+		y = float8_mi(plist[i].y, p->y);
 
 		/* compute previous to current point crossing */
 		if ((cross = lseg_crossing(x, y, prev_x, prev_y)) == POINT_ON_POLYGON)
 			return 2;
 		total_cross += cross;
 
 		prev_x = x;
 		prev_y = y;
 	}
 
@@ -5151,69 +5185,74 @@ point_inside(Point *p, int npts, Point *plist)
 /* lseg_crossing()
  * Returns +/-2 if line segment crosses the positive X-axis in a +/- direction.
  * Returns +/-1 if one point is on the positive X-axis.
  * Returns 0 if both points are on the positive X-axis, or there is no crossing.
  * Returns POINT_ON_POLYGON if the segment contains (0,0).
  * Wow, that is one confusing API, but it is used above, and when summed,
  * can tell is if a point is in a polygon.
  */
 
 static int
-lseg_crossing(double x, double y, double prev_x, double prev_y)
+lseg_crossing(float8 x, float8 y, float8 prev_x, float8 prev_y)
 {
-	double		z;
+	float8		z;
 	int			y_sign;
 
 	if (FPzero(y))
 	{							/* y == 0, on X axis */
 		if (FPzero(x))			/* (x,y) is (0,0)? */
 			return POINT_ON_POLYGON;
 		else if (FPgt(x, 0))
 		{						/* x > 0 */
 			if (FPzero(prev_y)) /* y and prev_y are zero */
 				/* prev_x > 0? */
-				return FPgt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
-			return FPlt(prev_y, 0) ? 1 : -1;
+				return FPgt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
+			return FPlt(prev_y, 0.0) ? 1 : -1;
 		}
 		else
 		{						/* x < 0, x not on positive X axis */
 			if (FPzero(prev_y))
 				/* prev_x < 0? */
-				return FPlt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
+				return FPlt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
 			return 0;
 		}
 	}
 	else
 	{							/* y != 0 */
 		/* compute y crossing direction from previous point */
-		y_sign = FPgt(y, 0) ? 1 : -1;
+		y_sign = FPgt(y, 0.0) ? 1 : -1;
 
 		if (FPzero(prev_y))
 			/* previous point was on X axis, so new point is either off or on */
-			return FPlt(prev_x, 0) ? 0 : y_sign;
-		else if (FPgt(y_sign * prev_y, 0))
+			return FPlt(prev_x, 0.0) ? 0 : y_sign;
+		else if ((y_sign < 0 && FPlt(prev_y, 0.0)) ||
+				 (y_sign > 0 && FPgt(prev_y, 0.0)))
 			/* both above or below X axis */
 			return 0;			/* same sign */
 		else
 		{						/* y and prev_y cross X-axis */
-			if (FPge(x, 0) && FPgt(prev_x, 0))
+			if (FPge(x, 0.0) && FPgt(prev_x, 0.0))
 				/* both non-negative so cross positive X-axis */
 				return 2 * y_sign;
-			if (FPlt(x, 0) && FPle(prev_x, 0))
+			if (FPlt(x, 0.0) && FPle(prev_x, 0.0))
 				/* both non-positive so do not cross positive X-axis */
 				return 0;
 
 			/* x and y cross axises, see URL above point_inside() */
-			z = (x - prev_x) * y - (y - prev_y) * x;
+			z = float8_mi(float8_mul(float8_mi(x, prev_x), y),
+						  float8_mul(float8_mi(y, prev_y), x));
 			if (FPzero(z))
 				return POINT_ON_POLYGON;
-			return FPgt((y_sign * z), 0) ? 0 : 2 * y_sign;
+			if ((y_sign < 0 && FPlt(z, 0.0)) ||
+				(y_sign > 0 && FPgt(z, 0.0)))
+				return 0;
+			return 2 * y_sign;
 		}
 	}
 }
 
 
 static bool
 plist_same(int npts, Point *p1, Point *p2)
 {
 	int			i,
 				ii,
@@ -5283,47 +5322,52 @@ plist_same(int npts, Point *p1, Point *p2)
  *					 = x * sqrt( 1 + y^2/x^2 )
  *					 = x * sqrt( 1 + y/x * y/x )
  *
  * It is expected that this routine will eventually be replaced with the
  * C99 hypot() function.
  *
  * This implementation conforms to IEEE Std 1003.1 and GLIBC, in that the
  * case of hypot(inf,nan) results in INF, and not NAN.
  *-----------------------------------------------------------------------
  */
-double
-pg_hypot(double x, double y)
+float8
+pg_hypot(float8 x, float8 y)
 {
-	double		yx;
+	float8		yx,
+				result;
 
 	/* Handle INF and NaN properly */
 	if (isinf(x) || isinf(y))
 		return get_float8_infinity();
 
 	if (isnan(x) || isnan(y))
 		return get_float8_nan();
 
 	/* Else, drop any minus signs */
 	x = fabs(x);
 	y = fabs(y);
 
 	/* Swap x and y if needed to make x the larger one */
 	if (x < y)
 	{
-		double		temp = x;
+		float8		temp = x;
 
 		x = y;
 		y = temp;
 	}
 
 	/*
 	 * If y is zero, the hypotenuse is x.  This test saves a few cycles in
 	 * such cases, but more importantly it also protects against
 	 * divide-by-zero errors, since now x >= y.
 	 */
 	if (y == 0.0)
 		return x;
 
 	/* Determine the hypotenuse */
 	yx = y / x;
-	return x * sqrt(1.0 + (yx * yx));
+	result = x * sqrt(1.0 + (yx * yx));
+
+	check_float8_val(result, false, false);
+
+	return result;
 }
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index 096e59f817..b4008d7423 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -76,38 +76,38 @@
 #include "access/spgist.h"
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
 #include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
- * is going only going to be used in a place to effect the performance
+ * is only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
 compareDoubles(const void *a, const void *b)
 {
-	double		x = *(double *) a;
-	double		y = *(double *) b;
+	float8		x = *(float8 *) a;
+	float8		y = *(float8 *) b;
 
 	if (x == y)
 		return 0;
 	return (x > y) ? 1 : -1;
 }
 
 typedef struct
 {
-	double		low;
-	double		high;
+	float8		low;
+	float8		high;
 } Range;
 
 typedef struct
 {
 	Range		left;
 	Range		right;
 } RangeBox;
 
 typedef struct
 {
@@ -167,21 +167,21 @@ getRangeBox(BOX *box)
 /*
  * Initialize the traversal value
  *
  * In the beginning, we don't have any restrictions.  We have to
  * initialize the struct to cover the whole 4D space.
  */
 static RectBox *
 initRectBox(void)
 {
 	RectBox    *rect_box = (RectBox *) palloc(sizeof(RectBox));
-	double		infinity = get_float8_infinity();
+	float8		infinity = get_float8_infinity();
 
 	rect_box->range_box_x.left.low = -infinity;
 	rect_box->range_box_x.left.high = infinity;
 
 	rect_box->range_box_x.right.low = -infinity;
 	rect_box->range_box_x.right.high = infinity;
 
 	rect_box->range_box_y.left.low = -infinity;
 	rect_box->range_box_y.left.high = infinity;
 
@@ -410,40 +410,40 @@ spg_box_quad_choose(PG_FUNCTION_ARGS)
  * point as the median of the coordinates of the boxes.
  */
 Datum
 spg_box_quad_picksplit(PG_FUNCTION_ARGS)
 {
 	spgPickSplitIn *in = (spgPickSplitIn *) PG_GETARG_POINTER(0);
 	spgPickSplitOut *out = (spgPickSplitOut *) PG_GETARG_POINTER(1);
 	BOX		   *centroid;
 	int			median,
 				i;
-	double	   *lowXs = palloc(sizeof(double) * in->nTuples);
-	double	   *highXs = palloc(sizeof(double) * in->nTuples);
-	double	   *lowYs = palloc(sizeof(double) * in->nTuples);
-	double	   *highYs = palloc(sizeof(double) * in->nTuples);
+	float8	   *lowXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *lowYs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highYs = palloc(sizeof(float8) * in->nTuples);
 
 	/* Calculate median of all 4D coordinates */
 	for (i = 0; i < in->nTuples; i++)
 	{
 		BOX		   *box = DatumGetBoxP(in->datums[i]);
 
 		lowXs[i] = box->low.x;
 		highXs[i] = box->high.x;
 		lowYs[i] = box->low.y;
 		highYs[i] = box->high.y;
 	}
 
-	qsort(lowXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(lowYs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highYs, in->nTuples, sizeof(double), compareDoubles);
+	qsort(lowXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(lowYs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highYs, in->nTuples, sizeof(float8), compareDoubles);
 
 	median = in->nTuples / 2;
 
 	centroid = palloc(sizeof(BOX));
 
 	centroid->low.x = lowXs[median];
 	centroid->high.x = highXs[median];
 	centroid->low.y = lowYs[median];
 	centroid->high.y = highYs[median];
 
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index aeb31515e4..d14e8c8f72 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -1,42 +1,41 @@
 /*-------------------------------------------------------------------------
  *
  * geo_decls.h - Declarations for various 2D constructs.
  *
  *
  * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * src/include/utils/geo_decls.h
  *
- * NOTE
- *	  These routines do *not* use the float types from adt/.
- *
  *	  XXX These routines were not written by a numerical analyst.
  *
  *	  XXX I have made some attempt to flesh out the operators
  *		and data types. There are still some more to do. - tgl 97/04/19
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEO_DECLS_H
 #define GEO_DECLS_H
 
 #include <math.h>
 
 #include "fmgr.h"
 #include "utils/float.h"
 
 /*--------------------------------------------------------------------
  * Useful floating point utilities and constants.
- *-------------------------------------------------------------------*/
-
+ *-------------------------------------------------------------------
+ *
+ * XXX They are not NaN-aware.
+ */
 
 #define EPSILON					1.0E-06
 
 #ifdef EPSILON
 #define FPzero(A)				(fabs(A) <= EPSILON)
 #define FPeq(A,B)				(fabs((A) - (B)) <= EPSILON)
 #define FPne(A,B)				(fabs((A) - (B)) > EPSILON)
 #define FPlt(A,B)				((B) - (A) > EPSILON)
 #define FPle(A,B)				((A) - (B) <= EPSILON)
 #define FPgt(A,B)				((A) - (B) > EPSILON)
@@ -51,21 +50,21 @@
 #define FPge(A,B)				((A) >= (B))
 #endif
 
 #define HYPOT(A, B)				pg_hypot(A, B)
 
 /*---------------------------------------------------------------------
  * Point - (x,y)
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		x,
+	float8		x,
 				y;
 } Point;
 
 
 /*---------------------------------------------------------------------
  * LSEG - A straight line, specified by endpoints.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		p[2];
@@ -83,21 +82,21 @@ typedef struct
 	int32		dummy;			/* padding to make it double align */
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } PATH;
 
 
 /*---------------------------------------------------------------------
  * LINE - Specified by its general equation (Ax+By+C=0).
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		A,
+	float8		A,
 				B,
 				C;
 } LINE;
 
 
 /*---------------------------------------------------------------------
  * BOX	- Specified by two corner points, which are
  *		 sorted to save calculation time later.
  *-------------------------------------------------------------------*/
 typedef struct
@@ -118,21 +117,21 @@ typedef struct
 	BOX			boundbox;
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } POLYGON;
 
 /*---------------------------------------------------------------------
  * CIRCLE - Specified by a center point and radius.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		center;
-	double		radius;
+	float8		radius;
 } CIRCLE;
 
 /*
  * fmgr interface macros
  *
  * Path and Polygon are toastable varlena types, the others are just
  * fixed-size pass-by-reference types.
  */
 
 #define DatumGetPointP(X)	 ((Point *) DatumGetPointer(X))
@@ -172,13 +171,13 @@ typedef struct
 #define DatumGetCircleP(X)	  ((CIRCLE *) DatumGetPointer(X))
 #define CirclePGetDatum(X)	  PointerGetDatum(X)
 #define PG_GETARG_CIRCLE_P(n) DatumGetCircleP(PG_GETARG_DATUM(n))
 #define PG_RETURN_CIRCLE_P(x) return CirclePGetDatum(x)
 
 
 /*
  * in geo_ops.c
  */
 
-extern double pg_hypot(double x, double y);
+extern float8 pg_hypot(float8 x, float8 y);
 
 #endif							/* GEO_DECLS_H */
-- 
2.14.3 (Apple Git-98)

0001-geo-funcs-v07.patchapplication/octet-stream; name=0001-geo-funcs-v07.patchDownload
From ec531bf7ae2add306bc9c83c26b28468721ed198 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 27 May 2017 11:27:18 -0400
Subject: [PATCH 1/6] geo-funcs-v07

Refactor geometric functions and operators code

Most of the geometric types were not using functions of each other's.
I believe the reason behind this is simpler types line point and line
being developed after more complicated ones.  This patch reduces
duplicate code and makes functions of different datatypes more
compatible.  The changes can be summarised as:

* Eliminate SQL level function calls
* Re-use more functions to implement others
* Unify internal function names and signatures
* Remove private functions from geo_decls.h
* Replace not-possible checks with Assert()
* Add comments to describe some functions
* Remove some unreachable code
* Define delimiter symbols of line datatype like the other ones
* Remove debugging print()s from the refactored functions

This commits aims to not cause any user visible changes, but it is
almost impossible to stay completely bug-compatible with the old code.
---
 src/backend/utils/adt/geo_ops.c    | 1915 +++++++++++++++++-------------------
 src/backend/utils/adt/geo_spgist.c |    3 +-
 src/include/utils/geo_decls.h      |    4 -
 src/test/regress/regress.c         |   11 +-
 4 files changed, 891 insertions(+), 1042 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index f57380a4df..e3119efea0 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -31,75 +31,104 @@
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
+/* Routines for points */
+static inline void point_construct(Point *result, float8 x, float8 y);
+static inline void point_add_point(Point *result, Point *pt1, Point *pt2);
+static inline void point_sub_point(Point *result, Point *pt1, Point *pt2);
+static inline void point_mul_point(Point *result, Point *pt1, Point *pt2);
+static inline void point_div_point(Point *result, Point *pt1, Point *pt2);
+static inline bool point_eq_point(Point *pt1, Point *pt2);
+static inline float8 point_dt(Point *pt1, Point *pt2);
+static inline float8 point_sl(Point *pt1, Point *pt2);
 static int	point_inside(Point *p, int npts, Point *plist);
+
+/* Routines for lines */
+static inline void line_construct(LINE *result, Point *pt, float8 m);
+static inline float8 line_invsl(LINE *line);
+static bool	line_interpt_line(Point *result, LINE *l1, LINE *l2);
+static bool line_contain_point(LINE *line, Point *point);
+static float8 line_closept_point(Point *result, LINE *line, Point *pt);
+
+/* Routines for line segments */
+static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
+static inline float8 lseg_sl(LSEG *lseg);
+static inline float8 lseg_invsl(LSEG *lseg);
+static bool	lseg_interpt_line(Point *result, LSEG *lseg, LINE *line);
+static bool	lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2);
 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_fill(BOX *result, double x1, double x2, double y1, double y2);
+static bool	lseg_contain_point(LSEG *lseg, Point *point);
+static float8 lseg_closept_point(Point *result, LSEG *lseg, Point *pt);
+static float8 lseg_closept_line(Point *result, LSEG *lseg, LINE *line);
+static float8 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2);
+
+/* Routines for boxes */
+static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
+static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
+static double box_ar(BOX *box);
 static double box_ht(BOX *box);
 static double box_wd(BOX *box);
+static bool box_contain_point(BOX *box, Point *point);
+static bool box_contain_box(BOX *box1, BOX *box2);
+static bool box_contain_lseg(BOX *box, LSEG *lseg);
+static bool box_interpt_lseg(Point *result, BOX *box, LSEG *lseg);
+static float8 box_closept_point(Point *result, BOX *box, Point *point);
+static float8 box_closept_lseg(Point *result, BOX *box, LSEG *lseg);
+
+/* Routines for circles */
 static double circle_ar(CIRCLE *circle);
-static CIRCLE *circle_copy(CIRCLE *circle);
-static LINE *line_construct_pm(Point *pt, double m);
-static void line_construct_pts(LINE *line, Point *pt1, Point *pt2);
-static bool lseg_intersect_internal(LSEG *l1, LSEG *l2);
-static double lseg_dt(LSEG *l1, LSEG *l2);
-static bool on_ps_internal(Point *pt, LSEG *lseg);
+
+/* Routines for polygons */
 static void make_bound_box(POLYGON *poly);
+static void poly_to_circle(CIRCLE *result, POLYGON *poly);
+static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
+static bool poly_contain_poly(POLYGON *polya, POLYGON *polyb);
 static bool plist_same(int npts, Point *p1, Point *p2);
-static Point *point_construct(double x, double y);
-static Point *point_copy(Point *pt);
+static float8 dist_ppoly_internal(Point *pt, POLYGON *poly);
+
+/* Routines for encoding and decoding */
 static double single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
 static void pair_decode(char *str, double *x, double *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
 static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
-static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
-static double box_ar(BOX *box);
-static void box_cn(Point *center, BOX *box);
-static Point *interpt_sl(LSEG *lseg, LINE *line);
-static bool has_interpt_sl(LSEG *lseg, LINE *line);
-static double dist_pl_internal(Point *pt, LINE *line);
-static double dist_ps_internal(Point *pt, LSEG *lseg);
-static Point *line_interpt_internal(LINE *l1, LINE *l2);
-static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
-static Point *lseg_interpt_internal(LSEG *l1, LSEG *l2);
-static double dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 
 /*
  * Delimiters for input and output strings.
  * LDELIM, RDELIM, and DELIM are left, right, and separator delimiters, respectively.
  * LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints.
  */
 
 #define LDELIM			'('
 #define RDELIM			')'
 #define DELIM			','
 #define LDELIM_EP		'['
 #define RDELIM_EP		']'
 #define LDELIM_C		'<'
 #define RDELIM_C		'>'
+#define LDELIM_L		'{'
+#define RDELIM_L		'}'
 
 
 /*
  * Geometric data types are composed of points.
  * This code tries to support a common format throughout the data types,
  *	to allow for more predictable usage and data type conversion.
  * The fundamental unit is the point. Other units are line segments,
  *	open paths, boxes, closed paths, and polygons (which should be considered
  *	non-intersecting closed paths).
  *
@@ -229,26 +258,23 @@ path_decode(char *str, bool opentype, int npts, Point *p,
 	}
 
 	for (i = 0; i < npts; i++)
 	{
 		pair_decode(str, &(p->x), &(p->y), &str, type_name, orig_string);
 		if (*str == DELIM)
 			str++;
 		p++;
 	}
 
-	while (isspace((unsigned char) *str))
-		str++;
 	while (depth > 0)
 	{
-		if ((*str == RDELIM)
-			|| ((*str == RDELIM_EP) && (*isopen) && (depth == 1)))
+		if (*str == RDELIM || (*str == RDELIM_EP && *isopen && depth == 1))
 		{
 			depth--;
 			str++;
 			while (isspace((unsigned char) *str))
 				str++;
 		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
@@ -433,89 +459,61 @@ box_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, box->high.x);
 	pq_sendfloat8(&buf, box->high.y);
 	pq_sendfloat8(&buf, box->low.x);
 	pq_sendfloat8(&buf, box->low.y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*		box_construct	-		fill in a new box.
  */
-static BOX *
-box_construct(double x1, double x2, double y1, double y2)
+static inline void
+box_construct(BOX *result, Point *pt1, Point *pt2)
 {
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	return box_fill(result, x1, x2, y1, y2);
-}
-
-
-/*		box_fill		-		fill in a given box struct
- */
-static BOX *
-box_fill(BOX *result, double x1, double x2, double y1, double y2)
-{
-	if (x1 > x2)
+	if (pt1->x > pt2->x)
 	{
-		result->high.x = x1;
-		result->low.x = x2;
+		result->high.x = pt1->x;
+		result->low.x = pt2->x;
 	}
 	else
 	{
-		result->high.x = x2;
-		result->low.x = x1;
+		result->high.x = pt2->x;
+		result->low.x = pt1->x;
 	}
-	if (y1 > y2)
+	if (pt1->y > pt2->y)
 	{
-		result->high.y = y1;
-		result->low.y = y2;
+		result->high.y = pt1->y;
+		result->low.y = pt2->y;
 	}
 	else
 	{
-		result->high.y = y2;
-		result->low.y = y1;
+		result->high.y = pt2->y;
+		result->low.y = pt1->y;
 	}
-
-	return result;
-}
-
-
-/*		box_copy		-		copy a box
- */
-BOX *
-box_copy(BOX *box)
-{
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	memcpy((char *) result, (char *) box, sizeof(BOX));
-
-	return result;
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for BOXes.
  *		<, >, <=, >=, and == are based on box area.
  *---------------------------------------------------------*/
 
 /*		box_same		-		are two boxes identical?
  */
 Datum
 box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPeq(box1->high.x, box2->high.x) &&
-				   FPeq(box1->low.x, box2->low.x) &&
-				   FPeq(box1->high.y, box2->high.y) &&
-				   FPeq(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(point_eq_point(&box1->high, &box2->high) &&
+				   point_eq_point(&box1->low, &box2->low));
 }
 
 /*		box_overlap		-		does box1 overlap box2?
  */
 Datum
 box_overlap(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
@@ -630,38 +628,44 @@ box_overabove(PG_FUNCTION_ARGS)
 }
 
 /*		box_contained	-		is box1 contained by box2?
  */
 Datum
 box_contained(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPle(box1->high.x, box2->high.x) &&
-				   FPge(box1->low.x, box2->low.x) &&
-				   FPle(box1->high.y, box2->high.y) &&
-				   FPge(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(box_contain_box(box2, box1));
 }
 
 /*		box_contain		-		does box1 contain box2?
  */
 Datum
 box_contain(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPge(box1->high.x, box2->high.x) &&
-				   FPle(box1->low.x, box2->low.x) &&
-				   FPge(box1->high.y, box2->high.y) &&
-				   FPle(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(box_contain_box(box1, box2));
+}
+
+/*
+ * Check whether the box is in the box or on its border
+ */
+static bool
+box_contain_box(BOX *box1, BOX *box2)
+{
+	return FPge(box1->high.x, box2->high.x) &&
+		   FPle(box1->low.x, box2->low.x) &&
+		   FPge(box1->high.y, box2->high.y) &&
+		   FPle(box1->low.y, box2->low.y);
 }
 
 
 /*		box_positionop	-
  *				is box1 entirely {above,below} box2?
  *
  * box_below_eq and box_above_eq are obsolete versions that (probably
  * erroneously) accept the equal-boundaries case.  Since these are not
  * in sync with the box_left and box_right code, they are deprecated and
  * not supported in the PG 8.1 rtree operator class extension.
@@ -750,51 +754,51 @@ box_area(PG_FUNCTION_ARGS)
 
 
 /*		box_width		-		returns the width of the box
  *								  (horizontal magnitude).
  */
 Datum
 box_width(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.x - box->low.x);
+	PG_RETURN_FLOAT8(box_wd(box));
 }
 
 
 /*		box_height		-		returns the height of the box
  *								  (vertical magnitude).
  */
 Datum
 box_height(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.y - box->low.y);
+	PG_RETURN_FLOAT8(box_ht(box));
 }
 
 
 /*		box_distance	-		returns the distance between the
  *								  center points of two boxes.
  */
 Datum
 box_distance(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 	Point		a,
 				b;
 
 	box_cn(&a, box1);
 	box_cn(&b, box2);
 
-	PG_RETURN_FLOAT8(HYPOT(a.x - b.x, a.y - b.y));
+	PG_RETURN_FLOAT8(point_dt(&a, &b));
 }
 
 
 /*		box_center		-		returns the center point of the box.
  */
 Datum
 box_center(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *result = (Point *) palloc(sizeof(Point));
@@ -898,76 +902,77 @@ static bool
 line_decode(char *s, const char *str, LINE *line)
 {
 	/* s was already advanced over leading '{' */
 	line->A = single_decode(s, &s, "line", str);
 	if (*s++ != DELIM)
 		return false;
 	line->B = single_decode(s, &s, "line", str);
 	if (*s++ != DELIM)
 		return false;
 	line->C = single_decode(s, &s, "line", str);
-	if (*s++ != '}')
+	if (*s++ != RDELIM_L)
 		return false;
 	while (isspace((unsigned char) *s))
 		s++;
 	if (*s != '\0')
 		return false;
 	return true;
 }
 
 Datum
 line_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	LINE	   *line = (LINE *) palloc(sizeof(LINE));
 	LSEG		lseg;
 	bool		isopen;
 	char	   *s;
 
 	s = str;
 	while (isspace((unsigned char) *s))
 		s++;
-	if (*s == '{')
+	if (*s == LDELIM_L)
 	{
 		if (!line_decode(s + 1, str, line))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
 							"line", str)));
 		if (FPzero(line->A) && FPzero(line->B))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: A and B cannot both be zero")));
 	}
 	else
 	{
-		path_decode(s, true, 2, &(lseg.p[0]), &isopen, NULL, "line", str);
-		if (FPeq(lseg.p[0].x, lseg.p[1].x) && FPeq(lseg.p[0].y, lseg.p[1].y))
+		path_decode(s, true, 2, &lseg.p[0], &isopen, NULL, "line", str);
+		if (point_eq_point(&lseg.p[0], &lseg.p[1]))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: must be two distinct points")));
-		line_construct_pts(line, &lseg.p[0], &lseg.p[1]);
+		line_construct(line, &lseg.p[0], lseg_sl(&lseg));
 	}
 
 	PG_RETURN_LINE_P(line);
 }
 
 
 Datum
 line_out(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	char	   *astr = float8out_internal(line->A);
 	char	   *bstr = float8out_internal(line->B);
 	char	   *cstr = float8out_internal(line->C);
 
-	PG_RETURN_CSTRING(psprintf("{%s,%s,%s}", astr, bstr, cstr));
+	PG_RETURN_CSTRING(psprintf("%c%s%c%s%c%s%c", LDELIM_L, astr, DELIM, bstr,
+							   DELIM, cstr, RDELIM_L));
 }
 
 /*
  *		line_recv			- converts external binary format to line
  */
 Datum
 line_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LINE	   *line;
@@ -996,128 +1001,85 @@ line_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, line->C);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*----------------------------------------------------------
  *	Conversion routines from one line formula to internal.
  *		Internal form:	Ax+By+C=0
  *---------------------------------------------------------*/
 
-/* line_construct_pm()
- * point-slope
+/*
+ * Fill already-allocated LINE struct from the point and the slope
  */
-static LINE *
-line_construct_pm(Point *pt, double m)
+static inline void
+line_construct(LINE *result, Point *pt, float8 m)
 {
-	LINE	   *result = (LINE *) palloc(sizeof(LINE));
-
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
 		result->A = -1;
 		result->B = 0;
 		result->C = pt->x;
 	}
+	else if (m == 0.0)
+	{
+		/* horizontal - use "y = C" */
+		result->A = 0.0;
+		result->B = -1.0;
+		result->C = pt->y;
+	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
 		result->C = pt->y - m * pt->x;
 	}
-
-	return result;
-}
-
-/*
- * Fill already-allocated LINE struct from two points on the line
- */
-static void
-line_construct_pts(LINE *line, Point *pt1, Point *pt2)
-{
-	if (FPeq(pt1->x, pt2->x))
-	{							/* vertical */
-		/* use "x = C" */
-		line->A = -1;
-		line->B = 0;
-		line->C = pt1->x;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is vertical\n");
-#endif
-	}
-	else if (FPeq(pt1->y, pt2->y))
-	{							/* horizontal */
-		/* use "y = C" */
-		line->A = 0;
-		line->B = -1;
-		line->C = pt1->y;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is horizontal\n");
-#endif
-	}
-	else
-	{
-		/* use "mx - y + yinter = 0" */
-		line->A = (pt2->y - pt1->y) / (pt2->x - pt1->x);
-		line->B = -1.0;
-		line->C = pt1->y - line->A * pt1->x;
-		/* on some platforms, the preceding expression tends to produce -0 */
-		if (line->C == 0.0)
-			line->C = 0.0;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is neither vertical nor horizontal (diffs x=%.*g, y=%.*g\n",
-			   DBL_DIG, (pt2->x - pt1->x), DBL_DIG, (pt2->y - pt1->y));
-#endif
-	}
 }
 
 /* line_construct_pp()
  * two points
  */
 Datum
 line_construct_pp(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 	LINE	   *result = (LINE *) palloc(sizeof(LINE));
 
-	line_construct_pts(result, pt1, pt2);
+	line_construct(result, pt1, point_sl(pt1, pt2));
+
 	PG_RETURN_LINE_P(result);
 }
 
 
 /*----------------------------------------------------------
  *	Relative position routines.
  *---------------------------------------------------------*/
 
 Datum
 line_intersect(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(!DatumGetBool(DirectFunctionCall2(line_parallel,
-													 LinePGetDatum(l1),
-													 LinePGetDatum(l2))));
+	PG_RETURN_BOOL(line_interpt_line(NULL, l1, l2));
 }
 
 Datum
 line_parallel(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
-	if (FPzero(l1->B))
-		PG_RETURN_BOOL(FPzero(l2->B));
-
-	PG_RETURN_BOOL(FPeq(l2->A, l1->A * (l2->B / l1->B)));
+	PG_RETURN_BOOL(!line_interpt_line(NULL, l1, l2));
 }
 
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
@@ -1162,105 +1124,113 @@ line_eq(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(FPeq(l1->A, k * l2->A) &&
 				   FPeq(l1->B, k * l2->B) &&
 				   FPeq(l1->C, k * l2->C));
 }
 
 
 /*----------------------------------------------------------
  *	Line arithmetic routines.
  *---------------------------------------------------------*/
 
+/*
+ * Return inverse slope of the line
+ */
+static inline float8
+line_invsl(LINE *line)
+{
+	if (FPzero(line->A))
+		return DBL_MAX;
+	if (FPzero(line->B))
+		return 0.0;
+	return line->B / line->A;
+}
+
+
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
-	Point	   *tmp;
+	Point		tmp;
 
-	if (!DatumGetBool(DirectFunctionCall2(line_parallel,
-										  LinePGetDatum(l1),
-										  LinePGetDatum(l2))))
+	if (line_interpt_line(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
 		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
-	tmp = point_construct(0.0, l1->C);
-	result = dist_pl_internal(tmp, l2);
+	point_construct(&tmp, 0.0, l1->C);
+	result = line_closept_point(NULL, l2, &tmp);
 	PG_RETURN_FLOAT8(result);
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
-	result = line_interpt_internal(l1, l2);
+	result = (Point *) palloc(sizeof(Point));
 
-	if (result == NULL)
+	if (!line_interpt_line(result, l1, l2))
 		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
 
 /*
  * Internal version of line_interpt
  *
- * returns a NULL pointer if no intersection point
+ * This returns true if two lines intersect (they do, if they are not
+ * parallel), false if they do not.  This also sets the intersection point
+ * to *result, if it is not NULL.
+ *
+ * NOTE If the lines are identical then we will find they are parallel
+ * and report "no intersection".  This is a little weird, but since
+ * there's no *unique* intersection, maybe it's appropriate behavior.
  */
-static Point *
-line_interpt_internal(LINE *l1, LINE *l2)
+static bool
+line_interpt_line(Point *result, LINE *l1, LINE *l2)
 {
-	Point	   *result;
 	double		x,
 				y;
 
-	/*
-	 * NOTE: if the lines are identical then we will find they are parallel
-	 * and report "no intersection".  This is a little weird, but since
-	 * there's no *unique* intersection, maybe it's appropriate behavior.
-	 */
-	if (DatumGetBool(DirectFunctionCall2(line_parallel,
-										 LinePGetDatum(l1),
-										 LinePGetDatum(l2))))
-		return NULL;
-
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
+		if (FPzero(l2->B))		/* l2 vertical? */
+			return false;
+
 		x = l1->C;
 		y = (l2->A * x + l2->C);
 	}
 	else if (FPzero(l2->B))		/* l2 vertical? */
 	{
 		x = l2->C;
 		y = (l1->A * x + l1->C);
 	}
 	else
 	{
+		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+			return false;
+
 		x = (l1->C - l2->C) / (l2->A - l1->A);
 		y = (l1->A * x + l1->C);
 	}
-	result = point_construct(x, y);
+	if (result != NULL)
+		point_construct(result, x, y);
 
-#ifdef GEODEBUG
-	printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
-		   DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
-	printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
-#endif
-
-	return result;
+	return true;
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D paths (sequences of line segments, also
  **				called `polylines').
  **
  **				This is not a general package for geometric paths,
  **				which of course include polygons; the emphasis here
@@ -1555,22 +1525,21 @@ path_inter(PG_FUNCTION_ARGS)
 {
 	PATH	   *p1 = PG_GETARG_PATH_P(0);
 	PATH	   *p2 = PG_GETARG_PATH_P(1);
 	BOX			b1,
 				b2;
 	int			i,
 				j;
 	LSEG		seg1,
 				seg2;
 
-	if (p1->npts <= 0 || p2->npts <= 0)
-		PG_RETURN_BOOL(false);
+	Assert(p1->npts > 0 && p2->npts > 0);
 
 	b1.high.x = b1.low.x = p1->p[0].x;
 	b1.high.y = b1.low.y = p1->p[0].y;
 	for (i = 1; i < p1->npts; i++)
 	{
 		b1.high.x = Max(p1->p[i].x, b1.high.x);
 		b1.high.y = Max(p1->p[i].y, b1.high.y);
 		b1.low.x = Min(p1->p[i].x, b1.low.x);
 		b1.low.y = Min(p1->p[i].y, b1.low.y);
 	}
@@ -1608,21 +1577,21 @@ path_inter(PG_FUNCTION_ARGS)
 				jprev = j - 1;
 			else
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
-			if (lseg_intersect_internal(&seg1, &seg2))
+			if (lseg_interpt_lseg(NULL, &seg1, &seg2))
 				PG_RETURN_BOOL(true);
 		}
 	}
 
 	/* if we dropped through, no two segs intersected */
 	PG_RETURN_BOOL(false);
 }
 
 /* path_distance()
  * This essentially does a cartesian product of the lsegs in the
@@ -1663,23 +1632,21 @@ path_distance(PG_FUNCTION_ARGS)
 			else
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
-			tmp = DatumGetFloat8(DirectFunctionCall2(lseg_distance,
-													 LsegPGetDatum(&seg1),
-													 LsegPGetDatum(&seg2)));
+			tmp = lseg_closept_lseg(NULL, &seg1, &seg2);
 			if (!have_min || tmp < min)
 			{
 				min = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	if (!have_min)
 		PG_RETURN_NULL();
@@ -1773,44 +1740,31 @@ point_send(PG_FUNCTION_ARGS)
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	StringInfoData buf;
 
 	pq_begintypsend(&buf);
 	pq_sendfloat8(&buf, pt->x);
 	pq_sendfloat8(&buf, pt->y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
-static Point *
-point_construct(double x, double y)
+/*
+ * Initialize a point
+ *
+ * This function is over-simple, but it is, at least, useful when the new
+ * point is calculated using the existing one.
+ */
+static inline void
+point_construct(Point *result, float8 x, float8 y)
 {
-	Point	   *result = (Point *) palloc(sizeof(Point));
-
 	result->x = x;
 	result->y = y;
-	return result;
-}
-
-
-static Point *
-point_copy(Point *pt)
-{
-	Point	   *result;
-
-	if (!PointerIsValid(pt))
-		return NULL;
-
-	result = (Point *) palloc(sizeof(Point));
-
-	result->x = pt->x;
-	result->y = pt->y;
-	return result;
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for Points.
  *		Since we do have a sense of coordinates being
  *		"equal" to a given accuracy (point_vert, point_horiz),
  *		the other ops must preserve that sense.  This means
  *		that results may, strictly speaking, be a lie (unless
  *		EPSILON = 0.0).
@@ -1869,71 +1823,97 @@ point_horiz(PG_FUNCTION_ARGS)
 
 	PG_RETURN_BOOL(FPeq(pt1->y, pt2->y));
 }
 
 Datum
 point_eq(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y));
+	PG_RETURN_BOOL(point_eq_point(pt1, pt2));
 }
 
 Datum
 point_ne(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPne(pt1->x, pt2->x) || FPne(pt1->y, pt2->y));
+	PG_RETURN_BOOL(!point_eq_point(pt1, pt2));
 }
 
+static inline bool
+point_eq_point(Point *pt1, Point *pt2)
+{
+	return FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y);
+}
+
+
 /*----------------------------------------------------------
  *	"Arithmetic" operators on points.
  *---------------------------------------------------------*/
 
 Datum
 point_distance(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_FLOAT8(HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
+	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
-double
+static inline float8
 point_dt(Point *pt1, Point *pt2)
 {
-#ifdef GEODEBUG
-	printf("point_dt- segment (%f,%f),(%f,%f) length is %f\n",
-		   pt1->x, pt1->y, pt2->x, pt2->y, HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
-#endif
 	return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
 }
 
 Datum
 point_slope(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_sl(pt1, pt2));
 }
 
 
-double
+/*
+ * Return slope of two points
+ *
+ * Note that this function returns DBL_MAX when the points are the same.
+ */
+static inline float8
 point_sl(Point *pt1, Point *pt2)
 {
-	return (FPeq(pt1->x, pt2->x)
-			? (double) DBL_MAX
-			: (pt1->y - pt2->y) / (pt1->x - pt2->x));
+	if (FPeq(pt1->x, pt2->x))
+		return DBL_MAX;
+	if (FPeq(pt1->y, pt2->y))
+		return 0.0;
+	return (pt1->y - pt2->y) / (pt1->x - pt2->x);
+}
+
+
+/*
+ * Return inverse slope of two points
+ *
+ * Note that this function returns 0.0 when the points are the same.
+ */
+static inline float8
+point_invsl(Point *pt1, Point *pt2)
+{
+	if (FPeq(pt1->x, pt2->x))
+		return 0.0;
+	if (FPeq(pt1->y, pt2->y))
+		return DBL_MAX;
+	return (pt1->x - pt2->x) / (pt2->y - pt1->y);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D line segments.
  **
  ***********************************************************************/
 
 /*----------------------------------------------------------
@@ -1945,31 +1925,31 @@ point_sl(Point *pt1, Point *pt2)
  *		(old form)		"(x1, y1, x2, y2)"
  *---------------------------------------------------------*/
 
 Datum
 lseg_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	LSEG	   *lseg = (LSEG *) palloc(sizeof(LSEG));
 	bool		isopen;
 
-	path_decode(str, true, 2, &(lseg->p[0]), &isopen, NULL, "lseg", str);
+	path_decode(str, true, 2, &lseg->p[0], &isopen, NULL, "lseg", str);
 	PG_RETURN_LSEG_P(lseg);
 }
 
 
 Datum
 lseg_out(PG_FUNCTION_ARGS)
 {
 	LSEG	   *ls = PG_GETARG_LSEG_P(0);
 
-	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, (Point *) &(ls->p[0])));
+	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, &ls->p[0]));
 }
 
 /*
  *		lseg_recv			- converts external binary format to lseg
  */
 Datum
 lseg_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LSEG	   *lseg;
@@ -2005,38 +1985,56 @@ lseg_send(PG_FUNCTION_ARGS)
 /* lseg_construct -
  *		form a LSEG from two Points.
  */
 Datum
 lseg_construct(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 	LSEG	   *result = (LSEG *) palloc(sizeof(LSEG));
 
-	result->p[0].x = pt1->x;
-	result->p[0].y = pt1->y;
-	result->p[1].x = pt2->x;
-	result->p[1].y = pt2->y;
+	statlseg_construct(result, pt1, pt2);
 
 	PG_RETURN_LSEG_P(result);
 }
 
 /* like lseg_construct, but assume space already allocated */
-static void
+static inline void
 statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2)
 {
 	lseg->p[0].x = pt1->x;
 	lseg->p[0].y = pt1->y;
 	lseg->p[1].x = pt2->x;
 	lseg->p[1].y = pt2->y;
 }
 
+
+/*
+ * Return slope of the line segment
+ */
+static inline float8
+lseg_sl(LSEG *lseg)
+{
+	return point_sl(&lseg->p[0], &lseg->p[1]);
+}
+
+
+/*
+ * Return inverse slope of the line segment
+ */
+static inline float8
+lseg_invsl(LSEG *lseg)
+{
+	return point_invsl(&lseg->p[0], &lseg->p[1]);
+}
+
+
 Datum
 lseg_length(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 
 	PG_RETURN_FLOAT8(point_dt(&lseg->p[0], &lseg->p[1]));
 }
 
 /*----------------------------------------------------------
  *	Relative position routines.
@@ -2045,79 +2043,43 @@ lseg_length(PG_FUNCTION_ARGS)
 /*
  **  find intersection of the two lines, and see if it falls on
  **  both segments.
  */
 Datum
 lseg_intersect(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(lseg_intersect_internal(l1, l2));
+	PG_RETURN_BOOL(lseg_interpt_lseg(NULL, l1, l2));
 }
 
-static bool
-lseg_intersect_internal(LSEG *l1, LSEG *l2)
-{
-	LINE		ln;
-	Point	   *interpt;
-	bool		retval;
-
-	line_construct_pts(&ln, &l2->p[0], &l2->p[1]);
-	interpt = interpt_sl(l1, &ln);
-
-	if (interpt != NULL && on_ps_internal(interpt, l2))
-		retval = true;			/* interpt on l1 and l2 */
-	else
-		retval = false;
-	return retval;
-}
 
 Datum
 lseg_parallel(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPeq(point_sl(&l1->p[0], &l1->p[1]),
-						point_sl(&l2->p[0], &l2->p[1])));
+	PG_RETURN_BOOL(FPeq(lseg_sl(l1), lseg_sl(l2)));
 }
 
-/* lseg_perp()
+/*
  * Determine if two line segments are perpendicular.
- *
- * This code did not get the correct answer for
- *	'((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg
- * So, modified it to check explicitly for slope of vertical line
- *	returned by point_sl() and the results seem better.
- * - thomas 1998-01-31
  */
 Datum
 lseg_perp(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	double		m1,
-				m2;
 
-	m1 = point_sl(&(l1->p[0]), &(l1->p[1]));
-	m2 = point_sl(&(l2->p[0]), &(l2->p[1]));
-
-#ifdef GEODEBUG
-	printf("lseg_perp- slopes are %g and %g\n", m1, m2);
-#endif
-	if (FPzero(m1))
-		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
-	else if (FPzero(m2))
-		PG_RETURN_BOOL(FPeq(m1, DBL_MAX));
-
-	PG_RETURN_BOOL(FPeq(m1 / m2, -1.0));
+	PG_RETURN_BOOL(FPeq(lseg_sl(l1), lseg_invsl(l2)));
 }
 
 Datum
 lseg_vertical(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 
 	PG_RETURN_BOOL(FPeq(lseg->p[0].x, lseg->p[1].x));
 }
 
@@ -2129,36 +2091,32 @@ lseg_horizontal(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(FPeq(lseg->p[0].y, lseg->p[1].y));
 }
 
 
 Datum
 lseg_eq(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPeq(l1->p[0].x, l2->p[0].x) &&
-				   FPeq(l1->p[0].y, l2->p[0].y) &&
-				   FPeq(l1->p[1].x, l2->p[1].x) &&
-				   FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(point_eq_point(&l1->p[0], &l2->p[0]) &&
+				   point_eq_point(&l1->p[1], &l2->p[1]));
 }
 
 Datum
 lseg_ne(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(!FPeq(l1->p[0].x, l2->p[0].x) ||
-				   !FPeq(l1->p[0].y, l2->p[0].y) ||
-				   !FPeq(l1->p[1].x, l2->p[1].x) ||
-				   !FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(!point_eq_point(&l1->p[0], &l2->p[0]) ||
+				   !point_eq_point(&l1->p[1], &l2->p[1]));
 }
 
 Datum
 lseg_lt(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_BOOL(FPlt(point_dt(&l1->p[0], &l1->p[1]),
 						point_dt(&l2->p[0], &l2->p[1])));
@@ -2203,126 +2161,81 @@ lseg_ge(PG_FUNCTION_ARGS)
  *		If two segments don't intersect, then the closest
  *		point will be from one of the endpoints to the other
  *		segment.
  */
 Datum
 lseg_distance(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_FLOAT8(lseg_dt(l1, l2));
-}
-
-/* lseg_dt()
- * Distance between two line segments.
- * Must check both sets of endpoints to ensure minimum distance is found.
- * - thomas 1998-02-01
- */
-static double
-lseg_dt(LSEG *l1, LSEG *l2)
-{
-	double		result,
-				d;
-
-	if (lseg_intersect_internal(l1, l2))
-		return 0.0;
-
-	d = dist_ps_internal(&l1->p[0], l2);
-	result = d;
-	d = dist_ps_internal(&l1->p[1], l2);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[0], l1);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[1], l1);
-	result = Min(result, d);
-
-	return result;
+	PG_RETURN_FLOAT8(lseg_closept_lseg(NULL, l1, l2));
 }
 
 
 Datum
 lseg_center(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
 	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
 
 	PG_RETURN_POINT_P(result);
 }
 
-static Point *
-lseg_interpt_internal(LSEG *l1, LSEG *l2)
+
+/*
+ *		Find the intersection point of two segments (if any).
+ *
+ * This returns true if two line segments intersect, false if they do not.
+ * This also sets the intersection point to *result, if it is not NULL.
+ * This function is almost perfectly symmetric, even though it doesn't look
+ * like it.  See lseg_interpt_line() for the other half of it.
+ */
+static bool
+lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2)
 {
-	Point	   *result;
-	LINE		tmp1,
-				tmp2;
+	Point		interpt;
+	LINE		tmp;
+
+	line_construct(&tmp, &l2->p[0], lseg_sl(l2));
+	if (!lseg_interpt_line(&interpt, l1, &tmp))
+		return false;
 
 	/*
-	 * Find the intersection of the appropriate lines, if any.
+	 * If the line intersection point isn't within l2, there is no valid
+	 * segment intersection point at all.
 	 */
-	line_construct_pts(&tmp1, &l1->p[0], &l1->p[1]);
-	line_construct_pts(&tmp2, &l2->p[0], &l2->p[1]);
-	result = line_interpt_internal(&tmp1, &tmp2);
-	if (!PointerIsValid(result))
-		return NULL;
+	if (!lseg_contain_point(l2, &interpt))
+		return false;
 
-	/*
-	 * If the line intersection point isn't within l1 (or equivalently l2),
-	 * there is no valid segment intersection point at all.
-	 */
-	if (!on_ps_internal(result, l1) ||
-		!on_ps_internal(result, l2))
-	{
-		pfree(result);
-		return NULL;
-	}
+	if (result != NULL)
+		*result = interpt;
 
-	/*
-	 * If there is an intersection, then check explicitly for matching
-	 * endpoints since there may be rounding effects with annoying lsb
-	 * residue. - tgl 1997-07-09
-	 */
-	if ((FPeq(l1->p[0].x, l2->p[0].x) && FPeq(l1->p[0].y, l2->p[0].y)) ||
-		(FPeq(l1->p[0].x, l2->p[1].x) && FPeq(l1->p[0].y, l2->p[1].y)))
-	{
-		result->x = l1->p[0].x;
-		result->y = l1->p[0].y;
-	}
-	else if ((FPeq(l1->p[1].x, l2->p[0].x) && FPeq(l1->p[1].y, l2->p[0].y)) ||
-			 (FPeq(l1->p[1].x, l2->p[1].x) && FPeq(l1->p[1].y, l2->p[1].y)))
-	{
-		result->x = l1->p[1].x;
-		result->y = l1->p[1].y;
-	}
-
-	return result;
+	return true;
 }
 
-/* lseg_interpt -
- *		Find the intersection point of two segments (if any).
- */
 Datum
 lseg_interpt(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
-	result = lseg_interpt_internal(l1, l2);
-	if (!PointerIsValid(result))
-		PG_RETURN_NULL();
+	result = (Point *) palloc(sizeof(Point));
 
+	if (!lseg_interpt_lseg(result, l1, l2))
+		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
 
 /***********************************************************************
  **
  **		Routines for position comparisons of differently-typed
  **				2D objects.
  **
  ***********************************************************************/
 
@@ -2333,215 +2246,128 @@ lseg_interpt(PG_FUNCTION_ARGS)
 
 /*
  * Distance from a point to a line
  */
 Datum
 dist_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_FLOAT8(dist_pl_internal(pt, line));
+	PG_RETURN_FLOAT8(line_closept_point(NULL, line, pt));
 }
 
-static double
-dist_pl_internal(Point *pt, LINE *line)
-{
-	return fabs((line->A * pt->x + line->B * pt->y + line->C) /
-				HYPOT(line->A, line->B));
-}
 
 /*
  * Distance from a point to a lseg
  */
 Datum
 dist_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_FLOAT8(dist_ps_internal(pt, lseg));
-}
-
-static double
-dist_ps_internal(Point *pt, LSEG *lseg)
-{
-	double		m;				/* slope of perp. */
-	LINE	   *ln;
-	double		result,
-				tmpdist;
-	Point	   *ip;
-
-	/*
-	 * Construct a line perpendicular to the input segment and through the
-	 * input point
-	 */
-	if (lseg->p[1].x == lseg->p[0].x)
-		m = 0;
-	else if (lseg->p[1].y == lseg->p[0].y)
-		m = (double) DBL_MAX;	/* slope is infinite */
-	else
-		m = (lseg->p[0].x - lseg->p[1].x) / (lseg->p[1].y - lseg->p[0].y);
-	ln = line_construct_pm(pt, m);
-
-#ifdef GEODEBUG
-	printf("dist_ps- line is A=%g B=%g C=%g from (point) slope (%f,%f) %g\n",
-		   ln->A, ln->B, ln->C, pt->x, pt->y, m);
-#endif
-
-	/*
-	 * Calculate distance to the line segment or to the nearest endpoint of
-	 * the segment.
-	 */
-
-	/* intersection is on the line segment? */
-	if ((ip = interpt_sl(lseg, ln)) != NULL)
-	{
-		/* yes, so use distance to the intersection point */
-		result = point_dt(pt, ip);
-#ifdef GEODEBUG
-		printf("dist_ps- distance is %f to intersection point is (%f,%f)\n",
-			   result, ip->x, ip->y);
-#endif
-	}
-	else
-	{
-		/* no, so use distance to the nearer endpoint */
-		result = point_dt(pt, &lseg->p[0]);
-		tmpdist = point_dt(pt, &lseg->p[1]);
-		if (tmpdist < result)
-			result = tmpdist;
-	}
-
-	return result;
+	PG_RETURN_FLOAT8(lseg_closept_point(NULL, lseg, pt));
 }
 
 /*
  * Distance from a point to a path
  */
 Datum
 dist_ppath(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	PATH	   *path = PG_GETARG_PATH_P(1);
 	float8		result = 0.0;	/* keep compiler quiet */
 	bool		have_min = false;
 	float8		tmp;
 	int			i;
 	LSEG		lseg;
 
-	switch (path->npts)
+	Assert(path->npts > 0);
+
+	/*
+	 * The distance from a point to a path is the smallest distance
+	 * from the point to any of its constituent segments.
+	 */
+	for (i = 0; i < path->npts; i++)
 	{
-		case 0:
-			/* no points in path? then result is undefined... */
-			PG_RETURN_NULL();
-		case 1:
-			/* one point in path? then get distance between two points... */
-			result = point_dt(pt, &path->p[0]);
-			break;
-		default:
-			/* make sure the path makes sense... */
-			Assert(path->npts > 1);
+		int			iprev;
 
-			/*
-			 * the distance from a point to a path is the smallest distance
-			 * from the point to any of its constituent segments.
-			 */
-			for (i = 0; i < path->npts; i++)
-			{
-				int			iprev;
+		if (i > 0)
+			iprev = i - 1;
+		else
+		{
+			if (!path->closed)
+				continue;
+			iprev = path->npts - 1; /* Include the closure segment */
+		}
 
-				if (i > 0)
-					iprev = i - 1;
-				else
-				{
-					if (!path->closed)
-						continue;
-					iprev = path->npts - 1; /* include the closure segment */
-				}
-
-				statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
-				tmp = dist_ps_internal(pt, &lseg);
-				if (!have_min || tmp < result)
-				{
-					result = tmp;
-					have_min = true;
-				}
-			}
-			break;
+		statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
+		tmp = lseg_closept_point(NULL, &lseg, pt);
+		if (!have_min || tmp < result)
+		{
+			result = tmp;
+			have_min = true;
+		}
 	}
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a point to a box
  */
 Datum
 dist_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
-	float8		result;
-	Point	   *near;
 
-	near = DatumGetPointP(DirectFunctionCall2(close_pb,
-											  PointPGetDatum(pt),
-											  BoxPGetDatum(box)));
-	result = point_dt(near, pt);
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(box_closept_point(NULL, box, pt));
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	float8		result,
 				d2;
 
-	if (has_interpt_sl(lseg, line))
+	if (lseg_interpt_line(NULL, lseg, line))
 		result = 0.0;
 	else
 	{
-		result = dist_pl_internal(&lseg->p[0], line);
-		d2 = dist_pl_internal(&lseg->p[1], line);
+		result = line_closept_point(NULL, line, &lseg->p[0]);
+		d2 = line_closept_point(NULL, line, &lseg->p[1]);
 		/* XXX shouldn't we take the min not max? */
 		if (d2 > result)
 			result = d2;
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
-	Point	   *tmp;
-	Datum		result;
 
-	tmp = DatumGetPointP(DirectFunctionCall2(close_sb,
-											 LsegPGetDatum(lseg),
-											 BoxPGetDatum(box)));
-	result = DirectFunctionCall2(dist_pb,
-								 PointPGetDatum(tmp),
-								 BoxPGetDatum(box));
-
-	PG_RETURN_DATUM(result);
+	PG_RETURN_FLOAT8(box_closept_lseg(NULL, box, lseg));
 }
 
 /*
  * Distance from a line to a box
  */
 Datum
 dist_lb(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -2577,538 +2403,509 @@ dist_cpoly(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a point to a polygon
  */
 Datum
 dist_ppoly(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	POLYGON    *poly = PG_GETARG_POLYGON_P(1);
-	float8		result;
 
-	result = dist_ppoly_internal(point, poly);
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(dist_ppoly_internal(point, poly));
 }
 
 Datum
 dist_polyp(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	float8		result;
 
-	result = dist_ppoly_internal(point, poly);
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(dist_ppoly_internal(point, poly));
 }
 
-static double
+static float8
 dist_ppoly_internal(Point *pt, POLYGON *poly)
 {
 	float8		result;
 	float8		d;
 	int			i;
 	LSEG		seg;
 
 	if (point_inside(pt, poly->npts, poly->p) != 0)
 	{
 #ifdef GEODEBUG
 		printf("dist_ppoly_internal- point inside of polygon\n");
 #endif
 		return 0.0;
 	}
 
 	/* initialize distance with segment between first and last points */
 	seg.p[0].x = poly->p[0].x;
 	seg.p[0].y = poly->p[0].y;
 	seg.p[1].x = poly->p[poly->npts - 1].x;
 	seg.p[1].y = poly->p[poly->npts - 1].y;
-	result = dist_ps_internal(pt, &seg);
+	result = lseg_closept_point(NULL, &seg, pt);
 #ifdef GEODEBUG
-	printf("dist_ppoly_internal- segment 0/n distance is %f\n", result);
+	printf("dist_ppoly_internal- segment 0/n distance is %f\n", *result);
 #endif
 
 	/* check distances for other segments */
-	for (i = 0; (i < poly->npts - 1); i++)
+	for (i = 0; i < poly->npts - 1; i++)
 	{
 		seg.p[0].x = poly->p[i].x;
 		seg.p[0].y = poly->p[i].y;
 		seg.p[1].x = poly->p[i + 1].x;
 		seg.p[1].y = poly->p[i + 1].y;
-		d = dist_ps_internal(pt, &seg);
+		d = lseg_closept_point(NULL, &seg, pt);
 #ifdef GEODEBUG
 		printf("dist_ppoly_internal- segment %d distance is %f\n", (i + 1), d);
 #endif
 		if (d < result)
 			result = d;
 	}
 
 	return result;
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
  *				Intersection point of objects.
  *				We choose to ignore the "point" of intersection between
  *				  lines and boxes, since there are typically two.
  *-------------------------------------------------------------------*/
 
-/* Get intersection point of lseg and line; returns NULL if no intersection */
-static Point *
-interpt_sl(LSEG *lseg, LINE *line)
-{
-	LINE		tmp;
-	Point	   *p;
-
-	line_construct_pts(&tmp, &lseg->p[0], &lseg->p[1]);
-	p = line_interpt_internal(&tmp, line);
-#ifdef GEODEBUG
-	printf("interpt_sl- segment is (%.*g %.*g) (%.*g %.*g)\n",
-		   DBL_DIG, lseg->p[0].x, DBL_DIG, lseg->p[0].y, DBL_DIG, lseg->p[1].x, DBL_DIG, lseg->p[1].y);
-	printf("interpt_sl- segment becomes line A=%.*g B=%.*g C=%.*g\n",
-		   DBL_DIG, tmp.A, DBL_DIG, tmp.B, DBL_DIG, tmp.C);
-#endif
-	if (PointerIsValid(p))
-	{
-#ifdef GEODEBUG
-		printf("interpt_sl- intersection point is (%.*g %.*g)\n", DBL_DIG, p->x, DBL_DIG, p->y);
-#endif
-		if (on_ps_internal(p, lseg))
-		{
-#ifdef GEODEBUG
-			printf("interpt_sl- intersection point is on segment\n");
-#endif
-		}
-		else
-			p = NULL;
-	}
-
-	return p;
-}
-
-/* variant: just indicate if intersection point exists */
+/*
+ * Check if the line segment intersects with the line
+ *
+ * This returns true if line segment intersects with line, false if they
+ * do not.  This also sets the intersection point to *result, if it is not
+ * NULL.
+ */
 static bool
-has_interpt_sl(LSEG *lseg, LINE *line)
+lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
 {
-	Point	   *tmp;
+	Point		interpt;
+	LINE		tmp;
 
-	tmp = interpt_sl(lseg, line);
-	if (tmp)
+	line_construct(&tmp, &lseg->p[0], lseg_sl(lseg));
+	if (!line_interpt_line(&interpt, &tmp, line))
+		return false;
+
+	if (!lseg_contain_point(lseg, &interpt))
+		return false;
+
+	if (result == NULL)
 		return true;
-	return false;
+
+	/*
+	 * If there is an intersection, then check explicitly for matching
+	 * endpoints since there may be rounding effects with annoying LSB
+	 * residue.
+	 */
+	if (FPeq(lseg->p[0].x, interpt.x) && FPeq(lseg->p[0].y, interpt.y))
+		*result = lseg->p[0];
+	else if (FPeq(lseg->p[1].x, interpt.x) && FPeq(lseg->p[1].y, interpt.y))
+		*result = lseg->p[1];
+	else
+		*result = interpt;
+
+	return true;
 }
 
 /*---------------------------------------------------------------------
  *		close_
  *				Point of closest proximity between objects.
  *-------------------------------------------------------------------*/
 
-/* close_pl -
+/*
  *		The intersection point of a perpendicular of the line
  *		through the point.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
+static float8
+line_closept_point(Point *result, LINE *line, Point *point)
+{
+	bool		retval;
+	LINE		tmp;
+
+	/* Drop a perpendicular and find the intersection point */
+	line_construct(&tmp, point, line_invsl(line));
+	retval = line_interpt_line(result, line, &tmp);
+	Assert(retval);		/* XXX We need something better. */
+
+	/*
+	 * XXX We could use the distance to the closest point, but
+	 * line_interpt_line() is currently giving wrong results.
+	 */
+	return fabs((line->A * point->x + line->B * point->y + line->C) /
+				HYPOT(line->A, line->B));
+}
+
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
-	LINE	   *tmp;
-	double		invm;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	if (FPzero(line->B))		/* vertical? */
-	{
-		result->x = line->C;
-		result->y = pt->y;
-		PG_RETURN_POINT_P(result);
-	}
-	if (FPzero(line->A))		/* horizontal? */
-	{
-		result->x = pt->x;
-		result->y = line->C;
-		PG_RETURN_POINT_P(result);
-	}
-	/* drop a perpendicular and find the intersection point */
+	line_closept_point(result, line, pt);
 
-	/* invert and flip the sign on the slope to get a perpendicular */
-	invm = line->B / line->A;
-	tmp = line_construct_pm(pt, invm);
-	result = line_interpt_internal(tmp, line);
-	Assert(result != NULL);
 	PG_RETURN_POINT_P(result);
 }
 
 
-/* close_ps()
+/*
  * Closest point on line segment to specified point.
- * Take the closest endpoint if the point is left, right,
- *	above, or below the segment, otherwise find the intersection
- *	point of the segment and its perpendicular through the point.
  *
- * Some tricky code here, relying on boolean expressions
- *	evaluating to only zero or one to use as an array index.
- *		bug fixes by gthaker@atl.lmco.com; May 1, 1998
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
+static float8
+lseg_closept_point(Point *result, LSEG *lseg, Point *pt)
+{
+	Point		closept;
+	LINE		tmp;
+
+	/*
+	 * To find the closest point, we draw a perpendicular line from the point
+	 * to the line segment.
+	 */
+	line_construct(&tmp, pt, point_invsl(&lseg->p[0], &lseg->p[1]));
+	lseg_closept_line(&closept, lseg, &tmp);
+
+	if (result != NULL)
+		*result = closept;
+
+	return point_dt(&closept, pt);
+}
+
 Datum
 close_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
-	LINE	   *tmp;
-	double		invm;
-	int			xh,
-				yh;
+	Point	   *result;
 
-#ifdef GEODEBUG
-	printf("close_sp:pt->x %f pt->y %f\nlseg(0).x %f lseg(0).y %f  lseg(1).x %f lseg(1).y %f\n",
-		   pt->x, pt->y, lseg->p[0].x, lseg->p[0].y,
-		   lseg->p[1].x, lseg->p[1].y);
-#endif
+	result = (Point *) palloc(sizeof(Point));
 
-	/* xh (or yh) is the index of upper x( or y) end point of lseg */
-	/* !xh (or !yh) is the index of lower x( or y) end point of lseg */
-	xh = lseg->p[0].x < lseg->p[1].x;
-	yh = lseg->p[0].y < lseg->p[1].y;
-
-	if (FPeq(lseg->p[0].x, lseg->p[1].x))	/* vertical? */
-	{
-#ifdef GEODEBUG
-		printf("close_ps- segment is vertical\n");
-#endif
-		/* first check if point is below or above the entire lseg. */
-		if (pt->y < lseg->p[!yh].y)
-			result = point_copy(&lseg->p[!yh]); /* below the lseg */
-		else if (pt->y > lseg->p[yh].y)
-			result = point_copy(&lseg->p[yh]);	/* above the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
-
-		/* point lines along (to left or right) of the vertical lseg. */
-
-		result = (Point *) palloc(sizeof(Point));
-		result->x = lseg->p[0].x;
-		result->y = pt->y;
-		PG_RETURN_POINT_P(result);
-	}
-	else if (FPeq(lseg->p[0].y, lseg->p[1].y))	/* horizontal? */
-	{
-#ifdef GEODEBUG
-		printf("close_ps- segment is horizontal\n");
-#endif
-		/* first check if point is left or right of the entire lseg. */
-		if (pt->x < lseg->p[!xh].x)
-			result = point_copy(&lseg->p[!xh]); /* left of the lseg */
-		else if (pt->x > lseg->p[xh].x)
-			result = point_copy(&lseg->p[xh]);	/* right of the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
-
-		/* point lines along (at top or below) the horiz. lseg. */
-		result = (Point *) palloc(sizeof(Point));
-		result->x = pt->x;
-		result->y = lseg->p[0].y;
-		PG_RETURN_POINT_P(result);
-	}
-
-	/*
-	 * vert. and horiz. cases are down, now check if the closest point is one
-	 * of the end points or someplace on the lseg.
-	 */
-
-	invm = -1.0 / point_sl(&(lseg->p[0]), &(lseg->p[1]));
-	tmp = line_construct_pm(&lseg->p[!yh], invm);	/* lower edge of the
-													 * "band" */
-	if (pt->y < (tmp->A * pt->x + tmp->C))
-	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[!yh]); /* below the lseg, take lower end
-											 * pt */
-#ifdef GEODEBUG
-		printf("close_ps below: tmp A %f  B %f   C %f\n",
-			   tmp->A, tmp->B, tmp->C);
-#endif
-		PG_RETURN_POINT_P(result);
-	}
-	tmp = line_construct_pm(&lseg->p[yh], invm);	/* upper edge of the
-													 * "band" */
-	if (pt->y > (tmp->A * pt->x + tmp->C))
-	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[yh]);	/* above the lseg, take higher end
-											 * pt */
-#ifdef GEODEBUG
-		printf("close_ps above: tmp A %f  B %f   C %f\n",
-			   tmp->A, tmp->B, tmp->C);
-#endif
-		PG_RETURN_POINT_P(result);
-	}
-
-	/*
-	 * at this point the "normal" from point will hit lseg. The closest point
-	 * will be somewhere on the lseg
-	 */
-	tmp = line_construct_pm(pt, invm);
-#ifdef GEODEBUG
-	printf("close_ps- tmp A %f  B %f   C %f\n",
-		   tmp->A, tmp->B, tmp->C);
-#endif
-	result = interpt_sl(lseg, tmp);
-
-	/*
-	 * ordinarily we should always find an intersection point, but that could
-	 * fail in the presence of NaN coordinates, and perhaps even from simple
-	 * roundoff issues.  Return a SQL NULL if so.
-	 */
-	if (result == NULL)
+	if (isnan(lseg_closept_point(result, lseg, pt)))
 		PG_RETURN_NULL();
 
-#ifdef GEODEBUG
-	printf("close_ps- result.x %f  result.y %f\n", result->x, result->y);
-#endif
 	PG_RETURN_POINT_P(result);
 }
 
 
-/* close_lseg()
+/*
  * Closest point to l1 on l2.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
+ *
+ * XXX This function is wrong.  If must never set the *result to a point on
+ * the second segment.
  */
+static float8
+lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
+{
+	Point		point;
+	double		dist;
+	double		d;
+
+	d = lseg_closept_point(NULL, l1, &l2->p[0]);
+	dist = d;
+	if (result != NULL)
+		*result = l2->p[0];
+
+	d = lseg_closept_point(NULL, l1, &l2->p[1]);
+	if (d < dist)
+	{
+		dist = d;
+		if (result != NULL)
+			*result = l2->p[1];
+	}
+
+	if (lseg_closept_point(&point, l2, &l1->p[0]) < dist)
+		d = lseg_closept_point(result, l1, &point);
+
+	if (lseg_closept_point(&point, l2, &l1->p[1]) < dist)
+		d = lseg_closept_point(result, l1, &point);
+
+	if (d < dist)
+		dist = d;
+
+	return dist;
+}
+
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
-	Point		point;
-	double		dist;
-	double		d;
+	Point	   *result;
 
-	d = dist_ps_internal(&l1->p[0], l2);
-	dist = d;
-	memcpy(&point, &l1->p[0], sizeof(Point));
+	result = (Point *) palloc(sizeof(Point));
 
-	if ((d = dist_ps_internal(&l1->p[1], l2)) < dist)
-	{
-		dist = d;
-		memcpy(&point, &l1->p[1], sizeof(Point));
-	}
-
-	if (dist_ps_internal(&l2->p[0], l1) < dist)
-	{
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&l2->p[0]),
-													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
-													LsegPGetDatum(l2)));
-	}
-
-	if (dist_ps_internal(&l2->p[1], l1) < dist)
-	{
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&l2->p[1]),
-													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
-													LsegPGetDatum(l2)));
-	}
-
-	if (result == NULL)
-		result = point_copy(&point);
+	lseg_closept_lseg(result, l2, l1);
 
 	PG_RETURN_POINT_P(result);
 }
 
-/* close_pb()
+
+/*
  * Closest point on or in box to specified point.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
-Datum
-close_pb(PG_FUNCTION_ARGS)
+static float8
+box_closept_point(Point *result, BOX *box, Point *pt)
 {
-	Point	   *pt = PG_GETARG_POINT_P(0);
-	BOX		   *box = PG_GETARG_BOX_P(1);
-	LSEG		lseg,
-				seg;
-	Point		point;
+	LSEG		lseg;
+	Point		point,
+				closept;
 	double		dist,
 				d;
 
-	if (DatumGetBool(DirectFunctionCall2(on_pb,
-										 PointPGetDatum(pt),
-										 BoxPGetDatum(box))))
-		PG_RETURN_POINT_P(pt);
+	if (box_contain_point(box, pt))
+	{
+		if (result != NULL)
+			*result = *pt;
+
+		return 0.0;
+	}
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&lseg, &box->low, &point);
-	dist = dist_ps_internal(pt, &lseg);
+	dist = lseg_closept_point(result, &lseg, pt);
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	statlseg_construct(&lseg, &box->high, &point);
+	d = lseg_closept_point(&closept, &lseg, pt);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&lseg, &seg, sizeof(lseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
-	statlseg_construct(&seg, &box->low, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	statlseg_construct(&lseg, &box->low, &point);
+	d = lseg_closept_point(&closept, &lseg, pt);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&lseg, &seg, sizeof(lseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	statlseg_construct(&lseg, &box->high, &point);
+	d = lseg_closept_point(&closept, &lseg, pt);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&lseg, &seg, sizeof(lseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
-										PointPGetDatum(pt),
-										LsegPGetDatum(&lseg)));
+	return dist;
 }
 
+Datum
+close_pb(PG_FUNCTION_ARGS)
+{
+	Point	   *pt = PG_GETARG_POINT_P(0);
+	BOX		   *box = PG_GETARG_BOX_P(1);
+	Point	   *result;
+
+	result = (Point *) palloc(sizeof(Point));
+
+	box_closept_point(result, box, pt);
+
+	PG_RETURN_POINT_P(result);
+}
+
+
 /* close_sl()
  * Closest point on line to line segment.
  *
  * XXX THIS CODE IS WRONG
  * The code is actually calculating the point on the line segment
  *	which is backwards from the routine naming convention.
  * Copied code to new routine close_ls() but haven't fixed this one yet.
  * - thomas 1998-01-31
  */
 Datum
 close_sl(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 	float8		d1,
 				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
+	result = (Point *) palloc(sizeof(Point));
+
+	if (lseg_interpt_line(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
-	d1 = dist_pl_internal(&lseg->p[0], line);
-	d2 = dist_pl_internal(&lseg->p[1], line);
+	d1 = line_closept_point(NULL, line, &lseg->p[0]);
+	d2 = line_closept_point(NULL, line, &lseg->p[1]);
 	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
+		*result = lseg->p[0];
 	else
-		result = point_copy(&lseg->p[1]);
+		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
 
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_sl\" not implemented")));
 
 	PG_RETURN_NULL();
 }
 
-/* close_ls()
+/*
  * Closest point on line segment to line.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
+ *
+ * NOTE When the lines are parallel, endpoints of one of the line segment
+ * are FPeq(), in presence of NaN or Infinitive coordinates, or perhaps =
+ * even because of simple roundoff issues, there may not be a single closest
+ * point.  We are likely to set the result to the second endpoint in these
+ * cases.
  */
+static float8
+lseg_closept_line(Point *result, LSEG *lseg, LINE *line)
+{
+	float8		dist1,
+				dist2;
+
+	if (lseg_interpt_line(result, lseg, line))
+		return 0.0;
+
+	dist1 = line_closept_point(NULL, line, &lseg->p[0]);
+	dist2 = line_closept_point(NULL, line, &lseg->p[1]);
+
+	if (dist1 < dist2)
+	{
+		if (result != NULL)
+			*result = lseg->p[0];
+
+		return dist1;
+	}
+	else
+	{
+		if (result != NULL)
+			*result = lseg->p[1];
+
+		return dist2;
+	}
+}
+
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
-	float8		d1,
-				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
-		PG_RETURN_POINT_P(result);
+	result = (Point *) palloc(sizeof(Point));
 
-	d1 = dist_pl_internal(&lseg->p[0], line);
-	d2 = dist_pl_internal(&lseg->p[1], line);
-	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
-	else
-		result = point_copy(&lseg->p[1]);
+	lseg_closept_line(result, lseg, line);
 
 	PG_RETURN_POINT_P(result);
 }
 
-/* close_sb()
+
+/*
  * Closest point on or in box to line segment.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
-Datum
-close_sb(PG_FUNCTION_ARGS)
+static float8
+box_closept_lseg(Point *result, BOX *box, LSEG *lseg)
 {
-	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
-	BOX		   *box = PG_GETARG_BOX_P(1);
-	Point		point;
-	LSEG		bseg,
-				seg;
+	Point		point,
+				closept;
+	LSEG		bseg;
 	double		dist,
 				d;
 
-	/* segment intersects box? then just return closest point to center */
-	if (DatumGetBool(DirectFunctionCall2(inter_sb,
-										 LsegPGetDatum(lseg),
-										 BoxPGetDatum(box))))
-	{
-		box_cn(&point, box);
-		PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
-											PointPGetDatum(&point),
-											LsegPGetDatum(lseg)));
-	}
+	if (box_interpt_lseg(result, box, lseg))
+		return 0.0;
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	dist = lseg_dt(lseg, &bseg);
+	dist = lseg_closept_lseg(result, &bseg, lseg);
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	statlseg_construct(&bseg, &box->high, &point);
+	d = lseg_closept_lseg(&closept, &bseg, lseg);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&bseg, &seg, sizeof(bseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
-	statlseg_construct(&seg, &box->low, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	statlseg_construct(&bseg, &box->low, &point);
+	d = lseg_closept_lseg(&closept, &bseg, lseg);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&bseg, &seg, sizeof(bseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	statlseg_construct(&bseg, &box->high, &point);
+	d = lseg_closept_lseg(&closept, &bseg, lseg);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&bseg, &seg, sizeof(bseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	/* OK, we now have the closest line segment on the box boundary */
-	PG_RETURN_DATUM(DirectFunctionCall2(close_lseg,
-										LsegPGetDatum(lseg),
-										LsegPGetDatum(&bseg)));
+	return dist;
 }
 
+Datum
+close_sb(PG_FUNCTION_ARGS)
+{
+	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
+	BOX		   *box = PG_GETARG_BOX_P(1);
+	Point	   *result;
+
+	result = (Point *) palloc(sizeof(Point));
+
+	box_closept_lseg(result, box, lseg);
+
+	PG_RETURN_POINT_P(result);
+}
+
+
 Datum
 close_lb(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 #endif
 
 	/* think about this one for a while */
 	ereport(ERROR,
@@ -3116,71 +2913,87 @@ close_lb(PG_FUNCTION_ARGS)
 			 errmsg("function \"close_lb\" not implemented")));
 
 	PG_RETURN_NULL();
 }
 
 /*---------------------------------------------------------------------
  *		on_
  *				Whether one object lies completely within another.
  *-------------------------------------------------------------------*/
 
-/* on_pl -
+/*
  *		Does the point satisfy the equation?
  */
+static bool
+line_contain_point(LINE *line, Point *point)
+{
+	return FPzero(line->A * point->x + line->B * point->y + line->C);
+}
+
 Datum
 on_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(FPzero(line->A * pt->x + line->B * pt->y + line->C));
+	PG_RETURN_BOOL(line_contain_point(line, pt));
 }
 
 
-/* on_ps -
+/*
  *		Determine colinearity by detecting a triangle inequality.
  * This algorithm seems to behave nicely even with lsb residues - tgl 1997-07-09
  */
+static bool
+lseg_contain_point(LSEG *lseg, Point *pt)
+{
+	return FPeq(point_dt(pt, &lseg->p[0]) +
+				point_dt(pt, &lseg->p[1]),
+				point_dt(&lseg->p[0], &lseg->p[1]));
+}
+
 Datum
 on_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(on_ps_internal(pt, lseg));
+	PG_RETURN_BOOL(lseg_contain_point(lseg, pt));
 }
 
+
+/*
+ * Check whether the point is in the box or on its border
+ */
 static bool
-on_ps_internal(Point *pt, LSEG *lseg)
+box_contain_point(BOX *box, Point *point)
 {
-	return FPeq(point_dt(pt, &lseg->p[0]) + point_dt(pt, &lseg->p[1]),
-				point_dt(&lseg->p[0], &lseg->p[1]));
+	return box->high.x >= point->x && box->low.x <= point->x &&
+		   box->high.y >= point->y && box->low.y <= point-> y;
 }
 
 Datum
 on_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_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);
+	PG_RETURN_BOOL(box_contain_point(box, pt));
 }
 
 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);
+	PG_RETURN_BOOL(box_contain_point(box, pt));
 }
 
 /* on_ppath -
  *		Whether a point lies within (on) a polyline.
  *		If open, we have to (groan) check each segment.
  * (uses same algorithm as for point intersecting segment - tgl 1997-07-09)
  *		If closed, we use the old O(n) ray method for point-in-polygon.
  *				The ray is horizontal, from pt out to the right.
  *				Each segment that crosses the ray counts as an
  *				intersection; note that an endpoint or edge may touch
@@ -3210,158 +3023,184 @@ on_ppath(PG_FUNCTION_ARGS)
 				PG_RETURN_BOOL(true);
 			a = b;
 		}
 		PG_RETURN_BOOL(false);
 	}
 
 	/*-- CLOSED --*/
 	PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
 }
 
+
+/*
+ * Check whether the line segment is on the line or close enough
+ *
+ * It is, if both of its points are on the line or close enough.
+ */
 Datum
 on_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(DatumGetBool(DirectFunctionCall2(on_pl,
-													PointPGetDatum(&lseg->p[0]),
-													LinePGetDatum(line))) &&
-				   DatumGetBool(DirectFunctionCall2(on_pl,
-													PointPGetDatum(&lseg->p[1]),
-													LinePGetDatum(line))));
+	PG_RETURN_BOOL(line_contain_point(line, &lseg->p[0]) &&
+				   line_contain_point(line, &lseg->p[1]));
+}
+
+
+/*
+ * Check whether the line segment is in the box or on its border
+ *
+ * It is, if both of its points are in the box or on its border.
+ */
+static bool
+box_contain_lseg(BOX *box, LSEG *lseg)
+{
+	return box_contain_point(box, &lseg->p[0]) &&
+		   box_contain_point(box, &lseg->p[1]);
 }
 
 Datum
 on_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(DatumGetBool(DirectFunctionCall2(on_pb,
-													PointPGetDatum(&lseg->p[0]),
-													BoxPGetDatum(box))) &&
-				   DatumGetBool(DirectFunctionCall2(on_pb,
-													PointPGetDatum(&lseg->p[1]),
-													BoxPGetDatum(box))));
+	PG_RETURN_BOOL(box_contain_lseg(box, lseg));
 }
 
 /*---------------------------------------------------------------------
  *		inter_
  *				Whether one object intersects another.
  *-------------------------------------------------------------------*/
 
 Datum
 inter_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(has_interpt_sl(lseg, line));
+	PG_RETURN_BOOL(lseg_interpt_line(NULL, lseg, line));
 }
 
-/* inter_sb()
+
+/*
  * Do line segment and box intersect?
  *
  * Segment completely inside box counts as intersection.
  * If you want only segments crossing box boundaries,
  *	try converting box to path first.
  *
+ * This function also sets the *result to the closest point on the line
+ * segment to the center of the box when they overlap and the result is
+ * not NULL.  It is somewhat arbitrary, but maybe the best we can do as
+ * there are typically two points they intersect.
+ *
  * Optimize for non-intersection by checking for box intersection first.
  * - thomas 1998-01-30
  */
-Datum
-inter_sb(PG_FUNCTION_ARGS)
+static bool
+box_interpt_lseg(Point *result, BOX *box, LSEG *lseg)
 {
-	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
-	BOX		   *box = PG_GETARG_BOX_P(1);
 	BOX			lbox;
 	LSEG		bseg;
 	Point		point;
 
 	lbox.low.x = Min(lseg->p[0].x, lseg->p[1].x);
 	lbox.low.y = Min(lseg->p[0].y, lseg->p[1].y);
 	lbox.high.x = Max(lseg->p[0].x, lseg->p[1].x);
 	lbox.high.y = Max(lseg->p[0].y, lseg->p[1].y);
 
 	/* nothing close to overlap? then not going to intersect */
 	if (!box_ov(&lbox, box))
-		PG_RETURN_BOOL(false);
+		return false;
+
+	if (result != NULL)
+	{
+		box_cn(&point, box);
+		lseg_closept_point(result, lseg, &point);
+	}
 
 	/* an endpoint of segment is inside box? then clearly intersects */
-	if (DatumGetBool(DirectFunctionCall2(on_pb,
-										 PointPGetDatum(&lseg->p[0]),
-										 BoxPGetDatum(box))) ||
-		DatumGetBool(DirectFunctionCall2(on_pb,
-										 PointPGetDatum(&lseg->p[1]),
-										 BoxPGetDatum(box))))
-		PG_RETURN_BOOL(true);
+	if (box_contain_point(box, &lseg->p[0]) ||
+		box_contain_point(box, &lseg->p[1]))
+		return true;
 
 	/* pairwise check lseg intersections */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	/* if we dropped through, no two segs intersected */
-	PG_RETURN_BOOL(false);
+	return false;
 }
 
+Datum
+inter_sb(PG_FUNCTION_ARGS)
+{
+	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
+	BOX		   *box = PG_GETARG_BOX_P(1);
+
+	PG_RETURN_BOOL(box_interpt_lseg(NULL, box, lseg));
+}
+
+
 /* inter_lb()
  * Do line and box intersect?
  */
 Datum
 inter_lb(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	LSEG		bseg;
 	Point		p1,
 				p2;
 
 	/* pairwise check lseg intersections */
 	p1.x = box->low.x;
 	p1.y = box->low.y;
 	p2.x = box->low.x;
 	p2.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->high.x;
 	p1.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p2.x = box->high.x;
 	p2.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->low.x;
 	p1.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 
 	/* if we dropped through, no intersection */
 	PG_RETURN_BOOL(false);
 }
 
 /*------------------------------------------------------------------
  * The following routines define a data type and operator class for
  * POLYGONS .... Part of which (the polygon's bounding box) is built on
  * top of the BOX data type.
@@ -3374,42 +3213,40 @@ inter_lb(PG_FUNCTION_ARGS)
  *---------------------------------------------------------------------*/
 static void
 make_bound_box(POLYGON *poly)
 {
 	int			i;
 	double		x1,
 				y1,
 				x2,
 				y2;
 
-	if (poly->npts > 0)
-	{
-		x2 = x1 = poly->p[0].x;
-		y2 = y1 = poly->p[0].y;
-		for (i = 1; i < poly->npts; i++)
-		{
-			if (poly->p[i].x < x1)
-				x1 = poly->p[i].x;
-			if (poly->p[i].x > x2)
-				x2 = poly->p[i].x;
-			if (poly->p[i].y < y1)
-				y1 = poly->p[i].y;
-			if (poly->p[i].y > y2)
-				y2 = poly->p[i].y;
-		}
+	Assert(poly->npts > 0);
 
-		box_fill(&(poly->boundbox), x1, x2, y1, y2);
+	x1 = x2 = poly->p[0].x;
+	y2 = y1 = poly->p[0].y;
+	for (i = 1; i < poly->npts; i++)
+	{
+		if (poly->p[i].x < x1)
+			x1 = poly->p[i].x;
+		if (poly->p[i].x > x2)
+			x2 = poly->p[i].x;
+		if (poly->p[i].y < y1)
+			y1 = poly->p[i].y;
+		if (poly->p[i].y > y2)
+			y2 = poly->p[i].y;
 	}
-	else
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot create bounding box for empty polygon")));
+
+	poly->boundbox.low.x = x1;
+	poly->boundbox.high.x = x2;
+	poly->boundbox.low.y = y1;
+	poly->boundbox.high.y = y2;
 }
 
 /*------------------------------------------------------------------
  * poly_in - read in the polygon from a string specification
  *
  *		External format:
  *				"((x0,y0),...,(xn,yn))"
  *				"x0,y0,...,xn,yn"
  *				also supports the older style "(x1,...,xn,y1,...yn)"
  *------------------------------------------------------------------*/
@@ -3739,65 +3576,65 @@ poly_same(PG_FUNCTION_ARGS)
 /*-----------------------------------------------------------------
  * Determine if polygon A overlaps polygon B
  *-----------------------------------------------------------------*/
 Datum
 poly_overlap(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
+	Assert(polya->npts > 0 && polyb->npts > 0);
+
 	/* Quick check by bounding box */
-	result = (polya->npts > 0 && polyb->npts > 0 &&
-			  box_ov(&polya->boundbox, &polyb->boundbox)) ? true : false;
+	result = box_ov(&polya->boundbox, &polyb->boundbox);
 
 	/*
 	 * Brute-force algorithm - try to find intersected edges, if so then
 	 * polygons are overlapped else check is one polygon inside other or not
 	 * by testing single point of them.
 	 */
 	if (result)
 	{
 		int			ia,
 					ib;
 		LSEG		sa,
 					sb;
 
 		/* Init first of polya's edge with last point */
 		sa.p[0] = polya->p[polya->npts - 1];
 		result = false;
 
-		for (ia = 0; ia < polya->npts && result == false; ia++)
+		for (ia = 0; ia < polya->npts && !result; ia++)
 		{
 			/* Second point of polya's edge is a current one */
 			sa.p[1] = polya->p[ia];
 
 			/* Init first of polyb's edge with last point */
 			sb.p[0] = polyb->p[polyb->npts - 1];
 
-			for (ib = 0; ib < polyb->npts && result == false; ib++)
+			for (ib = 0; ib < polyb->npts && !result; ib++)
 			{
 				sb.p[1] = polyb->p[ib];
-				result = lseg_intersect_internal(&sa, &sb);
+				result = lseg_interpt_lseg(NULL, &sa, &sb);
 				sb.p[0] = sb.p[1];
 			}
 
 			/*
 			 * move current endpoint to the first point of next edge
 			 */
 			sa.p[0] = sa.p[1];
 		}
 
-		if (result == false)
+		if (!result)
 		{
-			result = (point_inside(polya->p, polyb->npts, polyb->p)
-					  ||
+			result = (point_inside(polya->p, polyb->npts, polyb->p) ||
 					  point_inside(polyb->p, polya->npts, polya->p));
 		}
 	}
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
@@ -3817,36 +3654,35 @@ poly_overlap(PG_FUNCTION_ARGS)
 
 static bool
 touched_lseg_inside_poly(Point *a, Point *b, LSEG *s, POLYGON *poly, int start)
 {
 	/* point a is on s, b is not */
 	LSEG		t;
 
 	t.p[0] = *a;
 	t.p[1] = *b;
 
-#define POINTEQ(pt1, pt2)	(FPeq((pt1)->x, (pt2)->x) && FPeq((pt1)->y, (pt2)->y))
-	if (POINTEQ(a, s->p))
+	if (point_eq_point(a, s->p))
 	{
-		if (on_ps_internal(s->p + 1, &t))
+		if (lseg_contain_point(&t, s->p + 1))
 			return lseg_inside_poly(b, s->p + 1, poly, start);
 	}
-	else if (POINTEQ(a, s->p + 1))
+	else if (point_eq_point(a, s->p + 1))
 	{
-		if (on_ps_internal(s->p, &t))
+		if (lseg_contain_point(&t, s->p))
 			return lseg_inside_poly(b, s->p, poly, start);
 	}
-	else if (on_ps_internal(s->p, &t))
+	else if (lseg_contain_point(&t, s->p))
 	{
 		return lseg_inside_poly(b, s->p, poly, start);
 	}
-	else if (on_ps_internal(s->p + 1, &t))
+	else if (lseg_contain_point(&t, s->p + 1))
 	{
 		return lseg_inside_poly(b, s->p + 1, poly, start);
 	}
 
 	return true;				/* may be not true, but that will check later */
 }
 
 /*
  * Returns true if segment (a,b) is in polygon, option
  * start is used for optimization - function checks
@@ -3860,50 +3696,49 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 	int			i;
 	bool		res = true,
 				intersection = false;
 
 	t.p[0] = *a;
 	t.p[1] = *b;
 	s.p[0] = poly->p[(start == 0) ? (poly->npts - 1) : (start - 1)];
 
 	for (i = start; i < poly->npts && res; i++)
 	{
-		Point	   *interpt;
+		Point		interpt;
 
 		CHECK_FOR_INTERRUPTS();
 
 		s.p[1] = poly->p[i];
 
-		if (on_ps_internal(t.p, &s))
+		if (lseg_contain_point(&s, t.p))
 		{
-			if (on_ps_internal(t.p + 1, &s))
+			if (lseg_contain_point(&s, t.p + 1))
 				return true;	/* t is contained by s */
 
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p, t.p + 1, &s, poly, i + 1);
 		}
-		else if (on_ps_internal(t.p + 1, &s))
+		else if (lseg_contain_point(&s, t.p + 1))
 		{
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p + 1, t.p, &s, poly, i + 1);
 		}
-		else if ((interpt = lseg_interpt_internal(&t, &s)) != NULL)
+		else if (lseg_interpt_lseg(&interpt, &t, &s))
 		{
 			/*
 			 * segments are X-crossing, go to check each subsegment
 			 */
 
 			intersection = true;
-			res = lseg_inside_poly(t.p, interpt, poly, i + 1);
+			res = lseg_inside_poly(t.p, &interpt, poly, i + 1);
 			if (res)
-				res = lseg_inside_poly(t.p + 1, interpt, poly, i + 1);
-			pfree(interpt);
+				res = lseg_inside_poly(t.p + 1, &interpt, poly, i + 1);
 		}
 
 		s.p[0] = s.p[1];
 	}
 
 	if (res && !intersection)
 	{
 		Point		p;
 
 		/*
@@ -3915,74 +3750,86 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 
 		res = point_inside(&p, poly->npts, poly->p);
 	}
 
 	return res;
 }
 
 /*-----------------------------------------------------------------
  * Determine if polygon A contains polygon B.
  *-----------------------------------------------------------------*/
+static bool
+poly_contain_poly(POLYGON *polya, POLYGON *polyb)
+{
+	int			i;
+	LSEG		s;
+
+	Assert(polya->npts > 0 && polyb->npts > 0);
+
+	/*
+	 * Quick check to see if bounding box is contained.
+	 */
+	if (!box_contain_box(&polya->boundbox, &polyb->boundbox))
+		return false;
+
+	s.p[0] = polyb->p[polyb->npts - 1];
+
+	for (i = 0; i < polyb->npts; i++)
+	{
+		s.p[1] = polyb->p[i];
+		if (!lseg_inside_poly(s.p, s.p + 1, polya, 0))
+			return false;
+		s.p[0] = s.p[1];
+	}
+
+	return true;
+}
+
 Datum
 poly_contain(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	/*
-	 * Quick check to see if bounding box is contained.
-	 */
-	if (polya->npts > 0 && polyb->npts > 0 &&
-		DatumGetBool(DirectFunctionCall2(box_contain,
-										 BoxPGetDatum(&polya->boundbox),
-										 BoxPGetDatum(&polyb->boundbox))))
-	{
-		int			i;
-		LSEG		s;
-
-		s.p[0] = polyb->p[polyb->npts - 1];
-		result = true;
-
-		for (i = 0; i < polyb->npts && result; i++)
-		{
-			s.p[1] = polyb->p[i];
-			result = lseg_inside_poly(s.p, s.p + 1, polya, 0);
-			s.p[0] = s.p[1];
-		}
-	}
-	else
-	{
-		result = false;
-	}
+	result = poly_contain_poly(polya, polyb);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
 
 /*-----------------------------------------------------------------
  * Determine if polygon A is contained by polygon B
  *-----------------------------------------------------------------*/
 Datum
 poly_contained(PG_FUNCTION_ARGS)
 {
-	Datum		polya = PG_GETARG_DATUM(0);
-	Datum		polyb = PG_GETARG_DATUM(1);
+	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
+	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
+	bool		result;
 
 	/* Just switch the arguments and pass it off to poly_contain */
-	PG_RETURN_DATUM(DirectFunctionCall2(poly_contain, polyb, polya));
+	result = poly_contain_poly(polyb, polya);
+
+	/*
+	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
+	 */
+	PG_FREE_IF_COPY(polya, 0);
+	PG_FREE_IF_COPY(polyb, 1);
+
+	PG_RETURN_BOOL(result);
 }
 
 
 Datum
 poly_contain_pt(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_BOOL(point_inside(p, poly->npts, poly->p) != 0);
@@ -4018,170 +3865,215 @@ poly_distance(PG_FUNCTION_ARGS)
  **
  **		Routines for 2D points.
  **
  ***********************************************************************/
 
 Datum
 construct_point(PG_FUNCTION_ARGS)
 {
 	float8		x = PG_GETARG_FLOAT8(0);
 	float8		y = PG_GETARG_FLOAT8(1);
+	Point	   *result;
 
-	PG_RETURN_POINT_P(point_construct(x, y));
+	result = (Point *) palloc(sizeof(Point));
+
+	point_construct(result, x, y);
+
+	PG_RETURN_POINT_P(result);
+}
+
+
+static inline void
+point_add_point(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x + pt2->x,
+					pt1->y + pt2->y);
 }
 
 Datum
 point_add(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x + p2->x);
-	result->y = (p1->y + p2->y);
+	point_add_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+
+static inline void
+point_sub_point(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x - pt2->x,
+					pt1->y - pt2->y);
+}
+
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x - p2->x);
-	result->y = (p1->y - p2->y);
+	point_sub_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+
+static inline void
+point_mul_point(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					(pt1->x * pt2->x) - (pt1->y * pt2->y),
+					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+}
+
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x * p2->x) - (p1->y * p2->y);
-	result->y = (p1->x * p2->y) + (p1->y * p2->x);
+	point_mul_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+
+static inline void
+point_div_point(Point *result, Point *pt1, Point *pt2)
+{
+	double		div;
+
+	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
+
+	if (div == 0.0)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	point_construct(result,
+					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
+					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+}
+
 Datum
 point_div(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
-	double		div;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	div = (p2->x * p2->x) + (p2->y * p2->y);
-
-	if (div == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result->x = ((p1->x * p2->x) + (p1->y * p2->y)) / div;
-	result->y = ((p2->x * p1->y) - (p2->y * p1->x)) / div;
+	point_div_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D boxes.
  **
  ***********************************************************************/
 
 Datum
 points_box(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct(p1->x, p2->x, p1->y, p2->y));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	box_construct(result, p1, p2);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_add(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct((box->high.x + p->x),
-								  (box->low.x + p->x),
-								  (box->high.y + p->y),
-								  (box->low.y + p->y)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_add_point(&result->high, &box->high, p);
+	point_add_point(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_sub(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct((box->high.x - p->x),
-								  (box->low.x - p->x),
-								  (box->high.y - p->y),
-								  (box->low.y - p->y)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_sub_point(&result->high, &box->high, p);
+	point_sub_point(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_mul(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
 
-	high = DatumGetPointP(DirectFunctionCall2(point_mul,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_mul,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	result = (BOX *) palloc(sizeof(BOX));
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	point_mul_point(&high, &box->high, p);
+	point_mul_point(&low, &box->low, p);
+
+	box_construct(result, &high, &low);
 
 	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_div(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
 
-	high = DatumGetPointP(DirectFunctionCall2(point_div,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_div,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	result = (BOX *) palloc(sizeof(BOX));
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	point_div_point(&high, &box->high, p);
+	point_div_point(&low, &box->low, p);
+
+	box_construct(result, &high, &low);
 
 	PG_RETURN_BOX_P(result);
 }
 
 /*
  * Convert point to empty box
  */
 Datum
 point_box(PG_FUNCTION_ARGS)
 {
@@ -4277,83 +4169,63 @@ path_add(PG_FUNCTION_ARGS)
  * Translation operators.
  */
 Datum
 path_add_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x += point->x;
-		path->p[i].y += point->y;
-	}
+		point_add_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_sub_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x -= point->x;
-		path->p[i].y -= point->y;
-	}
+		point_sub_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 /* path_mul_pt()
  * Rotation and scaling operators.
  */
 Datum
 path_mul_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_mul,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_mul_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_div_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_div,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_div_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 
 Datum
 path_center(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	PATH	   *path = PG_GETARG_PATH_P(0);
@@ -4414,42 +4286,40 @@ poly_npoints(PG_FUNCTION_ARGS)
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 
 	PG_RETURN_INT32(poly->npts);
 }
 
 
 Datum
 poly_center(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
-	Datum		result;
-	CIRCLE	   *circle;
+	Point	   *result;
+	CIRCLE		circle;
 
-	circle = DatumGetCircleP(DirectFunctionCall1(poly_circle,
-												 PolygonPGetDatum(poly)));
-	result = DirectFunctionCall1(circle_center,
-								 CirclePGetDatum(circle));
+	result = (Point *) palloc(sizeof(Point));
 
-	PG_RETURN_DATUM(result);
+	poly_to_circle(&circle, poly);
+	*result = circle.center;
+
+	PG_RETURN_POINT_P(result);
 }
 
 
 Datum
 poly_box(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	BOX		   *box;
 
-	if (poly->npts < 1)
-		PG_RETURN_NULL();
-
-	box = box_copy(&poly->boundbox);
+	box = (BOX *) palloc(sizeof(BOX));
+	*box = poly->boundbox;
 
 	PG_RETURN_BOX_P(box);
 }
 
 
 /* box_poly()
  * Convert a box to a polygon.
  */
 Datum
 box_poly(PG_FUNCTION_ARGS)
@@ -4467,22 +4337,21 @@ box_poly(PG_FUNCTION_ARGS)
 
 	poly->p[0].x = box->low.x;
 	poly->p[0].y = box->low.y;
 	poly->p[1].x = box->low.x;
 	poly->p[1].y = box->high.y;
 	poly->p[2].x = box->high.x;
 	poly->p[2].y = box->high.y;
 	poly->p[3].x = box->high.x;
 	poly->p[3].y = box->low.y;
 
-	box_fill(&poly->boundbox, box->high.x, box->low.x,
-			 box->high.y, box->low.y);
+	box_construct(&poly->boundbox, &box->high, &box->low);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
 
 Datum
 poly_path(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	PATH	   *path;
@@ -4557,22 +4426,21 @@ circle_in(PG_FUNCTION_ARGS)
 
 	circle->radius = single_decode(s, &s, "circle", str);
 	if (circle->radius < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
 
 	while (depth > 0)
 	{
-		if ((*s == RDELIM)
-			|| ((*s == RDELIM_C) && (depth == 1)))
+		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
 			s++;
 			while (isspace((unsigned char) *s))
 				s++;
 		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
@@ -4656,22 +4524,21 @@ circle_send(PG_FUNCTION_ARGS)
 
 /*		circles identical?
  */
 Datum
 circle_same(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPeq(circle1->radius, circle2->radius) &&
-				   FPeq(circle1->center.x, circle2->center.x) &&
-				   FPeq(circle1->center.y, circle2->center.y));
+				   point_eq_point(&circle1->center, &circle2->center));
 }
 
 /*		circle_overlap	-		does circle1 overlap circle2?
  */
 Datum
 circle_overlap(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
@@ -4730,32 +4597,34 @@ circle_overright(PG_FUNCTION_ARGS)
 }
 
 /*		circle_contained		-		is circle1 contained by circle2?
  */
 Datum
 circle_contained(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle1->radius), circle2->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						circle2->radius - circle1->radius));
 }
 
 /*		circle_contain	-		does circle1 contain circle2?
  */
 Datum
 circle_contain(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle2->radius), circle1->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						circle1->radius - circle2->radius));
 }
 
 
 /*		circle_below		-		is circle1 strictly below circle2?
  */
 Datum
 circle_below(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
@@ -4858,107 +4727,83 @@ circle_ge(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPge(circle_ar(circle1), circle_ar(circle2)));
 }
 
 
 /*----------------------------------------------------------
  *	"Arithmetic" operators on circles.
  *---------------------------------------------------------*/
 
-static CIRCLE *
-circle_copy(CIRCLE *circle)
-{
-	CIRCLE	   *result;
-
-	if (!PointerIsValid(circle))
-		return NULL;
-
-	result = (CIRCLE *) palloc(sizeof(CIRCLE));
-	memcpy((char *) result, (char *) circle, sizeof(CIRCLE));
-	return result;
-}
-
-
 /* circle_add_pt()
  * Translation operator.
  */
 Datum
 circle_add_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x += point->x;
-	result->center.y += point->y;
+	point_add_point(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_sub_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x -= point->x;
-	result->center.y -= point->y;
+	point_sub_point(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /* circle_mul_pt()
  * Rotation and scaling operators.
  */
 Datum
 circle_mul_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_mul,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
-	result->radius *= HYPOT(point->x, point->y);
+	point_mul_point(&result->center, &circle->center, point);
+	result->radius = circle->radius * HYPOT(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_div_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_div,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
-	result->radius /= HYPOT(point->x, point->y);
+	point_div_point(&result->center, &circle->center, point);
+	result->radius = circle->radius / HYPOT(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /*		circle_area		-		returns the area of the circle.
  */
 Datum
 circle_area(PG_FUNCTION_ARGS)
 {
@@ -4993,22 +4838,22 @@ circle_radius(PG_FUNCTION_ARGS)
 /*		circle_distance -		returns the distance between
  *								  two circles.
  */
 Datum
 circle_distance(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(&circle1->center, &circle2->center)
-		- (circle1->radius + circle2->radius);
+	result = point_dt(&circle1->center, &circle2->center) -
+		(circle1->radius + circle2->radius);
 	if (result < 0)
 		result = 0;
 	PG_RETURN_FLOAT8(result);
 }
 
 
 Datum
 circle_contain_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
@@ -5190,56 +5035,60 @@ circle_poly(PG_FUNCTION_ARGS)
 		angle = i * anglestep;
 		poly->p[i].x = circle->center.x - (circle->radius * cos(angle));
 		poly->p[i].y = circle->center.y + (circle->radius * sin(angle));
 	}
 
 	make_bound_box(poly);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
-/*		poly_circle		- convert polygon to circle
+/*
+ * Convert polygon to circle
+ *
+ * The result must be preallocated.
  *
  * XXX This algorithm should use weighted means of line segments
  *	rather than straight average values of points - tgl 97/01/21.
  */
+static void
+poly_to_circle(CIRCLE *result, POLYGON *poly)
+{
+	int			i;
+
+	Assert(poly->npts > 0);
+
+	result->center.x = 0;
+	result->center.y = 0;
+	result->radius = 0;
+
+	for (i = 0; i < poly->npts; i++)
+		point_add_point(&result->center, &result->center, &poly->p[i]);
+	result->center.x /= poly->npts;
+	result->center.y /= poly->npts;
+
+	for (i = 0; i < poly->npts; i++)
+		result->radius += point_dt(&poly->p[i], &result->center);
+	result->radius /= poly->npts;
+}
+
 Datum
 poly_circle(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
-	CIRCLE	   *circle;
-	int			i;
+	CIRCLE	   *result;
 
-	if (poly->npts < 1)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot convert empty polygon to circle")));
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
+	poly_to_circle(result, poly);
 
-	circle->center.x = 0;
-	circle->center.y = 0;
-	circle->radius = 0;
-
-	for (i = 0; i < poly->npts; i++)
-	{
-		circle->center.x += poly->p[i].x;
-		circle->center.y += poly->p[i].y;
-	}
-	circle->center.x /= poly->npts;
-	circle->center.y /= poly->npts;
-
-	for (i = 0; i < poly->npts; i++)
-		circle->radius += point_dt(&poly->p[i], &circle->center);
-	circle->radius /= poly->npts;
-
-	PG_RETURN_CIRCLE_P(circle);
+	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /***********************************************************************
  **
  **		Private routines for multiple types.
  **
  ***********************************************************************/
 
 /*
@@ -5261,22 +5110,21 @@ point_inside(Point *p, int npts, Point *plist)
 	double		x0,
 				y0;
 	double		prev_x,
 				prev_y;
 	int			i = 0;
 	double		x,
 				y;
 	int			cross,
 				total_cross = 0;
 
-	if (npts <= 0)
-		return 0;
+	Assert(npts > 0);
 
 	/* compute first polygon point relative to single point */
 	x0 = plist[0].x - p->x;
 	y0 = plist[0].y - p->y;
 
 	prev_x = x0;
 	prev_y = y0;
 	/* loop over polygon points and aggregate total_cross */
 	for (i = 1; i < npts; i++)
 	{
@@ -5371,51 +5219,48 @@ lseg_crossing(double x, double y, double prev_x, double prev_y)
 static bool
 plist_same(int npts, Point *p1, Point *p2)
 {
 	int			i,
 				ii,
 				j;
 
 	/* find match for first point */
 	for (i = 0; i < npts; i++)
 	{
-		if ((FPeq(p2[i].x, p1[0].x))
-			&& (FPeq(p2[i].y, p1[0].y)))
+		if (point_eq_point(&p2[i], &p1[0]))
 		{
 
 			/* match found? then look forward through remaining points */
 			for (ii = 1, j = i + 1; ii < npts; ii++, j++)
 			{
 				if (j >= npts)
 					j = 0;
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_point(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed forward match with %d\n", j, ii);
 #endif
 					break;
 				}
 			}
 #ifdef GEODEBUG
 			printf("plist_same- ii = %d/%d after forward match\n", ii, npts);
 #endif
 			if (ii == npts)
 				return true;
 
 			/* match not found forwards? then look backwards */
 			for (ii = 1, j = i - 1; ii < npts; ii++, j--)
 			{
 				if (j < 0)
 					j = (npts - 1);
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_point(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed reverse match with %d\n", j, ii);
 #endif
 					break;
 				}
 			}
 #ifdef GEODEBUG
 			printf("plist_same- ii = %d/%d after reverse match\n", ii, npts);
 #endif
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index 3f1a755cbb..0fe40499e0 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -786,14 +786,15 @@ spg_bbox_quad_config(PG_FUNCTION_ARGS)
 
 /*
  * 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);
+	box = (BOX *) palloc(sizeof(BOX));
+	*box = polygon->boundbox;
 
 	PG_RETURN_BOX_P(box);
 }
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index a589e4239f..0e066894cd 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -171,17 +171,13 @@ typedef struct
 #define DatumGetCircleP(X)	  ((CIRCLE *) DatumGetPointer(X))
 #define CirclePGetDatum(X)	  PointerGetDatum(X)
 #define PG_GETARG_CIRCLE_P(n) DatumGetCircleP(PG_GETARG_DATUM(n))
 #define PG_RETURN_CIRCLE_P(x) return CirclePGetDatum(x)
 
 
 /*
  * 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/regress.c b/src/test/regress/regress.c
index 13e7207457..994697d338 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -62,21 +62,23 @@ regress_dist_ptpath(PG_FUNCTION_ARGS)
 	float8		result = 0.0;	/* keep compiler quiet */
 	float8		tmp;
 	int			i;
 	LSEG		lseg;
 
 	switch (path->npts)
 	{
 		case 0:
 			PG_RETURN_NULL();
 		case 1:
-			result = point_dt(pt, &path->p[0]);
+			result = DatumGetFloat8(DirectFunctionCall2(point_distance,
+														PointPGetDatum(pt),
+												PointPGetDatum(&path->p[0])));
 			break;
 		default:
 
 			/*
 			 * the distance from a point to a path is the smallest distance
 			 * from the point to any of its constituent segments.
 			 */
 			Assert(path->npts > 1);
 			for (i = 0; i < path->npts - 1; ++i)
 			{
@@ -280,22 +282,27 @@ widget_out(PG_FUNCTION_ARGS)
 	PG_RETURN_CSTRING(str);
 }
 
 PG_FUNCTION_INFO_V1(pt_in_widget);
 
 Datum
 pt_in_widget(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	WIDGET	   *widget = (WIDGET *) PG_GETARG_POINTER(1);
+	float8		distance;
 
-	PG_RETURN_BOOL(point_dt(point, &widget->center) < widget->radius);
+	distance = DatumGetFloat8(DirectFunctionCall2(point_distance,
+												  PointPGetDatum(point),
+											PointPGetDatum(&widget->center)));
+
+	PG_RETURN_BOOL(distance < widget->radius);
 }
 
 PG_FUNCTION_INFO_V1(boxarea);
 
 Datum
 boxarea(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	double		width,
 				height;
-- 
2.14.3 (Apple Git-98)

0004-line-fixes-v07.patchapplication/octet-stream; name=0004-line-fixes-v07.patchDownload
From 00fad9622bd5d6ce1b0e20c8662149b6e2a81e7e Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sun, 28 May 2017 11:35:17 +0200
Subject: [PATCH 4/6] line-fixes-v07

Fix obvious problems around the line datatype

I have noticed some line operators retuning wrong results, and Tom Lane
spotted similar problems on more places.  Source history reveals that
during 1990s, the internal format of the line datatype is changed, but
most functions haven't got the hint.  The fixes include:

* Reject invalid specification A=B=0 on receive
* Reject same points on line_construct_pp()
* Avoid division by zero on perpendicular operator
* Fix intersection and distance operators when neither A nor B are 1
* Return NULL for closest point when objects are parallel
* Check whether closest point of line segments is the intersection point
* Fix closest point of line segments being on the wrong segment

The changes are also aiming make line operators more symmetric and less
sensitive to floating point precision loss.  The EPSILON interferes with
every minor change in different ways.  It is hard to guess which
behaviour is more expected, but we can assume threating both sides of
the operators more equally is more expected.

Previous discussion:
https://www.postgresql.org/message-id/flat/CAE2gYzw_-z%3DV2kh8QqFjenu%3D8MJXzOP44wRW%3DAzzeamrmTT1%3DQ%40mail.gmail.com
---
 src/backend/utils/adt/geo_ops.c | 143 +++++++++++++++++++++++++++-------------
 1 file changed, 98 insertions(+), 45 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index c925a99876..24d2602f4b 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -40,20 +40,21 @@ static inline void point_add_point(Point *result, Point *pt1, Point *pt2);
 static inline void point_sub_point(Point *result, Point *pt1, Point *pt2);
 static inline void point_mul_point(Point *result, Point *pt1, Point *pt2);
 static inline void point_div_point(Point *result, Point *pt1, Point *pt2);
 static inline bool point_eq_point(Point *pt1, Point *pt2);
 static inline float8 point_dt(Point *pt1, Point *pt2);
 static inline float8 point_sl(Point *pt1, Point *pt2);
 static int	point_inside(Point *p, int npts, Point *plist);
 
 /* Routines for lines */
 static inline void line_construct(LINE *result, Point *pt, float8 m);
+static inline float8 line_sl(LINE *line);
 static inline float8 line_invsl(LINE *line);
 static bool	line_interpt_line(Point *result, LINE *l1, LINE *l2);
 static bool line_contain_point(LINE *line, Point *point);
 static float8 line_closept_point(Point *result, LINE *line, Point *pt);
 
 /* Routines for line segments */
 static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
 static inline float8 lseg_sl(LSEG *lseg);
 static inline float8 lseg_invsl(LSEG *lseg);
 static bool	lseg_interpt_line(Point *result, LSEG *lseg, LINE *line);
@@ -972,20 +973,25 @@ line_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LINE	   *line;
 
 	line = (LINE *) palloc(sizeof(LINE));
 
 	line->A = pq_getmsgfloat8(buf);
 	line->B = pq_getmsgfloat8(buf);
 	line->C = pq_getmsgfloat8(buf);
 
+	if (FPzero(line->A) && FPzero(line->B))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("invalid line specification: A and B cannot both be zero")));
+
 	PG_RETURN_LINE_P(line);
 }
 
 /*
  *		line_send			- converts line to binary format
  */
 Datum
 line_send(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -1036,20 +1042,25 @@ line_construct(LINE *result, Point *pt, float8 m)
 /* line_construct_pp()
  * two points
  */
 Datum
 line_construct_pp(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 	LINE	   *result = (LINE *) palloc(sizeof(LINE));
 
+	if (point_eq_point(pt1, pt2))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("invalid line specification: must be two distinct points")));
+
 	line_construct(result, pt1, point_sl(pt1, pt2));
 
 	PG_RETURN_LINE_P(result);
 }
 
 
 /*----------------------------------------------------------
  *	Relative position routines.
  *---------------------------------------------------------*/
 
@@ -1072,22 +1083,26 @@ line_parallel(PG_FUNCTION_ARGS)
 }
 
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
+	else if (FPzero(l2->A))
+		PG_RETURN_BOOL(FPzero(l1->B));
 	else if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
+	else if (FPzero(l2->B))
+		PG_RETURN_BOOL(FPzero(l1->A));
 
 	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
 								   float8_mul(l1->B, l2->A)), -1.0));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
@@ -1131,20 +1146,34 @@ line_eq(PG_FUNCTION_ARGS)
 					FPeq(l1->B, float8_mul(ratio, l2->B))) &&
 				   ((isnan(l1->C) && isnan(l2->C)) ||
 					FPeq(l1->C, float8_mul(ratio, l2->C))));
 }
 
 
 /*----------------------------------------------------------
  *	Line arithmetic routines.
  *---------------------------------------------------------*/
 
+/*
+ * Return slope of the line
+ */
+static inline float8
+line_sl(LINE *line)
+{
+	if (FPzero(line->A))
+		return 0.0;
+	if (FPzero(line->B))
+		return DBL_MAX;
+	return float8_div(line->A, -line->B);
+}
+
+
 /*
  * Return inverse slope of the line
  */
 static inline float8
 line_invsl(LINE *line)
 {
 	if (FPzero(line->A))
 		return DBL_MAX;
 	if (FPzero(line->B))
 		return 0.0;
@@ -1153,30 +1182,35 @@ line_invsl(LINE *line)
 
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	float8		result;
-	Point		tmp;
+	float8		ratio;
 
 	if (line_interpt_line(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
-	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
-	point_construct(&tmp, 0.0, l1->C);
-	result = line_closept_point(NULL, l2, &tmp);
-	PG_RETURN_FLOAT8(result);
+
+	if (!FPzero(l1->A) && !isnan(l1->A) && !FPzero(l2->A) && !isnan(l2->A))
+		ratio = float8_div(l1->A, l2->A);
+	else if (!FPzero(l1->B) && !isnan(l1->B) && !FPzero(l2->B) && !isnan(l2->B))
+		ratio = float8_div(l1->B, l2->B);
+	else
+		ratio = 1.0;
+
+	PG_RETURN_FLOAT8(float8_div(fabs(float8_mi(l1->C,
+											   float8_mul(ratio, l2->C))),
+								HYPOT(l1->A, l1->B)));
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
@@ -1208,35 +1242,39 @@ static bool
 line_interpt_line(Point *result, LINE *l1, LINE *l2)
 {
 	float8		x,
 				y;
 
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
 		if (FPzero(l2->B))		/* l2 vertical? */
 			return false;
 
-		x = l1->C;
-		y = float8_pl(float8_mul(l2->A, x), l2->C);
+		x = float8_div(-l1->C, l1->A);
+		y = float8_div(-float8_pl(float8_mul(l2->A, x), l2->C), l2->B);
 	}
 	else if (FPzero(l2->B))		/* l2 vertical? */
 	{
-		x = l2->C;
-		y = float8_pl(float8_mul(l1->A, x), l1->C);
+		x = float8_div(-l2->C, l2->A);
+		y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
 	}
 	else
 	{
+		/* XXX This check break commutative property. */
 		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
 			return false;
 
-		x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
-		y = float8_pl(float8_mul(l1->A, x), l1->C);
+		x = float8_div(float8_mi(float8_mul(l1->B, l2->C),
+								 float8_mul(l2->B, l1->C)),
+					   float8_mi(float8_mul(l1->A, l2->B),
+								 float8_mul(l2->A, l1->B)));
+		y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
 	}
 	if (result != NULL)
 		point_construct(result, x, y);
 
 	return true;
 }
 
 
 /***********************************************************************
  **
@@ -2345,30 +2383,22 @@ dist_pb(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
-	float8		result;
 
-	if (lseg_interpt_line(NULL, lseg, line))
-		result = 0.0;
-	else
-		/* XXX shouldn't we take the min not max? */
-		result = float8_max(line_closept_point(NULL, line, &lseg->p[0]),
-							line_closept_point(NULL, line, &lseg->p[1]));
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(lseg_closept_line(NULL, lseg, line));
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
@@ -2533,34 +2563,43 @@ lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
 /*
  *		The intersection point of a perpendicular of the line
  *		through the point.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 line_closept_point(Point *result, LINE *line, Point *point)
 {
-	bool		retval;
+	Point		closept;
 	LINE		tmp;
 
 	/* Drop a perpendicular and find the intersection point */
 	line_construct(&tmp, point, line_invsl(line));
-	retval = line_interpt_line(result, line, &tmp);
-	Assert(retval);		/* XXX We need something better. */
 
 	/*
-	 * XXX We could use the distance to the closest point, but
-	 * line_interpt_line() is currently giving wrong results.
+	 * Ordinarily we should always find an intersection point, but that could
+	 * fail in the presence of NaN coordinates, and perhaps even from simple
+	 * roundoff issues.
 	 */
-	return fabs((line->A * point->x + line->B * point->y + line->C) /
-				HYPOT(line->A, line->B));
+	if (!line_interpt_line(&closept, &tmp, line))
+	{
+		if (result != NULL)
+			*result = *point;
+
+		return get_float8_nan();
+	}
+
+	if (result != NULL)
+		*result = closept;
+
+	return point_dt(&closept, point);
 }
 
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -2610,64 +2649,75 @@ close_ps(PG_FUNCTION_ARGS)
 		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point to l1 on l2.
  *
  * This sets the closest point to the *result if it is not NULL and returns
- * the distance to the closest point.
- *
- * XXX This function is wrong.  If must never set the *result to a point on
- * the second segment.
+ * the distance to the closest point.  We first eliminate the case
+ * the segments intersecting with each other.  Then we try to find
+ * the closest point on the first segment by trying the endpoints of
+ * the second.  Though, it is still possible for the closest point to be
+ * one of the endpoints, so we test them.
  */
 static float8
 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
 {
 	Point		point;
 	float8		dist,
 				d;
 
-	d = lseg_closept_point(NULL, l1, &l2->p[0]);
-	dist = d;
-	if (result != NULL)
-		*result = l2->p[0];
+	if (lseg_interpt_lseg(result, l1, l2))
+		return 0.0;
 
-	d = lseg_closept_point(NULL, l1, &l2->p[1]);
+	dist = lseg_closept_point(result, l1, &l2->p[0]);
+
+	d = lseg_closept_point(&point, l1, &l2->p[1]);
 	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
-			*result = l2->p[1];
+			*result = point;
 	}
 
-	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[0]), dist))
-		d = lseg_closept_point(result, l1, &point);
-
-	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[1]), dist))
-		d = lseg_closept_point(result, l1, &point);
-
+	d = lseg_closept_point(NULL, l2, &l1->p[0]);
 	if (float8_lt(d, dist))
+	{
 		dist = d;
+		if (result != NULL)
+			*result = l1->p[0];
+	}
+
+	d = lseg_closept_point(NULL, l2, &l1->p[1]);
+	if (float8_lt(d, dist))
+	{
+		dist = d;
+		if (result != NULL)
+			*result = l1->p[1];
+	}
 
 	return dist;
 }
 
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
+	if (lseg_sl(l1) == lseg_sl(l2))
+		PG_RETURN_NULL();
+
 	result = (Point *) palloc(sizeof(Point));
 
 	if (isnan(lseg_closept_lseg(result, l2, l1)))
 		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
@@ -2828,20 +2878,23 @@ lseg_closept_line(Point *result, LSEG *lseg, LINE *line)
 	}
 }
 
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
+	if (lseg_sl(lseg) == line_sl(line))
+		PG_RETURN_NULL();
+
 	result = (Point *) palloc(sizeof(Point));
 
 	if (isnan(lseg_closept_line(result, lseg, line)))
 		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
-- 
2.14.3 (Apple Git-98)

0005-float-zero-v03.patchapplication/octet-stream; name=0005-float-zero-v03.patchDownload
From 522c25447dd130b9631e430899f3e639e3990508 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Thu, 2 Nov 2017 12:21:19 +0100
Subject: [PATCH 5/6] float-zero-v03

Check for float -0 after multiplications and divisions
---
 src/include/utils/float.h | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/src/include/utils/float.h b/src/include/utils/float.h
index b1f34183de..7370d92452 100644
--- a/src/include/utils/float.h
+++ b/src/include/utils/float.h
@@ -213,64 +213,76 @@ float8_mi(float8 val1, float8 val2)
 
 static inline float4
 float4_mul(float4 val1, float4 val2)
 {
 	float4		result;
 
 	result = val1 * val2;
 	check_float4_val(result, isinf(val1) || isinf(val2),
 					 val1 == 0.0f || val2 == 0.0f);
 
+	if (result == -0.0f)
+		result = 0.0f;
+
 	return result;
 }
 
 static inline float8
 float8_mul(float8 val1, float8 val2)
 {
 	float8		result;
 
 	result = val1 * val2;
 	check_float8_val(result, isinf(val1) || isinf(val2),
 					 val1 == 0.0 || val2 == 0.0);
 
+	if (result == -0.0)
+		result = 0.0;
+
 	return result;
 }
 
 static inline float4
 float4_div(float4 val1, float4 val2)
 {
 	float4		result;
 
 	if (val2 == 0.0f)
 		ereport(ERROR,
 				(errcode(ERRCODE_DIVISION_BY_ZERO),
 				 errmsg("division by zero")));
 
 	result = val1 / val2;
 	check_float4_val(result, isinf(val1) || isinf(val2), val1 == 0.0f);
 
+	if (result == -0.0f)
+		result = 0.0f;
+
 	return result;
 }
 
 static inline float8
 float8_div(float8 val1, float8 val2)
 {
 	float8		result;
 
 	if (val2 == 0.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_DIVISION_BY_ZERO),
 				 errmsg("division by zero")));
 
 	result = val1 / val2;
 	check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
 
+	if (result == -0.0)
+		result = 0.0;
+
 	return result;
 }
 
 /*
  * Routines for NaN-aware comparisons
  *
  * We consider all NaNs to be equal and larger than any non-NaN. This is
  * somewhat arbitrary; the important thing is to have a consistent sort
  * order.
  */
-- 
2.14.3 (Apple Git-98)

0006-geo-tests-v03.patchapplication/octet-stream; name=0006-geo-tests-v03.patchDownload
From 3dee4e8b3dbfef57cc57fc721e7f1d7144d22658 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Tue, 24 Oct 2017 11:28:21 +0200
Subject: [PATCH 6/6] geo-tests-v03

Improve test coverage of geometric types

The tests for the geometric functions and operators were in sad state.
This commit increases test coverage of geo_ops.c significantly.  It
removes the alternative results to expect -0 on some platforms.  We
better try to return the same results on different platforms, but if we
can't we can add them back using the results from build farm.

The tests are added to geometric.sql file.  It is not clear where to
put them as there are many cross datatype operators.  Organising them
on a single file sorted by the left hand side of the operators appear
to be a simple solution.  We may take this further and remove the other
tests later.
---
 src/test/regress/expected/box.out          |   44 +-
 src/test/regress/expected/circle.out       |   39 +-
 src/test/regress/expected/create_index.out |   73 +-
 src/test/regress/expected/geometry.out     | 4879 ++++++++++++++++++++++++++--
 src/test/regress/expected/geometry_1.out   |  563 ----
 src/test/regress/expected/geometry_2.out   |  563 ----
 src/test/regress/expected/line.out         |  269 +-
 src/test/regress/expected/lseg.out         |   24 +-
 src/test/regress/expected/path.out         |   49 +-
 src/test/regress/expected/point.out        |  358 +-
 src/test/regress/expected/polygon.out      |  200 +-
 src/test/regress/sql/box.sql               |    9 +
 src/test/regress/sql/circle.sql            |   10 +-
 src/test/regress/sql/geometry.sql          |  400 ++-
 src/test/regress/sql/line.sql              |   78 +-
 src/test/regress/sql/lseg.sql              |    9 +-
 src/test/regress/sql/path.sql              |   22 +-
 src/test/regress/sql/point.sql             |   10 +
 src/test/regress/sql/polygon.sql           |   91 +-
 19 files changed, 5476 insertions(+), 2214 deletions(-)
 delete mode 100644 src/test/regress/expected/geometry_1.out
 delete mode 100644 src/test/regress/expected/geometry_2.out

diff --git a/src/test/regress/expected/box.out b/src/test/regress/expected/box.out
index 49af242c8c..998b52223c 100644
--- a/src/test/regress/expected/box.out
+++ b/src/test/regress/expected/box.out
@@ -11,92 +11,109 @@
 -- 1	| o-+-o
 --	|   |
 -- 0	+---+
 --
 --	0 1 2 3
 --
 -- boxes are specified by two points, given by four floats x1,y1,x2,y2
 CREATE TABLE BOX_TBL (f1 box);
 INSERT INTO BOX_TBL (f1) VALUES ('(2.0,2.0,0.0,0.0)');
 INSERT INTO BOX_TBL (f1) VALUES ('(1.0,1.0,3.0,3.0)');
+INSERT INTO BOX_TBL (f1) VALUES ('((-8, 2), (-2, -10))');
 -- degenerate cases where the box is a line or a point
 -- note that lines and points boxes all have zero area
 INSERT INTO BOX_TBL (f1) VALUES ('(2.5, 2.5, 2.5,3.5)');
 INSERT INTO BOX_TBL (f1) VALUES ('(3.0, 3.0,3.0,3.0)');
 -- badly formatted box inputs
 INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
 ERROR:  invalid input syntax for type box: "(2.3, 4.5)"
 LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
                                          ^
+INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+ERROR:  invalid input syntax for type box: "[1, 2, 3, 4)"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+                                         ^
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+ERROR:  invalid input syntax for type box: "(1, 2, 3, 4]"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+                                         ^
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+ERROR:  invalid input syntax for type box: "(1, 2, 3, 4) x"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+                                         ^
 INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
 ERROR:  invalid input syntax for type box: "asdfasdf(ad"
 LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
                                          ^
 SELECT '' AS four, * FROM BOX_TBL;
  four |         f1          
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
+      | (-2,2),(-8,-10)
       | (2.5,3.5),(2.5,2.5)
       | (3,3),(3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, b.*, area(b.f1) as barea
    FROM BOX_TBL b;
  four |         f1          | barea 
 ------+---------------------+-------
       | (2,2),(0,0)         |     4
       | (3,3),(1,1)         |     4
+      | (-2,2),(-8,-10)     |    72
       | (2.5,3.5),(2.5,2.5) |     0
       | (3,3),(3,3)         |     0
-(4 rows)
+(5 rows)
 
 -- overlap
 SELECT '' AS three, b.f1
    FROM BOX_TBL b
    WHERE b.f1 && box '(2.5,2.5,1.0,1.0)';
  three |         f1          
 -------+---------------------
        | (2,2),(0,0)
        | (3,3),(1,1)
        | (2.5,3.5),(2.5,2.5)
 (3 rows)
 
 -- left-or-overlap (x only)
 SELECT '' AS two, b1.*
    FROM BOX_TBL b1
    WHERE b1.f1 &< box '(2.0,2.0,2.5,2.5)';
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- right-or-overlap (x only)
 SELECT '' AS two, b1.*
    FROM BOX_TBL b1
    WHERE b1.f1 &> box '(2.0,2.0,2.5,2.5)';
  two |         f1          
 -----+---------------------
      | (2.5,3.5),(2.5,2.5)
      | (3,3),(3,3)
 (2 rows)
 
 -- left of
 SELECT '' AS two, b.f1
    FROM BOX_TBL b
    WHERE b.f1 << box '(3.0,3.0,5.0,5.0)';
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- area <=
 SELECT '' AS four, b.f1
    FROM BOX_TBL b
    WHERE b.f1 <= box '(3.0,3.0,5.0,5.0)';
  four |         f1          
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
       | (2.5,3.5),(2.5,2.5)
@@ -120,47 +137,50 @@ SELECT '' AS two, b.f1
  two |     f1      
 -----+-------------
      | (2,2),(0,0)
      | (3,3),(1,1)
 (2 rows)
 
 -- area >
 SELECT '' AS two, b.f1
    FROM BOX_TBL b				-- zero area
    WHERE b.f1 > box '(3.5,3.0,4.5,3.0)';
- two |     f1      
------+-------------
+ two |       f1        
+-----+-----------------
      | (2,2),(0,0)
      | (3,3),(1,1)
-(2 rows)
+     | (-2,2),(-8,-10)
+(3 rows)
 
 -- area >=
 SELECT '' AS four, b.f1
    FROM BOX_TBL b				-- zero area
    WHERE b.f1 >= box '(3.5,3.0,4.5,3.0)';
  four |         f1          
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
+      | (-2,2),(-8,-10)
       | (2.5,3.5),(2.5,2.5)
       | (3,3),(3,3)
-(4 rows)
+(5 rows)
 
 -- right of
 SELECT '' AS two, b.f1
    FROM BOX_TBL b
    WHERE box '(3.0,3.0,5.0,5.0)' >> b.f1;
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- contained in
 SELECT '' AS three, b.f1
    FROM BOX_TBL b
    WHERE b.f1 <@ box '(0,0,3,3)';
  three |     f1      
 -------+-------------
        | (2,2),(0,0)
        | (3,3),(1,1)
        | (3,3),(3,3)
@@ -186,41 +206,43 @@ SELECT '' AS one, b.f1
      | (3,3),(1,1)
 (1 row)
 
 -- center of box, left unary operator
 SELECT '' AS four, @@(b1.f1) AS p
    FROM BOX_TBL b1;
  four |    p    
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 -- wholly-contained
 SELECT '' AS one, b1.*, b2.*
    FROM BOX_TBL b1, BOX_TBL b2
    WHERE b1.f1 @> b2.f1 and not b1.f1 ~= b2.f1;
  one |     f1      |     f1      
 -----+-------------+-------------
      | (3,3),(1,1) | (3,3),(3,3)
 (1 row)
 
 SELECT '' AS four, height(f1), width(f1) FROM BOX_TBL;
  four | height | width 
 ------+--------+-------
       |      2 |     2
       |      2 |     2
+      |     12 |     6
       |      1 |     0
       |      0 |     0
-(4 rows)
+(5 rows)
 
 --
 -- Test the SP-GiST index
 --
 CREATE TEMPORARY TABLE box_temp (f1 box);
 INSERT INTO box_temp
 	SELECT box(point(i, i), point(i * 2, i * 2))
 	FROM generate_series(1, 50) AS i;
 CREATE INDEX box_spgist ON box_temp USING spgist (f1);
 INSERT INTO box_temp
diff --git a/src/test/regress/expected/circle.out b/src/test/regress/expected/circle.out
index 9ba4a0495d..2ed74cc6aa 100644
--- a/src/test/regress/expected/circle.out
+++ b/src/test/regress/expected/circle.out
@@ -1,99 +1,122 @@
 --
 -- CIRCLE
 --
 CREATE TABLE CIRCLE_TBL (f1 circle);
 INSERT INTO CIRCLE_TBL VALUES ('<(5,1),3>');
 INSERT INTO CIRCLE_TBL VALUES ('<(1,2),100>');
 INSERT INTO CIRCLE_TBL VALUES ('1,3,5');
 INSERT INTO CIRCLE_TBL VALUES ('((1,2),3)');
 INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10>');
-INSERT INTO CIRCLE_TBL VALUES ('<(100,1),115>');
+INSERT INTO CIRCLE_TBL VALUES (' < ( 100 , 1 ) , 115 > ');
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),0>');	-- Zero radius
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),NaN>');	-- NaN radius
 -- bad values
 INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
 ERROR:  invalid input syntax for type circle: "<(-100,0),-100>"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
                                        ^
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+ERROR:  invalid input syntax for type circle: "<(100,200),10"
+LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+                                       ^
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+ERROR:  invalid input syntax for type circle: "<(100,200),10> x"
+LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+                                       ^
 INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
 ERROR:  invalid input syntax for type circle: "1abc,3,5"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
                                        ^
 INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
 ERROR:  invalid input syntax for type circle: "(3,(1,2),3)"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
                                        ^
 SELECT * FROM CIRCLE_TBL;
        f1       
 ----------------
  <(5,1),3>
  <(1,2),100>
  <(1,3),5>
  <(1,2),3>
  <(100,200),10>
  <(100,1),115>
-(6 rows)
+ <(3,5),0>
+ <(3,5),NaN>
+(8 rows)
 
 SELECT '' AS six, center(f1) AS center
   FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS six, radius(f1) AS radius
   FROM CIRCLE_TBL;
  six | radius 
 -----+--------
      |      3
      |    100
      |      5
      |      3
      |     10
      |    115
-(6 rows)
+     |      0
+     |    NaN
+(8 rows)
 
 SELECT '' AS six, diameter(f1) AS diameter
   FROM CIRCLE_TBL;
  six | diameter 
 -----+----------
      |        6
      |      200
      |       10
      |        6
      |       20
      |      230
-(6 rows)
+     |        0
+     |      NaN
+(8 rows)
 
 SELECT '' AS two, f1 FROM CIRCLE_TBL WHERE radius(f1) < 5;
  two |    f1     
 -----+-----------
      | <(5,1),3>
      | <(1,2),3>
-(2 rows)
+     | <(3,5),0>
+(3 rows)
 
 SELECT '' AS four, f1 FROM CIRCLE_TBL WHERE diameter(f1) >= 10;
  four |       f1       
 ------+----------------
       | <(1,2),100>
       | <(1,3),5>
       | <(100,200),10>
       | <(100,1),115>
-(4 rows)
+      | <(3,5),NaN>
+(5 rows)
 
 SELECT '' as five, c1.f1 AS one, c2.f1 AS two, (c1.f1 <-> c2.f1) AS distance
   FROM CIRCLE_TBL c1, CIRCLE_TBL c2
   WHERE (c1.f1 < c2.f1) AND ((c1.f1 <-> c2.f1) > 0)
   ORDER BY distance, area(c1.f1), area(c2.f1);
  five |      one       |      two       |     distance     
 ------+----------------+----------------+------------------
+      | <(3,5),0>      | <(1,2),3>      | 0.60555127546399
+      | <(3,5),0>      | <(5,1),3>      | 1.47213595499958
       | <(100,200),10> | <(100,1),115>  |               74
       | <(100,200),10> | <(1,2),100>    | 111.370729772479
       | <(1,3),5>      | <(100,200),10> | 205.476756144497
       | <(5,1),3>      | <(100,200),10> |  207.51303816328
+      | <(3,5),0>      | <(100,200),10> | 207.793480159531
       | <(1,2),3>      | <(100,200),10> | 208.370729772479
-(5 rows)
+(8 rows)
 
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 031a0bcec9..ac300469b2 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -150,96 +150,103 @@ SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)';
 
 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
+     5
 (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
+     3
 (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
+     4
 (1 row)
 
 SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
  count 
 -------
      1
 (1 row)
 
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
  (-5,-12)
  (5.1,34.5)
+ (1e+300,Infinity)
+ (NaN,NaN)
  
-(7 rows)
+(10 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NULL;
  f1 
 ----
  
 (1 row)
 
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (1e-300,-1e-300)
  (0,0)
  (-3,4)
  (-10,0)
  (10,10)
  (-5,-12)
  (5.1,34.5)
-(6 rows)
+ (1e+300,Infinity)
+ (NaN,NaN)
+(9 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
  count 
 -------
      3
 (1 row)
 
 SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
  count 
 -------
@@ -561,21 +568,21 @@ SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,
                                        QUERY PLAN                                       
 ----------------------------------------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     4
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>';
                      QUERY PLAN                     
 ----------------------------------------------------
  Aggregate
    ->  Index Only Scan using gpointind on point_tbl
          Index Cond: (f1 <@ '<(50,50),50>'::circle)
 (3 rows)
@@ -606,21 +613,21 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     3
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl p WHERE p.f1 <^ '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only Scan using gpointind on point_tbl p
          Index Cond: (f1 <^ '(0,0)'::point)
 (3 rows)
@@ -636,21 +643,21 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 >^ '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     4
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only Scan using gpointind on point_tbl p
          Index Cond: (f1 ~= '(-5,-12)'::point)
 (3 rows)
@@ -663,30 +670,33 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
                   QUERY PLAN                  
 ----------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Order By: (f1 <-> '(0,1)'::point)
 (2 rows)
 
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (10,10)
+ (NaN,NaN)
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
- (10,10)
  (-5,-12)
  (5.1,34.5)
  
-(7 rows)
+ (1e+300,Infinity)
+(10 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 IS NULL;
                   QUERY PLAN                  
 ----------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Index Cond: (f1 IS NULL)
 (2 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NULL;
@@ -698,47 +708,51 @@ SELECT * FROM point_tbl WHERE f1 IS NULL;
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
                   QUERY PLAN                  
 ----------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Index Cond: (f1 IS NOT NULL)
    Order By: (f1 <-> '(0,1)'::point)
 (3 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (10,10)
+ (NaN,NaN)
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
- (10,10)
  (-5,-12)
  (5.1,34.5)
-(6 rows)
+ (1e+300,Infinity)
+(9 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
                    QUERY PLAN                   
 ------------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Index Cond: (f1 <@ '(10,10),(-10,-10)'::box)
    Order By: (f1 <-> '(0,1)'::point)
 (3 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
                         QUERY PLAN                         
 -----------------------------------------------------------
  Aggregate
    ->  Index Only Scan using sp_quad_ind on quad_point_tbl
          Index Cond: (p IS NULL)
 (3 rows)
 
@@ -1240,27 +1254,28 @@ SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0
 ------------------------------------------------------------
  Sort
    Sort Key: ((f1 <-> '(0,1)'::point))
    ->  Bitmap Heap Scan on point_tbl
          Recheck Cond: (f1 <@ '(10,10),(-10,-10)'::box)
          ->  Bitmap Index Scan on gpointind
                Index Cond: (f1 <@ '(10,10),(-10,-10)'::box)
 (6 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
                   QUERY PLAN                  
 ----------------------------------------------
  Aggregate
    ->  Bitmap Heap Scan on quad_point_tbl
          Recheck Cond: (p IS NULL)
          ->  Bitmap Index Scan on sp_quad_ind
                Index Cond: (p IS NULL)
diff --git a/src/test/regress/expected/geometry.out b/src/test/regress/expected/geometry.out
index e4c0039040..58051b8946 100644
--- a/src/test/regress/expected/geometry.out
+++ b/src/test/regress/expected/geometry.out
@@ -6,558 +6,4885 @@
 SET extra_float_digits TO -3;
 --
 -- Points
 --
 SELECT '' AS four, center(f1) AS center
    FROM BOX_TBL;
  four | center  
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, (@@ f1) AS center
    FROM BOX_TBL;
  four | center  
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS six, point(f1) AS center
    FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS six, (@@ f1) AS center
    FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS two, (@@ f1) AS center
    FROM POLYGON_TBL
    WHERE (# f1) > 2;
  two |            center             
 -----+-------------------------------
      | (1.33333333333,1.33333333333)
      | (2.33333333333,1.33333333333)
-(2 rows)
+     | (4,5)
+     | (4,5)
+     | (4,3)
+(5 rows)
 
 -- "is horizontal" function
 SELECT '' AS two, p1.f1
    FROM POINT_TBL p1
    WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 -- "is horizontal" operator
 SELECT '' AS two, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 -- "is vertical" function
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE isvertical(p1.f1, point '(5.1,34.5)');
  one |     f1     
 -----+------------
      | (5.1,34.5)
 (1 row)
 
 -- "is vertical" operator
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?| point '(5.1,34.5)';
  one |     f1     
 -----+------------
      | (5.1,34.5)
 (1 row)
 
+-- Slope
+SELECT p1.f1, p2.f1, slope(p1.f1, p2.f1) FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |       slope        
+-------------------+-------------------+--------------------
+ (0,0)             | (0,0)             | 1.79769313486e+308
+ (0,0)             | (-10,0)           |                  0
+ (0,0)             | (-3,4)            |     -1.33333333333
+ (0,0)             | (5.1,34.5)        |      6.76470588235
+ (0,0)             | (-5,-12)          |                2.4
+ (0,0)             | (1e-300,-1e-300)  | 1.79769313486e+308
+ (0,0)             | (1e+300,Infinity) |           Infinity
+ (0,0)             | (NaN,NaN)         |                NaN
+ (0,0)             | (10,10)           |                  1
+ (-10,0)           | (0,0)             |                  0
+ (-10,0)           | (-10,0)           | 1.79769313486e+308
+ (-10,0)           | (-3,4)            |     0.571428571429
+ (-10,0)           | (5.1,34.5)        |      2.28476821192
+ (-10,0)           | (-5,-12)          |               -2.4
+ (-10,0)           | (1e-300,-1e-300)  |                  0
+ (-10,0)           | (1e+300,Infinity) |           Infinity
+ (-10,0)           | (NaN,NaN)         |                NaN
+ (-10,0)           | (10,10)           |                0.5
+ (-3,4)            | (0,0)             |     -1.33333333333
+ (-3,4)            | (-10,0)           |     0.571428571429
+ (-3,4)            | (-3,4)            | 1.79769313486e+308
+ (-3,4)            | (5.1,34.5)        |      3.76543209877
+ (-3,4)            | (-5,-12)          |                  8
+ (-3,4)            | (1e-300,-1e-300)  |     -1.33333333333
+ (-3,4)            | (1e+300,Infinity) |           Infinity
+ (-3,4)            | (NaN,NaN)         |                NaN
+ (-3,4)            | (10,10)           |     0.461538461538
+ (5.1,34.5)        | (0,0)             |      6.76470588235
+ (5.1,34.5)        | (-10,0)           |      2.28476821192
+ (5.1,34.5)        | (-3,4)            |      3.76543209877
+ (5.1,34.5)        | (5.1,34.5)        | 1.79769313486e+308
+ (5.1,34.5)        | (-5,-12)          |      4.60396039604
+ (5.1,34.5)        | (1e-300,-1e-300)  |      6.76470588235
+ (5.1,34.5)        | (1e+300,Infinity) |           Infinity
+ (5.1,34.5)        | (NaN,NaN)         |                NaN
+ (5.1,34.5)        | (10,10)           |                 -5
+ (-5,-12)          | (0,0)             |                2.4
+ (-5,-12)          | (-10,0)           |               -2.4
+ (-5,-12)          | (-3,4)            |                  8
+ (-5,-12)          | (5.1,34.5)        |      4.60396039604
+ (-5,-12)          | (-5,-12)          | 1.79769313486e+308
+ (-5,-12)          | (1e-300,-1e-300)  |                2.4
+ (-5,-12)          | (1e+300,Infinity) |           Infinity
+ (-5,-12)          | (NaN,NaN)         |                NaN
+ (-5,-12)          | (10,10)           |      1.46666666667
+ (1e-300,-1e-300)  | (0,0)             | 1.79769313486e+308
+ (1e-300,-1e-300)  | (-10,0)           |                  0
+ (1e-300,-1e-300)  | (-3,4)            |     -1.33333333333
+ (1e-300,-1e-300)  | (5.1,34.5)        |      6.76470588235
+ (1e-300,-1e-300)  | (-5,-12)          |                2.4
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | 1.79769313486e+308
+ (1e-300,-1e-300)  | (1e+300,Infinity) |           Infinity
+ (1e-300,-1e-300)  | (NaN,NaN)         |                NaN
+ (1e-300,-1e-300)  | (10,10)           |                  1
+ (1e+300,Infinity) | (0,0)             |           Infinity
+ (1e+300,Infinity) | (-10,0)           |           Infinity
+ (1e+300,Infinity) | (-3,4)            |           Infinity
+ (1e+300,Infinity) | (5.1,34.5)        |           Infinity
+ (1e+300,Infinity) | (-5,-12)          |           Infinity
+ (1e+300,Infinity) | (1e-300,-1e-300)  |           Infinity
+ (1e+300,Infinity) | (1e+300,Infinity) | 1.79769313486e+308
+ (1e+300,Infinity) | (NaN,NaN)         |                NaN
+ (1e+300,Infinity) | (10,10)           |           Infinity
+ (NaN,NaN)         | (0,0)             |                NaN
+ (NaN,NaN)         | (-10,0)           |                NaN
+ (NaN,NaN)         | (-3,4)            |                NaN
+ (NaN,NaN)         | (5.1,34.5)        |                NaN
+ (NaN,NaN)         | (-5,-12)          |                NaN
+ (NaN,NaN)         | (1e-300,-1e-300)  |                NaN
+ (NaN,NaN)         | (1e+300,Infinity) |                NaN
+ (NaN,NaN)         | (NaN,NaN)         |                NaN
+ (NaN,NaN)         | (10,10)           |                NaN
+ (10,10)           | (0,0)             |                  1
+ (10,10)           | (-10,0)           |                0.5
+ (10,10)           | (-3,4)            |     0.461538461538
+ (10,10)           | (5.1,34.5)        |                 -5
+ (10,10)           | (-5,-12)          |      1.46666666667
+ (10,10)           | (1e-300,-1e-300)  |                  1
+ (10,10)           | (1e+300,Infinity) |           Infinity
+ (10,10)           | (NaN,NaN)         |                NaN
+ (10,10)           | (10,10)           | 1.79769313486e+308
+(81 rows)
+
+-- Add point
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |     ?column?      
+-------------------+-------------------+-------------------
+ (0,0)             | (0,0)             | (0,0)
+ (0,0)             | (-10,0)           | (-10,0)
+ (0,0)             | (-3,4)            | (-3,4)
+ (0,0)             | (5.1,34.5)        | (5.1,34.5)
+ (0,0)             | (-5,-12)          | (-5,-12)
+ (0,0)             | (1e-300,-1e-300)  | (1e-300,-1e-300)
+ (0,0)             | (1e+300,Infinity) | (1e+300,Infinity)
+ (0,0)             | (NaN,NaN)         | (NaN,NaN)
+ (0,0)             | (10,10)           | (10,10)
+ (-10,0)           | (0,0)             | (-10,0)
+ (-10,0)           | (-10,0)           | (-20,0)
+ (-10,0)           | (-3,4)            | (-13,4)
+ (-10,0)           | (5.1,34.5)        | (-4.9,34.5)
+ (-10,0)           | (-5,-12)          | (-15,-12)
+ (-10,0)           | (1e-300,-1e-300)  | (-10,-1e-300)
+ (-10,0)           | (1e+300,Infinity) | (1e+300,Infinity)
+ (-10,0)           | (NaN,NaN)         | (NaN,NaN)
+ (-10,0)           | (10,10)           | (0,10)
+ (-3,4)            | (0,0)             | (-3,4)
+ (-3,4)            | (-10,0)           | (-13,4)
+ (-3,4)            | (-3,4)            | (-6,8)
+ (-3,4)            | (5.1,34.5)        | (2.1,38.5)
+ (-3,4)            | (-5,-12)          | (-8,-8)
+ (-3,4)            | (1e-300,-1e-300)  | (-3,4)
+ (-3,4)            | (1e+300,Infinity) | (1e+300,Infinity)
+ (-3,4)            | (NaN,NaN)         | (NaN,NaN)
+ (-3,4)            | (10,10)           | (7,14)
+ (5.1,34.5)        | (0,0)             | (5.1,34.5)
+ (5.1,34.5)        | (-10,0)           | (-4.9,34.5)
+ (5.1,34.5)        | (-3,4)            | (2.1,38.5)
+ (5.1,34.5)        | (5.1,34.5)        | (10.2,69)
+ (5.1,34.5)        | (-5,-12)          | (0.1,22.5)
+ (5.1,34.5)        | (1e-300,-1e-300)  | (5.1,34.5)
+ (5.1,34.5)        | (1e+300,Infinity) | (1e+300,Infinity)
+ (5.1,34.5)        | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5)        | (10,10)           | (15.1,44.5)
+ (-5,-12)          | (0,0)             | (-5,-12)
+ (-5,-12)          | (-10,0)           | (-15,-12)
+ (-5,-12)          | (-3,4)            | (-8,-8)
+ (-5,-12)          | (5.1,34.5)        | (0.1,22.5)
+ (-5,-12)          | (-5,-12)          | (-10,-24)
+ (-5,-12)          | (1e-300,-1e-300)  | (-5,-12)
+ (-5,-12)          | (1e+300,Infinity) | (1e+300,Infinity)
+ (-5,-12)          | (NaN,NaN)         | (NaN,NaN)
+ (-5,-12)          | (10,10)           | (5,-2)
+ (1e-300,-1e-300)  | (0,0)             | (1e-300,-1e-300)
+ (1e-300,-1e-300)  | (-10,0)           | (-10,-1e-300)
+ (1e-300,-1e-300)  | (-3,4)            | (-3,4)
+ (1e-300,-1e-300)  | (5.1,34.5)        | (5.1,34.5)
+ (1e-300,-1e-300)  | (-5,-12)          | (-5,-12)
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | (2e-300,-2e-300)
+ (1e-300,-1e-300)  | (1e+300,Infinity) | (1e+300,Infinity)
+ (1e-300,-1e-300)  | (NaN,NaN)         | (NaN,NaN)
+ (1e-300,-1e-300)  | (10,10)           | (10,10)
+ (1e+300,Infinity) | (0,0)             | (1e+300,Infinity)
+ (1e+300,Infinity) | (-10,0)           | (1e+300,Infinity)
+ (1e+300,Infinity) | (-3,4)            | (1e+300,Infinity)
+ (1e+300,Infinity) | (5.1,34.5)        | (1e+300,Infinity)
+ (1e+300,Infinity) | (-5,-12)          | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e-300,-1e-300)  | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e+300,Infinity) | (2e+300,Infinity)
+ (1e+300,Infinity) | (NaN,NaN)         | (NaN,NaN)
+ (1e+300,Infinity) | (10,10)           | (1e+300,Infinity)
+ (NaN,NaN)         | (0,0)             | (NaN,NaN)
+ (NaN,NaN)         | (-10,0)           | (NaN,NaN)
+ (NaN,NaN)         | (-3,4)            | (NaN,NaN)
+ (NaN,NaN)         | (5.1,34.5)        | (NaN,NaN)
+ (NaN,NaN)         | (-5,-12)          | (NaN,NaN)
+ (NaN,NaN)         | (1e-300,-1e-300)  | (NaN,NaN)
+ (NaN,NaN)         | (1e+300,Infinity) | (NaN,NaN)
+ (NaN,NaN)         | (NaN,NaN)         | (NaN,NaN)
+ (NaN,NaN)         | (10,10)           | (NaN,NaN)
+ (10,10)           | (0,0)             | (10,10)
+ (10,10)           | (-10,0)           | (0,10)
+ (10,10)           | (-3,4)            | (7,14)
+ (10,10)           | (5.1,34.5)        | (15.1,44.5)
+ (10,10)           | (-5,-12)          | (5,-2)
+ (10,10)           | (1e-300,-1e-300)  | (10,10)
+ (10,10)           | (1e+300,Infinity) | (1e+300,Infinity)
+ (10,10)           | (NaN,NaN)         | (NaN,NaN)
+ (10,10)           | (10,10)           | (20,20)
+(81 rows)
+
+-- Subtract point
+SELECT p1.f1, p2.f1, p1.f1 - p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |      ?column?       
+-------------------+-------------------+---------------------
+ (0,0)             | (0,0)             | (0,0)
+ (0,0)             | (-10,0)           | (10,0)
+ (0,0)             | (-3,4)            | (3,-4)
+ (0,0)             | (5.1,34.5)        | (-5.1,-34.5)
+ (0,0)             | (-5,-12)          | (5,12)
+ (0,0)             | (1e-300,-1e-300)  | (-1e-300,1e-300)
+ (0,0)             | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (0,0)             | (NaN,NaN)         | (NaN,NaN)
+ (0,0)             | (10,10)           | (-10,-10)
+ (-10,0)           | (0,0)             | (-10,0)
+ (-10,0)           | (-10,0)           | (0,0)
+ (-10,0)           | (-3,4)            | (-7,-4)
+ (-10,0)           | (5.1,34.5)        | (-15.1,-34.5)
+ (-10,0)           | (-5,-12)          | (-5,12)
+ (-10,0)           | (1e-300,-1e-300)  | (-10,1e-300)
+ (-10,0)           | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-10,0)           | (NaN,NaN)         | (NaN,NaN)
+ (-10,0)           | (10,10)           | (-20,-10)
+ (-3,4)            | (0,0)             | (-3,4)
+ (-3,4)            | (-10,0)           | (7,4)
+ (-3,4)            | (-3,4)            | (0,0)
+ (-3,4)            | (5.1,34.5)        | (-8.1,-30.5)
+ (-3,4)            | (-5,-12)          | (2,16)
+ (-3,4)            | (1e-300,-1e-300)  | (-3,4)
+ (-3,4)            | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-3,4)            | (NaN,NaN)         | (NaN,NaN)
+ (-3,4)            | (10,10)           | (-13,-6)
+ (5.1,34.5)        | (0,0)             | (5.1,34.5)
+ (5.1,34.5)        | (-10,0)           | (15.1,34.5)
+ (5.1,34.5)        | (-3,4)            | (8.1,30.5)
+ (5.1,34.5)        | (5.1,34.5)        | (0,0)
+ (5.1,34.5)        | (-5,-12)          | (10.1,46.5)
+ (5.1,34.5)        | (1e-300,-1e-300)  | (5.1,34.5)
+ (5.1,34.5)        | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (5.1,34.5)        | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5)        | (10,10)           | (-4.9,24.5)
+ (-5,-12)          | (0,0)             | (-5,-12)
+ (-5,-12)          | (-10,0)           | (5,-12)
+ (-5,-12)          | (-3,4)            | (-2,-16)
+ (-5,-12)          | (5.1,34.5)        | (-10.1,-46.5)
+ (-5,-12)          | (-5,-12)          | (0,0)
+ (-5,-12)          | (1e-300,-1e-300)  | (-5,-12)
+ (-5,-12)          | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-5,-12)          | (NaN,NaN)         | (NaN,NaN)
+ (-5,-12)          | (10,10)           | (-15,-22)
+ (1e-300,-1e-300)  | (0,0)             | (1e-300,-1e-300)
+ (1e-300,-1e-300)  | (-10,0)           | (10,-1e-300)
+ (1e-300,-1e-300)  | (-3,4)            | (3,-4)
+ (1e-300,-1e-300)  | (5.1,34.5)        | (-5.1,-34.5)
+ (1e-300,-1e-300)  | (-5,-12)          | (5,12)
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | (0,0)
+ (1e-300,-1e-300)  | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (1e-300,-1e-300)  | (NaN,NaN)         | (NaN,NaN)
+ (1e-300,-1e-300)  | (10,10)           | (-10,-10)
+ (1e+300,Infinity) | (0,0)             | (1e+300,Infinity)
+ (1e+300,Infinity) | (-10,0)           | (1e+300,Infinity)
+ (1e+300,Infinity) | (-3,4)            | (1e+300,Infinity)
+ (1e+300,Infinity) | (5.1,34.5)        | (1e+300,Infinity)
+ (1e+300,Infinity) | (-5,-12)          | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e-300,-1e-300)  | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e+300,Infinity) | (0,NaN)
+ (1e+300,Infinity) | (NaN,NaN)         | (NaN,NaN)
+ (1e+300,Infinity) | (10,10)           | (1e+300,Infinity)
+ (NaN,NaN)         | (0,0)             | (NaN,NaN)
+ (NaN,NaN)         | (-10,0)           | (NaN,NaN)
+ (NaN,NaN)         | (-3,4)            | (NaN,NaN)
+ (NaN,NaN)         | (5.1,34.5)        | (NaN,NaN)
+ (NaN,NaN)         | (-5,-12)          | (NaN,NaN)
+ (NaN,NaN)         | (1e-300,-1e-300)  | (NaN,NaN)
+ (NaN,NaN)         | (1e+300,Infinity) | (NaN,NaN)
+ (NaN,NaN)         | (NaN,NaN)         | (NaN,NaN)
+ (NaN,NaN)         | (10,10)           | (NaN,NaN)
+ (10,10)           | (0,0)             | (10,10)
+ (10,10)           | (-10,0)           | (20,10)
+ (10,10)           | (-3,4)            | (13,6)
+ (10,10)           | (5.1,34.5)        | (4.9,-24.5)
+ (10,10)           | (-5,-12)          | (15,22)
+ (10,10)           | (1e-300,-1e-300)  | (10,10)
+ (10,10)           | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (10,10)           | (NaN,NaN)         | (NaN,NaN)
+ (10,10)           | (10,10)           | (0,0)
+(81 rows)
+
+-- Multiply with point
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+     f1     |        f1         |       ?column?        
+------------+-------------------+-----------------------
+ (5.1,34.5) | (0,0)             | (0,0)
+ (10,10)    | (0,0)             | (0,0)
+ (5.1,34.5) | (-10,0)           | (-51,-345)
+ (10,10)    | (-10,0)           | (-100,-100)
+ (5.1,34.5) | (-3,4)            | (-153.3,-83.1)
+ (10,10)    | (-3,4)            | (-70,10)
+ (5.1,34.5) | (5.1,34.5)        | (-1164.24,351.9)
+ (10,10)    | (5.1,34.5)        | (-294,396)
+ (5.1,34.5) | (-5,-12)          | (388.5,-233.7)
+ (10,10)    | (-5,-12)          | (70,-170)
+ (5.1,34.5) | (1e-300,-1e-300)  | (3.96e-299,2.94e-299)
+ (10,10)    | (1e-300,-1e-300)  | (2e-299,0)
+ (5.1,34.5) | (1e+300,Infinity) | (-Infinity,Infinity)
+ (10,10)    | (1e+300,Infinity) | (-Infinity,Infinity)
+ (5.1,34.5) | (NaN,NaN)         | (NaN,NaN)
+ (10,10)    | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5) | (10,10)           | (-294,396)
+ (10,10)    | (10,10)           | (0,200)
+(18 rows)
+
+-- Underflow error
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] < 1;
+ERROR:  value out of range: underflow
+-- Divide by point
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] BETWEEN 1 AND 1000;
+        f1         |     f1     |                 ?column?                  
+-------------------+------------+-------------------------------------------
+ (0,0)             | (5.1,34.5) | (0,0)
+ (0,0)             | (10,10)    | (0,0)
+ (-10,0)           | (5.1,34.5) | (-0.0419318237877,0.283656455034)
+ (-10,0)           | (10,10)    | (-0.5,0.5)
+ (-3,4)            | (5.1,34.5) | (0.100883034877,0.101869666025)
+ (-3,4)            | (10,10)    | (0.05,0.35)
+ (5.1,34.5)        | (5.1,34.5) | (1,0)
+ (5.1,34.5)        | (10,10)    | (1.98,1.47)
+ (-5,-12)          | (5.1,34.5) | (-0.361353657935,0.0915100389719)
+ (-5,-12)          | (10,10)    | (-0.85,-0.35)
+ (1e-300,-1e-300)  | (5.1,34.5) | (-2.41724631247e-302,-3.25588278822e-302)
+ (1e-300,-1e-300)  | (10,10)    | (0,-1e-301)
+ (1e+300,Infinity) | (5.1,34.5) | (Infinity,Infinity)
+ (1e+300,Infinity) | (10,10)    | (Infinity,Infinity)
+ (NaN,NaN)         | (5.1,34.5) | (NaN,NaN)
+ (NaN,NaN)         | (10,10)    | (NaN,NaN)
+ (10,10)           | (5.1,34.5) | (0.325588278822,-0.241724631247)
+ (10,10)           | (10,10)    | (1,0)
+(18 rows)
+
+-- Overflow error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] > 1000;
+ERROR:  value out of range: overflow
+-- Division by 0 error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to line
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LINE_TBL l;
+        f1         |                   s                   |      ?column?      
+-------------------+---------------------------------------+--------------------
+ (0,0)             | {0,-1,5}                              |                  5
+ (0,0)             | {1,0,5}                               |                  5
+ (0,0)             | {0,3,0}                               |                  0
+ (0,0)             | {1,-1,0}                              |                  0
+ (0,0)             | {-0.4,-1,-6}                          |      5.57086014531
+ (0,0)             | {-0.000184615384615,-1,15.3846153846} |      15.3846151224
+ (0,0)             | {3,NaN,5}                             |                NaN
+ (0,0)             | {NaN,NaN,NaN}                         |                NaN
+ (0,0)             | {0,-1,3}                              |                  3
+ (0,0)             | {-1,0,3}                              |                  3
+ (-10,0)           | {0,-1,5}                              |                  5
+ (-10,0)           | {1,0,5}                               |                  5
+ (-10,0)           | {0,3,0}                               |                  0
+ (-10,0)           | {1,-1,0}                              |      7.07106781187
+ (-10,0)           | {-0.4,-1,-6}                          |      1.85695338177
+ (-10,0)           | {-0.000184615384615,-1,15.3846153846} |      15.3864612763
+ (-10,0)           | {3,NaN,5}                             |                NaN
+ (-10,0)           | {NaN,NaN,NaN}                         |                NaN
+ (-10,0)           | {0,-1,3}                              |                  3
+ (-10,0)           | {-1,0,3}                              |                 13
+ (-3,4)            | {0,-1,5}                              |                  1
+ (-3,4)            | {1,0,5}                               |                  2
+ (-3,4)            | {0,3,0}                               |                  4
+ (-3,4)            | {1,-1,0}                              |      4.94974746831
+ (-3,4)            | {-0.4,-1,-6}                          |      8.17059487979
+ (-3,4)            | {-0.000184615384615,-1,15.3846153846} |      11.3851690368
+ (-3,4)            | {3,NaN,5}                             |                NaN
+ (-3,4)            | {NaN,NaN,NaN}                         |                NaN
+ (-3,4)            | {0,-1,3}                              |                  1
+ (-3,4)            | {-1,0,3}                              |                  6
+ (5.1,34.5)        | {0,-1,5}                              |               29.5
+ (5.1,34.5)        | {1,0,5}                               |               10.1
+ (5.1,34.5)        | {0,3,0}                               |               34.5
+ (5.1,34.5)        | {1,-1,0}                              |      20.7889393669
+ (5.1,34.5)        | {-0.4,-1,-6}                          |      39.4973984303
+ (5.1,34.5)        | {-0.000184615384615,-1,15.3846153846} |      19.1163258281
+ (5.1,34.5)        | {3,NaN,5}                             |                NaN
+ (5.1,34.5)        | {NaN,NaN,NaN}                         |                NaN
+ (5.1,34.5)        | {0,-1,3}                              |               31.5
+ (5.1,34.5)        | {-1,0,3}                              |                2.1
+ (-5,-12)          | {0,-1,5}                              |                 17
+ (-5,-12)          | {1,0,5}                               |                  0
+ (-5,-12)          | {0,3,0}                               |                 12
+ (-5,-12)          | {1,-1,0}                              |      4.94974746831
+ (-5,-12)          | {-0.4,-1,-6}                          |      7.42781352708
+ (-5,-12)          | {-0.000184615384615,-1,15.3846153846} |      27.3855379948
+ (-5,-12)          | {3,NaN,5}                             |                NaN
+ (-5,-12)          | {NaN,NaN,NaN}                         |                NaN
+ (-5,-12)          | {0,-1,3}                              |                 15
+ (-5,-12)          | {-1,0,3}                              |                  8
+ (1e-300,-1e-300)  | {0,-1,5}                              |                  5
+ (1e-300,-1e-300)  | {1,0,5}                               |                  5
+ (1e-300,-1e-300)  | {0,3,0}                               |             1e-300
+ (1e-300,-1e-300)  | {1,-1,0}                              | 1.41421356237e-300
+ (1e-300,-1e-300)  | {-0.4,-1,-6}                          |      5.57086014531
+ (1e-300,-1e-300)  | {-0.000184615384615,-1,15.3846153846} |      15.3846151224
+ (1e-300,-1e-300)  | {3,NaN,5}                             |                NaN
+ (1e-300,-1e-300)  | {NaN,NaN,NaN}                         |                NaN
+ (1e-300,-1e-300)  | {0,-1,3}                              |                  3
+ (1e-300,-1e-300)  | {-1,0,3}                              |                  3
+ (1e+300,Infinity) | {0,-1,5}                              |           Infinity
+ (1e+300,Infinity) | {1,0,5}                               |                NaN
+ (1e+300,Infinity) | {0,3,0}                               |           Infinity
+ (1e+300,Infinity) | {1,-1,0}                              |           Infinity
+ (1e+300,Infinity) | {-0.4,-1,-6}                          |           Infinity
+ (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} |           Infinity
+ (1e+300,Infinity) | {3,NaN,5}                             |                NaN
+ (1e+300,Infinity) | {NaN,NaN,NaN}                         |                NaN
+ (1e+300,Infinity) | {0,-1,3}                              |           Infinity
+ (1e+300,Infinity) | {-1,0,3}                              |                NaN
+ (NaN,NaN)         | {0,-1,5}                              |                NaN
+ (NaN,NaN)         | {1,0,5}                               |                NaN
+ (NaN,NaN)         | {0,3,0}                               |                NaN
+ (NaN,NaN)         | {1,-1,0}                              |                NaN
+ (NaN,NaN)         | {-0.4,-1,-6}                          |                NaN
+ (NaN,NaN)         | {-0.000184615384615,-1,15.3846153846} |                NaN
+ (NaN,NaN)         | {3,NaN,5}                             |                NaN
+ (NaN,NaN)         | {NaN,NaN,NaN}                         |                NaN
+ (NaN,NaN)         | {0,-1,3}                              |                NaN
+ (NaN,NaN)         | {-1,0,3}                              |                NaN
+ (10,10)           | {0,-1,5}                              |                  5
+ (10,10)           | {1,0,5}                               |                 15
+ (10,10)           | {0,3,0}                               |                 10
+ (10,10)           | {1,-1,0}                              |                  0
+ (10,10)           | {-0.4,-1,-6}                          |      18.5695338177
+ (10,10)           | {-0.000184615384615,-1,15.3846153846} |      5.38276913903
+ (10,10)           | {3,NaN,5}                             |                NaN
+ (10,10)           | {NaN,NaN,NaN}                         |                NaN
+ (10,10)           | {0,-1,3}                              |                  7
+ (10,10)           | {-1,0,3}                              |                  7
+(90 rows)
+
+-- Distance to line segment
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LSEG_TBL l;
+        f1         |               s               |      ?column?      
+-------------------+-------------------------------+--------------------
+ (0,0)             | [(1,2),(3,4)]                 |       2.2360679775
+ (0,0)             | [(0,0),(6,6)]                 |                  0
+ (0,0)             | [(10,-10),(-3,-4)]            |      4.88901207039
+ (0,0)             | [(-1000000,200),(300000,-40)] |      15.3846151224
+ (0,0)             | [(11,22),(33,44)]             |      24.5967477525
+ (0,0)             | [(-10,2),(-10,3)]             |      10.1980390272
+ (0,0)             | [(0,-20),(30,-20)]            |                 20
+ (0,0)             | [(NaN,1),(NaN,90)]            |                NaN
+ (-10,0)           | [(1,2),(3,4)]                 |      11.1803398875
+ (-10,0)           | [(0,0),(6,6)]                 |                 10
+ (-10,0)           | [(10,-10),(-3,-4)]            |       8.0622577483
+ (-10,0)           | [(-1000000,200),(300000,-40)] |      15.3864612763
+ (-10,0)           | [(11,22),(33,44)]             |      30.4138126515
+ (-10,0)           | [(-10,2),(-10,3)]             |                  2
+ (-10,0)           | [(0,-20),(30,-20)]            |       22.360679775
+ (-10,0)           | [(NaN,1),(NaN,90)]            |                NaN
+ (-3,4)            | [(1,2),(3,4)]                 |        4.472135955
+ (-3,4)            | [(0,0),(6,6)]                 |      4.94974746831
+ (-3,4)            | [(10,-10),(-3,-4)]            |                  8
+ (-3,4)            | [(-1000000,200),(300000,-40)] |      11.3851690367
+ (-3,4)            | [(11,22),(33,44)]             |       22.803508502
+ (-3,4)            | [(-10,2),(-10,3)]             |      7.07106781187
+ (-3,4)            | [(0,-20),(30,-20)]            |      24.1867732449
+ (-3,4)            | [(NaN,1),(NaN,90)]            |                NaN
+ (5.1,34.5)        | [(1,2),(3,4)]                 |      30.5722096028
+ (5.1,34.5)        | [(0,0),(6,6)]                 |      28.5142069853
+ (5.1,34.5)        | [(10,-10),(-3,-4)]            |      39.3428519556
+ (5.1,34.5)        | [(-1000000,200),(300000,-40)] |      19.1163258281
+ (5.1,34.5)        | [(11,22),(33,44)]             |      13.0107647738
+ (5.1,34.5)        | [(-10,2),(-10,3)]             |       34.932220084
+ (5.1,34.5)        | [(0,-20),(30,-20)]            |               54.5
+ (5.1,34.5)        | [(NaN,1),(NaN,90)]            |                NaN
+ (-5,-12)          | [(1,2),(3,4)]                 |      15.2315462117
+ (-5,-12)          | [(0,0),(6,6)]                 |                 13
+ (-5,-12)          | [(10,-10),(-3,-4)]            |      8.10179143093
+ (-5,-12)          | [(-1000000,200),(300000,-40)] |      27.3855379949
+ (-5,-12)          | [(11,22),(33,44)]             |      37.5765884561
+ (-5,-12)          | [(-10,2),(-10,3)]             |      14.8660687473
+ (-5,-12)          | [(0,-20),(30,-20)]            |      9.43398113206
+ (-5,-12)          | [(NaN,1),(NaN,90)]            |                NaN
+ (1e-300,-1e-300)  | [(1,2),(3,4)]                 |       2.2360679775
+ (1e-300,-1e-300)  | [(0,0),(6,6)]                 | 1.41421356237e-300
+ (1e-300,-1e-300)  | [(10,-10),(-3,-4)]            |      4.88901207039
+ (1e-300,-1e-300)  | [(-1000000,200),(300000,-40)] |      15.3846151224
+ (1e-300,-1e-300)  | [(11,22),(33,44)]             |      24.5967477525
+ (1e-300,-1e-300)  | [(-10,2),(-10,3)]             |      10.1980390272
+ (1e-300,-1e-300)  | [(0,-20),(30,-20)]            |                 20
+ (1e-300,-1e-300)  | [(NaN,1),(NaN,90)]            |                NaN
+ (1e+300,Infinity) | [(1,2),(3,4)]                 |           Infinity
+ (1e+300,Infinity) | [(0,0),(6,6)]                 |           Infinity
+ (1e+300,Infinity) | [(10,-10),(-3,-4)]            |           Infinity
+ (1e+300,Infinity) | [(-1000000,200),(300000,-40)] |           Infinity
+ (1e+300,Infinity) | [(11,22),(33,44)]             |           Infinity
+ (1e+300,Infinity) | [(-10,2),(-10,3)]             |           Infinity
+ (1e+300,Infinity) | [(0,-20),(30,-20)]            |           Infinity
+ (1e+300,Infinity) | [(NaN,1),(NaN,90)]            |           Infinity
+ (NaN,NaN)         | [(1,2),(3,4)]                 |                NaN
+ (NaN,NaN)         | [(0,0),(6,6)]                 |                NaN
+ (NaN,NaN)         | [(10,-10),(-3,-4)]            |                NaN
+ (NaN,NaN)         | [(-1000000,200),(300000,-40)] |                NaN
+ (NaN,NaN)         | [(11,22),(33,44)]             |                NaN
+ (NaN,NaN)         | [(-10,2),(-10,3)]             |                NaN
+ (NaN,NaN)         | [(0,-20),(30,-20)]            |                NaN
+ (NaN,NaN)         | [(NaN,1),(NaN,90)]            |                NaN
+ (10,10)           | [(1,2),(3,4)]                 |      9.21954445729
+ (10,10)           | [(0,0),(6,6)]                 |      5.65685424949
+ (10,10)           | [(10,-10),(-3,-4)]            |        18.15918769
+ (10,10)           | [(-1000000,200),(300000,-40)] |      5.38276913904
+ (10,10)           | [(11,22),(33,44)]             |      12.0415945788
+ (10,10)           | [(-10,2),(-10,3)]             |      21.1896201004
+ (10,10)           | [(0,-20),(30,-20)]            |                 30
+ (10,10)           | [(NaN,1),(NaN,90)]            |                NaN
+(72 rows)
+
+-- Distance to box
+SELECT p.f1, b.f1, p.f1 <-> b.f1 FROM POINT_TBL p, BOX_TBL b;
+        f1         |         f1          |      ?column?      
+-------------------+---------------------+--------------------
+ (0,0)             | (2,2),(0,0)         |                  0
+ (0,0)             | (3,3),(1,1)         |      1.41421356237
+ (0,0)             | (-2,2),(-8,-10)     |                  2
+ (0,0)             | (2.5,3.5),(2.5,2.5) |      3.53553390593
+ (0,0)             | (3,3),(3,3)         |      4.24264068712
+ (-10,0)           | (2,2),(0,0)         |                 10
+ (-10,0)           | (3,3),(1,1)         |      11.0453610172
+ (-10,0)           | (-2,2),(-8,-10)     |                  2
+ (-10,0)           | (2.5,3.5),(2.5,2.5) |       12.747548784
+ (-10,0)           | (3,3),(3,3)         |      13.3416640641
+ (-3,4)            | (2,2),(0,0)         |      3.60555127546
+ (-3,4)            | (3,3),(1,1)         |      4.12310562562
+ (-3,4)            | (-2,2),(-8,-10)     |                  2
+ (-3,4)            | (2.5,3.5),(2.5,2.5) |      5.52268050859
+ (-3,4)            | (3,3),(3,3)         |       6.0827625303
+ (5.1,34.5)        | (2,2),(0,0)         |      32.6475113906
+ (5.1,34.5)        | (3,3),(1,1)         |      31.5699223946
+ (5.1,34.5)        | (-2,2),(-8,-10)     |      33.2664996656
+ (5.1,34.5)        | (2.5,3.5),(2.5,2.5) |       31.108841187
+ (5.1,34.5)        | (3,3),(3,3)         |      31.5699223946
+ (-5,-12)          | (2,2),(0,0)         |                 13
+ (-5,-12)          | (3,3),(1,1)         |      14.3178210633
+ (-5,-12)          | (-2,2),(-8,-10)     |                  2
+ (-5,-12)          | (2.5,3.5),(2.5,2.5) |      16.3248277173
+ (-5,-12)          | (3,3),(3,3)         |                 17
+ (1e-300,-1e-300)  | (2,2),(0,0)         | 1.41421356237e-300
+ (1e-300,-1e-300)  | (3,3),(1,1)         |      1.41421356237
+ (1e-300,-1e-300)  | (-2,2),(-8,-10)     |                  2
+ (1e-300,-1e-300)  | (2.5,3.5),(2.5,2.5) |      3.53553390593
+ (1e-300,-1e-300)  | (3,3),(3,3)         |      4.24264068712
+ (1e+300,Infinity) | (2,2),(0,0)         |           Infinity
+ (1e+300,Infinity) | (3,3),(1,1)         |           Infinity
+ (1e+300,Infinity) | (-2,2),(-8,-10)     |           Infinity
+ (1e+300,Infinity) | (2.5,3.5),(2.5,2.5) |           Infinity
+ (1e+300,Infinity) | (3,3),(3,3)         |           Infinity
+ (NaN,NaN)         | (2,2),(0,0)         |                NaN
+ (NaN,NaN)         | (3,3),(1,1)         |                NaN
+ (NaN,NaN)         | (-2,2),(-8,-10)     |                NaN
+ (NaN,NaN)         | (2.5,3.5),(2.5,2.5) |                NaN
+ (NaN,NaN)         | (3,3),(3,3)         |                NaN
+ (10,10)           | (2,2),(0,0)         |       11.313708499
+ (10,10)           | (3,3),(1,1)         |      9.89949493661
+ (10,10)           | (-2,2),(-8,-10)     |      14.4222051019
+ (10,10)           | (2.5,3.5),(2.5,2.5) |      9.92471662064
+ (10,10)           | (3,3),(3,3)         |      9.89949493661
+(45 rows)
+
+-- Distance to path
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, PATH_TBL p1;
+        f1         |            f1             |      ?column?      
+-------------------+---------------------------+--------------------
+ (0,0)             | [(1,2),(3,4)]             |       2.2360679775
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | [(0,0),(3,0),(4,5),(1,6)] |                  0
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | [(1,2),(3,4)]             |       2.2360679775
+ (0,0)             | ((10,20))                 |       22.360679775
+ (0,0)             | [(11,12),(13,14)]         |      16.2788205961
+ (0,0)             | ((11,12),(13,14))         |      16.2788205961
+ (-10,0)           | [(1,2),(3,4)]             |      11.1803398875
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | [(0,0),(3,0),(4,5),(1,6)] |                 10
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | [(1,2),(3,4)]             |      11.1803398875
+ (-10,0)           | ((10,20))                 |      28.2842712475
+ (-10,0)           | [(11,12),(13,14)]         |      24.1867732449
+ (-10,0)           | ((11,12),(13,14))         |      24.1867732449
+ (-3,4)            | [(1,2),(3,4)]             |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | [(0,0),(3,0),(4,5),(1,6)] |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | [(1,2),(3,4)]             |        4.472135955
+ (-3,4)            | ((10,20))                 |      20.6155281281
+ (-3,4)            | [(11,12),(13,14)]         |      16.1245154966
+ (-3,4)            | ((11,12),(13,14))         |      16.1245154966
+ (5.1,34.5)        | [(1,2),(3,4)]             |      30.5722096028
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | [(0,0),(3,0),(4,5),(1,6)] |       28.793402022
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | [(1,2),(3,4)]             |      30.5722096028
+ (5.1,34.5)        | ((10,20))                 |      15.3055545473
+ (5.1,34.5)        | [(11,12),(13,14)]         |      21.9695243462
+ (5.1,34.5)        | ((11,12),(13,14))         |      21.9695243462
+ (-5,-12)          | [(1,2),(3,4)]             |      15.2315462117
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | [(0,0),(3,0),(4,5),(1,6)] |                 13
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | [(1,2),(3,4)]             |      15.2315462117
+ (-5,-12)          | ((10,20))                 |      35.3411940941
+ (-5,-12)          | [(11,12),(13,14)]         |      28.8444102037
+ (-5,-12)          | ((11,12),(13,14))         |      28.8444102037
+ (1e-300,-1e-300)  | [(1,2),(3,4)]             |       2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | [(0,0),(3,0),(4,5),(1,6)] | 1.41421356237e-300
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | [(1,2),(3,4)]             |       2.2360679775
+ (1e-300,-1e-300)  | ((10,20))                 |       22.360679775
+ (1e-300,-1e-300)  | [(11,12),(13,14)]         |      16.2788205961
+ (1e-300,-1e-300)  | ((11,12),(13,14))         |      16.2788205961
+ (1e+300,Infinity) | [(1,2),(3,4)]             |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | [(0,0),(3,0),(4,5),(1,6)] |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | [(1,2),(3,4)]             |           Infinity
+ (1e+300,Infinity) | ((10,20))                 |           Infinity
+ (1e+300,Infinity) | [(11,12),(13,14)]         |           Infinity
+ (1e+300,Infinity) | ((11,12),(13,14))         |           Infinity
+ (NaN,NaN)         | [(1,2),(3,4)]             |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | [(0,0),(3,0),(4,5),(1,6)] |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | [(1,2),(3,4)]             |                NaN
+ (NaN,NaN)         | ((10,20))                 |                NaN
+ (NaN,NaN)         | [(11,12),(13,14)]         |                NaN
+ (NaN,NaN)         | ((11,12),(13,14))         |                NaN
+ (10,10)           | [(1,2),(3,4)]             |      9.21954445729
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | [(0,0),(3,0),(4,5),(1,6)] |      7.81024967591
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | [(1,2),(3,4)]             |      9.21954445729
+ (10,10)           | ((10,20))                 |                 10
+ (10,10)           | [(11,12),(13,14)]         |       2.2360679775
+ (10,10)           | ((11,12),(13,14))         |       2.2360679775
+(81 rows)
+
+-- Distance to polygon
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, POLYGON_TBL p1;
+        f1         |             f1             |   ?column?    
+-------------------+----------------------------+---------------
+ (0,0)             | ((2,0),(2,4),(0,0))        |             0
+ (0,0)             | ((3,1),(3,3),(1,0))        |             1
+ (0,0)             | ((1,2),(3,4),(5,6),(7,8))  |  2.2360679775
+ (0,0)             | ((7,8),(5,6),(3,4),(1,2))  |  2.2360679775
+ (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | 1.58113883008
+ (0,0)             | ((0,0))                    |             0
+ (0,0)             | ((0,1),(0,1))              |             1
+ (-10,0)           | ((2,0),(2,4),(0,0))        |            10
+ (-10,0)           | ((3,1),(3,3),(1,0))        |            11
+ (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | 11.1803398875
+ (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | 11.1803398875
+ (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | 11.1803398875
+ (-10,0)           | ((0,0))                    |            10
+ (-10,0)           | ((0,1),(0,1))              | 10.0498756211
+ (-3,4)            | ((2,0),(2,4),(0,0))        |   4.472135955
+ (-3,4)            | ((3,1),(3,3),(1,0))        | 5.54700196225
+ (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  |   4.472135955
+ (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  |   4.472135955
+ (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) |   4.472135955
+ (-3,4)            | ((0,0))                    |             5
+ (-3,4)            | ((0,1),(0,1))              | 4.24264068712
+ (5.1,34.5)        | ((2,0),(2,4),(0,0))        | 30.6571362002
+ (5.1,34.5)        | ((3,1),(3,3),(1,0))        | 31.5699223946
+ (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | 26.5680258958
+ (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | 26.5680258958
+ (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | 26.5680258958
+ (5.1,34.5)        | ((0,0))                    | 34.8749193547
+ (5.1,34.5)        | ((0,1),(0,1))              | 33.8859853037
+ (-5,-12)          | ((2,0),(2,4),(0,0))        |            13
+ (-5,-12)          | ((3,1),(3,3),(1,0))        |  13.416407865
+ (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | 15.2315462117
+ (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | 15.2315462117
+ (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) |  11.313708499
+ (-5,-12)          | ((0,0))                    |            13
+ (-5,-12)          | ((0,1),(0,1))              | 13.9283882772
+ (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        |             0
+ (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        |             1
+ (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  |  2.2360679775
+ (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  |  2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | 1.58113883008
+ (1e-300,-1e-300)  | ((0,0))                    |             0
+ (1e-300,-1e-300)  | ((0,1),(0,1))              |             1
+ (1e+300,Infinity) | ((2,0),(2,4),(0,0))        |      Infinity
+ (1e+300,Infinity) | ((3,1),(3,3),(1,0))        |      Infinity
+ (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  |      Infinity
+ (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  |      Infinity
+ (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) |      Infinity
+ (1e+300,Infinity) | ((0,0))                    |      Infinity
+ (1e+300,Infinity) | ((0,1),(0,1))              |      Infinity
+ (NaN,NaN)         | ((2,0),(2,4),(0,0))        |             0
+ (NaN,NaN)         | ((3,1),(3,3),(1,0))        |             0
+ (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  |             0
+ (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  |             0
+ (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) |             0
+ (NaN,NaN)         | ((0,0))                    |             0
+ (NaN,NaN)         | ((0,1),(0,1))              |             0
+ (10,10)           | ((2,0),(2,4),(0,0))        |            10
+ (10,10)           | ((3,1),(3,3),(1,0))        | 9.89949493661
+ (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | 3.60555127546
+ (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | 3.60555127546
+ (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | 3.60555127546
+ (10,10)           | ((0,0))                    | 14.1421356237
+ (10,10)           | ((0,1),(0,1))              | 13.4536240471
+(63 rows)
+
+-- Closest point to line
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LINE_TBL l;
+        f1         |                   s                   |             ?column?             
+-------------------+---------------------------------------+----------------------------------
+ (0,0)             | {0,-1,5}                              | (0,5)
+ (0,0)             | {1,0,5}                               | (-5,0)
+ (0,0)             | {0,3,0}                               | (0,0)
+ (0,0)             | {1,-1,0}                              | (0,0)
+ (0,0)             | {-0.4,-1,-6}                          | (-2.06896551724,-5.1724137931)
+ (0,0)             | {-0.000184615384615,-1,15.3846153846} | (0.00284023658959,15.3846148603)
+ (0,0)             | {3,NaN,5}                             | 
+ (0,0)             | {NaN,NaN,NaN}                         | 
+ (0,0)             | {0,-1,3}                              | (0,3)
+ (0,0)             | {-1,0,3}                              | (3,0)
+ (-10,0)           | {0,-1,5}                              | (-10,5)
+ (-10,0)           | {1,0,5}                               | (-5,0)
+ (-10,0)           | {0,3,0}                               | (-10,0)
+ (-10,0)           | {1,-1,0}                              | (-5,-5)
+ (-10,0)           | {-0.4,-1,-6}                          | (-10.6896551724,-1.72413793103)
+ (-10,0)           | {-0.000184615384615,-1,15.3846153846} | (-9.99715942258,15.386461014)
+ (-10,0)           | {3,NaN,5}                             | 
+ (-10,0)           | {NaN,NaN,NaN}                         | 
+ (-10,0)           | {0,-1,3}                              | (-10,3)
+ (-10,0)           | {-1,0,3}                              | (3,0)
+ (-3,4)            | {0,-1,5}                              | (-3,5)
+ (-3,4)            | {1,0,5}                               | (-5,4)
+ (-3,4)            | {0,3,0}                               | (-3,0)
+ (-3,4)            | {1,-1,0}                              | (0.5,0.5)
+ (-3,4)            | {-0.4,-1,-6}                          | (-6.03448275862,-3.58620689655)
+ (-3,4)            | {-0.000184615384615,-1,15.3846153846} | (-2.99789812268,15.3851688427)
+ (-3,4)            | {3,NaN,5}                             | 
+ (-3,4)            | {NaN,NaN,NaN}                         | 
+ (-3,4)            | {0,-1,3}                              | (-3,3)
+ (-3,4)            | {-1,0,3}                              | (3,4)
+ (5.1,34.5)        | {0,-1,5}                              | (5.1,5)
+ (5.1,34.5)        | {1,0,5}                               | (-5,34.5)
+ (5.1,34.5)        | {0,3,0}                               | (5.1,0)
+ (5.1,34.5)        | {1,-1,0}                              | (19.8,19.8)
+ (5.1,34.5)        | {-0.4,-1,-6}                          | (-9.56896551724,-2.1724137931)
+ (5.1,34.5)        | {-0.000184615384615,-1,15.3846153846} | (5.09647083221,15.3836744977)
+ (5.1,34.5)        | {3,NaN,5}                             | 
+ (5.1,34.5)        | {NaN,NaN,NaN}                         | 
+ (5.1,34.5)        | {0,-1,3}                              | (5.1,3)
+ (5.1,34.5)        | {-1,0,3}                              | (3,34.5)
+ (-5,-12)          | {0,-1,5}                              | (-5,5)
+ (-5,-12)          | {1,0,5}                               | (-5,-12)
+ (-5,-12)          | {0,3,0}                               | (-5,0)
+ (-5,-12)          | {1,-1,0}                              | (-8.5,-8.5)
+ (-5,-12)          | {-0.4,-1,-6}                          | (-2.24137931034,-5.10344827586)
+ (-5,-12)          | {-0.000184615384615,-1,15.3846153846} | (-4.99494420846,15.3855375282)
+ (-5,-12)          | {3,NaN,5}                             | 
+ (-5,-12)          | {NaN,NaN,NaN}                         | 
+ (-5,-12)          | {0,-1,3}                              | (-5,3)
+ (-5,-12)          | {-1,0,3}                              | (3,-12)
+ (1e-300,-1e-300)  | {0,-1,5}                              | (1e-300,5)
+ (1e-300,-1e-300)  | {1,0,5}                               | (-5,-1e-300)
+ (1e-300,-1e-300)  | {0,3,0}                               | (1e-300,0)
+ (1e-300,-1e-300)  | {1,-1,0}                              | (0,0)
+ (1e-300,-1e-300)  | {-0.4,-1,-6}                          | (-2.06896551724,-5.1724137931)
+ (1e-300,-1e-300)  | {-0.000184615384615,-1,15.3846153846} | (0.00284023658959,15.3846148603)
+ (1e-300,-1e-300)  | {3,NaN,5}                             | 
+ (1e-300,-1e-300)  | {NaN,NaN,NaN}                         | 
+ (1e-300,-1e-300)  | {0,-1,3}                              | (1e-300,3)
+ (1e-300,-1e-300)  | {-1,0,3}                              | (3,-1e-300)
+ (1e+300,Infinity) | {0,-1,5}                              | (1e+300,5)
+ (1e+300,Infinity) | {1,0,5}                               | 
+ (1e+300,Infinity) | {0,3,0}                               | (1e+300,0)
+ (1e+300,Infinity) | {1,-1,0}                              | (Infinity,NaN)
+ (1e+300,Infinity) | {-0.4,-1,-6}                          | (-Infinity,NaN)
+ (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} | (-Infinity,NaN)
+ (1e+300,Infinity) | {3,NaN,5}                             | 
+ (1e+300,Infinity) | {NaN,NaN,NaN}                         | 
+ (1e+300,Infinity) | {0,-1,3}                              | (1e+300,3)
+ (1e+300,Infinity) | {-1,0,3}                              | 
+ (NaN,NaN)         | {0,-1,5}                              | 
+ (NaN,NaN)         | {1,0,5}                               | 
+ (NaN,NaN)         | {0,3,0}                               | 
+ (NaN,NaN)         | {1,-1,0}                              | 
+ (NaN,NaN)         | {-0.4,-1,-6}                          | 
+ (NaN,NaN)         | {-0.000184615384615,-1,15.3846153846} | 
+ (NaN,NaN)         | {3,NaN,5}                             | 
+ (NaN,NaN)         | {NaN,NaN,NaN}                         | 
+ (NaN,NaN)         | {0,-1,3}                              | 
+ (NaN,NaN)         | {-1,0,3}                              | 
+ (10,10)           | {0,-1,5}                              | (10,5)
+ (10,10)           | {1,0,5}                               | (-5,10)
+ (10,10)           | {0,3,0}                               | (10,0)
+ (10,10)           | {1,-1,0}                              | (10,10)
+ (10,10)           | {-0.4,-1,-6}                          | (3.10344827586,-7.24137931034)
+ (10,10)           | {-0.000184615384615,-1,15.3846153846} | (10.000993742,15.3827690473)
+ (10,10)           | {3,NaN,5}                             | 
+ (10,10)           | {NaN,NaN,NaN}                         | 
+ (10,10)           | {0,-1,3}                              | (10,3)
+ (10,10)           | {-1,0,3}                              | (3,10)
+(90 rows)
+
+-- Closest point to line segment
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LSEG_TBL l;
+        f1         |               s               |             ?column?             
+-------------------+-------------------------------+----------------------------------
+ (0,0)             | [(1,2),(3,4)]                 | (1,2)
+ (0,0)             | [(0,0),(6,6)]                 | (0,0)
+ (0,0)             | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ (0,0)             | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
+ (0,0)             | [(11,22),(33,44)]             | (11,22)
+ (0,0)             | [(-10,2),(-10,3)]             | (-10,2)
+ (0,0)             | [(0,-20),(30,-20)]            | (0,-20)
+ (0,0)             | [(NaN,1),(NaN,90)]            | 
+ (-10,0)           | [(1,2),(3,4)]                 | (1,2)
+ (-10,0)           | [(0,0),(6,6)]                 | (0,0)
+ (-10,0)           | [(10,-10),(-3,-4)]            | (-3,-4)
+ (-10,0)           | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
+ (-10,0)           | [(11,22),(33,44)]             | (11,22)
+ (-10,0)           | [(-10,2),(-10,3)]             | (-10,2)
+ (-10,0)           | [(0,-20),(30,-20)]            | (0,-20)
+ (-10,0)           | [(NaN,1),(NaN,90)]            | 
+ (-3,4)            | [(1,2),(3,4)]                 | (1,2)
+ (-3,4)            | [(0,0),(6,6)]                 | (0.5,0.5)
+ (-3,4)            | [(10,-10),(-3,-4)]            | (-3,-4)
+ (-3,4)            | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
+ (-3,4)            | [(11,22),(33,44)]             | (11,22)
+ (-3,4)            | [(-10,2),(-10,3)]             | (-10,3)
+ (-3,4)            | [(0,-20),(30,-20)]            | (0,-20)
+ (-3,4)            | [(NaN,1),(NaN,90)]            | 
+ (5.1,34.5)        | [(1,2),(3,4)]                 | (3,4)
+ (5.1,34.5)        | [(0,0),(6,6)]                 | (6,6)
+ (5.1,34.5)        | [(10,-10),(-3,-4)]            | (-3,-4)
+ (5.1,34.5)        | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
+ (5.1,34.5)        | [(11,22),(33,44)]             | (14.3,25.3)
+ (5.1,34.5)        | [(-10,2),(-10,3)]             | (-10,3)
+ (5.1,34.5)        | [(0,-20),(30,-20)]            | (5.1,-20)
+ (5.1,34.5)        | [(NaN,1),(NaN,90)]            | 
+ (-5,-12)          | [(1,2),(3,4)]                 | (1,2)
+ (-5,-12)          | [(0,0),(6,6)]                 | (0,0)
+ (-5,-12)          | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
+ (-5,-12)          | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
+ (-5,-12)          | [(11,22),(33,44)]             | (11,22)
+ (-5,-12)          | [(-10,2),(-10,3)]             | (-10,2)
+ (-5,-12)          | [(0,-20),(30,-20)]            | (0,-20)
+ (-5,-12)          | [(NaN,1),(NaN,90)]            | 
+ (1e-300,-1e-300)  | [(1,2),(3,4)]                 | (1,2)
+ (1e-300,-1e-300)  | [(0,0),(6,6)]                 | (0,0)
+ (1e-300,-1e-300)  | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ (1e-300,-1e-300)  | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
+ (1e-300,-1e-300)  | [(11,22),(33,44)]             | (11,22)
+ (1e-300,-1e-300)  | [(-10,2),(-10,3)]             | (-10,2)
+ (1e-300,-1e-300)  | [(0,-20),(30,-20)]            | (0,-20)
+ (1e-300,-1e-300)  | [(NaN,1),(NaN,90)]            | 
+ (1e+300,Infinity) | [(1,2),(3,4)]                 | (3,4)
+ (1e+300,Infinity) | [(0,0),(6,6)]                 | (6,6)
+ (1e+300,Infinity) | [(10,-10),(-3,-4)]            | (-3,-4)
+ (1e+300,Infinity) | [(-1000000,200),(300000,-40)] | (300000,-40)
+ (1e+300,Infinity) | [(11,22),(33,44)]             | (33,44)
+ (1e+300,Infinity) | [(-10,2),(-10,3)]             | (-10,3)
+ (1e+300,Infinity) | [(0,-20),(30,-20)]            | (30,-20)
+ (1e+300,Infinity) | [(NaN,1),(NaN,90)]            | (NaN,90)
+ (NaN,NaN)         | [(1,2),(3,4)]                 | 
+ (NaN,NaN)         | [(0,0),(6,6)]                 | 
+ (NaN,NaN)         | [(10,-10),(-3,-4)]            | 
+ (NaN,NaN)         | [(-1000000,200),(300000,-40)] | 
+ (NaN,NaN)         | [(11,22),(33,44)]             | 
+ (NaN,NaN)         | [(-10,2),(-10,3)]             | 
+ (NaN,NaN)         | [(0,-20),(30,-20)]            | 
+ (NaN,NaN)         | [(NaN,1),(NaN,90)]            | 
+ (10,10)           | [(1,2),(3,4)]                 | (3,4)
+ (10,10)           | [(0,0),(6,6)]                 | (6,6)
+ (10,10)           | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
+ (10,10)           | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
+ (10,10)           | [(11,22),(33,44)]             | (11,22)
+ (10,10)           | [(-10,2),(-10,3)]             | (-10,3)
+ (10,10)           | [(0,-20),(30,-20)]            | (10,-20)
+ (10,10)           | [(NaN,1),(NaN,90)]            | 
+(72 rows)
+
+-- Closest point to box
+SELECT p.f1, b.f1, p.f1 ## b.f1 FROM POINT_TBL p, BOX_TBL b;
+        f1         |         f1          |   ?column?   
+-------------------+---------------------+--------------
+ (0,0)             | (2,2),(0,0)         | (0,0)
+ (0,0)             | (3,3),(1,1)         | (1,1)
+ (0,0)             | (-2,2),(-8,-10)     | (-2,0)
+ (0,0)             | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (0,0)             | (3,3),(3,3)         | (3,3)
+ (-10,0)           | (2,2),(0,0)         | (0,0)
+ (-10,0)           | (3,3),(1,1)         | (1,1)
+ (-10,0)           | (-2,2),(-8,-10)     | (-8,0)
+ (-10,0)           | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (-10,0)           | (3,3),(3,3)         | (3,3)
+ (-3,4)            | (2,2),(0,0)         | (0,2)
+ (-3,4)            | (3,3),(1,1)         | (1,3)
+ (-3,4)            | (-2,2),(-8,-10)     | (-3,2)
+ (-3,4)            | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (-3,4)            | (3,3),(3,3)         | (3,3)
+ (5.1,34.5)        | (2,2),(0,0)         | (2,2)
+ (5.1,34.5)        | (3,3),(1,1)         | (3,3)
+ (5.1,34.5)        | (-2,2),(-8,-10)     | (-2,2)
+ (5.1,34.5)        | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (5.1,34.5)        | (3,3),(3,3)         | (3,3)
+ (-5,-12)          | (2,2),(0,0)         | (0,0)
+ (-5,-12)          | (3,3),(1,1)         | (1,1)
+ (-5,-12)          | (-2,2),(-8,-10)     | (-5,-10)
+ (-5,-12)          | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (-5,-12)          | (3,3),(3,3)         | (3,3)
+ (1e-300,-1e-300)  | (2,2),(0,0)         | (0,0)
+ (1e-300,-1e-300)  | (3,3),(1,1)         | (1,1)
+ (1e-300,-1e-300)  | (-2,2),(-8,-10)     | (-2,-1e-300)
+ (1e-300,-1e-300)  | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (1e-300,-1e-300)  | (3,3),(3,3)         | (3,3)
+ (1e+300,Infinity) | (2,2),(0,0)         | (0,2)
+ (1e+300,Infinity) | (3,3),(1,1)         | (1,3)
+ (1e+300,Infinity) | (-2,2),(-8,-10)     | (-8,2)
+ (1e+300,Infinity) | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (1e+300,Infinity) | (3,3),(3,3)         | (3,3)
+ (NaN,NaN)         | (2,2),(0,0)         | 
+ (NaN,NaN)         | (3,3),(1,1)         | 
+ (NaN,NaN)         | (-2,2),(-8,-10)     | 
+ (NaN,NaN)         | (2.5,3.5),(2.5,2.5) | 
+ (NaN,NaN)         | (3,3),(3,3)         | 
+ (10,10)           | (2,2),(0,0)         | (2,2)
+ (10,10)           | (3,3),(1,1)         | (3,3)
+ (10,10)           | (-2,2),(-8,-10)     | (-2,2)
+ (10,10)           | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (10,10)           | (3,3),(3,3)         | (3,3)
+(45 rows)
+
+-- On line
+SELECT p.f1, l.s FROM POINT_TBL p, LINE_TBL l WHERE p.f1 <@ l.s;
+        f1        |    s     
+------------------+----------
+ (0,0)            | {0,3,0}
+ (0,0)            | {1,-1,0}
+ (-10,0)          | {0,3,0}
+ (-5,-12)         | {1,0,5}
+ (1e-300,-1e-300) | {0,3,0}
+ (1e-300,-1e-300) | {1,-1,0}
+ (10,10)          | {1,-1,0}
+(7 rows)
+
+-- On line segment
+SELECT p.f1, l.s FROM POINT_TBL p, LSEG_TBL l WHERE p.f1 <@ l.s;
+        f1        |       s       
+------------------+---------------
+ (0,0)            | [(0,0),(6,6)]
+ (1e-300,-1e-300) | [(0,0),(6,6)]
+(2 rows)
+
+-- On path
+SELECT p.f1, p1.f1 FROM POINT_TBL p, PATH_TBL p1 WHERE p.f1 <@ p1.f1;
+        f1        |            f1             
+------------------+---------------------------
+ (0,0)            | [(0,0),(3,0),(4,5),(1,6)]
+ (1e-300,-1e-300) | [(0,0),(3,0),(4,5),(1,6)]
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((10,20))
+ (NaN,NaN)        | ((11,12),(13,14))
+(7 rows)
+
+--
+-- Lines
+--
+-- Vertical
+SELECT s FROM LINE_TBL WHERE ?| s;
+    s     
+----------
+ {1,0,5}
+ {-1,0,3}
+(2 rows)
+
+-- Horizontal
+SELECT s FROM LINE_TBL WHERE ?- s;
+    s     
+----------
+ {0,-1,5}
+ {0,3,0}
+ {0,-1,3}
+(3 rows)
+
+-- Same as line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s = l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {0,-1,5}
+ {1,0,5}                               | {1,0,5}
+ {0,3,0}                               | {0,3,0}
+ {1,-1,0}                              | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846}
+ {3,NaN,5}                             | {3,NaN,5}
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}
+ {0,-1,3}                              | {0,-1,3}
+ {-1,0,3}                              | {-1,0,3}
+(10 rows)
+
+-- Parallel to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?|| l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {0,-1,5}
+ {0,-1,5}                              | {0,3,0}
+ {0,-1,5}                              | {0,-1,3}
+ {1,0,5}                               | {1,0,5}
+ {1,0,5}                               | {-1,0,3}
+ {0,3,0}                               | {0,-1,5}
+ {0,3,0}                               | {0,3,0}
+ {0,3,0}                               | {0,-1,3}
+ {1,-1,0}                              | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,3}                              | {0,-1,5}
+ {0,-1,3}                              | {0,3,0}
+ {0,-1,3}                              | {0,-1,3}
+ {-1,0,3}                              | {1,0,5}
+ {-1,0,3}                              | {-1,0,3}
+(16 rows)
+
+-- Perpendicular to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?-| l2.s;
+    s     |    s     
+----------+----------
+ {0,-1,5} | {1,0,5}
+ {0,-1,5} | {-1,0,3}
+ {1,0,5}  | {0,-1,5}
+ {1,0,5}  | {0,3,0}
+ {1,0,5}  | {0,-1,3}
+ {0,3,0}  | {1,0,5}
+ {0,3,0}  | {-1,0,3}
+ {0,-1,3} | {1,0,5}
+ {0,-1,3} | {-1,0,3}
+ {-1,0,3} | {0,-1,5}
+ {-1,0,3} | {0,3,0}
+ {-1,0,3} | {0,-1,3}
+(12 rows)
+
+-- Distance to line
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2;
+                   s                   |                   s                   | ?column? 
+---------------------------------------+---------------------------------------+----------
+ {0,-1,5}                              | {0,-1,5}                              |        0
+ {0,-1,5}                              | {1,0,5}                               |        0
+ {0,-1,5}                              | {0,3,0}                               |        5
+ {0,-1,5}                              | {1,-1,0}                              |        0
+ {0,-1,5}                              | {-0.4,-1,-6}                          |        0
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,-1,5}                              | {3,NaN,5}                             |        0
+ {0,-1,5}                              | {NaN,NaN,NaN}                         |        0
+ {0,-1,5}                              | {0,-1,3}                              |        2
+ {0,-1,5}                              | {-1,0,3}                              |        0
+ {1,0,5}                               | {0,-1,5}                              |        0
+ {1,0,5}                               | {1,0,5}                               |        0
+ {1,0,5}                               | {0,3,0}                               |        0
+ {1,0,5}                               | {1,-1,0}                              |        0
+ {1,0,5}                               | {-0.4,-1,-6}                          |        0
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846} |        0
+ {1,0,5}                               | {3,NaN,5}                             |        0
+ {1,0,5}                               | {NaN,NaN,NaN}                         |        0
+ {1,0,5}                               | {0,-1,3}                              |        0
+ {1,0,5}                               | {-1,0,3}                              |        8
+ {0,3,0}                               | {0,-1,5}                              |        5
+ {0,3,0}                               | {1,0,5}                               |        0
+ {0,3,0}                               | {0,3,0}                               |        0
+ {0,3,0}                               | {1,-1,0}                              |        0
+ {0,3,0}                               | {-0.4,-1,-6}                          |        0
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,3,0}                               | {3,NaN,5}                             |        0
+ {0,3,0}                               | {NaN,NaN,NaN}                         |        0
+ {0,3,0}                               | {0,-1,3}                              |        3
+ {0,3,0}                               | {-1,0,3}                              |        0
+ {1,-1,0}                              | {0,-1,5}                              |        0
+ {1,-1,0}                              | {1,0,5}                               |        0
+ {1,-1,0}                              | {0,3,0}                               |        0
+ {1,-1,0}                              | {1,-1,0}                              |        0
+ {1,-1,0}                              | {-0.4,-1,-6}                          |        0
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {1,-1,0}                              | {3,NaN,5}                             |        0
+ {1,-1,0}                              | {NaN,NaN,NaN}                         |        0
+ {1,-1,0}                              | {0,-1,3}                              |        0
+ {1,-1,0}                              | {-1,0,3}                              |        0
+ {-0.4,-1,-6}                          | {0,-1,5}                              |        0
+ {-0.4,-1,-6}                          | {1,0,5}                               |        0
+ {-0.4,-1,-6}                          | {0,3,0}                               |        0
+ {-0.4,-1,-6}                          | {1,-1,0}                              |        0
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}                          |        0
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846} |        0
+ {-0.4,-1,-6}                          | {3,NaN,5}                             |        0
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}                         |        0
+ {-0.4,-1,-6}                          | {0,-1,3}                              |        0
+ {-0.4,-1,-6}                          | {-1,0,3}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}                               |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}                               |        0
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}                          |        0
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} |        0
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}                             |        0
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}                         |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}                              |        0
+ {3,NaN,5}                             | {0,-1,5}                              |        0
+ {3,NaN,5}                             | {1,0,5}                               |        0
+ {3,NaN,5}                             | {0,3,0}                               |        0
+ {3,NaN,5}                             | {1,-1,0}                              |        0
+ {3,NaN,5}                             | {-0.4,-1,-6}                          |        0
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846} |        0
+ {3,NaN,5}                             | {3,NaN,5}                             |        0
+ {3,NaN,5}                             | {NaN,NaN,NaN}                         |        0
+ {3,NaN,5}                             | {0,-1,3}                              |        0
+ {3,NaN,5}                             | {-1,0,3}                              |        0
+ {NaN,NaN,NaN}                         | {0,-1,5}                              |        0
+ {NaN,NaN,NaN}                         | {1,0,5}                               |        0
+ {NaN,NaN,NaN}                         | {0,3,0}                               |        0
+ {NaN,NaN,NaN}                         | {1,-1,0}                              |        0
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}                          |        0
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846} |        0
+ {NaN,NaN,NaN}                         | {3,NaN,5}                             |        0
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}                         |        0
+ {NaN,NaN,NaN}                         | {0,-1,3}                              |        0
+ {NaN,NaN,NaN}                         | {-1,0,3}                              |        0
+ {0,-1,3}                              | {0,-1,5}                              |        2
+ {0,-1,3}                              | {1,0,5}                               |        0
+ {0,-1,3}                              | {0,3,0}                               |        3
+ {0,-1,3}                              | {1,-1,0}                              |        0
+ {0,-1,3}                              | {-0.4,-1,-6}                          |        0
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,-1,3}                              | {3,NaN,5}                             |        0
+ {0,-1,3}                              | {NaN,NaN,NaN}                         |        0
+ {0,-1,3}                              | {0,-1,3}                              |        0
+ {0,-1,3}                              | {-1,0,3}                              |        0
+ {-1,0,3}                              | {0,-1,5}                              |        0
+ {-1,0,3}                              | {1,0,5}                               |        8
+ {-1,0,3}                              | {0,3,0}                               |        0
+ {-1,0,3}                              | {1,-1,0}                              |        0
+ {-1,0,3}                              | {-0.4,-1,-6}                          |        0
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {-1,0,3}                              | {3,NaN,5}                             |        0
+ {-1,0,3}                              | {NaN,NaN,NaN}                         |        0
+ {-1,0,3}                              | {0,-1,3}                              |        0
+ {-1,0,3}                              | {-1,0,3}                              |        0
+(100 rows)
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LINE_TBL l, BOX_TBL b;
+ERROR:  function "dist_lb" not implemented
+-- Intersect with line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?# l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {1,0,5}
+ {0,-1,5}                              | {1,-1,0}
+ {0,-1,5}                              | {-0.4,-1,-6}
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,5}                              | {3,NaN,5}
+ {0,-1,5}                              | {NaN,NaN,NaN}
+ {0,-1,5}                              | {-1,0,3}
+ {1,0,5}                               | {0,-1,5}
+ {1,0,5}                               | {0,3,0}
+ {1,0,5}                               | {1,-1,0}
+ {1,0,5}                               | {-0.4,-1,-6}
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846}
+ {1,0,5}                               | {3,NaN,5}
+ {1,0,5}                               | {NaN,NaN,NaN}
+ {1,0,5}                               | {0,-1,3}
+ {0,3,0}                               | {1,0,5}
+ {0,3,0}                               | {1,-1,0}
+ {0,3,0}                               | {-0.4,-1,-6}
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846}
+ {0,3,0}                               | {3,NaN,5}
+ {0,3,0}                               | {NaN,NaN,NaN}
+ {0,3,0}                               | {-1,0,3}
+ {1,-1,0}                              | {0,-1,5}
+ {1,-1,0}                              | {1,0,5}
+ {1,-1,0}                              | {0,3,0}
+ {1,-1,0}                              | {-0.4,-1,-6}
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846}
+ {1,-1,0}                              | {3,NaN,5}
+ {1,-1,0}                              | {NaN,NaN,NaN}
+ {1,-1,0}                              | {0,-1,3}
+ {1,-1,0}                              | {-1,0,3}
+ {-0.4,-1,-6}                          | {0,-1,5}
+ {-0.4,-1,-6}                          | {1,0,5}
+ {-0.4,-1,-6}                          | {0,3,0}
+ {-0.4,-1,-6}                          | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846}
+ {-0.4,-1,-6}                          | {3,NaN,5}
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}
+ {-0.4,-1,-6}                          | {0,-1,3}
+ {-0.4,-1,-6}                          | {-1,0,3}
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}
+ {3,NaN,5}                             | {0,-1,5}
+ {3,NaN,5}                             | {1,0,5}
+ {3,NaN,5}                             | {0,3,0}
+ {3,NaN,5}                             | {1,-1,0}
+ {3,NaN,5}                             | {-0.4,-1,-6}
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846}
+ {3,NaN,5}                             | {3,NaN,5}
+ {3,NaN,5}                             | {NaN,NaN,NaN}
+ {3,NaN,5}                             | {0,-1,3}
+ {3,NaN,5}                             | {-1,0,3}
+ {NaN,NaN,NaN}                         | {0,-1,5}
+ {NaN,NaN,NaN}                         | {1,0,5}
+ {NaN,NaN,NaN}                         | {0,3,0}
+ {NaN,NaN,NaN}                         | {1,-1,0}
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846}
+ {NaN,NaN,NaN}                         | {3,NaN,5}
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}
+ {NaN,NaN,NaN}                         | {0,-1,3}
+ {NaN,NaN,NaN}                         | {-1,0,3}
+ {0,-1,3}                              | {1,0,5}
+ {0,-1,3}                              | {1,-1,0}
+ {0,-1,3}                              | {-0.4,-1,-6}
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,3}                              | {3,NaN,5}
+ {0,-1,3}                              | {NaN,NaN,NaN}
+ {0,-1,3}                              | {-1,0,3}
+ {-1,0,3}                              | {0,-1,5}
+ {-1,0,3}                              | {0,3,0}
+ {-1,0,3}                              | {1,-1,0}
+ {-1,0,3}                              | {-0.4,-1,-6}
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846}
+ {-1,0,3}                              | {3,NaN,5}
+ {-1,0,3}                              | {NaN,NaN,NaN}
+ {-1,0,3}                              | {0,-1,3}
+(84 rows)
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LINE_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+      s       |         f1          
+--------------+---------------------
+ {1,0,5}      | (-2,2),(-8,-10)
+ {0,3,0}      | (2,2),(0,0)
+ {0,3,0}      | (-2,2),(-8,-10)
+ {1,-1,0}     | (2,2),(0,0)
+ {1,-1,0}     | (3,3),(1,1)
+ {1,-1,0}     | (-2,2),(-8,-10)
+ {1,-1,0}     | (2.5,3.5),(2.5,2.5)
+ {1,-1,0}     | (3,3),(3,3)
+ {-0.4,-1,-6} | (-2,2),(-8,-10)
+ {0,-1,3}     | (3,3),(1,1)
+ {0,-1,3}     | (2.5,3.5),(2.5,2.5)
+ {0,-1,3}     | (3,3),(3,3)
+ {-1,0,3}     | (3,3),(1,1)
+(13 rows)
+
+-- Intersection point with line
+SELECT l1.s, l2.s, l1.s # l2.s FROM LINE_TBL l1, LINE_TBL l2;
+                   s                   |                   s                   |             ?column?              
+---------------------------------------+---------------------------------------+-----------------------------------
+ {0,-1,5}                              | {0,-1,5}                              | 
+ {0,-1,5}                              | {1,0,5}                               | (-5,5)
+ {0,-1,5}                              | {0,3,0}                               | 
+ {0,-1,5}                              | {1,-1,0}                              | (5,5)
+ {0,-1,5}                              | {-0.4,-1,-6}                          | (-27.5,5)
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846} | (56250,5)
+ {0,-1,5}                              | {3,NaN,5}                             | (NaN,NaN)
+ {0,-1,5}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,-1,5}                              | {0,-1,3}                              | 
+ {0,-1,5}                              | {-1,0,3}                              | (3,5)
+ {1,0,5}                               | {0,-1,5}                              | (-5,5)
+ {1,0,5}                               | {1,0,5}                               | 
+ {1,0,5}                               | {0,3,0}                               | (-5,0)
+ {1,0,5}                               | {1,-1,0}                              | (-5,-5)
+ {1,0,5}                               | {-0.4,-1,-6}                          | (-5,-4)
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846} | (-5,15.3855384615)
+ {1,0,5}                               | {3,NaN,5}                             | (-5,NaN)
+ {1,0,5}                               | {NaN,NaN,NaN}                         | (-5,NaN)
+ {1,0,5}                               | {0,-1,3}                              | (-5,3)
+ {1,0,5}                               | {-1,0,3}                              | 
+ {0,3,0}                               | {0,-1,5}                              | 
+ {0,3,0}                               | {1,0,5}                               | (-5,0)
+ {0,3,0}                               | {0,3,0}                               | 
+ {0,3,0}                               | {1,-1,0}                              | (0,0)
+ {0,3,0}                               | {-0.4,-1,-6}                          | (-15,0)
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846} | (83333.3333333,0)
+ {0,3,0}                               | {3,NaN,5}                             | (NaN,NaN)
+ {0,3,0}                               | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,3,0}                               | {0,-1,3}                              | 
+ {0,3,0}                               | {-1,0,3}                              | (3,0)
+ {1,-1,0}                              | {0,-1,5}                              | (5,5)
+ {1,-1,0}                              | {1,0,5}                               | (-5,-5)
+ {1,-1,0}                              | {0,3,0}                               | (0,0)
+ {1,-1,0}                              | {1,-1,0}                              | 
+ {1,-1,0}                              | {-0.4,-1,-6}                          | (-4.28571428571,-4.28571428571)
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846} | (15.3817756722,15.3817756722)
+ {1,-1,0}                              | {3,NaN,5}                             | (NaN,NaN)
+ {1,-1,0}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {1,-1,0}                              | {0,-1,3}                              | (3,3)
+ {1,-1,0}                              | {-1,0,3}                              | (3,3)
+ {-0.4,-1,-6}                          | {0,-1,5}                              | (-27.5,5)
+ {-0.4,-1,-6}                          | {1,0,5}                               | (-5,-4)
+ {-0.4,-1,-6}                          | {0,3,0}                               | (-15,0)
+ {-0.4,-1,-6}                          | {1,-1,0}                              | (-4.28571428571,-4.28571428571)
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}                          | 
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846} | (-53.4862244113,15.3944897645)
+ {-0.4,-1,-6}                          | {3,NaN,5}                             | (NaN,NaN)
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-0.4,-1,-6}                          | {0,-1,3}                              | (-22.5,3)
+ {-0.4,-1,-6}                          | {-1,0,3}                              | (3,-7.2)
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}                              | (56250,5)
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}                               | (-5,15.3855384615)
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}                               | (83333.3333333,-1.7763568394e-15)
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}                              | (15.3817756722,15.3817756722)
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}                          | (-53.4862244113,15.3944897645)
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} | 
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}                             | (NaN,NaN)
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}                              | (67083.3333333,3)
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}                              | (3,15.3840615385)
+ {3,NaN,5}                             | {0,-1,5}                              | (NaN,NaN)
+ {3,NaN,5}                             | {1,0,5}                               | (-5,NaN)
+ {3,NaN,5}                             | {0,3,0}                               | (NaN,NaN)
+ {3,NaN,5}                             | {1,-1,0}                              | (NaN,NaN)
+ {3,NaN,5}                             | {-0.4,-1,-6}                          | (NaN,NaN)
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ {3,NaN,5}                             | {3,NaN,5}                             | (NaN,NaN)
+ {3,NaN,5}                             | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {3,NaN,5}                             | {0,-1,3}                              | (NaN,NaN)
+ {3,NaN,5}                             | {-1,0,3}                              | (3,NaN)
+ {NaN,NaN,NaN}                         | {0,-1,5}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {1,0,5}                               | (-5,NaN)
+ {NaN,NaN,NaN}                         | {0,3,0}                               | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {1,-1,0}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}                          | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {3,NaN,5}                             | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,-1,3}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-1,0,3}                              | (3,NaN)
+ {0,-1,3}                              | {0,-1,5}                              | 
+ {0,-1,3}                              | {1,0,5}                               | (-5,3)
+ {0,-1,3}                              | {0,3,0}                               | 
+ {0,-1,3}                              | {1,-1,0}                              | (3,3)
+ {0,-1,3}                              | {-0.4,-1,-6}                          | (-22.5,3)
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846} | (67083.3333333,3)
+ {0,-1,3}                              | {3,NaN,5}                             | (NaN,NaN)
+ {0,-1,3}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,-1,3}                              | {0,-1,3}                              | 
+ {0,-1,3}                              | {-1,0,3}                              | (3,3)
+ {-1,0,3}                              | {0,-1,5}                              | (3,5)
+ {-1,0,3}                              | {1,0,5}                               | 
+ {-1,0,3}                              | {0,3,0}                               | (3,0)
+ {-1,0,3}                              | {1,-1,0}                              | (3,3)
+ {-1,0,3}                              | {-0.4,-1,-6}                          | (3,-7.2)
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846} | (3,15.3840615385)
+ {-1,0,3}                              | {3,NaN,5}                             | (3,NaN)
+ {-1,0,3}                              | {NaN,NaN,NaN}                         | (3,NaN)
+ {-1,0,3}                              | {0,-1,3}                              | (3,3)
+ {-1,0,3}                              | {-1,0,3}                              | 
+(100 rows)
+
+-- Closest point to line segment
+SELECT l.s, l1.s, l.s ## l1.s FROM LINE_TBL l, LSEG_TBL l1;
+                   s                   |               s               |             ?column?              
+---------------------------------------+-------------------------------+-----------------------------------
+ {0,-1,5}                              | [(1,2),(3,4)]                 | (3,4)
+ {0,-1,5}                              | [(0,0),(6,6)]                 | (5,5)
+ {0,-1,5}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,-1,5}                              | [(-1000000,200),(300000,-40)] | (56250,5)
+ {0,-1,5}                              | [(11,22),(33,44)]             | (11,22)
+ {0,-1,5}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {0,-1,5}                              | [(0,-20),(30,-20)]            | 
+ {0,-1,5}                              | [(NaN,1),(NaN,90)]            | 
+ {1,0,5}                               | [(1,2),(3,4)]                 | (1,2)
+ {1,0,5}                               | [(0,0),(6,6)]                 | (0,0)
+ {1,0,5}                               | [(10,-10),(-3,-4)]            | (-3,-4)
+ {1,0,5}                               | [(-1000000,200),(300000,-40)] | (-5,15.3855384615)
+ {1,0,5}                               | [(11,22),(33,44)]             | (11,22)
+ {1,0,5}                               | [(-10,2),(-10,3)]             | 
+ {1,0,5}                               | [(0,-20),(30,-20)]            | (0,-20)
+ {1,0,5}                               | [(NaN,1),(NaN,90)]            | 
+ {0,3,0}                               | [(1,2),(3,4)]                 | (1,2)
+ {0,3,0}                               | [(0,0),(6,6)]                 | (0,0)
+ {0,3,0}                               | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,3,0}                               | [(-1000000,200),(300000,-40)] | (83333.3333333,-1.7763568394e-15)
+ {0,3,0}                               | [(11,22),(33,44)]             | (11,22)
+ {0,3,0}                               | [(-10,2),(-10,3)]             | (-10,2)
+ {0,3,0}                               | [(0,-20),(30,-20)]            | 
+ {0,3,0}                               | [(NaN,1),(NaN,90)]            | 
+ {1,-1,0}                              | [(1,2),(3,4)]                 | 
+ {1,-1,0}                              | [(0,0),(6,6)]                 | 
+ {1,-1,0}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {1,-1,0}                              | [(-1000000,200),(300000,-40)] | (15.3817756722,15.3817756722)
+ {1,-1,0}                              | [(11,22),(33,44)]             | 
+ {1,-1,0}                              | [(-10,2),(-10,3)]             | (-10,2)
+ {1,-1,0}                              | [(0,-20),(30,-20)]            | (0,-20)
+ {1,-1,0}                              | [(NaN,1),(NaN,90)]            | 
+ {-0.4,-1,-6}                          | [(1,2),(3,4)]                 | (1,2)
+ {-0.4,-1,-6}                          | [(0,0),(6,6)]                 | (0,0)
+ {-0.4,-1,-6}                          | [(10,-10),(-3,-4)]            | (10,-10)
+ {-0.4,-1,-6}                          | [(-1000000,200),(300000,-40)] | (-53.4862244113,15.3944897645)
+ {-0.4,-1,-6}                          | [(11,22),(33,44)]             | (11,22)
+ {-0.4,-1,-6}                          | [(-10,2),(-10,3)]             | (-10,2)
+ {-0.4,-1,-6}                          | [(0,-20),(30,-20)]            | (30,-20)
+ {-0.4,-1,-6}                          | [(NaN,1),(NaN,90)]            | 
+ {-0.000184615384615,-1,15.3846153846} | [(1,2),(3,4)]                 | (3,4)
+ {-0.000184615384615,-1,15.3846153846} | [(0,0),(6,6)]                 | (6,6)
+ {-0.000184615384615,-1,15.3846153846} | [(10,-10),(-3,-4)]            | (-3,-4)
+ {-0.000184615384615,-1,15.3846153846} | [(-1000000,200),(300000,-40)] | 
+ {-0.000184615384615,-1,15.3846153846} | [(11,22),(33,44)]             | (11,22)
+ {-0.000184615384615,-1,15.3846153846} | [(-10,2),(-10,3)]             | (-10,3)
+ {-0.000184615384615,-1,15.3846153846} | [(0,-20),(30,-20)]            | (30,-20)
+ {-0.000184615384615,-1,15.3846153846} | [(NaN,1),(NaN,90)]            | 
+ {3,NaN,5}                             | [(1,2),(3,4)]                 | 
+ {3,NaN,5}                             | [(0,0),(6,6)]                 | 
+ {3,NaN,5}                             | [(10,-10),(-3,-4)]            | 
+ {3,NaN,5}                             | [(-1000000,200),(300000,-40)] | 
+ {3,NaN,5}                             | [(11,22),(33,44)]             | 
+ {3,NaN,5}                             | [(-10,2),(-10,3)]             | 
+ {3,NaN,5}                             | [(0,-20),(30,-20)]            | 
+ {3,NaN,5}                             | [(NaN,1),(NaN,90)]            | 
+ {NaN,NaN,NaN}                         | [(1,2),(3,4)]                 | 
+ {NaN,NaN,NaN}                         | [(0,0),(6,6)]                 | 
+ {NaN,NaN,NaN}                         | [(10,-10),(-3,-4)]            | 
+ {NaN,NaN,NaN}                         | [(-1000000,200),(300000,-40)] | 
+ {NaN,NaN,NaN}                         | [(11,22),(33,44)]             | 
+ {NaN,NaN,NaN}                         | [(-10,2),(-10,3)]             | 
+ {NaN,NaN,NaN}                         | [(0,-20),(30,-20)]            | 
+ {NaN,NaN,NaN}                         | [(NaN,1),(NaN,90)]            | 
+ {0,-1,3}                              | [(1,2),(3,4)]                 | (2,3)
+ {0,-1,3}                              | [(0,0),(6,6)]                 | (3,3)
+ {0,-1,3}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,-1,3}                              | [(-1000000,200),(300000,-40)] | (67083.3333333,3)
+ {0,-1,3}                              | [(11,22),(33,44)]             | (11,22)
+ {0,-1,3}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {0,-1,3}                              | [(0,-20),(30,-20)]            | 
+ {0,-1,3}                              | [(NaN,1),(NaN,90)]            | 
+ {-1,0,3}                              | [(1,2),(3,4)]                 | (3,4)
+ {-1,0,3}                              | [(0,0),(6,6)]                 | (3,3)
+ {-1,0,3}                              | [(10,-10),(-3,-4)]            | (3,-6.76923076923)
+ {-1,0,3}                              | [(-1000000,200),(300000,-40)] | (3,15.3840615385)
+ {-1,0,3}                              | [(11,22),(33,44)]             | (11,22)
+ {-1,0,3}                              | [(-10,2),(-10,3)]             | 
+ {-1,0,3}                              | [(0,-20),(30,-20)]            | (3,-20)
+ {-1,0,3}                              | [(NaN,1),(NaN,90)]            | 
+(80 rows)
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LINE_TBL l, BOX_TBL b;
+ERROR:  function "close_lb" not implemented
 --
 -- Line segments
 --
 -- intersection
 SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
    FROM LSEG_TBL l, POINT_TBL p;
 ERROR:  operator does not exist: lseg # point
 LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
                                            ^
 HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (-0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
+-- Length
+SELECT s, @-@ s FROM LSEG_TBL;
+               s               |   ?column?    
+-------------------------------+---------------
+ [(1,2),(3,4)]                 | 2.82842712475
+ [(0,0),(6,6)]                 | 8.48528137424
+ [(10,-10),(-3,-4)]            | 14.3178210633
+ [(-1000000,200),(300000,-40)] | 1300000.02215
+ [(11,22),(33,44)]             | 31.1126983722
+ [(-10,2),(-10,3)]             |             1
+ [(0,-20),(30,-20)]            |            30
+ [(NaN,1),(NaN,90)]            |           NaN
+(8 rows)
+
+-- Vertical
+SELECT s FROM LSEG_TBL WHERE ?| s;
+         s         
+-------------------
+ [(-10,2),(-10,3)]
+(1 row)
+
+-- Horizontal
+SELECT s FROM LSEG_TBL WHERE ?- s;
+         s          
+--------------------
+ [(0,-20),(30,-20)]
+(1 row)
+
+-- Center
+SELECT s, @@ s FROM LSEG_TBL;
+               s               |   ?column?   
+-------------------------------+--------------
+ [(1,2),(3,4)]                 | (2,3)
+ [(0,0),(6,6)]                 | (3,3)
+ [(10,-10),(-3,-4)]            | (3.5,-7)
+ [(-1000000,200),(300000,-40)] | (-350000,80)
+ [(11,22),(33,44)]             | (22,33)
+ [(-10,2),(-10,3)]             | (-10,2.5)
+ [(0,-20),(30,-20)]            | (15,-20)
+ [(NaN,1),(NaN,90)]            | (NaN,45.5)
+(8 rows)
+
+-- To point
+SELECT s, s::point FROM LSEG_TBL;
+               s               |      s       
+-------------------------------+--------------
+ [(1,2),(3,4)]                 | (2,3)
+ [(0,0),(6,6)]                 | (3,3)
+ [(10,-10),(-3,-4)]            | (3.5,-7)
+ [(-1000000,200),(300000,-40)] | (-350000,80)
+ [(11,22),(33,44)]             | (22,33)
+ [(-10,2),(-10,3)]             | (-10,2.5)
+ [(0,-20),(30,-20)]            | (15,-20)
+ [(NaN,1),(NaN,90)]            | (NaN,45.5)
+(8 rows)
+
+-- Has points less than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s < l2.s;
+         s          |               s               
+--------------------+-------------------------------
+ [(1,2),(3,4)]      | [(0,0),(6,6)]
+ [(1,2),(3,4)]      | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]      | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]      | [(11,22),(33,44)]
+ [(1,2),(3,4)]      | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]      | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]      | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]      | [(11,22),(33,44)]
+ [(0,0),(6,6)]      | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)] | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)] | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]  | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]  | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]  | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]  | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]  | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]  | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]  | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)] | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)] | [(11,22),(33,44)]
+(21 rows)
+
+-- Has points less than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s <= l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(28 rows)
+
+-- Has points equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s = l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]
+(8 rows)
+
+-- Has points greater than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s >= l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(28 rows)
+
+-- Has points greater than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s > l2.s;
+               s               |         s          
+-------------------------------+--------------------
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+(21 rows)
+
+-- Has points not equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s != l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)]
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]
+(56 rows)
+
+-- Parallel with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?|| l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(13 rows)
+
+-- Perpendicular with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?-| l2.s;
+         s          |         s          
+--------------------+--------------------
+ [(-10,2),(-10,3)]  | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)] | [(-10,2),(-10,3)]
+(2 rows)
+
+-- Distance to line
+SELECT l.s, l1.s, l.s <-> l1.s FROM LSEG_TBL l, LINE_TBL l1;
+               s               |                   s                   |    ?column?    
+-------------------------------+---------------------------------------+----------------
+ [(1,2),(3,4)]                 | {0,-1,5}                              |              1
+ [(0,0),(6,6)]                 | {0,-1,5}                              |              0
+ [(10,-10),(-3,-4)]            | {0,-1,5}                              |              9
+ [(-1000000,200),(300000,-40)] | {0,-1,5}                              |              0
+ [(11,22),(33,44)]             | {0,-1,5}                              |             17
+ [(-10,2),(-10,3)]             | {0,-1,5}                              |              2
+ [(0,-20),(30,-20)]            | {0,-1,5}                              |             25
+ [(NaN,1),(NaN,90)]            | {0,-1,5}                              |            NaN
+ [(1,2),(3,4)]                 | {1,0,5}                               |              6
+ [(0,0),(6,6)]                 | {1,0,5}                               |              5
+ [(10,-10),(-3,-4)]            | {1,0,5}                               |              2
+ [(-1000000,200),(300000,-40)] | {1,0,5}                               |              0
+ [(11,22),(33,44)]             | {1,0,5}                               |             16
+ [(-10,2),(-10,3)]             | {1,0,5}                               |              5
+ [(0,-20),(30,-20)]            | {1,0,5}                               |              5
+ [(NaN,1),(NaN,90)]            | {1,0,5}                               |            NaN
+ [(1,2),(3,4)]                 | {0,3,0}                               |              2
+ [(0,0),(6,6)]                 | {0,3,0}                               |              0
+ [(10,-10),(-3,-4)]            | {0,3,0}                               |              4
+ [(-1000000,200),(300000,-40)] | {0,3,0}                               |              0
+ [(11,22),(33,44)]             | {0,3,0}                               |             22
+ [(-10,2),(-10,3)]             | {0,3,0}                               |              2
+ [(0,-20),(30,-20)]            | {0,3,0}                               |             20
+ [(NaN,1),(NaN,90)]            | {0,3,0}                               |            NaN
+ [(1,2),(3,4)]                 | {1,-1,0}                              | 0.707106781187
+ [(0,0),(6,6)]                 | {1,-1,0}                              |              0
+ [(10,-10),(-3,-4)]            | {1,-1,0}                              | 0.707106781187
+ [(-1000000,200),(300000,-40)] | {1,-1,0}                              |              0
+ [(11,22),(33,44)]             | {1,-1,0}                              |  7.77817459305
+ [(-10,2),(-10,3)]             | {1,-1,0}                              |  8.48528137424
+ [(0,-20),(30,-20)]            | {1,-1,0}                              |  14.1421356237
+ [(NaN,1),(NaN,90)]            | {1,-1,0}                              |            NaN
+ [(1,2),(3,4)]                 | {-0.4,-1,-6}                          |  7.79920420344
+ [(0,0),(6,6)]                 | {-0.4,-1,-6}                          |  5.57086014531
+ [(10,-10),(-3,-4)]            | {-0.4,-1,-6}                          |              0
+ [(-1000000,200),(300000,-40)] | {-0.4,-1,-6}                          |              0
+ [(11,22),(33,44)]             | {-0.4,-1,-6}                          |  30.0826447847
+ [(-10,2),(-10,3)]             | {-0.4,-1,-6}                          |  3.71390676354
+ [(0,-20),(30,-20)]            | {-0.4,-1,-6}                          |  1.85695338177
+ [(NaN,1),(NaN,90)]            | {-0.4,-1,-6}                          |            NaN
+ [(1,2),(3,4)]                 | {-0.000184615384615,-1,15.3846153846} |  11.3840613445
+ [(0,0),(6,6)]                 | {-0.000184615384615,-1,15.3846153846} |   9.3835075324
+ [(10,-10),(-3,-4)]            | {-0.000184615384615,-1,15.3846153846} |  19.3851689004
+ [(-1000000,200),(300000,-40)] | {-0.000184615384615,-1,15.3846153846} |              0
+ [(11,22),(33,44)]             | {-0.000184615384615,-1,15.3846153846} |  6.61741527185
+ [(-10,2),(-10,3)]             | {-0.000184615384615,-1,15.3846153846} |  12.3864613274
+ [(0,-20),(30,-20)]            | {-0.000184615384615,-1,15.3846153846} |  35.3790763202
+ [(NaN,1),(NaN,90)]            | {-0.000184615384615,-1,15.3846153846} |            NaN
+ [(1,2),(3,4)]                 | {3,NaN,5}                             |            NaN
+ [(0,0),(6,6)]                 | {3,NaN,5}                             |            NaN
+ [(10,-10),(-3,-4)]            | {3,NaN,5}                             |            NaN
+ [(-1000000,200),(300000,-40)] | {3,NaN,5}                             |            NaN
+ [(11,22),(33,44)]             | {3,NaN,5}                             |            NaN
+ [(-10,2),(-10,3)]             | {3,NaN,5}                             |            NaN
+ [(0,-20),(30,-20)]            | {3,NaN,5}                             |            NaN
+ [(NaN,1),(NaN,90)]            | {3,NaN,5}                             |            NaN
+ [(1,2),(3,4)]                 | {NaN,NaN,NaN}                         |            NaN
+ [(0,0),(6,6)]                 | {NaN,NaN,NaN}                         |            NaN
+ [(10,-10),(-3,-4)]            | {NaN,NaN,NaN}                         |            NaN
+ [(-1000000,200),(300000,-40)] | {NaN,NaN,NaN}                         |            NaN
+ [(11,22),(33,44)]             | {NaN,NaN,NaN}                         |            NaN
+ [(-10,2),(-10,3)]             | {NaN,NaN,NaN}                         |            NaN
+ [(0,-20),(30,-20)]            | {NaN,NaN,NaN}                         |            NaN
+ [(NaN,1),(NaN,90)]            | {NaN,NaN,NaN}                         |            NaN
+ [(1,2),(3,4)]                 | {0,-1,3}                              |              0
+ [(0,0),(6,6)]                 | {0,-1,3}                              |              0
+ [(10,-10),(-3,-4)]            | {0,-1,3}                              |              7
+ [(-1000000,200),(300000,-40)] | {0,-1,3}                              |              0
+ [(11,22),(33,44)]             | {0,-1,3}                              |             19
+ [(-10,2),(-10,3)]             | {0,-1,3}                              |              0
+ [(0,-20),(30,-20)]            | {0,-1,3}                              |             23
+ [(NaN,1),(NaN,90)]            | {0,-1,3}                              |            NaN
+ [(1,2),(3,4)]                 | {-1,0,3}                              |              0
+ [(0,0),(6,6)]                 | {-1,0,3}                              |              0
+ [(10,-10),(-3,-4)]            | {-1,0,3}                              |              0
+ [(-1000000,200),(300000,-40)] | {-1,0,3}                              |              0
+ [(11,22),(33,44)]             | {-1,0,3}                              |              8
+ [(-10,2),(-10,3)]             | {-1,0,3}                              |             13
+ [(0,-20),(30,-20)]            | {-1,0,3}                              |              0
+ [(NaN,1),(NaN,90)]            | {-1,0,3}                              |            NaN
+(80 rows)
+
+-- Distance to line segment
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               |    ?column?    
+-------------------------------+-------------------------------+----------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 |              0
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 0.707106781187
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            |  7.12398901685
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] |  11.3840613445
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             |  19.6977156036
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             |             11
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            |             22
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            |            NaN
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 0.707106781187
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 |              0
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            |  4.88901207039
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] |   9.3835075324
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             |  16.7630546142
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             |  10.1980390272
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            |             20
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            |            NaN
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 |  7.12398901685
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 |  4.88901207039
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            |              0
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] |  19.3851689004
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             |  29.4737584815
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             |  9.21954445729
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            |             10
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            |            NaN
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 |  11.3840613445
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 |   9.3835075324
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            |  19.3851689004
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] |              0
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             |  6.61741527185
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             |  12.3864613274
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            |  35.3790763202
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            |            NaN
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 |  19.6977156036
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 |  16.7630546142
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            |  29.4737584815
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] |  6.61741527185
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             |              0
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             |   28.319604517
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            |             42
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            |            NaN
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 |             11
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 |  10.1980390272
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            |  9.21954445729
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] |  12.3864613274
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             |   28.319604517
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             |              0
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            |  24.1660919472
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            |            NaN
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 |             22
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 |             20
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            |             10
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] |  35.3790763202
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             |             42
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             |  24.1660919472
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            |              0
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 |            NaN
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 |            NaN
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] |            NaN
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             |            NaN
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             |            NaN
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            |            NaN
+(64 rows)
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LSEG_TBL l, BOX_TBL b;
+               s               |         f1          |    ?column?    
+-------------------------------+---------------------+----------------
+ [(1,2),(3,4)]                 | (2,2),(0,0)         |              0
+ [(1,2),(3,4)]                 | (3,3),(1,1)         |              0
+ [(1,2),(3,4)]                 | (-2,2),(-8,-10)     |              3
+ [(1,2),(3,4)]                 | (2.5,3.5),(2.5,2.5) |              0
+ [(1,2),(3,4)]                 | (3,3),(3,3)         | 0.707106781187
+ [(0,0),(6,6)]                 | (2,2),(0,0)         |              0
+ [(0,0),(6,6)]                 | (3,3),(1,1)         |              0
+ [(0,0),(6,6)]                 | (-2,2),(-8,-10)     |              2
+ [(0,0),(6,6)]                 | (2.5,3.5),(2.5,2.5) |              0
+ [(0,0),(6,6)]                 | (3,3),(3,3)         |              0
+ [(10,-10),(-3,-4)]            | (2,2),(0,0)         |  4.88901207039
+ [(10,-10),(-3,-4)]            | (3,3),(1,1)         |  6.21602963235
+ [(10,-10),(-3,-4)]            | (-2,2),(-8,-10)     |              0
+ [(10,-10),(-3,-4)]            | (2.5,3.5),(2.5,2.5) |  8.20655597529
+ [(10,-10),(-3,-4)]            | (3,3),(3,3)         |  8.87006475627
+ [(-1000000,200),(300000,-40)] | (2,2),(0,0)         |  13.3842459258
+ [(-1000000,200),(300000,-40)] | (3,3),(1,1)         |  12.3840613274
+ [(-1000000,200),(300000,-40)] | (-2,2),(-8,-10)     |  13.3849843873
+ [(-1000000,200),(300000,-40)] | (2.5,3.5),(2.5,2.5) |  11.8841536436
+ [(-1000000,200),(300000,-40)] | (3,3),(3,3)         |  12.3840613274
+ [(11,22),(33,44)]             | (2,2),(0,0)         |  21.9317121995
+ [(11,22),(33,44)]             | (3,3),(1,1)         |  20.6155281281
+ [(11,22),(33,44)]             | (-2,2),(-8,-10)     |  23.8537208838
+ [(11,22),(33,44)]             | (2.5,3.5),(2.5,2.5) |  20.3592730715
+ [(11,22),(33,44)]             | (3,3),(3,3)         |  20.6155281281
+ [(-10,2),(-10,3)]             | (2,2),(0,0)         |             10
+ [(-10,2),(-10,3)]             | (3,3),(1,1)         |             11
+ [(-10,2),(-10,3)]             | (-2,2),(-8,-10)     |              2
+ [(-10,2),(-10,3)]             | (2.5,3.5),(2.5,2.5) |           12.5
+ [(-10,2),(-10,3)]             | (3,3),(3,3)         |             13
+ [(0,-20),(30,-20)]            | (2,2),(0,0)         |             20
+ [(0,-20),(30,-20)]            | (3,3),(1,1)         |             21
+ [(0,-20),(30,-20)]            | (-2,2),(-8,-10)     |  10.1980390272
+ [(0,-20),(30,-20)]            | (2.5,3.5),(2.5,2.5) |           22.5
+ [(0,-20),(30,-20)]            | (3,3),(3,3)         |             23
+ [(NaN,1),(NaN,90)]            | (2,2),(0,0)         |            NaN
+ [(NaN,1),(NaN,90)]            | (3,3),(1,1)         |            NaN
+ [(NaN,1),(NaN,90)]            | (-2,2),(-8,-10)     |            NaN
+ [(NaN,1),(NaN,90)]            | (2.5,3.5),(2.5,2.5) |            NaN
+ [(NaN,1),(NaN,90)]            | (3,3),(3,3)         |            NaN
+(40 rows)
+
+-- Intersect with line segment
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s ?# l1.s;
+               s               |      s       
+-------------------------------+--------------
+ [(0,0),(6,6)]                 | {0,-1,5}
+ [(-1000000,200),(300000,-40)] | {0,-1,5}
+ [(-1000000,200),(300000,-40)] | {1,0,5}
+ [(0,0),(6,6)]                 | {0,3,0}
+ [(-1000000,200),(300000,-40)] | {0,3,0}
+ [(-1000000,200),(300000,-40)] | {1,-1,0}
+ [(10,-10),(-3,-4)]            | {-0.4,-1,-6}
+ [(-1000000,200),(300000,-40)] | {-0.4,-1,-6}
+ [(1,2),(3,4)]                 | {0,-1,3}
+ [(0,0),(6,6)]                 | {0,-1,3}
+ [(-1000000,200),(300000,-40)] | {0,-1,3}
+ [(-10,2),(-10,3)]             | {0,-1,3}
+ [(1,2),(3,4)]                 | {-1,0,3}
+ [(0,0),(6,6)]                 | {-1,0,3}
+ [(10,-10),(-3,-4)]            | {-1,0,3}
+ [(-1000000,200),(300000,-40)] | {-1,0,3}
+ [(0,-20),(30,-20)]            | {-1,0,3}
+(17 rows)
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+         s          |         f1          
+--------------------+---------------------
+ [(1,2),(3,4)]      | (2,2),(0,0)
+ [(1,2),(3,4)]      | (3,3),(1,1)
+ [(1,2),(3,4)]      | (2.5,3.5),(2.5,2.5)
+ [(0,0),(6,6)]      | (2,2),(0,0)
+ [(0,0),(6,6)]      | (3,3),(1,1)
+ [(0,0),(6,6)]      | (2.5,3.5),(2.5,2.5)
+ [(0,0),(6,6)]      | (3,3),(3,3)
+ [(10,-10),(-3,-4)] | (-2,2),(-8,-10)
+(8 rows)
+
+-- Intersection point with line segment
+SELECT l1.s, l2.s, l1.s # l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               | ?column? 
+-------------------------------+-------------------------------+----------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 | 
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            | 
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] | 
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             | 
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             | 
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            | 
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            | 
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 | 
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            | 
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] | 
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             | 
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             | 
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            | 
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            | 
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 | 
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 | 
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            | 
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] | 
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             | 
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             | 
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            | 
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            | 
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 | 
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 | 
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            | 
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] | 
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             | 
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             | 
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            | 
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            | 
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 | 
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 | 
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            | 
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] | 
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             | 
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             | 
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            | 
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            | 
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 | 
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 | 
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            | 
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] | 
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             | 
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             | 
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            | 
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            | 
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 | 
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 | 
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            | 
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] | 
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             | 
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             | 
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            | 
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            | 
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 | 
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 | 
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            | 
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] | 
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             | 
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             | 
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            | 
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            | 
+(64 rows)
+
+-- Closest point to line
+SELECT l.s, l1.s, l.s ## l1.s FROM LSEG_TBL l, LINE_TBL l1;
+ERROR:  function "close_sl" not implemented
+-- Closest point to line segment
+SELECT l1.s, l2.s, l1.s ## l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               |            ?column?             
+-------------------------------+-------------------------------+---------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 | 
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            | (-1.98536585366,-4.46829268293)
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] | (3.00210167283,15.3840611505)
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             | 
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             | (-10,2)
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            | (1,-20)
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            | 
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 | 
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] | (6.00173233982,15.3835073725)
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             | 
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             | (-10,2)
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            | (0,-20)
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            | 
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 | (1,2)
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 | (0,0)
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            | 
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] | (-2.99642119965,15.3851685701)
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             | (11,22)
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             | (-10,2)
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            | (10,-20)
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            | 
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 | (3,4)
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 | (6,6)
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            | (-3,-4)
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] | 
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             | (11,22)
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             | (-10,3)
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            | (30,-20)
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            | 
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 | 
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 | 
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            | (-1.3512195122,-4.76097560976)
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] | (10.9987783234,15.3825848409)
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             | 
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             | (-10,3)
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            | (11,-20)
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            | 
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 | (1,2)
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 | (0,0)
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            | (-3,-4)
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] | (-9.99771326872,15.3864611163)
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             | (11,22)
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             | 
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            | (0,-20)
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            | 
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 | (1,2)
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 | (0,0)
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            | (10,-10)
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] | (30.0065315217,15.3790757173)
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             | (11,22)
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             | (-10,2)
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            | 
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            | 
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 | 
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 | 
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            | 
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] | 
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             | 
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             | 
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            | 
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            | 
+(64 rows)
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LSEG_TBL l, BOX_TBL b;
+               s               |         f1          |  ?column?   
+-------------------------------+---------------------+-------------
+ [(1,2),(3,4)]                 | (2,2),(0,0)         | (1,2)
+ [(1,2),(3,4)]                 | (3,3),(1,1)         | (1.5,2.5)
+ [(1,2),(3,4)]                 | (-2,2),(-8,-10)     | (-2,2)
+ [(1,2),(3,4)]                 | (2.5,3.5),(2.5,2.5) | (2.25,3.25)
+ [(1,2),(3,4)]                 | (3,3),(3,3)         | (3,3)
+ [(0,0),(6,6)]                 | (2,2),(0,0)         | (1,1)
+ [(0,0),(6,6)]                 | (3,3),(1,1)         | (2,2)
+ [(0,0),(6,6)]                 | (-2,2),(-8,-10)     | (-2,0)
+ [(0,0),(6,6)]                 | (2.5,3.5),(2.5,2.5) | (2.75,2.75)
+ [(0,0),(6,6)]                 | (3,3),(3,3)         | (3,3)
+ [(10,-10),(-3,-4)]            | (2,2),(0,0)         | (0,0)
+ [(10,-10),(-3,-4)]            | (3,3),(1,1)         | (1,1)
+ [(10,-10),(-3,-4)]            | (-2,2),(-8,-10)     | (-3,-4)
+ [(10,-10),(-3,-4)]            | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ [(10,-10),(-3,-4)]            | (3,3),(3,3)         | (3,3)
+ [(-1000000,200),(300000,-40)] | (2,2),(0,0)         | (2,2)
+ [(-1000000,200),(300000,-40)] | (3,3),(1,1)         | (3,3)
+ [(-1000000,200),(300000,-40)] | (-2,2),(-8,-10)     | (-2,2)
+ [(-1000000,200),(300000,-40)] | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ [(-1000000,200),(300000,-40)] | (3,3),(3,3)         | (3,3)
+ [(11,22),(33,44)]             | (2,2),(0,0)         | (2,2)
+ [(11,22),(33,44)]             | (3,3),(1,1)         | (3,3)
+ [(11,22),(33,44)]             | (-2,2),(-8,-10)     | (-2,2)
+ [(11,22),(33,44)]             | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ [(11,22),(33,44)]             | (3,3),(3,3)         | (3,3)
+ [(-10,2),(-10,3)]             | (2,2),(0,0)         | (0,2)
+ [(-10,2),(-10,3)]             | (3,3),(1,1)         | (1,2)
+ [(-10,2),(-10,3)]             | (-2,2),(-8,-10)     | (-8,2)
+ [(-10,2),(-10,3)]             | (2.5,3.5),(2.5,2.5) | (2.5,3)
+ [(-10,2),(-10,3)]             | (3,3),(3,3)         | (3,3)
+ [(0,-20),(30,-20)]            | (2,2),(0,0)         | (0,0)
+ [(0,-20),(30,-20)]            | (3,3),(1,1)         | (1,1)
+ [(0,-20),(30,-20)]            | (-2,2),(-8,-10)     | (-2,-10)
+ [(0,-20),(30,-20)]            | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ [(0,-20),(30,-20)]            | (3,3),(3,3)         | (3,3)
+ [(NaN,1),(NaN,90)]            | (2,2),(0,0)         | 
+ [(NaN,1),(NaN,90)]            | (3,3),(1,1)         | 
+ [(NaN,1),(NaN,90)]            | (-2,2),(-8,-10)     | 
+ [(NaN,1),(NaN,90)]            | (2.5,3.5),(2.5,2.5) | 
+ [(NaN,1),(NaN,90)]            | (3,3),(3,3)         | 
+(40 rows)
+
+-- On line
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s <@ l1.s;
+               s               |                   s                   
+-------------------------------+---------------------------------------
+ [(0,0),(6,6)]                 | {1,-1,0}
+ [(-1000000,200),(300000,-40)] | {-0.000184615384615,-1,15.3846153846}
+(2 rows)
+
+-- On box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s <@ b.f1;
+ s | f1 
+---+----
+(0 rows)
 
 --
 -- Boxes
 --
 SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
  six |                              box                               
 -----+----------------------------------------------------------------
      | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
      | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
      | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
      | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
      | (107.071067812,207.071067812),(92.9289321881,192.928932188)
      | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
+     | (3,5),(3,5)
+     | (NaN,NaN),(NaN,NaN)
+(8 rows)
 
 -- translation
 SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
+ twentyfour |             translation             
+------------+-------------------------------------
             | (2,2),(0,0)
             | (3,3),(1,1)
+            | (-2,2),(-8,-10)
             | (2.5,3.5),(2.5,2.5)
             | (3,3),(3,3)
             | (-8,2),(-10,0)
             | (-7,3),(-9,1)
+            | (-12,2),(-18,-10)
             | (-7.5,3.5),(-7.5,2.5)
             | (-7,3),(-7,3)
             | (-1,6),(-3,4)
             | (0,7),(-2,5)
+            | (-5,6),(-11,-6)
             | (-0.5,7.5),(-0.5,6.5)
             | (0,7),(0,7)
             | (7.1,36.5),(5.1,34.5)
             | (8.1,37.5),(6.1,35.5)
+            | (3.1,36.5),(-2.9,24.5)
             | (7.6,38),(7.6,37)
             | (8.1,37.5),(8.1,37.5)
             | (-3,-10),(-5,-12)
             | (-2,-9),(-4,-11)
+            | (-7,-10),(-13,-22)
             | (-2.5,-8.5),(-2.5,-9.5)
             | (-2,-9),(-2,-9)
+            | (2,2),(1e-300,-1e-300)
+            | (3,3),(1,1)
+            | (-2,2),(-8,-10)
+            | (2.5,3.5),(2.5,2.5)
+            | (3,3),(3,3)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
             | (12,12),(10,10)
             | (13,13),(11,11)
+            | (8,12),(2,0)
             | (12.5,13.5),(12.5,12.5)
             | (13,13),(13,13)
-(24 rows)
+(45 rows)
 
 SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
+ twentyfour |               translation               
+------------+-----------------------------------------
             | (2,2),(0,0)
             | (3,3),(1,1)
+            | (-2,2),(-8,-10)
             | (2.5,3.5),(2.5,2.5)
             | (3,3),(3,3)
             | (12,2),(10,0)
             | (13,3),(11,1)
+            | (8,2),(2,-10)
             | (12.5,3.5),(12.5,2.5)
             | (13,3),(13,3)
             | (5,-2),(3,-4)
             | (6,-1),(4,-3)
+            | (1,-2),(-5,-14)
             | (5.5,-0.5),(5.5,-1.5)
             | (6,-1),(6,-1)
             | (-3.1,-32.5),(-5.1,-34.5)
             | (-2.1,-31.5),(-4.1,-33.5)
+            | (-7.1,-32.5),(-13.1,-44.5)
             | (-2.6,-31),(-2.6,-32)
             | (-2.1,-31.5),(-2.1,-31.5)
             | (7,14),(5,12)
             | (8,15),(6,13)
+            | (3,14),(-3,2)
             | (7.5,15.5),(7.5,14.5)
             | (8,15),(8,15)
+            | (2,2),(-1e-300,1e-300)
+            | (3,3),(1,1)
+            | (-2,2),(-8,-10)
+            | (2.5,3.5),(2.5,2.5)
+            | (3,3),(3,3)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
             | (-8,-8),(-10,-10)
             | (-7,-7),(-9,-9)
+            | (-12,-8),(-18,-20)
             | (-7.5,-6.5),(-7.5,-7.5)
             | (-7,-7),(-7,-7)
-(24 rows)
+(45 rows)
 
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (-0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (-0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,-0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
+-- Multiply with point
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+         f1          |     f1     |          ?column?           
+---------------------+------------+-----------------------------
+ (2,2),(0,0)         | (5.1,34.5) | (0,79.2),(-58.8,0)
+ (2,2),(0,0)         | (10,10)    | (0,40),(0,0)
+ (3,3),(1,1)         | (5.1,34.5) | (-29.4,118.8),(-88.2,39.6)
+ (3,3),(1,1)         | (10,10)    | (0,60),(0,20)
+ (-2,2),(-8,-10)     | (5.1,34.5) | (304.2,-58.8),(-79.2,-327)
+ (-2,2),(-8,-10)     | (10,10)    | (20,0),(-40,-180)
+ (2.5,3.5),(2.5,2.5) | (5.1,34.5) | (-73.5,104.1),(-108,99)
+ (2.5,3.5),(2.5,2.5) | (10,10)    | (0,60),(-10,50)
+ (3,3),(3,3)         | (5.1,34.5) | (-88.2,118.8),(-88.2,118.8)
+ (3,3),(3,3)         | (10,10)    | (0,60),(0,60)
+(10 rows)
 
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,-0),(-0.2,-0.2)
-        | (0.08,-0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (-0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
+-- Overflow error
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] > 1000;
+         f1          |        f1         |                  ?column?                  
+---------------------+-------------------+--------------------------------------------
+ (2,2),(0,0)         | (1e+300,Infinity) | (NaN,NaN),(-Infinity,Infinity)
+ (2,2),(0,0)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (3,3),(1,1)         | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (3,3),(1,1)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (-2,2),(-8,-10)     | (1e+300,Infinity) | (Infinity,-Infinity),(-Infinity,-Infinity)
+ (-2,2),(-8,-10)     | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (2.5,3.5),(2.5,2.5) | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (2.5,3.5),(2.5,2.5) | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (3,3),(3,3)         | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (3,3),(3,3)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+(10 rows)
 
+-- Divide by point
+SELECT b.f1, p.f1, b.f1 / p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+         f1          |     f1     |                               ?column?                               
+---------------------+------------+----------------------------------------------------------------------
+ (2,2),(0,0)         | (5.1,34.5) | (0.0651176557644,0),(0,-0.0483449262493)
+ (2,2),(0,0)         | (10,10)    | (0.2,0),(0,0)
+ (3,3),(1,1)         | (5.1,34.5) | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
+ (3,3),(1,1)         | (10,10)    | (0.3,0),(0.1,0)
+ (-2,2),(-8,-10)     | (5.1,34.5) | (0.0483449262493,0.18499334024),(-0.317201914064,0.0651176557644)
+ (-2,2),(-8,-10)     | (10,10)    | (0,0.2),(-0.9,-0.1)
+ (2.5,3.5),(2.5,2.5) | (5.1,34.5) | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
+ (2.5,3.5),(2.5,2.5) | (10,10)    | (0.3,0.05),(0.25,0)
+ (3,3),(3,3)         | (5.1,34.5) | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
+ (3,3),(3,3)         | (10,10)    | (0.3,0),(0.3,0)
+(10 rows)
+
+-- To box
 SELECT f1::box
 	FROM POINT_TBL;
-          f1           
------------------------
+                 f1                  
+-------------------------------------
  (0,0),(0,0)
  (-10,0),(-10,0)
  (-3,4),(-3,4)
  (5.1,34.5),(5.1,34.5)
  (-5,-12),(-5,-12)
+ (1e-300,-1e-300),(1e-300,-1e-300)
+ (1e+300,Infinity),(1e+300,Infinity)
+ (NaN,NaN),(NaN,NaN)
  (10,10),(10,10)
-(6 rows)
+(9 rows)
 
 SELECT bound_box(a.f1, b.f1)
 	FROM BOX_TBL a, BOX_TBL b;
       bound_box      
 ---------------------
  (2,2),(0,0)
  (3,3),(0,0)
+ (2,2),(-8,-10)
  (2.5,3.5),(0,0)
  (3,3),(0,0)
  (3,3),(0,0)
  (3,3),(1,1)
+ (3,3),(-8,-10)
  (3,3.5),(1,1)
  (3,3),(1,1)
+ (2,2),(-8,-10)
+ (3,3),(-8,-10)
+ (-2,2),(-8,-10)
+ (2.5,3.5),(-8,-10)
+ (3,3),(-8,-10)
  (2.5,3.5),(0,0)
  (3,3.5),(1,1)
+ (2.5,3.5),(-8,-10)
  (2.5,3.5),(2.5,2.5)
  (3,3.5),(2.5,2.5)
  (3,3),(0,0)
  (3,3),(1,1)
+ (3,3),(-8,-10)
  (3,3.5),(2.5,2.5)
  (3,3),(3,3)
-(16 rows)
+(25 rows)
+
+-- Below box
+SELECT b1.f1, b2.f1, b1.f1 <^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          | ?column? 
+---------------------+---------------------+----------
+ (2,2),(0,0)         | (2,2),(0,0)         | f
+ (2,2),(0,0)         | (3,3),(1,1)         | f
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | f
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | t
+ (2,2),(0,0)         | (3,3),(3,3)         | t
+ (3,3),(1,1)         | (2,2),(0,0)         | f
+ (3,3),(1,1)         | (3,3),(1,1)         | f
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | f
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(1,1)         | (3,3),(3,3)         | t
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | f
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | f
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | f
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | t
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | t
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | f
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | f
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | f
+ (3,3),(3,3)         | (2,2),(0,0)         | f
+ (3,3),(3,3)         | (3,3),(1,1)         | f
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | f
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(3,3)         | (3,3),(3,3)         | t
+(25 rows)
+
+-- Above box
+SELECT b1.f1, b2.f1, b1.f1 >^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          | ?column? 
+---------------------+---------------------+----------
+ (2,2),(0,0)         | (2,2),(0,0)         | f
+ (2,2),(0,0)         | (3,3),(1,1)         | f
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | f
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | f
+ (2,2),(0,0)         | (3,3),(3,3)         | f
+ (3,3),(1,1)         | (2,2),(0,0)         | f
+ (3,3),(1,1)         | (3,3),(1,1)         | f
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | f
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(1,1)         | (3,3),(3,3)         | f
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | f
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | f
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | f
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | f
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | f
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | t
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | f
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | t
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | f
+ (3,3),(3,3)         | (2,2),(0,0)         | t
+ (3,3),(3,3)         | (3,3),(1,1)         | t
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | t
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(3,3)         | (3,3),(3,3)         | t
+(25 rows)
+
+-- Intersection point with box
+SELECT b1.f1, b2.f1, b1.f1 # b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          |      ?column?       
+---------------------+---------------------+---------------------
+ (2,2),(0,0)         | (2,2),(0,0)         | (2,2),(0,0)
+ (2,2),(0,0)         | (3,3),(1,1)         | (2,2),(1,1)
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | 
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | 
+ (2,2),(0,0)         | (3,3),(3,3)         | 
+ (3,3),(1,1)         | (2,2),(0,0)         | (2,2),(1,1)
+ (3,3),(1,1)         | (3,3),(1,1)         | (3,3),(1,1)
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | 
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | (2.5,3),(2.5,2.5)
+ (3,3),(1,1)         | (3,3),(3,3)         | (3,3),(3,3)
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | 
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | 
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | (-2,2),(-8,-10)
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | 
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | 
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | 
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | (2.5,3),(2.5,2.5)
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | 
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5)
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | 
+ (3,3),(3,3)         | (2,2),(0,0)         | 
+ (3,3),(3,3)         | (3,3),(1,1)         | (3,3),(3,3)
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | 
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | 
+ (3,3),(3,3)         | (3,3),(3,3)         | (3,3),(3,3)
+(25 rows)
+
+-- Diagonal
+SELECT f1, diagonal(f1) FROM BOX_TBL;
+         f1          |       diagonal        
+---------------------+-----------------------
+ (2,2),(0,0)         | [(2,2),(0,0)]
+ (3,3),(1,1)         | [(3,3),(1,1)]
+ (-2,2),(-8,-10)     | [(-2,2),(-8,-10)]
+ (2.5,3.5),(2.5,2.5) | [(2.5,3.5),(2.5,2.5)]
+ (3,3),(3,3)         | [(3,3),(3,3)]
+(5 rows)
+
+-- Distance to box
+SELECT b1.f1, b2.f1, b1.f1 <-> b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          |   ?column?    
+---------------------+---------------------+---------------
+ (2,2),(0,0)         | (2,2),(0,0)         |             0
+ (2,2),(0,0)         | (3,3),(1,1)         | 1.41421356237
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | 7.81024967591
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) |           2.5
+ (2,2),(0,0)         | (3,3),(3,3)         | 2.82842712475
+ (3,3),(1,1)         | (2,2),(0,0)         | 1.41421356237
+ (3,3),(1,1)         | (3,3),(1,1)         |             0
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | 9.21954445729
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | 1.11803398875
+ (3,3),(1,1)         | (3,3),(3,3)         | 1.41421356237
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | 7.81024967591
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | 9.21954445729
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     |             0
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | 10.2591422643
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | 10.6301458127
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         |           2.5
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | 1.11803398875
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | 10.2591422643
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) |             0
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         |           0.5
+ (3,3),(3,3)         | (2,2),(0,0)         | 2.82842712475
+ (3,3),(3,3)         | (3,3),(1,1)         | 1.41421356237
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | 10.6301458127
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) |           0.5
+ (3,3),(3,3)         | (3,3),(3,3)         |             0
+(25 rows)
 
 --
 -- Paths
 --
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
+-- Points
+SELECT f1, npoints(f1) FROM PATH_TBL;
+            f1             | npoints 
+---------------------------+---------
+ [(1,2),(3,4)]             |       2
+ ((1,2),(3,4))             |       2
+ [(0,0),(3,0),(4,5),(1,6)] |       4
+ ((1,2),(3,4))             |       2
+ ((1,2),(3,4))             |       2
+ [(1,2),(3,4)]             |       2
+ ((10,20))                 |       1
+ [(11,12),(13,14)]         |       2
+ ((11,12),(13,14))         |       2
+(9 rows)
 
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
+-- Area
+SELECT f1, area(f1) FROM PATH_TBL;
+            f1             | area 
+---------------------------+------
+ [(1,2),(3,4)]             |     
+ ((1,2),(3,4))             |    0
+ [(0,0),(3,0),(4,5),(1,6)] |     
+ ((1,2),(3,4))             |    0
+ ((1,2),(3,4))             |    0
+ [(1,2),(3,4)]             |     
+ ((10,20))                 |    0
+ [(11,12),(13,14)]         |     
+ ((11,12),(13,14))         |    0
+(9 rows)
 
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
+-- Length
+SELECT f1, @-@ f1 FROM PATH_TBL;
+            f1             |   ?column?    
+---------------------------+---------------
+ [(1,2),(3,4)]             | 2.82842712475
+ ((1,2),(3,4))             | 5.65685424949
+ [(0,0),(3,0),(4,5),(1,6)] | 11.2612971738
+ ((1,2),(3,4))             | 5.65685424949
+ ((1,2),(3,4))             | 5.65685424949
+ [(1,2),(3,4)]             | 2.82842712475
+ ((10,20))                 |             0
+ [(11,12),(13,14)]         | 2.82842712475
+ ((11,12),(13,14))         | 5.65685424949
+(9 rows)
 
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
+-- Center
+SELECT f1, @@ f1 FROM PATH_TBL;
+ERROR:  function "path_center" not implemented
+-- To polygon
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isclosed(f1);
+        f1         |        f1         
+-------------------+-------------------
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((10,20))         | ((10,20))
+ ((11,12),(13,14)) | ((11,12),(13,14))
+(5 rows)
+
+-- Open path cannot be converted to polygon error
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isopen(f1);
+ERROR:  open path cannot be converted to polygon
+-- Has points less than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 < p2.f1;
+        f1         |            f1             
+-------------------+---------------------------
+ [(1,2),(3,4)]     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]     | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))         | [(1,2),(3,4)]
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | [(1,2),(3,4)]
+ ((10,20))         | [(11,12),(13,14)]
+ ((10,20))         | ((11,12),(13,14))
+ [(11,12),(13,14)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((11,12),(13,14)) | [(0,0),(3,0),(4,5),(1,6)]
+(15 rows)
+
+-- Has points less than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 <= p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | [(1,2),(3,4)]
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | [(1,2),(3,4)]
+ ((10,20))                 | ((10,20))
+ ((10,20))                 | [(11,12),(13,14)]
+ ((10,20))                 | ((11,12),(13,14))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(66 rows)
+
+-- Has points equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 = p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | ((10,20))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(51 rows)
+
+-- Has points greater than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 >= p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | ((10,20))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((10,20))
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((10,20))
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(66 rows)
+
+-- Has points greater than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 > p2.f1;
+            f1             |        f1         
+---------------------------+-------------------
+ [(1,2),(3,4)]             | ((10,20))
+ ((1,2),(3,4))             | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | ((10,20))
+ [(1,2),(3,4)]             | ((10,20))
+ [(11,12),(13,14)]         | ((10,20))
+ ((11,12),(13,14))         | ((10,20))
+(15 rows)
+
+-- Add path
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+            f1             |            f1             |                     ?column?                      
+---------------------------+---------------------------+---------------------------------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4),(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))                 | 
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         | [(1,2),(3,4),(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6),(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6),(0,0),(3,0),(4,5),(1,6)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6),(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))                 | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6),(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4),(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))                 | 
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         | [(1,2),(3,4),(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))         | 
+ ((10,20))                 | [(1,2),(3,4)]             | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | [(1,2),(3,4)]             | 
+ ((10,20))                 | ((10,20))                 | 
+ ((10,20))                 | [(11,12),(13,14)]         | 
+ ((10,20))                 | ((11,12),(13,14))         | 
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             | [(11,12),(13,14),(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14),(0,0),(3,0),(4,5),(1,6)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             | [(11,12),(13,14),(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((10,20))                 | 
+ [(11,12),(13,14)]         | [(11,12),(13,14)]         | [(11,12),(13,14),(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))         | 
+ ((11,12),(13,14))         | [(1,2),(3,4)]             | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | [(1,2),(3,4)]             | 
+ ((11,12),(13,14))         | ((10,20))                 | 
+ ((11,12),(13,14))         | [(11,12),(13,14)]         | 
+ ((11,12),(13,14))         | ((11,12),(13,14))         | 
+(81 rows)
+
+-- Add point
+SELECT p.f1, p1.f1, p.f1 + p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                                 ?column?                                  
+---------------------------+-------------------+---------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((10,20))                 | (0,0)             | ((10,20))
+ [(11,12),(13,14)]         | (0,0)             | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (0,0)             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (-10,0)           | [(-9,2),(-7,4)]
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(-10,0),(-7,0),(-6,5),(-9,6)]
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ [(1,2),(3,4)]             | (-10,0)           | [(-9,2),(-7,4)]
+ ((10,20))                 | (-10,0)           | ((0,20))
+ [(11,12),(13,14)]         | (-10,0)           | [(1,12),(3,14)]
+ ((11,12),(13,14))         | (-10,0)           | ((1,12),(3,14))
+ [(1,2),(3,4)]             | (-3,4)            | [(-2,6),(0,8)]
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(-3,4),(0,4),(1,9),(-2,10)]
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ [(1,2),(3,4)]             | (-3,4)            | [(-2,6),(0,8)]
+ ((10,20))                 | (-3,4)            | ((7,24))
+ [(11,12),(13,14)]         | (-3,4)            | [(8,16),(10,18)]
+ ((11,12),(13,14))         | (-3,4)            | ((8,16),(10,18))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(6.1,36.5),(8.1,38.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(5.1,34.5),(8.1,34.5),(9.1,39.5),(6.1,40.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(6.1,36.5),(8.1,38.5)]
+ ((10,20))                 | (5.1,34.5)        | ((15.1,54.5))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(16.1,46.5),(18.1,48.5)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((16.1,46.5),(18.1,48.5))
+ [(1,2),(3,4)]             | (-5,-12)          | [(-4,-10),(-2,-8)]
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(-5,-12),(-2,-12),(-1,-7),(-4,-6)]
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ [(1,2),(3,4)]             | (-5,-12)          | [(-4,-10),(-2,-8)]
+ ((10,20))                 | (-5,-12)          | ((5,8))
+ [(11,12),(13,14)]         | (-5,-12)          | [(6,0),(8,2)]
+ ((11,12),(13,14))         | (-5,-12)          | ((6,0),(8,2))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(1e-300,-1e-300),(3,-1e-300),(4,5),(1,6)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((10,20))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity),(1e+300,Infinity),(1e+300,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((1e+300,Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(11,12),(13,14)]
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(10,10),(13,10),(14,15),(11,16)]
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (10,10)           | [(11,12),(13,14)]
+ ((10,20))                 | (10,10)           | ((20,30))
+ [(11,12),(13,14)]         | (10,10)           | [(21,22),(23,24)]
+ ((11,12),(13,14))         | (10,10)           | ((21,22),(23,24))
+(81 rows)
+
+-- Subtract point
+SELECT p.f1, p1.f1, p.f1 - p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                                     ?column?                                      
+---------------------------+-------------------+-----------------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((10,20))                 | (0,0)             | ((10,20))
+ [(11,12),(13,14)]         | (0,0)             | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (0,0)             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (-10,0)           | [(11,2),(13,4)]
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(10,0),(13,0),(14,5),(11,6)]
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ [(1,2),(3,4)]             | (-10,0)           | [(11,2),(13,4)]
+ ((10,20))                 | (-10,0)           | ((20,20))
+ [(11,12),(13,14)]         | (-10,0)           | [(21,12),(23,14)]
+ ((11,12),(13,14))         | (-10,0)           | ((21,12),(23,14))
+ [(1,2),(3,4)]             | (-3,4)            | [(4,-2),(6,0)]
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(3,-4),(6,-4),(7,1),(4,2)]
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ [(1,2),(3,4)]             | (-3,4)            | [(4,-2),(6,0)]
+ ((10,20))                 | (-3,4)            | ((13,16))
+ [(11,12),(13,14)]         | (-3,4)            | [(14,8),(16,10)]
+ ((11,12),(13,14))         | (-3,4)            | ((14,8),(16,10))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-4.1,-32.5),(-2.1,-30.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(-5.1,-34.5),(-2.1,-34.5),(-1.1,-29.5),(-4.1,-28.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-4.1,-32.5),(-2.1,-30.5)]
+ ((10,20))                 | (5.1,34.5)        | ((4.9,-14.5))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(5.9,-22.5),(7.9,-20.5)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((5.9,-22.5),(7.9,-20.5))
+ [(1,2),(3,4)]             | (-5,-12)          | [(6,14),(8,16)]
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(5,12),(8,12),(9,17),(6,18)]
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ [(1,2),(3,4)]             | (-5,-12)          | [(6,14),(8,16)]
+ ((10,20))                 | (-5,-12)          | ((15,32))
+ [(11,12),(13,14)]         | (-5,-12)          | [(16,24),(18,26)]
+ ((11,12),(13,14))         | (-5,-12)          | ((16,24),(18,26))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(-1e-300,1e-300),(3,1e-300),(4,5),(1,6)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((10,20))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity),(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((-1e+300,-Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(-9,-8),(-7,-6)]
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(-10,-10),(-7,-10),(-6,-5),(-9,-4)]
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ [(1,2),(3,4)]             | (10,10)           | [(-9,-8),(-7,-6)]
+ ((10,20))                 | (10,10)           | ((0,10))
+ [(11,12),(13,14)]         | (10,10)           | [(1,2),(3,4)]
+ ((11,12),(13,14))         | (10,10)           | ((1,2),(3,4))
+(81 rows)
+
+-- Multiply with point
+SELECT p.f1, p1.f1, p.f1 * p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                               ?column?                               
+---------------------------+-------------------+----------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(0,0),(0,0)]
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(0,0),(0,0),(0,0)]
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ [(1,2),(3,4)]             | (0,0)             | [(0,0),(0,0)]
+ ((10,20))                 | (0,0)             | ((0,0))
+ [(11,12),(13,14)]         | (0,0)             | [(0,0),(0,0)]
+ ((11,12),(13,14))         | (0,0)             | ((0,0),(0,0))
+ [(1,2),(3,4)]             | (-10,0)           | [(-10,-20),(-30,-40)]
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(0,0),(-30,0),(-40,-50),(-10,-60)]
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ [(1,2),(3,4)]             | (-10,0)           | [(-10,-20),(-30,-40)]
+ ((10,20))                 | (-10,0)           | ((-100,-200))
+ [(11,12),(13,14)]         | (-10,0)           | [(-110,-120),(-130,-140)]
+ ((11,12),(13,14))         | (-10,0)           | ((-110,-120),(-130,-140))
+ [(1,2),(3,4)]             | (-3,4)            | [(-11,-2),(-25,0)]
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(0,0),(-9,12),(-32,1),(-27,-14)]
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ [(1,2),(3,4)]             | (-3,4)            | [(-11,-2),(-25,0)]
+ ((10,20))                 | (-3,4)            | ((-110,-20))
+ [(11,12),(13,14)]         | (-3,4)            | [(-81,8),(-95,10)]
+ ((11,12),(13,14))         | (-3,4)            | ((-81,8),(-95,10))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-63.9,44.7),(-122.7,123.9)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(0,0),(15.3,103.5),(-152.1,163.5),(-201.9,65.1)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-63.9,44.7),(-122.7,123.9)]
+ ((10,20))                 | (5.1,34.5)        | ((-639,447))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(-357.9,440.7),(-416.7,519.9)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((-357.9,440.7),(-416.7,519.9))
+ [(1,2),(3,4)]             | (-5,-12)          | [(19,-22),(33,-56)]
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(0,0),(-15,-36),(40,-73),(67,-42)]
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ [(1,2),(3,4)]             | (-5,-12)          | [(19,-22),(33,-56)]
+ ((10,20))                 | (-5,-12)          | ((190,-220))
+ [(11,12),(13,14)]         | (-5,-12)          | [(89,-192),(103,-226)]
+ ((11,12),(13,14))         | (-5,-12)          | ((89,-192),(103,-226))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(3e-300,1e-300),(7e-300,1e-300)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(0,0),(3e-300,-3e-300),(9e-300,1e-300),(7e-300,5e-300)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(3e-300,1e-300),(7e-300,1e-300)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((3e-299,1e-299))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(2.3e-299,1e-300),(2.7e-299,1e-300)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((2.3e-299,1e-300),(2.7e-299,1e-300))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(NaN,NaN),(NaN,Infinity),(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((-Infinity,Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(-10,30),(-10,70)]
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(0,0),(30,30),(-10,90),(-50,70)]
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ [(1,2),(3,4)]             | (10,10)           | [(-10,30),(-10,70)]
+ ((10,20))                 | (10,10)           | ((-100,300))
+ [(11,12),(13,14)]         | (10,10)           | [(-10,230),(-10,270)]
+ ((11,12),(13,14))         | (10,10)           | ((-10,230),(-10,270))
+(81 rows)
+
+-- Divide by point
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+            f1             |     f1     |                                                    ?column?                                                     
+---------------------------+------------+-----------------------------------------------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (5.1,34.5) | [(0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952)]
+ [(1,2),(3,4)]             | (10,10)    | [(0.15,0.05),(0.35,0.05)]
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5) | [(0,0),(0.0125795471363,-0.0850969365103),(0.158600957032,-0.0924966701199),(0.174387055399,-0.00320655123082)]
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)    | [(0,0),(0.15,-0.15),(0.45,0.05),(0.35,0.25)]
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ [(1,2),(3,4)]             | (5.1,34.5) | [(0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952)]
+ [(1,2),(3,4)]             | (10,10)    | [(0.15,0.05),(0.35,0.05)]
+ ((10,20))                 | (5.1,34.5) | ((0.609244733856,-0.199792807459))
+ ((10,20))                 | (10,10)    | ((1.5,0.5))
+ [(11,12),(13,14)]         | (5.1,34.5) | [(0.386512752208,-0.261703911993),(0.451630407972,-0.310048838242)]
+ [(11,12),(13,14)]         | (10,10)    | [(1.15,0.05),(1.35,0.05)]
+ ((11,12),(13,14))         | (5.1,34.5) | ((0.386512752208,-0.261703911993),(0.451630407972,-0.310048838242))
+ ((11,12),(13,14))         | (10,10)    | ((1.15,0.05),(1.35,0.05))
+(18 rows)
+
+-- Division by 0 error
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to path
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+            f1             |            f1             |    ?column?    
+---------------------------+---------------------------+----------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((10,20))                 |  17.4642491966
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         |   11.313708499
+ [(1,2),(3,4)]             | ((11,12),(13,14))         |   11.313708499
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)] |              0
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))                 |  16.1554944214
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]         |  9.89949493661
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))         |  9.89949493661
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((10,20))                 |  17.4642491966
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         |   11.313708499
+ [(1,2),(3,4)]             | ((11,12),(13,14))         |   11.313708499
+ ((10,20))                 | [(1,2),(3,4)]             |  17.4642491966
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)] |  16.1554944214
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | [(1,2),(3,4)]             |  17.4642491966
+ ((10,20))                 | ((10,20))                 |              0
+ ((10,20))                 | [(11,12),(13,14)]         |   6.7082039325
+ ((10,20))                 | ((11,12),(13,14))         |   6.7082039325
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             |   11.313708499
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)] |  9.89949493661
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             |   11.313708499
+ [(11,12),(13,14)]         | ((10,20))                 |   6.7082039325
+ [(11,12),(13,14)]         | [(11,12),(13,14)]         |              0
+ [(11,12),(13,14)]         | ((11,12),(13,14))         |              0
+ ((11,12),(13,14))         | [(1,2),(3,4)]             |   11.313708499
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)] |  9.89949493661
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | [(1,2),(3,4)]             |   11.313708499
+ ((11,12),(13,14))         | ((10,20))                 |   6.7082039325
+ ((11,12),(13,14))         | [(11,12),(13,14)]         |              0
+ ((11,12),(13,14))         | ((11,12),(13,14))         |              0
+(81 rows)
 
 --
 -- Polygons
 --
 -- containment
 SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
    FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
+ twentyfour |        f1         |             f1             | contains 
+------------+-------------------+----------------------------+----------
+            | (0,0)             | ((2,0),(2,4),(0,0))        | t
+            | (0,0)             | ((3,1),(3,3),(1,0))        | f
+            | (0,0)             | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (0,0)             | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (0,0)             | ((0,0))                    | t
+            | (0,0)             | ((0,1),(0,1))              | f
+            | (-10,0)           | ((2,0),(2,4),(0,0))        | f
+            | (-10,0)           | ((3,1),(3,3),(1,0))        | f
+            | (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-10,0)           | ((0,0))                    | f
+            | (-10,0)           | ((0,1),(0,1))              | f
+            | (-3,4)            | ((2,0),(2,4),(0,0))        | f
+            | (-3,4)            | ((3,1),(3,3),(1,0))        | f
+            | (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-3,4)            | ((0,0))                    | f
+            | (-3,4)            | ((0,1),(0,1))              | f
+            | (5.1,34.5)        | ((2,0),(2,4),(0,0))        | f
+            | (5.1,34.5)        | ((3,1),(3,3),(1,0))        | f
+            | (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (5.1,34.5)        | ((0,0))                    | f
+            | (5.1,34.5)        | ((0,1),(0,1))              | f
+            | (-5,-12)          | ((2,0),(2,4),(0,0))        | f
+            | (-5,-12)          | ((3,1),(3,3),(1,0))        | f
+            | (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-5,-12)          | ((0,0))                    | f
+            | (-5,-12)          | ((0,1),(0,1))              | f
+            | (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        | t
+            | (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        | f
+            | (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e-300,-1e-300)  | ((0,0))                    | t
+            | (1e-300,-1e-300)  | ((0,1),(0,1))              | f
+            | (1e+300,Infinity) | ((2,0),(2,4),(0,0))        | f
+            | (1e+300,Infinity) | ((3,1),(3,3),(1,0))        | f
+            | (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e+300,Infinity) | ((0,0))                    | f
+            | (1e+300,Infinity) | ((0,1),(0,1))              | f
+            | (NaN,NaN)         | ((2,0),(2,4),(0,0))        | t
+            | (NaN,NaN)         | ((3,1),(3,3),(1,0))        | t
+            | (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  | t
+            | (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  | t
+            | (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) | t
+            | (NaN,NaN)         | ((0,0))                    | t
+            | (NaN,NaN)         | ((0,1),(0,1))              | t
+            | (10,10)           | ((2,0),(2,4),(0,0))        | f
+            | (10,10)           | ((3,1),(3,3),(1,0))        | f
+            | (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (10,10)           | ((0,0))                    | f
+            | (10,10)           | ((0,1),(0,1))              | f
+(63 rows)
 
 SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
    FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
+ twentyfour |        f1         |             f1             | contained 
+------------+-------------------+----------------------------+-----------
+            | (0,0)             | ((2,0),(2,4),(0,0))        | t
+            | (0,0)             | ((3,1),(3,3),(1,0))        | f
+            | (0,0)             | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (0,0)             | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (0,0)             | ((0,0))                    | t
+            | (0,0)             | ((0,1),(0,1))              | f
+            | (-10,0)           | ((2,0),(2,4),(0,0))        | f
+            | (-10,0)           | ((3,1),(3,3),(1,0))        | f
+            | (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-10,0)           | ((0,0))                    | f
+            | (-10,0)           | ((0,1),(0,1))              | f
+            | (-3,4)            | ((2,0),(2,4),(0,0))        | f
+            | (-3,4)            | ((3,1),(3,3),(1,0))        | f
+            | (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-3,4)            | ((0,0))                    | f
+            | (-3,4)            | ((0,1),(0,1))              | f
+            | (5.1,34.5)        | ((2,0),(2,4),(0,0))        | f
+            | (5.1,34.5)        | ((3,1),(3,3),(1,0))        | f
+            | (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (5.1,34.5)        | ((0,0))                    | f
+            | (5.1,34.5)        | ((0,1),(0,1))              | f
+            | (-5,-12)          | ((2,0),(2,4),(0,0))        | f
+            | (-5,-12)          | ((3,1),(3,3),(1,0))        | f
+            | (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-5,-12)          | ((0,0))                    | f
+            | (-5,-12)          | ((0,1),(0,1))              | f
+            | (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        | t
+            | (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        | f
+            | (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e-300,-1e-300)  | ((0,0))                    | t
+            | (1e-300,-1e-300)  | ((0,1),(0,1))              | f
+            | (1e+300,Infinity) | ((2,0),(2,4),(0,0))        | f
+            | (1e+300,Infinity) | ((3,1),(3,3),(1,0))        | f
+            | (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e+300,Infinity) | ((0,0))                    | f
+            | (1e+300,Infinity) | ((0,1),(0,1))              | f
+            | (NaN,NaN)         | ((2,0),(2,4),(0,0))        | t
+            | (NaN,NaN)         | ((3,1),(3,3),(1,0))        | t
+            | (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  | t
+            | (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  | t
+            | (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) | t
+            | (NaN,NaN)         | ((0,0))                    | t
+            | (NaN,NaN)         | ((0,1),(0,1))              | t
+            | (10,10)           | ((2,0),(2,4),(0,0))        | f
+            | (10,10)           | ((3,1),(3,3),(1,0))        | f
+            | (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (10,10)           | ((0,0))                    | f
+            | (10,10)           | ((0,1),(0,1))              | f
+(63 rows)
 
 SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
    FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
+ four | npoints |          polygon           
+------+---------+----------------------------
       |       3 | ((2,0),(2,4),(0,0))
       |       3 | ((3,1),(3,3),(1,0))
+      |       4 | ((1,2),(3,4),(5,6),(7,8))
+      |       4 | ((7,8),(5,6),(3,4),(1,2))
+      |       4 | ((1,2),(7,8),(5,6),(3,-4))
       |       1 | ((0,0))
       |       2 | ((0,1),(0,1))
-(4 rows)
+(7 rows)
 
 SELECT '' AS four, polygon(f1)
    FROM BOX_TBL;
  four |                  polygon                  
 ------+-------------------------------------------
       | ((0,0),(0,2),(2,2),(2,0))
       | ((1,1),(1,3),(3,3),(3,1))
+      | ((-8,-10),(-8,2),(-2,2),(-2,-10))
       | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
       | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, polygon(f1)
    FROM PATH_TBL WHERE isclosed(f1);
  four |      polygon      
 ------+-------------------
       | ((1,2),(3,4))
       | ((1,2),(3,4))
       | ((1,2),(3,4))
+      | ((10,20))
       | ((11,12),(13,14))
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
    FROM PATH_TBL
    WHERE isopen(f1);
  four |         open_path         |          polygon          
 ------+---------------------------+---------------------------
       | [(1,2),(3,4)]             | ((1,2),(3,4))
       | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
       | [(1,2),(3,4)]             | ((1,2),(3,4))
       | [(11,12),(13,14)]         | ((11,12),(13,14))
 (4 rows)
 
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
+-- To box
+SELECT f1, f1::box FROM POLYGON_TBL;
+             f1             |      f1      
+----------------------------+--------------
+ ((2,0),(2,4),(0,0))        | (2,4),(0,0)
+ ((3,1),(3,3),(1,0))        | (3,3),(1,0)
+ ((1,2),(3,4),(5,6),(7,8))  | (7,8),(1,2)
+ ((7,8),(5,6),(3,4),(1,2))  | (7,8),(1,2)
+ ((1,2),(7,8),(5,6),(3,-4)) | (7,8),(1,-4)
+ ((0,0))                    | (0,0),(0,0)
+ ((0,1),(0,1))              | (0,1),(0,1)
+(7 rows)
 
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
+-- To path
+SELECT f1, f1::path FROM POLYGON_TBL;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(7 rows)
 
+-- Same as polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 ~= p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(9 rows)
+
+-- Contained by polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <@ p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(12 rows)
+
+-- Contains polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 @> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(12 rows)
+
+-- Overlap with polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 && p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(25 rows)
+
+-- Left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 << p2.f1;
+      f1       |             f1             
+---------------+----------------------------
+ ((0,0))       | ((3,1),(3,3),(1,0))
+ ((0,0))       | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))       | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))       | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1)) | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1)) | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1)) | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1)) | ((1,2),(7,8),(5,6),(3,-4))
+(8 rows)
+
+-- Overlap of left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &< p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))                    | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1))              | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(32 rows)
+
+-- Right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 >> p2.f1;
+             f1             |      f1       
+----------------------------+---------------
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((0,1),(0,1))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1))
+(8 rows)
+
+-- Overlap of right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((2,0),(2,4),(0,0))        | ((0,1),(0,1))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((0,1),(0,1))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((3,1),(3,3),(1,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(37 rows)
+
+-- Below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <<| p2.f1;
+      f1       |            f1             
+---------------+---------------------------
+ ((0,0))       | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))       | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))       | ((0,1),(0,1))
+ ((0,1),(0,1)) | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1)) | ((7,8),(5,6),(3,4),(1,2))
+(5 rows)
+
+-- Overlap or below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &<| p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))                    | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1))              | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(31 rows)
+
+-- Above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |>> p2.f1;
+            f1             |      f1       
+---------------------------+---------------
+ ((1,2),(3,4),(5,6),(7,8)) | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8)) | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2)) | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2)) | ((0,1),(0,1))
+ ((0,1),(0,1))             | ((0,0))
+(5 rows)
+
+-- Overlap or above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |&> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((3,1),(3,3),(1,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(32 rows)
+
+-- Distance to polygon
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2;
+ERROR:  function "poly_distance" not implemented
 --
 -- Circles
 --
 SELECT '' AS six, circle(f1, 50.0)
    FROM POINT_TBL;
- six |     circle      
------+-----------------
+ six |         circle         
+-----+------------------------
      | <(0,0),50>
      | <(-10,0),50>
      | <(-3,4),50>
      | <(5.1,34.5),50>
      | <(-5,-12),50>
+     | <(1e-300,-1e-300),50>
+     | <(1e+300,Infinity),50>
+     | <(NaN,NaN),50>
      | <(10,10),50>
-(6 rows)
+(9 rows)
 
 SELECT '' AS four, circle(f1)
    FROM BOX_TBL;
- four |        circle         
-------+-----------------------
+ four |         circle         
+------+------------------------
       | <(1,1),1.41421356237>
       | <(2,2),1.41421356237>
+      | <(-5,-4),6.7082039325>
       | <(2.5,3),0.5>
       | <(3,3),0>
-(4 rows)
+(5 rows)
 
 SELECT '' AS two, circle(f1)
    FROM POLYGON_TBL
    WHERE (# f1) >= 3;
  two |                    circle                     
 -----+-----------------------------------------------
      | <(1.33333333333,1.33333333333),2.04168905064>
      | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
+     | <(4,5),2.82842712475>
+     | <(4,5),2.82842712475>
+     | <(4,3),4.80664375676>
+(5 rows)
 
 SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
    FROM CIRCLE_TBL c1, POINT_TBL p1
    WHERE (p1.f1 <-> c1.f1) > 0
    ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
+ twentyfour |     circle     |       point       |   distance    
+------------+----------------+-------------------+---------------
+            | <(1,2),3>      | (-3,4)            |   1.472135955
+            | <(5,1),3>      | (0,0)             | 2.09901951359
+            | <(5,1),3>      | (1e-300,-1e-300)  | 2.09901951359
+            | <(5,1),3>      | (-3,4)            | 5.54400374532
+            | <(3,5),0>      | (0,0)             | 5.83095189485
+            | <(3,5),0>      | (1e-300,-1e-300)  | 5.83095189485
+            | <(3,5),0>      | (-3,4)            |  6.0827625303
+            | <(1,3),5>      | (-10,0)           | 6.40175425099
+            | <(1,3),5>      | (10,10)           | 6.40175425099
+            | <(5,1),3>      | (10,10)           | 7.29563014099
+            | <(1,2),3>      | (-10,0)           |  8.1803398875
+            | <(3,5),0>      | (10,10)           | 8.60232526704
+            | <(1,2),3>      | (10,10)           | 9.04159457879
+            | <(1,3),5>      | (-5,-12)          | 11.1554944214
+            | <(5,1),3>      | (-10,0)           | 12.0332963784
+            | <(1,2),3>      | (-5,-12)          | 12.2315462117
+            | <(5,1),3>      | (-5,-12)          | 13.4012194669
+            | <(3,5),0>      | (-10,0)           | 13.9283882772
+            | <(3,5),0>      | (-5,-12)          | 18.7882942281
+            | <(1,3),5>      | (5.1,34.5)        | 26.7657047773
+            | <(3,5),0>      | (5.1,34.5)        | 29.5746513082
+            | <(1,2),3>      | (5.1,34.5)        | 29.7575945393
+            | <(5,1),3>      | (5.1,34.5)        | 30.5001492534
+            | <(100,200),10> | (5.1,34.5)        | 180.778038568
+            | <(100,200),10> | (10,10)           | 200.237960416
+            | <(100,200),10> | (-3,4)            | 211.415898255
+            | <(100,200),10> | (0,0)             |  213.60679775
+            | <(100,200),10> | (1e-300,-1e-300)  |  213.60679775
+            | <(100,200),10> | (-10,0)           |  218.25424421
+            | <(100,200),10> | (-5,-12)          | 226.577682802
+            | <(3,5),0>      | (1e+300,Infinity) |      Infinity
+            | <(1,2),3>      | (1e+300,Infinity) |      Infinity
+            | <(5,1),3>      | (1e+300,Infinity) |      Infinity
+            | <(1,3),5>      | (1e+300,Infinity) |      Infinity
+            | <(100,200),10> | (1e+300,Infinity) |      Infinity
+            | <(1,2),100>    | (1e+300,Infinity) |      Infinity
+            | <(100,1),115>  | (1e+300,Infinity) |      Infinity
+            | <(3,5),0>      | (NaN,NaN)         |           NaN
+            | <(1,2),3>      | (NaN,NaN)         |           NaN
+            | <(5,1),3>      | (NaN,NaN)         |           NaN
+            | <(1,3),5>      | (NaN,NaN)         |           NaN
+            | <(100,200),10> | (NaN,NaN)         |           NaN
+            | <(1,2),100>    | (NaN,NaN)         |           NaN
+            | <(100,1),115>  | (NaN,NaN)         |           NaN
+            | <(3,5),NaN>    | (-10,0)           |           NaN
+            | <(3,5),NaN>    | (-5,-12)          |           NaN
+            | <(3,5),NaN>    | (-3,4)            |           NaN
+            | <(3,5),NaN>    | (0,0)             |           NaN
+            | <(3,5),NaN>    | (1e-300,-1e-300)  |           NaN
+            | <(3,5),NaN>    | (5.1,34.5)        |           NaN
+            | <(3,5),NaN>    | (10,10)           |           NaN
+            | <(3,5),NaN>    | (1e+300,Infinity) |           NaN
+            | <(3,5),NaN>    | (NaN,NaN)         |           NaN
+(53 rows)
+
+-- To polygon
+SELECT f1, f1::polygon FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+       f1       |                                                                                                          f1                                                                                                          
+----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ <(5,1),3>      | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
+ <(1,2),100>    | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
+ <(1,3),5>      | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
+ <(1,2),3>      | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
+ <(100,200),10> | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
+ <(100,1),115>  | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
+(6 rows)
+
+-- To polygon with less points
+SELECT f1, polygon(8, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+       f1       |                                                                             polygon                                                                              
+----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ <(5,1),3>      | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
+ <(1,2),100>    | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
+ <(1,3),5>      | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
+ <(1,2),3>      | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
+ <(100,200),10> | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
+ <(100,1),115>  | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
+(6 rows)
+
+-- Too less points error
+SELECT f1, polygon(1, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+ERROR:  must request at least 2 points
+-- Zero radius error
+SELECT f1, polygon(10, f1) FROM CIRCLE_TBL WHERE f1 < '<(0,0),1>';
+ERROR:  cannot convert circle with radius zero to polygon
+-- Same as circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 ~= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+ <(3,5),NaN>    | <(3,5),0>
+ <(3,5),NaN>    | <(3,5),NaN>
+(9 rows)
+
+-- Overlap with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 && c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,1),115>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(100,1),115>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(33 rows)
+
+-- Overlap or left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &< c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(28 rows)
+
+-- Left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 << c2.f1;
+    f1     |       f1       
+-----------+----------------
+ <(5,1),3> | <(100,200),10>
+ <(1,3),5> | <(100,200),10>
+ <(1,2),3> | <(100,200),10>
+ <(3,5),0> | <(100,200),10>
+(4 rows)
+
+-- Right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >> c2.f1;
+       f1       |    f1     
+----------------+-----------
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(3,5),0>
+(4 rows)
+
+-- Overlap or right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(28 rows)
+
+-- Contained by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <@ c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(17 rows)
+
+-- Contain by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 @> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(3,5),0>
+(17 rows)
+
+-- Below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <<| c2.f1;
+      f1       |       f1       
+---------------+----------------
+ <(5,1),3>     | <(100,200),10>
+ <(5,1),3>     | <(3,5),0>
+ <(1,2),100>   | <(100,200),10>
+ <(1,3),5>     | <(100,200),10>
+ <(1,2),3>     | <(100,200),10>
+ <(100,1),115> | <(100,200),10>
+ <(3,5),0>     | <(100,200),10>
+(7 rows)
+
+-- Above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |>> c2.f1;
+       f1       |      f1       
+----------------+---------------
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(3,5),0>      | <(5,1),3>
+(7 rows)
+
+-- Overlap or below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &<| c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Overlap or above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |&> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 = c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(9 rows)
+
+-- Area not equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 != c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(40 rows)
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 > c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(3,5),0>
+(20 rows)
+
+-- Area less than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area greater than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Add point
+SELECT c.f1, p.f1, c.f1 + p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |        ?column?         
+----------------+-------------------+-------------------------
+ <(5,1),3>      | (0,0)             | <(5,1),3>
+ <(1,2),100>    | (0,0)             | <(1,2),100>
+ <(1,3),5>      | (0,0)             | <(1,3),5>
+ <(1,2),3>      | (0,0)             | <(1,2),3>
+ <(100,200),10> | (0,0)             | <(100,200),10>
+ <(100,1),115>  | (0,0)             | <(100,1),115>
+ <(3,5),0>      | (0,0)             | <(3,5),0>
+ <(3,5),NaN>    | (0,0)             | <(3,5),NaN>
+ <(5,1),3>      | (-10,0)           | <(-5,1),3>
+ <(1,2),100>    | (-10,0)           | <(-9,2),100>
+ <(1,3),5>      | (-10,0)           | <(-9,3),5>
+ <(1,2),3>      | (-10,0)           | <(-9,2),3>
+ <(100,200),10> | (-10,0)           | <(90,200),10>
+ <(100,1),115>  | (-10,0)           | <(90,1),115>
+ <(3,5),0>      | (-10,0)           | <(-7,5),0>
+ <(3,5),NaN>    | (-10,0)           | <(-7,5),NaN>
+ <(5,1),3>      | (-3,4)            | <(2,5),3>
+ <(1,2),100>    | (-3,4)            | <(-2,6),100>
+ <(1,3),5>      | (-3,4)            | <(-2,7),5>
+ <(1,2),3>      | (-3,4)            | <(-2,6),3>
+ <(100,200),10> | (-3,4)            | <(97,204),10>
+ <(100,1),115>  | (-3,4)            | <(97,5),115>
+ <(3,5),0>      | (-3,4)            | <(0,9),0>
+ <(3,5),NaN>    | (-3,4)            | <(0,9),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(10.1,35.5),3>
+ <(1,2),100>    | (5.1,34.5)        | <(6.1,36.5),100>
+ <(1,3),5>      | (5.1,34.5)        | <(6.1,37.5),5>
+ <(1,2),3>      | (5.1,34.5)        | <(6.1,36.5),3>
+ <(100,200),10> | (5.1,34.5)        | <(105.1,234.5),10>
+ <(100,1),115>  | (5.1,34.5)        | <(105.1,35.5),115>
+ <(3,5),0>      | (5.1,34.5)        | <(8.1,39.5),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(8.1,39.5),NaN>
+ <(5,1),3>      | (-5,-12)          | <(0,-11),3>
+ <(1,2),100>    | (-5,-12)          | <(-4,-10),100>
+ <(1,3),5>      | (-5,-12)          | <(-4,-9),5>
+ <(1,2),3>      | (-5,-12)          | <(-4,-10),3>
+ <(100,200),10> | (-5,-12)          | <(95,188),10>
+ <(100,1),115>  | (-5,-12)          | <(95,-11),115>
+ <(3,5),0>      | (-5,-12)          | <(-2,-7),0>
+ <(3,5),NaN>    | (-5,-12)          | <(-2,-7),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(5,1),3>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(1,2),100>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(1,3),5>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(1,2),3>
+ <(100,200),10> | (1e-300,-1e-300)  | <(100,200),10>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(100,1),115>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(3,5),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(3,5),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(1e+300,Infinity),3>
+ <(1,2),100>    | (1e+300,Infinity) | <(1e+300,Infinity),100>
+ <(1,3),5>      | (1e+300,Infinity) | <(1e+300,Infinity),5>
+ <(1,2),3>      | (1e+300,Infinity) | <(1e+300,Infinity),3>
+ <(100,200),10> | (1e+300,Infinity) | <(1e+300,Infinity),10>
+ <(100,1),115>  | (1e+300,Infinity) | <(1e+300,Infinity),115>
+ <(3,5),0>      | (1e+300,Infinity) | <(1e+300,Infinity),0>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(1e+300,Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),100>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),5>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),10>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),115>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),0>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(15,11),3>
+ <(1,2),100>    | (10,10)           | <(11,12),100>
+ <(1,3),5>      | (10,10)           | <(11,13),5>
+ <(1,2),3>      | (10,10)           | <(11,12),3>
+ <(100,200),10> | (10,10)           | <(110,210),10>
+ <(100,1),115>  | (10,10)           | <(110,11),115>
+ <(3,5),0>      | (10,10)           | <(13,15),0>
+ <(3,5),NaN>    | (10,10)           | <(13,15),NaN>
+(72 rows)
+
+-- Subtract point
+SELECT c.f1, p.f1, c.f1 - p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |         ?column?          
+----------------+-------------------+---------------------------
+ <(5,1),3>      | (0,0)             | <(5,1),3>
+ <(1,2),100>    | (0,0)             | <(1,2),100>
+ <(1,3),5>      | (0,0)             | <(1,3),5>
+ <(1,2),3>      | (0,0)             | <(1,2),3>
+ <(100,200),10> | (0,0)             | <(100,200),10>
+ <(100,1),115>  | (0,0)             | <(100,1),115>
+ <(3,5),0>      | (0,0)             | <(3,5),0>
+ <(3,5),NaN>    | (0,0)             | <(3,5),NaN>
+ <(5,1),3>      | (-10,0)           | <(15,1),3>
+ <(1,2),100>    | (-10,0)           | <(11,2),100>
+ <(1,3),5>      | (-10,0)           | <(11,3),5>
+ <(1,2),3>      | (-10,0)           | <(11,2),3>
+ <(100,200),10> | (-10,0)           | <(110,200),10>
+ <(100,1),115>  | (-10,0)           | <(110,1),115>
+ <(3,5),0>      | (-10,0)           | <(13,5),0>
+ <(3,5),NaN>    | (-10,0)           | <(13,5),NaN>
+ <(5,1),3>      | (-3,4)            | <(8,-3),3>
+ <(1,2),100>    | (-3,4)            | <(4,-2),100>
+ <(1,3),5>      | (-3,4)            | <(4,-1),5>
+ <(1,2),3>      | (-3,4)            | <(4,-2),3>
+ <(100,200),10> | (-3,4)            | <(103,196),10>
+ <(100,1),115>  | (-3,4)            | <(103,-3),115>
+ <(3,5),0>      | (-3,4)            | <(6,1),0>
+ <(3,5),NaN>    | (-3,4)            | <(6,1),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(-0.1,-33.5),3>
+ <(1,2),100>    | (5.1,34.5)        | <(-4.1,-32.5),100>
+ <(1,3),5>      | (5.1,34.5)        | <(-4.1,-31.5),5>
+ <(1,2),3>      | (5.1,34.5)        | <(-4.1,-32.5),3>
+ <(100,200),10> | (5.1,34.5)        | <(94.9,165.5),10>
+ <(100,1),115>  | (5.1,34.5)        | <(94.9,-33.5),115>
+ <(3,5),0>      | (5.1,34.5)        | <(-2.1,-29.5),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(-2.1,-29.5),NaN>
+ <(5,1),3>      | (-5,-12)          | <(10,13),3>
+ <(1,2),100>    | (-5,-12)          | <(6,14),100>
+ <(1,3),5>      | (-5,-12)          | <(6,15),5>
+ <(1,2),3>      | (-5,-12)          | <(6,14),3>
+ <(100,200),10> | (-5,-12)          | <(105,212),10>
+ <(100,1),115>  | (-5,-12)          | <(105,13),115>
+ <(3,5),0>      | (-5,-12)          | <(8,17),0>
+ <(3,5),NaN>    | (-5,-12)          | <(8,17),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(5,1),3>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(1,2),100>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(1,3),5>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(1,2),3>
+ <(100,200),10> | (1e-300,-1e-300)  | <(100,200),10>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(100,1),115>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(3,5),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(3,5),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(-1e+300,-Infinity),3>
+ <(1,2),100>    | (1e+300,Infinity) | <(-1e+300,-Infinity),100>
+ <(1,3),5>      | (1e+300,Infinity) | <(-1e+300,-Infinity),5>
+ <(1,2),3>      | (1e+300,Infinity) | <(-1e+300,-Infinity),3>
+ <(100,200),10> | (1e+300,Infinity) | <(-1e+300,-Infinity),10>
+ <(100,1),115>  | (1e+300,Infinity) | <(-1e+300,-Infinity),115>
+ <(3,5),0>      | (1e+300,Infinity) | <(-1e+300,-Infinity),0>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(-1e+300,-Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),100>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),5>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),10>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),115>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),0>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(-5,-9),3>
+ <(1,2),100>    | (10,10)           | <(-9,-8),100>
+ <(1,3),5>      | (10,10)           | <(-9,-7),5>
+ <(1,2),3>      | (10,10)           | <(-9,-8),3>
+ <(100,200),10> | (10,10)           | <(90,190),10>
+ <(100,1),115>  | (10,10)           | <(90,-9),115>
+ <(3,5),0>      | (10,10)           | <(-7,-5),0>
+ <(3,5),NaN>    | (10,10)           | <(-7,-5),NaN>
+(72 rows)
+
+-- Multiply with point
+SELECT c.f1, p.f1, c.f1 * p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |                  ?column?                  
+----------------+-------------------+--------------------------------------------
+ <(5,1),3>      | (0,0)             | <(0,0),0>
+ <(1,2),100>    | (0,0)             | <(0,0),0>
+ <(1,3),5>      | (0,0)             | <(0,0),0>
+ <(1,2),3>      | (0,0)             | <(0,0),0>
+ <(100,200),10> | (0,0)             | <(0,0),0>
+ <(100,1),115>  | (0,0)             | <(0,0),0>
+ <(3,5),0>      | (0,0)             | <(0,0),0>
+ <(3,5),NaN>    | (0,0)             | <(0,0),NaN>
+ <(5,1),3>      | (-10,0)           | <(-50,-10),30>
+ <(1,2),100>    | (-10,0)           | <(-10,-20),1000>
+ <(1,3),5>      | (-10,0)           | <(-10,-30),50>
+ <(1,2),3>      | (-10,0)           | <(-10,-20),30>
+ <(100,200),10> | (-10,0)           | <(-1000,-2000),100>
+ <(100,1),115>  | (-10,0)           | <(-1000,-10),1150>
+ <(3,5),0>      | (-10,0)           | <(-30,-50),0>
+ <(3,5),NaN>    | (-10,0)           | <(-30,-50),NaN>
+ <(5,1),3>      | (-3,4)            | <(-19,17),15>
+ <(1,2),100>    | (-3,4)            | <(-11,-2),500>
+ <(1,3),5>      | (-3,4)            | <(-15,-5),25>
+ <(1,2),3>      | (-3,4)            | <(-11,-2),15>
+ <(100,200),10> | (-3,4)            | <(-1100,-200),50>
+ <(100,1),115>  | (-3,4)            | <(-304,397),575>
+ <(3,5),0>      | (-3,4)            | <(-29,-3),0>
+ <(3,5),NaN>    | (-3,4)            | <(-29,-3),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(-9,177.6),104.624758064>
+ <(1,2),100>    | (5.1,34.5)        | <(-63.9,44.7),3487.49193547>
+ <(1,3),5>      | (5.1,34.5)        | <(-98.4,49.8),174.374596774>
+ <(1,2),3>      | (5.1,34.5)        | <(-63.9,44.7),104.624758064>
+ <(100,200),10> | (5.1,34.5)        | <(-6390,4470),348.749193547>
+ <(100,1),115>  | (5.1,34.5)        | <(475.5,3455.1),4010.6157258>
+ <(3,5),0>      | (5.1,34.5)        | <(-157.2,129),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(-157.2,129),NaN>
+ <(5,1),3>      | (-5,-12)          | <(-13,-65),39>
+ <(1,2),100>    | (-5,-12)          | <(19,-22),1300>
+ <(1,3),5>      | (-5,-12)          | <(31,-27),65>
+ <(1,2),3>      | (-5,-12)          | <(19,-22),39>
+ <(100,200),10> | (-5,-12)          | <(1900,-2200),130>
+ <(100,1),115>  | (-5,-12)          | <(-488,-1205),1495>
+ <(3,5),0>      | (-5,-12)          | <(45,-61),0>
+ <(3,5),NaN>    | (-5,-12)          | <(45,-61),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(6e-300,-4e-300),4.24264068712e-300>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(3e-300,1e-300),1.41421356237e-298>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(4e-300,2e-300),7.07106781187e-300>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(3e-300,1e-300),4.24264068712e-300>
+ <(100,200),10> | (1e-300,-1e-300)  | <(3e-298,1e-298),1.41421356237e-299>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(1.01e-298,-9.9e-299),1.62634559673e-298>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(8e-300,2e-300),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(8e-300,2e-300),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,2),100>    | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,3),5>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,2),3>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(100,200),10> | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(100,1),115>  | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(3,5),0>      | (1e+300,Infinity) | <(-Infinity,Infinity),NaN>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(-Infinity,Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(40,60),42.4264068712>
+ <(1,2),100>    | (10,10)           | <(-10,30),1414.21356237>
+ <(1,3),5>      | (10,10)           | <(-20,40),70.7106781187>
+ <(1,2),3>      | (10,10)           | <(-10,30),42.4264068712>
+ <(100,200),10> | (10,10)           | <(-1000,3000),141.421356237>
+ <(100,1),115>  | (10,10)           | <(990,1010),1626.34559673>
+ <(3,5),0>      | (10,10)           | <(-20,80),0>
+ <(3,5),NaN>    | (10,10)           | <(-20,80),NaN>
+(72 rows)
+
+-- Divide by point
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+       f1       |     f1     |                       ?column?                       
+----------------+------------+------------------------------------------------------
+ <(5,1),3>      | (5.1,34.5) | <(0.0493315573973,-0.137635045138),0.0860217042937>
+ <(5,1),3>      | (10,10)    | <(0.3,-0.2),0.212132034356>
+ <(1,2),100>    | (5.1,34.5) | <(0.0609244733856,-0.0199792807459),2.86739014312>
+ <(1,2),100>    | (10,10)    | <(0.15,0.05),7.07106781187>
+ <(1,3),5>      | (5.1,34.5) | <(0.0892901188891,-0.0157860983671),0.143369507156>
+ <(1,3),5>      | (10,10)    | <(0.2,0.1),0.353553390593>
+ <(1,2),3>      | (5.1,34.5) | <(0.0609244733856,-0.0199792807459),0.0860217042937>
+ <(1,2),3>      | (10,10)    | <(0.15,0.05),0.212132034356>
+ <(100,200),10> | (5.1,34.5) | <(6.09244733856,-1.99792807459),0.286739014312>
+ <(100,200),10> | (10,10)    | <(15,5),0.707106781187>
+ <(100,1),115>  | (5.1,34.5) | <(0.44768388338,-2.83237136796),3.29749866459>
+ <(100,1),115>  | (10,10)    | <(5.05,-4.95),8.13172798365>
+ <(3,5),0>      | (5.1,34.5) | <(0.154407774653,-0.0641310246164),0>
+ <(3,5),0>      | (10,10)    | <(0.4,0.1),0>
+ <(3,5),NaN>    | (5.1,34.5) | <(0.154407774653,-0.0641310246164),NaN>
+ <(3,5),NaN>    | (10,10)    | <(0.4,0.1),NaN>
+(16 rows)
+
+-- Overflow error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] > 1000;
+ERROR:  value out of range: overflow
+-- Division by 0 error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to polygon
+SELECT c.f1, p.f1, c.f1 <-> p.f1 FROM CIRCLE_TBL c, POLYGON_TBL p;
+       f1       |             f1             |    ?column?    
+----------------+----------------------------+----------------
+ <(5,1),3>      | ((2,0),(2,4),(0,0))        |              0
+ <(5,1),3>      | ((3,1),(3,3),(1,0))        |              0
+ <(5,1),3>      | ((1,2),(3,4),(5,6),(7,8))  | 0.535533905933
+ <(5,1),3>      | ((7,8),(5,6),(3,4),(1,2))  | 0.535533905933
+ <(5,1),3>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(5,1),3>      | ((0,0))                    |  2.09901951359
+ <(5,1),3>      | ((0,1),(0,1))              |              2
+ <(1,2),100>    | ((2,0),(2,4),(0,0))        |              0
+ <(1,2),100>    | ((3,1),(3,3),(1,0))        |              0
+ <(1,2),100>    | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,2),100>    | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,2),100>    | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,2),100>    | ((0,0))                    |              0
+ <(1,2),100>    | ((0,1),(0,1))              |              0
+ <(1,3),5>      | ((2,0),(2,4),(0,0))        |              0
+ <(1,3),5>      | ((3,1),(3,3),(1,0))        |              0
+ <(1,3),5>      | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,3),5>      | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,3),5>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,3),5>      | ((0,0))                    |              0
+ <(1,3),5>      | ((0,1),(0,1))              |              0
+ <(1,2),3>      | ((2,0),(2,4),(0,0))        |              0
+ <(1,2),3>      | ((3,1),(3,3),(1,0))        |              0
+ <(1,2),3>      | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,2),3>      | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,2),3>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,2),3>      | ((0,0))                    |              0
+ <(1,2),3>      | ((0,1),(0,1))              |              0
+ <(100,200),10> | ((2,0),(2,4),(0,0))        |  209.134661795
+ <(100,200),10> | ((3,1),(3,3),(1,0))        |  209.585974051
+ <(100,200),10> | ((1,2),(3,4),(5,6),(7,8))  |  203.337760371
+ <(100,200),10> | ((7,8),(5,6),(3,4),(1,2))  |  203.337760371
+ <(100,200),10> | ((1,2),(7,8),(5,6),(3,-4)) |  203.337760371
+ <(100,200),10> | ((0,0))                    |   213.60679775
+ <(100,200),10> | ((0,1),(0,1))              |  212.712819568
+ <(100,1),115>  | ((2,0),(2,4),(0,0))        |              0
+ <(100,1),115>  | ((3,1),(3,3),(1,0))        |              0
+ <(100,1),115>  | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(100,1),115>  | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(100,1),115>  | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(100,1),115>  | ((0,0))                    |              0
+ <(100,1),115>  | ((0,1),(0,1))              |              0
+ <(3,5),0>      | ((2,0),(2,4),(0,0))        |  1.41421356237
+ <(3,5),0>      | ((3,1),(3,3),(1,0))        |              2
+ <(3,5),0>      | ((1,2),(3,4),(5,6),(7,8))  | 0.707106781187
+ <(3,5),0>      | ((7,8),(5,6),(3,4),(1,2))  | 0.707106781187
+ <(3,5),0>      | ((1,2),(7,8),(5,6),(3,-4)) | 0.707106781187
+ <(3,5),0>      | ((0,0))                    |  5.83095189485
+ <(3,5),0>      | ((0,1),(0,1))              |              5
+ <(3,5),NaN>    | ((2,0),(2,4),(0,0))        |            NaN
+ <(3,5),NaN>    | ((3,1),(3,3),(1,0))        |            NaN
+ <(3,5),NaN>    | ((1,2),(3,4),(5,6),(7,8))  |            NaN
+ <(3,5),NaN>    | ((7,8),(5,6),(3,4),(1,2))  |            NaN
+ <(3,5),NaN>    | ((1,2),(7,8),(5,6),(3,-4)) |            NaN
+ <(3,5),NaN>    | ((0,0))                    |            NaN
+ <(3,5),NaN>    | ((0,1),(0,1))              |            NaN
+(56 rows)
 
diff --git a/src/test/regress/expected/geometry_1.out b/src/test/regress/expected/geometry_1.out
deleted file mode 100644
index 3b92e23059..0000000000
--- a/src/test/regress/expected/geometry_1.out
+++ /dev/null
@@ -1,563 +0,0 @@
---
--- GEOMETRY
---
--- Back off displayed precision a little bit to reduce platform-to-platform
--- variation in results.
-SET extra_float_digits TO -3;
---
--- Points
---
-SELECT '' AS four, center(f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS four, (@@ f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS six, point(f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS six, (@@ f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS two, (@@ f1) AS center
-   FROM POLYGON_TBL
-   WHERE (# f1) > 2;
- two |            center             
------+-------------------------------
-     | (1.33333333333,1.33333333333)
-     | (2.33333333333,1.33333333333)
-(2 rows)
-
--- "is horizontal" function
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is horizontal" operator
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is vertical" function
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE isvertical(p1.f1, point '(5.1,34.5)');
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
--- "is vertical" operator
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?| point '(5.1,34.5)';
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
---
--- Line segments
---
--- intersection
-SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-   FROM LSEG_TBL l, POINT_TBL p;
-ERROR:  operator does not exist: lseg # point
-LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-                                           ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
-
---
--- Boxes
---
-SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
- six |                              box                               
------+----------------------------------------------------------------
-     | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
-     | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
-     | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
-     | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
-     | (107.071067812,207.071067812),(92.9289321881,192.928932188)
-     | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
-
--- translation
-SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (-8,2),(-10,0)
-            | (-7,3),(-9,1)
-            | (-7.5,3.5),(-7.5,2.5)
-            | (-7,3),(-7,3)
-            | (-1,6),(-3,4)
-            | (0,7),(-2,5)
-            | (-0.5,7.5),(-0.5,6.5)
-            | (0,7),(0,7)
-            | (7.1,36.5),(5.1,34.5)
-            | (8.1,37.5),(6.1,35.5)
-            | (7.6,38),(7.6,37)
-            | (8.1,37.5),(8.1,37.5)
-            | (-3,-10),(-5,-12)
-            | (-2,-9),(-4,-11)
-            | (-2.5,-8.5),(-2.5,-9.5)
-            | (-2,-9),(-2,-9)
-            | (12,12),(10,10)
-            | (13,13),(11,11)
-            | (12.5,13.5),(12.5,12.5)
-            | (13,13),(13,13)
-(24 rows)
-
-SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (12,2),(10,0)
-            | (13,3),(11,1)
-            | (12.5,3.5),(12.5,2.5)
-            | (13,3),(13,3)
-            | (5,-2),(3,-4)
-            | (6,-1),(4,-3)
-            | (5.5,-0.5),(5.5,-1.5)
-            | (6,-1),(6,-1)
-            | (-3.1,-32.5),(-5.1,-34.5)
-            | (-2.1,-31.5),(-4.1,-33.5)
-            | (-2.6,-31),(-2.6,-32)
-            | (-2.1,-31.5),(-2.1,-31.5)
-            | (7,14),(5,12)
-            | (8,15),(6,13)
-            | (7.5,15.5),(7.5,14.5)
-            | (8,15),(8,15)
-            | (-8,-8),(-10,-10)
-            | (-7,-7),(-9,-9)
-            | (-7.5,-6.5),(-7.5,-7.5)
-            | (-7,-7),(-7,-7)
-(24 rows)
-
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
-
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,0),(-0.2,-0.2)
-        | (0.08,0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
-
-SELECT f1::box
-	FROM POINT_TBL;
-          f1           
------------------------
- (0,0),(0,0)
- (-10,0),(-10,0)
- (-3,4),(-3,4)
- (5.1,34.5),(5.1,34.5)
- (-5,-12),(-5,-12)
- (10,10),(10,10)
-(6 rows)
-
-SELECT bound_box(a.f1, b.f1)
-	FROM BOX_TBL a, BOX_TBL b;
-      bound_box      
----------------------
- (2,2),(0,0)
- (3,3),(0,0)
- (2.5,3.5),(0,0)
- (3,3),(0,0)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(1,1)
- (3,3),(1,1)
- (2.5,3.5),(0,0)
- (3,3.5),(1,1)
- (2.5,3.5),(2.5,2.5)
- (3,3.5),(2.5,2.5)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(2.5,2.5)
- (3,3),(3,3)
-(16 rows)
-
---
--- Paths
---
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
-
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
-
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
-
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
-
---
--- Polygons
---
--- containment
-SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
-   FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
-      |       3 | ((2,0),(2,4),(0,0))
-      |       3 | ((3,1),(3,3),(1,0))
-      |       1 | ((0,0))
-      |       2 | ((0,1),(0,1))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM BOX_TBL;
- four |                  polygon                  
-------+-------------------------------------------
-      | ((0,0),(0,2),(2,2),(2,0))
-      | ((1,1),(1,3),(3,3),(3,1))
-      | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
-      | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM PATH_TBL WHERE isclosed(f1);
- four |      polygon      
-------+-------------------
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((11,12),(13,14))
-(4 rows)
-
-SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
-   FROM PATH_TBL
-   WHERE isopen(f1);
- four |         open_path         |          polygon          
-------+---------------------------+---------------------------
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(11,12),(13,14)]         | ((11,12),(13,14))
-(4 rows)
-
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
-
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
-
---
--- Circles
---
-SELECT '' AS six, circle(f1, 50.0)
-   FROM POINT_TBL;
- six |     circle      
------+-----------------
-     | <(0,0),50>
-     | <(-10,0),50>
-     | <(-3,4),50>
-     | <(5.1,34.5),50>
-     | <(-5,-12),50>
-     | <(10,10),50>
-(6 rows)
-
-SELECT '' AS four, circle(f1)
-   FROM BOX_TBL;
- four |        circle         
-------+-----------------------
-      | <(1,1),1.41421356237>
-      | <(2,2),1.41421356237>
-      | <(2.5,3),0.5>
-      | <(3,3),0>
-(4 rows)
-
-SELECT '' AS two, circle(f1)
-   FROM POLYGON_TBL
-   WHERE (# f1) >= 3;
- two |                    circle                     
------+-----------------------------------------------
-     | <(1.33333333333,1.33333333333),2.04168905064>
-     | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
-
-SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
-   FROM CIRCLE_TBL c1, POINT_TBL p1
-   WHERE (p1.f1 <-> c1.f1) > 0
-   ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
-
diff --git a/src/test/regress/expected/geometry_2.out b/src/test/regress/expected/geometry_2.out
deleted file mode 100644
index 5a922bcd3f..0000000000
--- a/src/test/regress/expected/geometry_2.out
+++ /dev/null
@@ -1,563 +0,0 @@
---
--- GEOMETRY
---
--- Back off displayed precision a little bit to reduce platform-to-platform
--- variation in results.
-SET extra_float_digits TO -3;
---
--- Points
---
-SELECT '' AS four, center(f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS four, (@@ f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS six, point(f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS six, (@@ f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS two, (@@ f1) AS center
-   FROM POLYGON_TBL
-   WHERE (# f1) > 2;
- two |            center             
------+-------------------------------
-     | (1.33333333333,1.33333333333)
-     | (2.33333333333,1.33333333333)
-(2 rows)
-
--- "is horizontal" function
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is horizontal" operator
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is vertical" function
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE isvertical(p1.f1, point '(5.1,34.5)');
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
--- "is vertical" operator
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?| point '(5.1,34.5)';
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
---
--- Line segments
---
--- intersection
-SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-   FROM LSEG_TBL l, POINT_TBL p;
-ERROR:  operator does not exist: lseg # point
-LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-                                           ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
-
---
--- Boxes
---
-SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
- six |                              box                               
------+----------------------------------------------------------------
-     | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
-     | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
-     | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
-     | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
-     | (107.071067812,207.071067812),(92.9289321881,192.928932188)
-     | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
-
--- translation
-SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (-8,2),(-10,0)
-            | (-7,3),(-9,1)
-            | (-7.5,3.5),(-7.5,2.5)
-            | (-7,3),(-7,3)
-            | (-1,6),(-3,4)
-            | (0,7),(-2,5)
-            | (-0.5,7.5),(-0.5,6.5)
-            | (0,7),(0,7)
-            | (7.1,36.5),(5.1,34.5)
-            | (8.1,37.5),(6.1,35.5)
-            | (7.6,38),(7.6,37)
-            | (8.1,37.5),(8.1,37.5)
-            | (-3,-10),(-5,-12)
-            | (-2,-9),(-4,-11)
-            | (-2.5,-8.5),(-2.5,-9.5)
-            | (-2,-9),(-2,-9)
-            | (12,12),(10,10)
-            | (13,13),(11,11)
-            | (12.5,13.5),(12.5,12.5)
-            | (13,13),(13,13)
-(24 rows)
-
-SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (12,2),(10,0)
-            | (13,3),(11,1)
-            | (12.5,3.5),(12.5,2.5)
-            | (13,3),(13,3)
-            | (5,-2),(3,-4)
-            | (6,-1),(4,-3)
-            | (5.5,-0.5),(5.5,-1.5)
-            | (6,-1),(6,-1)
-            | (-3.1,-32.5),(-5.1,-34.5)
-            | (-2.1,-31.5),(-4.1,-33.5)
-            | (-2.6,-31),(-2.6,-32)
-            | (-2.1,-31.5),(-2.1,-31.5)
-            | (7,14),(5,12)
-            | (8,15),(6,13)
-            | (7.5,15.5),(7.5,14.5)
-            | (8,15),(8,15)
-            | (-8,-8),(-10,-10)
-            | (-7,-7),(-9,-9)
-            | (-7.5,-6.5),(-7.5,-7.5)
-            | (-7,-7),(-7,-7)
-(24 rows)
-
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (-0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (-0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,-0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
-
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,-0),(-0.2,-0.2)
-        | (0.08,-0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (-0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
-
-SELECT f1::box
-	FROM POINT_TBL;
-          f1           
------------------------
- (0,0),(0,0)
- (-10,0),(-10,0)
- (-3,4),(-3,4)
- (5.1,34.5),(5.1,34.5)
- (-5,-12),(-5,-12)
- (10,10),(10,10)
-(6 rows)
-
-SELECT bound_box(a.f1, b.f1)
-	FROM BOX_TBL a, BOX_TBL b;
-      bound_box      
----------------------
- (2,2),(0,0)
- (3,3),(0,0)
- (2.5,3.5),(0,0)
- (3,3),(0,0)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(1,1)
- (3,3),(1,1)
- (2.5,3.5),(0,0)
- (3,3.5),(1,1)
- (2.5,3.5),(2.5,2.5)
- (3,3.5),(2.5,2.5)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(2.5,2.5)
- (3,3),(3,3)
-(16 rows)
-
---
--- Paths
---
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
-
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
-
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
-
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
-
---
--- Polygons
---
--- containment
-SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
-   FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
-      |       3 | ((2,0),(2,4),(0,0))
-      |       3 | ((3,1),(3,3),(1,0))
-      |       1 | ((0,0))
-      |       2 | ((0,1),(0,1))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM BOX_TBL;
- four |                  polygon                  
-------+-------------------------------------------
-      | ((0,0),(0,2),(2,2),(2,0))
-      | ((1,1),(1,3),(3,3),(3,1))
-      | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
-      | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM PATH_TBL WHERE isclosed(f1);
- four |      polygon      
-------+-------------------
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((11,12),(13,14))
-(4 rows)
-
-SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
-   FROM PATH_TBL
-   WHERE isopen(f1);
- four |         open_path         |          polygon          
-------+---------------------------+---------------------------
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(11,12),(13,14)]         | ((11,12),(13,14))
-(4 rows)
-
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
-
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
-
---
--- Circles
---
-SELECT '' AS six, circle(f1, 50.0)
-   FROM POINT_TBL;
- six |     circle      
------+-----------------
-     | <(0,0),50>
-     | <(-10,0),50>
-     | <(-3,4),50>
-     | <(5.1,34.5),50>
-     | <(-5,-12),50>
-     | <(10,10),50>
-(6 rows)
-
-SELECT '' AS four, circle(f1)
-   FROM BOX_TBL;
- four |        circle         
-------+-----------------------
-      | <(1,1),1.41421356237>
-      | <(2,2),1.41421356237>
-      | <(2.5,3),0.5>
-      | <(3,3),0>
-(4 rows)
-
-SELECT '' AS two, circle(f1)
-   FROM POLYGON_TBL
-   WHERE (# f1) >= 3;
- two |                    circle                     
------+-----------------------------------------------
-     | <(1.33333333333,1.33333333333),2.04168905064>
-     | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
-
-SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
-   FROM CIRCLE_TBL c1, POINT_TBL p1
-   WHERE (p1.f1 <-> c1.f1) > 0
-   ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
-
diff --git a/src/test/regress/expected/line.out b/src/test/regress/expected/line.out
index f20abdc430..02a10dbb78 100644
--- a/src/test/regress/expected/line.out
+++ b/src/test/regress/expected/line.out
@@ -1,271 +1,80 @@
 --
 -- LINE
 -- Infinite lines
 --
 --DROP TABLE LINE_TBL;
 CREATE TABLE LINE_TBL (s line);
-INSERT INTO LINE_TBL VALUES ('{1,-1,1}');
-INSERT INTO LINE_TBL VALUES ('(0,0),(6,6)');
+INSERT INTO LINE_TBL VALUES ('{0,-1,5}');	-- A == 0
+INSERT INTO LINE_TBL VALUES ('{1,0,5}');	-- B == 0
+INSERT INTO LINE_TBL VALUES ('{0,3,0}');	-- A == C == 0
+INSERT INTO LINE_TBL VALUES (' (0,0), (6,6)');
 INSERT INTO LINE_TBL VALUES ('10,-10 ,-5,-4');
 INSERT INTO LINE_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LINE_TBL VALUES ('(11,22,33,44)');
-INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
-ERROR:  invalid line specification: must be two distinct points
-LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
-                                     ^
+INSERT INTO LINE_TBL VALUES ('{3,NaN,5}');
+INSERT INTO LINE_TBL VALUES ('{NaN,NaN,NaN}');
 -- horizontal
 INSERT INTO LINE_TBL VALUES ('[(1,3),(2,3)]');
 -- vertical
-INSERT INTO LINE_TBL VALUES ('[(3,1),(3,2)]');
+INSERT INTO LINE_TBL VALUES (line(point '(3,1)', point '(3,2)'));
 -- bad values for parser testing
+INSERT INTO LINE_TBL VALUES ('{}');
+ERROR:  invalid input syntax for type line: "{}"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{}');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0');
+ERROR:  invalid input syntax for type line: "{0"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0,0}');
+ERROR:  invalid input syntax for type line: "{0,0}"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0}');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0,0,1');
+ERROR:  invalid input syntax for type line: "{0,0,1"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1');
+                                     ^
 INSERT INTO LINE_TBL VALUES ('{0,0,1}');
 ERROR:  invalid line specification: A and B cannot both be zero
 LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1}');
                                      ^
+INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
+ERROR:  invalid input syntax for type line: "{0,0,1} x"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
+                                     ^
 INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
 ERROR:  invalid input syntax for type line: "(3asdf,2 ,3,4r2)"
 LINE 1: INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
                                      ^
 INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
 ERROR:  invalid input syntax for type line: "[1,2,3, 4"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
                                      ^
 INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
 ERROR:  invalid input syntax for type line: "[(,2),(3,4)]"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
                                      ^
 INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
 ERROR:  invalid input syntax for type line: "[(1,2),(3,4)"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
                                      ^
+INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
+ERROR:  invalid line specification: must be two distinct points
+LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
+                                     ^
+INSERT INTO LINE_TBL VALUES (line(point '(1,0)', point '(1,0)'));
+ERROR:  invalid line specification: must be two distinct points
 select * from LINE_TBL;
                       s                      
 ---------------------------------------------
- {1,-1,1}
+ {0,-1,5}
+ {1,0,5}
+ {0,3,0}
  {1,-1,0}
  {-0.4,-1,-6}
  {-0.000184615384615385,-1,15.3846153846154}
- {1,-1,11}
+ {3,NaN,5}
+ {NaN,NaN,NaN}
  {0,-1,3}
  {-1,0,3}
-(7 rows)
-
--- functions and operators
-SELECT * FROM LINE_TBL WHERE (s <-> line '[(1,2),(3,4)]') < 10;
-                      s                      
----------------------------------------------
- {1,-1,1}
- {1,-1,0}
- {-0.4,-1,-6}
- {-0.000184615384615385,-1,15.3846153846154}
- {1,-1,11}
- {0,-1,3}
- {-1,0,3}
-(7 rows)
-
-SELECT * FROM LINE_TBL WHERE (point '(0.1,0.1)' <-> s) < 1;
-    s     
-----------
- {1,-1,1}
- {1,-1,0}
-(2 rows)
-
-SELECT * FROM LINE_TBL WHERE (lseg '[(0.1,0.1),(0.2,0.2)]' <-> s) < 1;
-    s     
-----------
- {1,-1,1}
- {1,-1,0}
-(2 rows)
-
-SELECT line '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
- ?column? 
-----------
-        2
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
- ?column? 
-----------
-        2
-(1 row)
-
-SELECT point '(-1,1)' <-> line '[(-3,0),(-4,0)]';
- ?column? 
-----------
-        1
-(1 row)
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(2,0),(0,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# box '(0,0,2,2)';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(3,0),(4,1)]' ?# box '(0,0,2,2)';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(1,1)' <@ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT point '(1,1)' <@ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(1,1)' @ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT point '(1,1)' @ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT lseg '[(1,1),(2,2)]' <@ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' <@ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT lseg '[(1,1),(2,2)]' @ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' @ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(0,1)' ## line '[(0,0),(1,1)]';
- ?column?  
------------
- (0.5,0.5)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ## lseg '[(1,0),(2,0)]';
- ?column? 
-----------
- (1,0)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(2,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(1,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(2,1)]';
- ?column? 
-----------
- 
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(1,1)]';
- ?column? 
-----------
- (1,1)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(2,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,0)]' ?-| line '[(0,0),(0,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?-| line '[(1,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT ?- line '[(0,0),(1,0)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT ?- line '[(0,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT ?| line '[(0,0),(0,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT ?| line '[(0,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line(point '(1,2)', point '(3,4)');
-   line   
-----------
- {1,-1,1}
-(1 row)
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,5)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,4)]';  -- false
- ?column? 
-----------
- f
-(1 row)
+(10 rows)
 
diff --git a/src/test/regress/expected/lseg.out b/src/test/regress/expected/lseg.out
index bba1f3ee80..7e878b5577 100644
--- a/src/test/regress/expected/lseg.out
+++ b/src/test/regress/expected/lseg.out
@@ -1,21 +1,24 @@
 --
 -- LSEG
 -- Line segments
 --
 --DROP TABLE LSEG_TBL;
 CREATE TABLE LSEG_TBL (s lseg);
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('(0,0),(6,6)');
 INSERT INTO LSEG_TBL VALUES ('10,-10 ,-3,-4');
 INSERT INTO LSEG_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LSEG_TBL VALUES ('(11,22,33,44)');
+INSERT INTO LSEG_TBL VALUES (lseg(point(11, 22), point(33,44)));
+INSERT INTO LSEG_TBL VALUES ('[(-10,2),(-10,3)]');	-- vertical
+INSERT INTO LSEG_TBL VALUES ('[(0,-20),(30,-20)]');	-- horizontal
+INSERT INTO LSEG_TBL VALUES ('[(NaN,1),(NaN,90)]');	-- NaN
 -- bad values for parser testing
 INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
 ERROR:  invalid input syntax for type lseg: "(3asdf,2 ,3,4r2)"
 LINE 1: INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
                                      ^
 INSERT INTO LSEG_TBL VALUES ('[1,2,3, 4');
 ERROR:  invalid input syntax for type lseg: "[1,2,3, 4"
 LINE 1: INSERT INTO LSEG_TBL VALUES ('[1,2,3, 4');
                                      ^
 INSERT INTO LSEG_TBL VALUES ('[(,2),(3,4)]');
@@ -27,26 +30,15 @@ ERROR:  invalid input syntax for type lseg: "[(1,2),(3,4)"
 LINE 1: INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)');
                                      ^
 select * from LSEG_TBL;
                s               
 -------------------------------
  [(1,2),(3,4)]
  [(0,0),(6,6)]
  [(10,-10),(-3,-4)]
  [(-1000000,200),(300000,-40)]
  [(11,22),(33,44)]
-(5 rows)
-
-SELECT * FROM LSEG_TBL WHERE s <= lseg '[(1,2),(3,4)]';
-       s       
----------------
- [(1,2),(3,4)]
-(1 row)
-
-SELECT * FROM LSEG_TBL WHERE (s <-> lseg '[(1,2),(3,4)]') < 10;
-         s          
---------------------
- [(1,2),(3,4)]
- [(0,0),(6,6)]
- [(10,-10),(-3,-4)]
-(3 rows)
+ [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]
+ [(NaN,1),(NaN,90)]
+(8 rows)
 
diff --git a/src/test/regress/expected/path.out b/src/test/regress/expected/path.out
index 08d6d61dda..bd6e467752 100644
--- a/src/test/regress/expected/path.out
+++ b/src/test/regress/expected/path.out
@@ -1,79 +1,82 @@
 --
 -- PATH
 --
 --DROP TABLE PATH_TBL;
 CREATE TABLE PATH_TBL (f1 path);
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)]');
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
-INSERT INTO PATH_TBL VALUES ('[(0,0),(3,0),(4,5),(1,6)]');
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
-INSERT INTO PATH_TBL VALUES ('1,2 ,3,4');
-INSERT INTO PATH_TBL VALUES ('[1,2,3, 4]');
-INSERT INTO PATH_TBL VALUES ('[11,12,13,14]');
-INSERT INTO PATH_TBL VALUES ('(11,12,13,14)');
+INSERT INTO PATH_TBL VALUES (' ( ( 1 , 2 ) , ( 3 , 4 ) ) ');
+INSERT INTO PATH_TBL VALUES ('[ (0,0),(3,0),(4,5),(1,6) ]');
+INSERT INTO PATH_TBL VALUES ('((1,2) ,(3,4 ))');
+INSERT INTO PATH_TBL VALUES ('1,2 ,3,4 ');
+INSERT INTO PATH_TBL VALUES (' [1,2,3, 4] ');
+INSERT INTO PATH_TBL VALUES ('((10,20))');	-- Only one point
+INSERT INTO PATH_TBL VALUES ('[ 11,12,13,14 ]');
+INSERT INTO PATH_TBL VALUES ('( 11,12,13,14) ');
 -- bad values for parser testing
+INSERT INTO PATH_TBL VALUES ('[]');
+ERROR:  invalid input syntax for type path: "[]"
+LINE 1: INSERT INTO PATH_TBL VALUES ('[]');
+                                     ^
 INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
 ERROR:  invalid input syntax for type path: "[(,2),(3,4)]"
 LINE 1: INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
                                      ^
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
 ERROR:  invalid input syntax for type path: "[(1,2),(3,4)"
 LINE 1: INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
                                      ^
-SELECT f1 FROM PATH_TBL;
-            f1             
----------------------------
- [(1,2),(3,4)]
- ((1,2),(3,4))
- [(0,0),(3,0),(4,5),(1,6)]
- ((1,2),(3,4))
- ((1,2),(3,4))
- [(1,2),(3,4)]
- [(11,12),(13,14)]
- ((11,12),(13,14))
-(8 rows)
-
+INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+ERROR:  invalid input syntax for type path: "(1,2,3,4"
+LINE 1: INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+                                     ^
+INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
+ERROR:  invalid input syntax for type path: "(1,2),(3,4)]"
+LINE 1: INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
+                                     ^
 SELECT '' AS count, f1 AS open_path FROM PATH_TBL WHERE isopen(f1);
  count |         open_path         
 -------+---------------------------
        | [(1,2),(3,4)]
        | [(0,0),(3,0),(4,5),(1,6)]
        | [(1,2),(3,4)]
        | [(11,12),(13,14)]
 (4 rows)
 
 SELECT '' AS count, f1 AS closed_path FROM PATH_TBL WHERE isclosed(f1);
  count |    closed_path    
 -------+-------------------
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
+       | ((10,20))
        | ((11,12),(13,14))
-(4 rows)
+(5 rows)
 
 SELECT '' AS count, pclose(f1) AS closed_path FROM PATH_TBL;
  count |        closed_path        
 -------+---------------------------
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((0,0),(3,0),(4,5),(1,6))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
+       | ((10,20))
        | ((11,12),(13,14))
        | ((11,12),(13,14))
-(8 rows)
+(9 rows)
 
 SELECT '' AS count, popen(f1) AS open_path FROM PATH_TBL;
  count |         open_path         
 -------+---------------------------
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
        | [(0,0),(3,0),(4,5),(1,6)]
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
+       | [(10,20)]
        | [(11,12),(13,14)]
        | [(11,12),(13,14)]
-(8 rows)
+(9 rows)
 
diff --git a/src/test/regress/expected/point.out b/src/test/regress/expected/point.out
index bfc0962749..c18e865370 100644
--- a/src/test/regress/expected/point.out
+++ b/src/test/regress/expected/point.out
@@ -1,43 +1,57 @@
 --
 -- POINT
 --
 CREATE TABLE POINT_TBL(f1 point);
 INSERT INTO POINT_TBL(f1) VALUES ('(0.0,0.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-10.0,0.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-3.0,4.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(5.1, 34.5)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-5.0,-12.0)');
+INSERT INTO POINT_TBL(f1) VALUES ('(1e-300,-1e-300)');	-- To underflow
+INSERT INTO POINT_TBL(f1) VALUES ('(1e+300,Inf)');		-- To overflow
+INSERT INTO POINT_TBL(f1) VALUES (' ( Nan , NaN ) ');
 -- bad format points
 INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
 ERROR:  invalid input syntax for type point: "asdfasdf"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
                                           ^
 INSERT INTO POINT_TBL(f1) VALUES ('10.0,10.0');
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
 ERROR:  invalid input syntax for type point: "(10.0 10.0)"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
                                           ^
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+ERROR:  invalid input syntax for type point: "(10.0, 10.0) x"
+LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+                                          ^
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
 ERROR:  invalid input syntax for type point: "(10.0,10.0"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
                                           ^
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');	-- Out of range
+ERROR:  "1e+500" is out of range for type double precision
+LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');
+                                          ^
 SELECT '' AS six, * FROM POINT_TBL;
- six |     f1     
------+------------
+ six |        f1         
+-----+-------------------
      | (0,0)
      | (-10,0)
      | (-3,4)
      | (5.1,34.5)
      | (-5,-12)
+     | (1e-300,-1e-300)
+     | (1e+300,Infinity)
+     | (NaN,NaN)
      | (10,10)
-(6 rows)
+(9 rows)
 
 -- left of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE p.f1 << '(0.0, 0.0)';
  three |    f1    
 -------+----------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
 (3 rows)
 
@@ -85,172 +99,282 @@ 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    
--------+----------
+ three |        f1         
+-------+-------------------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
-(3 rows)
+       | (1e-300,-1e-300)
+       | (1e+300,Infinity)
+       | (NaN,NaN)
+(6 rows)
 
 SELECT '' AS two, p.* FROM POINT_TBL p
    WHERE p.f1 <@ path '[(0,0),(-10,0),(-10,10)]';
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 SELECT '' AS three, p.* FROM POINT_TBL p
    WHERE not box '(0,0,100,100)' @> p.f1;
- three |    f1    
--------+----------
+ three |        f1         
+-------+-------------------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
-(3 rows)
+       | (1e-300,-1e-300)
+       | (1e+300,Infinity)
+       | (NaN,NaN)
+(6 rows)
 
 SELECT '' AS six, p.f1, p.f1 <-> point '(0,0)' AS dist
    FROM POINT_TBL p
    ORDER BY dist;
- six |     f1     |       dist       
------+------------+------------------
-     | (0,0)      |                0
-     | (-3,4)     |                5
-     | (-10,0)    |               10
-     | (-5,-12)   |               13
-     | (10,10)    |  14.142135623731
-     | (5.1,34.5) | 34.8749193547455
-(6 rows)
+ six |        f1         |         dist         
+-----+-------------------+----------------------
+     | (0,0)             |                    0
+     | (1e-300,-1e-300)  | 1.4142135623731e-300
+     | (-3,4)            |                    5
+     | (-10,0)           |                   10
+     | (-5,-12)          |                   13
+     | (10,10)           |      14.142135623731
+     | (5.1,34.5)        |     34.8749193547455
+     | (1e+300,Infinity) |             Infinity
+     | (NaN,NaN)         |                  NaN
+(9 rows)
 
 SELECT '' AS thirtysix, p1.f1 AS point1, p2.f1 AS point2, p1.f1 <-> p2.f1 AS dist
    FROM POINT_TBL p1, POINT_TBL p2
    ORDER BY dist, p1.f1[0], p2.f1[0];
- thirtysix |   point1   |   point2   |       dist       
------------+------------+------------+------------------
-           | (-10,0)    | (-10,0)    |                0
-           | (-5,-12)   | (-5,-12)   |                0
-           | (-3,4)     | (-3,4)     |                0
-           | (0,0)      | (0,0)      |                0
-           | (5.1,34.5) | (5.1,34.5) |                0
-           | (10,10)    | (10,10)    |                0
-           | (-3,4)     | (0,0)      |                5
-           | (0,0)      | (-3,4)     |                5
-           | (-10,0)    | (-3,4)     | 8.06225774829855
-           | (-3,4)     | (-10,0)    | 8.06225774829855
-           | (-10,0)    | (0,0)      |               10
-           | (0,0)      | (-10,0)    |               10
-           | (-10,0)    | (-5,-12)   |               13
-           | (-5,-12)   | (-10,0)    |               13
-           | (-5,-12)   | (0,0)      |               13
-           | (0,0)      | (-5,-12)   |               13
-           | (0,0)      | (10,10)    |  14.142135623731
-           | (10,10)    | (0,0)      |  14.142135623731
-           | (-3,4)     | (10,10)    | 14.3178210632764
-           | (10,10)    | (-3,4)     | 14.3178210632764
-           | (-5,-12)   | (-3,4)     | 16.1245154965971
-           | (-3,4)     | (-5,-12)   | 16.1245154965971
-           | (-10,0)    | (10,10)    | 22.3606797749979
-           | (10,10)    | (-10,0)    | 22.3606797749979
-           | (5.1,34.5) | (10,10)    | 24.9851956166046
-           | (10,10)    | (5.1,34.5) | 24.9851956166046
-           | (-5,-12)   | (10,10)    | 26.6270539113887
-           | (10,10)    | (-5,-12)   | 26.6270539113887
-           | (-3,4)     | (5.1,34.5) | 31.5572495632937
-           | (5.1,34.5) | (-3,4)     | 31.5572495632937
-           | (0,0)      | (5.1,34.5) | 34.8749193547455
-           | (5.1,34.5) | (0,0)      | 34.8749193547455
-           | (-10,0)    | (5.1,34.5) | 37.6597928831267
-           | (5.1,34.5) | (-10,0)    | 37.6597928831267
-           | (-5,-12)   | (5.1,34.5) | 47.5842410888311
-           | (5.1,34.5) | (-5,-12)   | 47.5842410888311
-(36 rows)
+ thirtysix |      point1       |      point2       |         dist         
+-----------+-------------------+-------------------+----------------------
+           | (-10,0)           | (-10,0)           |                    0
+           | (-5,-12)          | (-5,-12)          |                    0
+           | (-3,4)            | (-3,4)            |                    0
+           | (0,0)             | (0,0)             |                    0
+           | (1e-300,-1e-300)  | (1e-300,-1e-300)  |                    0
+           | (5.1,34.5)        | (5.1,34.5)        |                    0
+           | (10,10)           | (10,10)           |                    0
+           | (0,0)             | (1e-300,-1e-300)  | 1.4142135623731e-300
+           | (1e-300,-1e-300)  | (0,0)             | 1.4142135623731e-300
+           | (-3,4)            | (0,0)             |                    5
+           | (-3,4)            | (1e-300,-1e-300)  |                    5
+           | (0,0)             | (-3,4)            |                    5
+           | (1e-300,-1e-300)  | (-3,4)            |                    5
+           | (-10,0)           | (-3,4)            |     8.06225774829855
+           | (-3,4)            | (-10,0)           |     8.06225774829855
+           | (-10,0)           | (0,0)             |                   10
+           | (-10,0)           | (1e-300,-1e-300)  |                   10
+           | (0,0)             | (-10,0)           |                   10
+           | (1e-300,-1e-300)  | (-10,0)           |                   10
+           | (-10,0)           | (-5,-12)          |                   13
+           | (-5,-12)          | (-10,0)           |                   13
+           | (-5,-12)          | (0,0)             |                   13
+           | (-5,-12)          | (1e-300,-1e-300)  |                   13
+           | (0,0)             | (-5,-12)          |                   13
+           | (1e-300,-1e-300)  | (-5,-12)          |                   13
+           | (0,0)             | (10,10)           |      14.142135623731
+           | (1e-300,-1e-300)  | (10,10)           |      14.142135623731
+           | (10,10)           | (0,0)             |      14.142135623731
+           | (10,10)           | (1e-300,-1e-300)  |      14.142135623731
+           | (-3,4)            | (10,10)           |     14.3178210632764
+           | (10,10)           | (-3,4)            |     14.3178210632764
+           | (-5,-12)          | (-3,4)            |     16.1245154965971
+           | (-3,4)            | (-5,-12)          |     16.1245154965971
+           | (-10,0)           | (10,10)           |     22.3606797749979
+           | (10,10)           | (-10,0)           |     22.3606797749979
+           | (5.1,34.5)        | (10,10)           |     24.9851956166046
+           | (10,10)           | (5.1,34.5)        |     24.9851956166046
+           | (-5,-12)          | (10,10)           |     26.6270539113887
+           | (10,10)           | (-5,-12)          |     26.6270539113887
+           | (-3,4)            | (5.1,34.5)        |     31.5572495632937
+           | (5.1,34.5)        | (-3,4)            |     31.5572495632937
+           | (0,0)             | (5.1,34.5)        |     34.8749193547455
+           | (1e-300,-1e-300)  | (5.1,34.5)        |     34.8749193547455
+           | (5.1,34.5)        | (0,0)             |     34.8749193547455
+           | (5.1,34.5)        | (1e-300,-1e-300)  |     34.8749193547455
+           | (-10,0)           | (5.1,34.5)        |     37.6597928831267
+           | (5.1,34.5)        | (-10,0)           |     37.6597928831267
+           | (-5,-12)          | (5.1,34.5)        |     47.5842410888311
+           | (5.1,34.5)        | (-5,-12)          |     47.5842410888311
+           | (-10,0)           | (1e+300,Infinity) |             Infinity
+           | (-5,-12)          | (1e+300,Infinity) |             Infinity
+           | (-3,4)            | (1e+300,Infinity) |             Infinity
+           | (0,0)             | (1e+300,Infinity) |             Infinity
+           | (1e-300,-1e-300)  | (1e+300,Infinity) |             Infinity
+           | (5.1,34.5)        | (1e+300,Infinity) |             Infinity
+           | (10,10)           | (1e+300,Infinity) |             Infinity
+           | (1e+300,Infinity) | (-10,0)           |             Infinity
+           | (1e+300,Infinity) | (-5,-12)          |             Infinity
+           | (1e+300,Infinity) | (-3,4)            |             Infinity
+           | (1e+300,Infinity) | (0,0)             |             Infinity
+           | (1e+300,Infinity) | (1e-300,-1e-300)  |             Infinity
+           | (1e+300,Infinity) | (5.1,34.5)        |             Infinity
+           | (1e+300,Infinity) | (10,10)           |             Infinity
+           | (-10,0)           | (NaN,NaN)         |                  NaN
+           | (-5,-12)          | (NaN,NaN)         |                  NaN
+           | (-3,4)            | (NaN,NaN)         |                  NaN
+           | (0,0)             | (NaN,NaN)         |                  NaN
+           | (1e-300,-1e-300)  | (NaN,NaN)         |                  NaN
+           | (5.1,34.5)        | (NaN,NaN)         |                  NaN
+           | (10,10)           | (NaN,NaN)         |                  NaN
+           | (1e+300,Infinity) | (1e+300,Infinity) |                  NaN
+           | (1e+300,Infinity) | (NaN,NaN)         |                  NaN
+           | (NaN,NaN)         | (-10,0)           |                  NaN
+           | (NaN,NaN)         | (-5,-12)          |                  NaN
+           | (NaN,NaN)         | (-3,4)            |                  NaN
+           | (NaN,NaN)         | (0,0)             |                  NaN
+           | (NaN,NaN)         | (1e-300,-1e-300)  |                  NaN
+           | (NaN,NaN)         | (5.1,34.5)        |                  NaN
+           | (NaN,NaN)         | (10,10)           |                  NaN
+           | (NaN,NaN)         | (1e+300,Infinity) |                  NaN
+           | (NaN,NaN)         | (NaN,NaN)         |                  NaN
+(81 rows)
 
 SELECT '' AS thirty, p1.f1 AS point1, p2.f1 AS point2
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3;
- thirty |   point1   |   point2   
---------+------------+------------
-        | (0,0)      | (-10,0)
-        | (0,0)      | (-3,4)
-        | (0,0)      | (5.1,34.5)
-        | (0,0)      | (-5,-12)
-        | (0,0)      | (10,10)
-        | (-10,0)    | (0,0)
-        | (-10,0)    | (-3,4)
-        | (-10,0)    | (5.1,34.5)
-        | (-10,0)    | (-5,-12)
-        | (-10,0)    | (10,10)
-        | (-3,4)     | (0,0)
-        | (-3,4)     | (-10,0)
-        | (-3,4)     | (5.1,34.5)
-        | (-3,4)     | (-5,-12)
-        | (-3,4)     | (10,10)
-        | (5.1,34.5) | (0,0)
-        | (5.1,34.5) | (-10,0)
-        | (5.1,34.5) | (-3,4)
-        | (5.1,34.5) | (-5,-12)
-        | (5.1,34.5) | (10,10)
-        | (-5,-12)   | (0,0)
-        | (-5,-12)   | (-10,0)
-        | (-5,-12)   | (-3,4)
-        | (-5,-12)   | (5.1,34.5)
-        | (-5,-12)   | (10,10)
-        | (10,10)    | (0,0)
-        | (10,10)    | (-10,0)
-        | (10,10)    | (-3,4)
-        | (10,10)    | (5.1,34.5)
-        | (10,10)    | (-5,-12)
-(30 rows)
+ thirty |      point1       |      point2       
+--------+-------------------+-------------------
+        | (0,0)             | (-10,0)
+        | (0,0)             | (-3,4)
+        | (0,0)             | (5.1,34.5)
+        | (0,0)             | (-5,-12)
+        | (0,0)             | (1e+300,Infinity)
+        | (0,0)             | (NaN,NaN)
+        | (0,0)             | (10,10)
+        | (-10,0)           | (0,0)
+        | (-10,0)           | (-3,4)
+        | (-10,0)           | (5.1,34.5)
+        | (-10,0)           | (-5,-12)
+        | (-10,0)           | (1e-300,-1e-300)
+        | (-10,0)           | (1e+300,Infinity)
+        | (-10,0)           | (NaN,NaN)
+        | (-10,0)           | (10,10)
+        | (-3,4)            | (0,0)
+        | (-3,4)            | (-10,0)
+        | (-3,4)            | (5.1,34.5)
+        | (-3,4)            | (-5,-12)
+        | (-3,4)            | (1e-300,-1e-300)
+        | (-3,4)            | (1e+300,Infinity)
+        | (-3,4)            | (NaN,NaN)
+        | (-3,4)            | (10,10)
+        | (5.1,34.5)        | (0,0)
+        | (5.1,34.5)        | (-10,0)
+        | (5.1,34.5)        | (-3,4)
+        | (5.1,34.5)        | (-5,-12)
+        | (5.1,34.5)        | (1e-300,-1e-300)
+        | (5.1,34.5)        | (1e+300,Infinity)
+        | (5.1,34.5)        | (NaN,NaN)
+        | (5.1,34.5)        | (10,10)
+        | (-5,-12)          | (0,0)
+        | (-5,-12)          | (-10,0)
+        | (-5,-12)          | (-3,4)
+        | (-5,-12)          | (5.1,34.5)
+        | (-5,-12)          | (1e-300,-1e-300)
+        | (-5,-12)          | (1e+300,Infinity)
+        | (-5,-12)          | (NaN,NaN)
+        | (-5,-12)          | (10,10)
+        | (1e-300,-1e-300)  | (-10,0)
+        | (1e-300,-1e-300)  | (-3,4)
+        | (1e-300,-1e-300)  | (5.1,34.5)
+        | (1e-300,-1e-300)  | (-5,-12)
+        | (1e-300,-1e-300)  | (1e+300,Infinity)
+        | (1e-300,-1e-300)  | (NaN,NaN)
+        | (1e-300,-1e-300)  | (10,10)
+        | (1e+300,Infinity) | (0,0)
+        | (1e+300,Infinity) | (-10,0)
+        | (1e+300,Infinity) | (-3,4)
+        | (1e+300,Infinity) | (5.1,34.5)
+        | (1e+300,Infinity) | (-5,-12)
+        | (1e+300,Infinity) | (1e-300,-1e-300)
+        | (1e+300,Infinity) | (1e+300,Infinity)
+        | (1e+300,Infinity) | (NaN,NaN)
+        | (1e+300,Infinity) | (10,10)
+        | (NaN,NaN)         | (0,0)
+        | (NaN,NaN)         | (-10,0)
+        | (NaN,NaN)         | (-3,4)
+        | (NaN,NaN)         | (5.1,34.5)
+        | (NaN,NaN)         | (-5,-12)
+        | (NaN,NaN)         | (1e-300,-1e-300)
+        | (NaN,NaN)         | (1e+300,Infinity)
+        | (NaN,NaN)         | (NaN,NaN)
+        | (NaN,NaN)         | (10,10)
+        | (10,10)           | (0,0)
+        | (10,10)           | (-10,0)
+        | (10,10)           | (-3,4)
+        | (10,10)           | (5.1,34.5)
+        | (10,10)           | (-5,-12)
+        | (10,10)           | (1e-300,-1e-300)
+        | (10,10)           | (1e+300,Infinity)
+        | (10,10)           | (NaN,NaN)
+(72 rows)
 
 -- put distance result into output to allow sorting with GEQ optimizer - tgl 97/05/10
 SELECT '' AS fifteen, p1.f1 AS point1, p2.f1 AS point2, (p1.f1 <-> p2.f1) AS distance
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3 and p1.f1 << p2.f1
    ORDER BY distance, p1.f1[0], p2.f1[0];
- fifteen |   point1   |   point2   |     distance     
----------+------------+------------+------------------
-         | (-3,4)     | (0,0)      |                5
-         | (-10,0)    | (-3,4)     | 8.06225774829855
-         | (-10,0)    | (0,0)      |               10
-         | (-10,0)    | (-5,-12)   |               13
-         | (-5,-12)   | (0,0)      |               13
-         | (0,0)      | (10,10)    |  14.142135623731
-         | (-3,4)     | (10,10)    | 14.3178210632764
-         | (-5,-12)   | (-3,4)     | 16.1245154965971
-         | (-10,0)    | (10,10)    | 22.3606797749979
-         | (5.1,34.5) | (10,10)    | 24.9851956166046
-         | (-5,-12)   | (10,10)    | 26.6270539113887
-         | (-3,4)     | (5.1,34.5) | 31.5572495632937
-         | (0,0)      | (5.1,34.5) | 34.8749193547455
-         | (-10,0)    | (5.1,34.5) | 37.6597928831267
-         | (-5,-12)   | (5.1,34.5) | 47.5842410888311
-(15 rows)
+ fifteen |      point1      |      point2       |     distance     
+---------+------------------+-------------------+------------------
+         | (-3,4)           | (0,0)             |                5
+         | (-3,4)           | (1e-300,-1e-300)  |                5
+         | (-10,0)          | (-3,4)            | 8.06225774829855
+         | (-10,0)          | (0,0)             |               10
+         | (-10,0)          | (1e-300,-1e-300)  |               10
+         | (-10,0)          | (-5,-12)          |               13
+         | (-5,-12)         | (0,0)             |               13
+         | (-5,-12)         | (1e-300,-1e-300)  |               13
+         | (0,0)            | (10,10)           |  14.142135623731
+         | (1e-300,-1e-300) | (10,10)           |  14.142135623731
+         | (-3,4)           | (10,10)           | 14.3178210632764
+         | (-5,-12)         | (-3,4)            | 16.1245154965971
+         | (-10,0)          | (10,10)           | 22.3606797749979
+         | (5.1,34.5)       | (10,10)           | 24.9851956166046
+         | (-5,-12)         | (10,10)           | 26.6270539113887
+         | (-3,4)           | (5.1,34.5)        | 31.5572495632937
+         | (0,0)            | (5.1,34.5)        | 34.8749193547455
+         | (1e-300,-1e-300) | (5.1,34.5)        | 34.8749193547455
+         | (-10,0)          | (5.1,34.5)        | 37.6597928831267
+         | (-5,-12)         | (5.1,34.5)        | 47.5842410888311
+         | (-10,0)          | (1e+300,Infinity) |         Infinity
+         | (-5,-12)         | (1e+300,Infinity) |         Infinity
+         | (-3,4)           | (1e+300,Infinity) |         Infinity
+         | (0,0)            | (1e+300,Infinity) |         Infinity
+         | (1e-300,-1e-300) | (1e+300,Infinity) |         Infinity
+         | (5.1,34.5)       | (1e+300,Infinity) |         Infinity
+         | (10,10)          | (1e+300,Infinity) |         Infinity
+(27 rows)
 
 -- put distance result into output to allow sorting with GEQ optimizer - tgl 97/05/10
 SELECT '' AS three, p1.f1 AS point1, p2.f1 AS point2, (p1.f1 <-> p2.f1) AS distance
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3 and p1.f1 << p2.f1 and p1.f1 >^ p2.f1
    ORDER BY distance;
- three |   point1   |  point2  |     distance     
--------+------------+----------+------------------
-       | (-3,4)     | (0,0)    |                5
-       | (-10,0)    | (-5,-12) |               13
-       | (5.1,34.5) | (10,10)  | 24.9851956166046
-(3 rows)
+ three |   point1   |      point2      |     distance     
+-------+------------+------------------+------------------
+       | (-3,4)     | (0,0)            |                5
+       | (-3,4)     | (1e-300,-1e-300) |                5
+       | (-10,0)    | (-5,-12)         |               13
+       | (5.1,34.5) | (10,10)          | 24.9851956166046
+(4 rows)
 
 -- Test that GiST indexes provide same behavior as sequential scan
 CREATE TEMP TABLE point_gist_tbl(f1 point);
 INSERT INTO point_gist_tbl SELECT '(0,0)' FROM generate_series(0,1000);
 CREATE INDEX point_gist_tbl_index ON point_gist_tbl USING gist (f1);
 INSERT INTO point_gist_tbl VALUES ('(0.0000009,0.0000009)');
 SET enable_seqscan TO true;
 SET enable_indexscan TO false;
 SET enable_bitmapscan TO false;
 SELECT COUNT(*) FROM point_gist_tbl WHERE f1 ~= '(0.0000009,0.0000009)'::point;
diff --git a/src/test/regress/expected/polygon.out b/src/test/regress/expected/polygon.out
index 4a1f60427a..be5f76bf9d 100644
--- a/src/test/regress/expected/polygon.out
+++ b/src/test/regress/expected/polygon.out
@@ -1,18 +1,21 @@
 --
 -- POLYGON
 --
 -- polygon logic
 --
 CREATE TABLE POLYGON_TBL(f1 polygon);
 INSERT INTO POLYGON_TBL(f1) VALUES ('(2.0,0.0),(2.0,4.0),(0.0,0.0)');
 INSERT INTO POLYGON_TBL(f1) VALUES ('(3.0,1.0),(3.0,3.0),(1.0,0.0)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(3,4),(5,6),(7,8)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(7,8),(5,6),(3,4),(1,2)'); -- Reverse
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(7,8),(5,6),(3,-4)');
 -- degenerate polygons
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,0.0)');
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,1.0),(0.0,1.0)');
 -- bad polygon input strings
 INSERT INTO POLYGON_TBL(f1) VALUES ('0.0');
 ERROR:  invalid input syntax for type polygon: "0.0"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('0.0');
                                             ^
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0 0.0');
 ERROR:  invalid input syntax for type polygon: "(0.0 0.0"
@@ -24,215 +27,30 @@ LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2)');
                                             ^
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2,3');
 ERROR:  invalid input syntax for type polygon: "(0,1,2,3"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2,3');
                                             ^
 INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
 ERROR:  invalid input syntax for type polygon: "asdf"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
                                             ^
 SELECT '' AS four, * FROM POLYGON_TBL;
- four |         f1          
-------+---------------------
+ four |             f1             
+------+----------------------------
       | ((2,0),(2,4),(0,0))
       | ((3,1),(3,3),(1,0))
+      | ((1,2),(3,4),(5,6),(7,8))
+      | ((7,8),(5,6),(3,4),(1,2))
+      | ((1,2),(7,8),(5,6),(3,-4))
       | ((0,0))
       | ((0,1),(0,1))
-(4 rows)
-
--- overlap
-SELECT '' AS three, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 && '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- three |         f1          
--------+---------------------
-       | ((2,0),(2,4),(0,0))
-       | ((3,1),(3,3),(1,0))
-(2 rows)
-
--- left overlap
-SELECT '' AS four, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &< '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- four |         f1          
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
-
--- right overlap
-SELECT '' AS two, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- two |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- left of
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 << '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |      f1       
------+---------------
-     | ((0,0))
-     | ((0,1),(0,1))
-(2 rows)
-
--- right of
-SELECT '' AS zero, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 >> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- zero | f1 
-------+----
-(0 rows)
-
--- contained
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- same
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- contains
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
---
--- polygon logic
---
--- left of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- left overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
- true 
-------
- f
-(1 row)
-
--- right overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' &> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- right of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' >> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- contained in
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- contains
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((0,4),(6,4),(3,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
-SELECT '((1,1),(1,4),(5,4),(5,3),(2,3),(2,2),(5,2),(5,1))'::polygon @> '((3,2),(3,3),(4,3),(4,2))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((0,0),(0,3),(3,3),(3,0))'::polygon @> '((2,1),(2,2),(3,2),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
--- same
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' && polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
- true 
-------
- t
-(1 row)
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon && '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
-SELECT '((1,4),(1,1),(4,1),(4,2),(2,2),(2,4),(1,4))'::polygon && '((3,3),(4,3),(4,4),(3,4),(3,3))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((200,800),(800,800),(800,200),(200,200))' &&  '(1000,1000,0,0)'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
--- distance from a point
-SELECT	'(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
-	'(1,1)'::point <-> '((0,0),(2,2),(1,3))'::polygon as on_segment,
-	'(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;
- on_corner | on_segment | inside |   near_corner   | near_segment 
------------+------------+--------+-----------------+--------------
-         0 |          0 |      0 | 1.4142135623731 |          3.2
-(1 row)
+(7 rows)
 
 --
 -- 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
diff --git a/src/test/regress/sql/box.sql b/src/test/regress/sql/box.sql
index 135ac108eb..6710fc90f5 100644
--- a/src/test/regress/sql/box.sql
+++ b/src/test/regress/sql/box.sql
@@ -18,29 +18,38 @@
 
 -- boxes are specified by two points, given by four floats x1,y1,x2,y2
 
 
 CREATE TABLE BOX_TBL (f1 box);
 
 INSERT INTO BOX_TBL (f1) VALUES ('(2.0,2.0,0.0,0.0)');
 
 INSERT INTO BOX_TBL (f1) VALUES ('(1.0,1.0,3.0,3.0)');
 
+INSERT INTO BOX_TBL (f1) VALUES ('((-8, 2), (-2, -10))');
+
+
 -- degenerate cases where the box is a line or a point
 -- note that lines and points boxes all have zero area
 INSERT INTO BOX_TBL (f1) VALUES ('(2.5, 2.5, 2.5,3.5)');
 
 INSERT INTO BOX_TBL (f1) VALUES ('(3.0, 3.0,3.0,3.0)');
 
 -- badly formatted box inputs
 INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
 
+INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+
 INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
 
 
 SELECT '' AS four, * FROM BOX_TBL;
 
 SELECT '' AS four, b.*, area(b.f1) as barea
    FROM BOX_TBL b;
 
 -- overlap
 SELECT '' AS three, b.f1
diff --git a/src/test/regress/sql/circle.sql b/src/test/regress/sql/circle.sql
index c0284b2b59..46c96e1400 100644
--- a/src/test/regress/sql/circle.sql
+++ b/src/test/regress/sql/circle.sql
@@ -7,26 +7,34 @@ CREATE TABLE CIRCLE_TBL (f1 circle);
 INSERT INTO CIRCLE_TBL VALUES ('<(5,1),3>');
 
 INSERT INTO CIRCLE_TBL VALUES ('<(1,2),100>');
 
 INSERT INTO CIRCLE_TBL VALUES ('1,3,5');
 
 INSERT INTO CIRCLE_TBL VALUES ('((1,2),3)');
 
 INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10>');
 
-INSERT INTO CIRCLE_TBL VALUES ('<(100,1),115>');
+INSERT INTO CIRCLE_TBL VALUES (' < ( 100 , 1 ) , 115 > ');
+
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),0>');	-- Zero radius
+
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),NaN>');	-- NaN radius
 
 -- bad values
 
 INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
 
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+
 INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
 
 INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
 
 SELECT * FROM CIRCLE_TBL;
 
 SELECT '' AS six, center(f1) AS center
   FROM CIRCLE_TBL;
 
 SELECT '' AS six, radius(f1) AS radius
diff --git a/src/test/regress/sql/geometry.sql b/src/test/regress/sql/geometry.sql
index 1429ee772a..ce98b3e90c 100644
--- a/src/test/regress/sql/geometry.sql
+++ b/src/test/regress/sql/geometry.sql
@@ -39,74 +39,298 @@ SELECT '' AS two, p1.f1
 -- "is vertical" function
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE isvertical(p1.f1, point '(5.1,34.5)');
 
 -- "is vertical" operator
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?| point '(5.1,34.5)';
 
+-- Slope
+SELECT p1.f1, p2.f1, slope(p1.f1, p2.f1) FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Add point
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Subtract point
+SELECT p1.f1, p2.f1, p1.f1 - p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Multiply with point
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+
+-- Underflow error
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] < 1;
+
+-- Divide by point
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] BETWEEN 1 AND 1000;
+
+-- Overflow error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] > 1000;
+
+-- Division by 0 error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1 ~= '(0,0)'::point;
+
+-- Distance to line
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LINE_TBL l;
+
+-- Distance to line segment
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LSEG_TBL l;
+
+-- Distance to box
+SELECT p.f1, b.f1, p.f1 <-> b.f1 FROM POINT_TBL p, BOX_TBL b;
+
+-- Distance to path
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, PATH_TBL p1;
+
+-- Distance to polygon
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, POLYGON_TBL p1;
+
+-- Closest point to line
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LINE_TBL l;
+
+-- Closest point to line segment
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LSEG_TBL l;
+
+-- Closest point to box
+SELECT p.f1, b.f1, p.f1 ## b.f1 FROM POINT_TBL p, BOX_TBL b;
+
+-- On line
+SELECT p.f1, l.s FROM POINT_TBL p, LINE_TBL l WHERE p.f1 <@ l.s;
+
+-- On line segment
+SELECT p.f1, l.s FROM POINT_TBL p, LSEG_TBL l WHERE p.f1 <@ l.s;
+
+-- On path
+SELECT p.f1, p1.f1 FROM POINT_TBL p, PATH_TBL p1 WHERE p.f1 <@ p1.f1;
+
+--
+-- Lines
+--
+
+-- Vertical
+SELECT s FROM LINE_TBL WHERE ?| s;
+
+-- Horizontal
+SELECT s FROM LINE_TBL WHERE ?- s;
+
+-- Same as line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s = l2.s;
+
+-- Parallel to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?|| l2.s;
+
+-- Perpendicular to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?-| l2.s;
+
+-- Distance to line
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2;
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LINE_TBL l, BOX_TBL b;
+
+-- Intersect with line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?# l2.s;
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LINE_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+
+-- Intersection point with line
+SELECT l1.s, l2.s, l1.s # l2.s FROM LINE_TBL l1, LINE_TBL l2;
+
+-- Closest point to line segment
+SELECT l.s, l1.s, l.s ## l1.s FROM LINE_TBL l, LSEG_TBL l1;
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LINE_TBL l, BOX_TBL b;
+
 --
 -- Line segments
 --
 
 -- intersection
 SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
    FROM LSEG_TBL l, POINT_TBL p;
 
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
+-- Length
+SELECT s, @-@ s FROM LSEG_TBL;
+
+-- Vertical
+SELECT s FROM LSEG_TBL WHERE ?| s;
+
+-- Horizontal
+SELECT s FROM LSEG_TBL WHERE ?- s;
+
+-- Center
+SELECT s, @@ s FROM LSEG_TBL;
+
+-- To point
+SELECT s, s::point FROM LSEG_TBL;
+
+-- Has points less than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s < l2.s;
+
+-- Has points less than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s <= l2.s;
+
+-- Has points equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s = l2.s;
+
+-- Has points greater than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s >= l2.s;
+
+-- Has points greater than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s > l2.s;
+
+-- Has points not equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s != l2.s;
+
+-- Parallel with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?|| l2.s;
+
+-- Perpendicular with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?-| l2.s;
+
+-- Distance to line
+SELECT l.s, l1.s, l.s <-> l1.s FROM LSEG_TBL l, LINE_TBL l1;
+
+-- Distance to line segment
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LSEG_TBL l, BOX_TBL b;
+
+-- Intersect with line segment
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s ?# l1.s;
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+
+-- Intersection point with line segment
+SELECT l1.s, l2.s, l1.s # l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Closest point to line
+SELECT l.s, l1.s, l.s ## l1.s FROM LSEG_TBL l, LINE_TBL l1;
+
+-- Closest point to line segment
+SELECT l1.s, l2.s, l1.s ## l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LSEG_TBL l, BOX_TBL b;
+
+-- On line
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s <@ l1.s;
+
+-- On box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s <@ b.f1;
 
 --
 -- Boxes
 --
 
 SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
 
 -- translation
 SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
 
 SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
 
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
+-- Multiply with point
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
 
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
+-- Overflow error
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] > 1000;
 
+-- Divide by point
+SELECT b.f1, p.f1, b.f1 / p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+
+-- To box
 SELECT f1::box
 	FROM POINT_TBL;
 
 SELECT bound_box(a.f1, b.f1)
 	FROM BOX_TBL a, BOX_TBL b;
 
+-- Below box
+SELECT b1.f1, b2.f1, b1.f1 <^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Above box
+SELECT b1.f1, b2.f1, b1.f1 >^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Intersection point with box
+SELECT b1.f1, b2.f1, b1.f1 # b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Diagonal
+SELECT f1, diagonal(f1) FROM BOX_TBL;
+
+-- Distance to box
+SELECT b1.f1, b2.f1, b1.f1 <-> b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
 --
 -- Paths
 --
 
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
+-- Points
+SELECT f1, npoints(f1) FROM PATH_TBL;
 
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
+-- Area
+SELECT f1, area(f1) FROM PATH_TBL;
 
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
+-- Length
+SELECT f1, @-@ f1 FROM PATH_TBL;
 
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
+-- Center
+SELECT f1, @@ f1 FROM PATH_TBL;
+
+-- To polygon
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isclosed(f1);
+
+-- Open path cannot be converted to polygon error
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isopen(f1);
+
+-- Has points less than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 < p2.f1;
+
+-- Has points less than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 <= p2.f1;
+
+-- Has points equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 = p2.f1;
+
+-- Has points greater than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 >= p2.f1;
+
+-- Has points greater than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 > p2.f1;
+
+-- Add path
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+
+-- Add point
+SELECT p.f1, p1.f1, p.f1 + p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+
+-- Subtract point
+SELECT p.f1, p1.f1, p.f1 - p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+
+-- Multiply with point
+SELECT p.f1, p1.f1, p.f1 * p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+
+-- Divide by point
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+
+-- Division by 0 error
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1 ~= '(0,0)'::point;
+
+-- Distance to path
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
 
 --
 -- Polygons
 --
 
 -- containment
 SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
    FROM POLYGON_TBL poly, POINT_TBL p;
 
 SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
@@ -118,36 +342,166 @@ SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
 SELECT '' AS four, polygon(f1)
    FROM BOX_TBL;
 
 SELECT '' AS four, polygon(f1)
    FROM PATH_TBL WHERE isclosed(f1);
 
 SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
    FROM PATH_TBL
    WHERE isopen(f1);
 
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
+-- To box
+SELECT f1, f1::box FROM POLYGON_TBL;
 
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
+-- To path
+SELECT f1, f1::path FROM POLYGON_TBL;
+
+-- Same as polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 ~= p2.f1;
+
+-- Contained by polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <@ p2.f1;
+
+-- Contains polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 @> p2.f1;
+
+-- Overlap with polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 && p2.f1;
+
+-- Left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 << p2.f1;
+
+-- Overlap of left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &< p2.f1;
+
+-- Right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 >> p2.f1;
+
+-- Overlap of right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &> p2.f1;
+
+-- Below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <<| p2.f1;
+
+-- Overlap or below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &<| p2.f1;
+
+-- Above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |>> p2.f1;
+
+-- Overlap or above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |&> p2.f1;
+
+-- Distance to polygon
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2;
 
 --
 -- Circles
 --
 
 SELECT '' AS six, circle(f1, 50.0)
    FROM POINT_TBL;
 
 SELECT '' AS four, circle(f1)
    FROM BOX_TBL;
 
 SELECT '' AS two, circle(f1)
    FROM POLYGON_TBL
    WHERE (# f1) >= 3;
 
 SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
    FROM CIRCLE_TBL c1, POINT_TBL p1
    WHERE (p1.f1 <-> c1.f1) > 0
    ORDER BY distance, area(c1.f1), p1.f1[0];
+
+-- To polygon
+SELECT f1, f1::polygon FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+
+-- To polygon with less points
+SELECT f1, polygon(8, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+
+-- Too less points error
+SELECT f1, polygon(1, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+
+-- Zero radius error
+SELECT f1, polygon(10, f1) FROM CIRCLE_TBL WHERE f1 < '<(0,0),1>';
+
+-- Same as circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 ~= c2.f1;
+
+-- Overlap with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 && c2.f1;
+
+-- Overlap or left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &< c2.f1;
+
+-- Left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 << c2.f1;
+
+-- Right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >> c2.f1;
+
+-- Overlap or right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &> c2.f1;
+
+-- Contained by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <@ c2.f1;
+
+-- Contain by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 @> c2.f1;
+
+-- Below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <<| c2.f1;
+
+-- Above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |>> c2.f1;
+
+-- Overlap or below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &<| c2.f1;
+
+-- Overlap or above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |&> c2.f1;
+
+-- Area equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 = c2.f1;
+
+-- Area not equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 != c2.f1;
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 > c2.f1;
+
+-- Area less than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <= c2.f1;
+
+-- Area greater than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >= c2.f1;
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+
+-- Add point
+SELECT c.f1, p.f1, c.f1 + p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Subtract point
+SELECT c.f1, p.f1, c.f1 - p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Multiply with point
+SELECT c.f1, p.f1, c.f1 * p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Divide by point
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+
+-- Overflow error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] > 1000;
+
+-- Division by 0 error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1 ~= '(0,0)'::point;
+
+-- Distance to polygon
+SELECT c.f1, p.f1, c.f1 <-> p.f1 FROM CIRCLE_TBL c, POLYGON_TBL p;
diff --git a/src/test/regress/sql/line.sql b/src/test/regress/sql/line.sql
index 94067b0cee..2353073118 100644
--- a/src/test/regress/sql/line.sql
+++ b/src/test/regress/sql/line.sql
@@ -1,87 +1,39 @@
 --
 -- LINE
 -- Infinite lines
 --
 
 --DROP TABLE LINE_TBL;
 CREATE TABLE LINE_TBL (s line);
 
-INSERT INTO LINE_TBL VALUES ('{1,-1,1}');
-INSERT INTO LINE_TBL VALUES ('(0,0),(6,6)');
+INSERT INTO LINE_TBL VALUES ('{0,-1,5}');	-- A == 0
+INSERT INTO LINE_TBL VALUES ('{1,0,5}');	-- B == 0
+INSERT INTO LINE_TBL VALUES ('{0,3,0}');	-- A == C == 0
+INSERT INTO LINE_TBL VALUES (' (0,0), (6,6)');
 INSERT INTO LINE_TBL VALUES ('10,-10 ,-5,-4');
 INSERT INTO LINE_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LINE_TBL VALUES ('(11,22,33,44)');
 
-INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
+INSERT INTO LINE_TBL VALUES ('{3,NaN,5}');
+INSERT INTO LINE_TBL VALUES ('{NaN,NaN,NaN}');
 
 -- horizontal
 INSERT INTO LINE_TBL VALUES ('[(1,3),(2,3)]');
 -- vertical
-INSERT INTO LINE_TBL VALUES ('[(3,1),(3,2)]');
+INSERT INTO LINE_TBL VALUES (line(point '(3,1)', point '(3,2)'));
 
 -- bad values for parser testing
+INSERT INTO LINE_TBL VALUES ('{}');
+INSERT INTO LINE_TBL VALUES ('{0');
+INSERT INTO LINE_TBL VALUES ('{0,0}');
+INSERT INTO LINE_TBL VALUES ('{0,0,1');
 INSERT INTO LINE_TBL VALUES ('{0,0,1}');
+INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
 INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
 INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
 INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
 INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
+INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
+
+INSERT INTO LINE_TBL VALUES (line(point '(1,0)', point '(1,0)'));
 
 select * from LINE_TBL;
-
-
--- functions and operators
-
-SELECT * FROM LINE_TBL WHERE (s <-> line '[(1,2),(3,4)]') < 10;
-
-SELECT * FROM LINE_TBL WHERE (point '(0.1,0.1)' <-> s) < 1;
-
-SELECT * FROM LINE_TBL WHERE (lseg '[(0.1,0.1),(0.2,0.2)]' <-> s) < 1;
-
-SELECT line '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
-SELECT lseg '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
-SELECT point '(-1,1)' <-> line '[(-3,0),(-4,0)]';
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(2,0),(0,2)]';  -- true
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(0,0),(1,0)]';  -- false
-
-SELECT line '[(0,0),(1,1)]' ?# box '(0,0,2,2)';  -- true
-SELECT line '[(3,0),(4,1)]' ?# box '(0,0,2,2)';  -- false
-
-SELECT point '(1,1)' <@ line '[(0,0),(2,2)]';  -- true
-SELECT point '(1,1)' <@ line '[(0,0),(1,0)]';  -- false
-
-SELECT point '(1,1)' @ line '[(0,0),(2,2)]';  -- true
-SELECT point '(1,1)' @ line '[(0,0),(1,0)]';  -- false
-
-SELECT lseg '[(1,1),(2,2)]' <@ line '[(0,0),(2,2)]';  -- true
-SELECT lseg '[(1,1),(2,1)]' <@ line '[(0,0),(1,0)]';  -- false
-
-SELECT lseg '[(1,1),(2,2)]' @ line '[(0,0),(2,2)]';  -- true
-SELECT lseg '[(1,1),(2,1)]' @ line '[(0,0),(1,0)]';  -- false
-
-SELECT point '(0,1)' ## line '[(0,0),(1,1)]';
-
-SELECT line '[(0,0),(1,1)]' ## lseg '[(1,0),(2,0)]';
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(2,1)]';  -- false
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(1,1)]';  -- true
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(2,1)]';
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(1,1)]';
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(2,1)]';  -- true
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(1,1)]';  -- false
-
-SELECT line '[(0,0),(1,0)]' ?-| line '[(0,0),(0,1)]';  -- true
-SELECT line '[(0,0),(1,1)]' ?-| line '[(1,0),(1,1)]';  -- false
-
-SELECT ?- line '[(0,0),(1,0)]';  -- true
-SELECT ?- line '[(0,0),(1,1)]';  -- false
-
-SELECT ?| line '[(0,0),(0,1)]';  -- true
-SELECT ?| line '[(0,0),(1,1)]';  -- false
-
-SELECT line(point '(1,2)', point '(3,4)');
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,5)]';  -- true
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,4)]';  -- false
diff --git a/src/test/regress/sql/lseg.sql b/src/test/regress/sql/lseg.sql
index 07c5a29e0a..f266ca3e09 100644
--- a/src/test/regress/sql/lseg.sql
+++ b/src/test/regress/sql/lseg.sql
@@ -3,23 +3,22 @@
 -- Line segments
 --
 
 --DROP TABLE LSEG_TBL;
 CREATE TABLE LSEG_TBL (s lseg);
 
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('(0,0),(6,6)');
 INSERT INTO LSEG_TBL VALUES ('10,-10 ,-3,-4');
 INSERT INTO LSEG_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LSEG_TBL VALUES ('(11,22,33,44)');
+INSERT INTO LSEG_TBL VALUES (lseg(point(11, 22), point(33,44)));
+INSERT INTO LSEG_TBL VALUES ('[(-10,2),(-10,3)]');	-- vertical
+INSERT INTO LSEG_TBL VALUES ('[(0,-20),(30,-20)]');	-- horizontal
+INSERT INTO LSEG_TBL VALUES ('[(NaN,1),(NaN,90)]');	-- NaN
 
 -- bad values for parser testing
 INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
 INSERT INTO LSEG_TBL VALUES ('[1,2,3, 4');
 INSERT INTO LSEG_TBL VALUES ('[(,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)');
 
 select * from LSEG_TBL;
-
-SELECT * FROM LSEG_TBL WHERE s <= lseg '[(1,2),(3,4)]';
-
-SELECT * FROM LSEG_TBL WHERE (s <-> lseg '[(1,2),(3,4)]') < 10;
diff --git a/src/test/regress/sql/path.sql b/src/test/regress/sql/path.sql
index 7e69b539ad..318decf974 100644
--- a/src/test/regress/sql/path.sql
+++ b/src/test/regress/sql/path.sql
@@ -1,38 +1,44 @@
 --
 -- PATH
 --
 
 --DROP TABLE PATH_TBL;
 
 CREATE TABLE PATH_TBL (f1 path);
 
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)]');
 
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
+INSERT INTO PATH_TBL VALUES (' ( ( 1 , 2 ) , ( 3 , 4 ) ) ');
 
-INSERT INTO PATH_TBL VALUES ('[(0,0),(3,0),(4,5),(1,6)]');
+INSERT INTO PATH_TBL VALUES ('[ (0,0),(3,0),(4,5),(1,6) ]');
 
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
+INSERT INTO PATH_TBL VALUES ('((1,2) ,(3,4 ))');
 
-INSERT INTO PATH_TBL VALUES ('1,2 ,3,4');
+INSERT INTO PATH_TBL VALUES ('1,2 ,3,4 ');
 
-INSERT INTO PATH_TBL VALUES ('[1,2,3, 4]');
+INSERT INTO PATH_TBL VALUES (' [1,2,3, 4] ');
 
-INSERT INTO PATH_TBL VALUES ('[11,12,13,14]');
+INSERT INTO PATH_TBL VALUES ('((10,20))');	-- Only one point
 
-INSERT INTO PATH_TBL VALUES ('(11,12,13,14)');
+INSERT INTO PATH_TBL VALUES ('[ 11,12,13,14 ]');
+
+INSERT INTO PATH_TBL VALUES ('( 11,12,13,14) ');
 
 -- bad values for parser testing
+INSERT INTO PATH_TBL VALUES ('[]');
+
 INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
 
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
 
-SELECT f1 FROM PATH_TBL;
+INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+
+INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
 
 SELECT '' AS count, f1 AS open_path FROM PATH_TBL WHERE isopen(f1);
 
 SELECT '' AS count, f1 AS closed_path FROM PATH_TBL WHERE isclosed(f1);
 
 SELECT '' AS count, pclose(f1) AS closed_path FROM PATH_TBL;
 
 SELECT '' AS count, popen(f1) AS open_path FROM PATH_TBL;
diff --git a/src/test/regress/sql/point.sql b/src/test/regress/sql/point.sql
index 63a803a809..a209f3bfeb 100644
--- a/src/test/regress/sql/point.sql
+++ b/src/test/regress/sql/point.sql
@@ -7,29 +7,39 @@ CREATE TABLE POINT_TBL(f1 point);
 INSERT INTO POINT_TBL(f1) VALUES ('(0.0,0.0)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-10.0,0.0)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-3.0,4.0)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(5.1, 34.5)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-5.0,-12.0)');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(1e-300,-1e-300)');	-- To underflow
+
+INSERT INTO POINT_TBL(f1) VALUES ('(1e+300,Inf)');		-- To overflow
+
+INSERT INTO POINT_TBL(f1) VALUES (' ( Nan , NaN ) ');
+
 -- bad format points
 INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
 
 INSERT INTO POINT_TBL(f1) VALUES ('10.0,10.0');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');	-- Out of range
+
 
 SELECT '' AS six, * FROM POINT_TBL;
 
 -- left of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE p.f1 << '(0.0, 0.0)';
 
 -- right of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE '(0.0,0.0)' >> p.f1;
 
 -- above
diff --git a/src/test/regress/sql/polygon.sql b/src/test/regress/sql/polygon.sql
index 7e8cb08cd8..d3d2fe3457 100644
--- a/src/test/regress/sql/polygon.sql
+++ b/src/test/regress/sql/polygon.sql
@@ -4,126 +4,43 @@
 -- polygon logic
 --
 
 CREATE TABLE POLYGON_TBL(f1 polygon);
 
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(2.0,0.0),(2.0,4.0),(0.0,0.0)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(3.0,1.0),(3.0,3.0),(1.0,0.0)');
 
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(3,4),(5,6),(7,8)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(7,8),(5,6),(3,4),(1,2)'); -- Reverse
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(7,8),(5,6),(3,-4)');
+
 -- degenerate polygons
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,0.0)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,1.0),(0.0,1.0)');
 
 -- bad polygon input strings
 INSERT INTO POLYGON_TBL(f1) VALUES ('0.0');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0 0.0');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2,3');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
 
 
 SELECT '' AS four, * FROM POLYGON_TBL;
 
--- overlap
-SELECT '' AS three, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 && '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- left overlap
-SELECT '' AS four, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &< '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- right overlap
-SELECT '' AS two, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- left of
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 << '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- right of
-SELECT '' AS zero, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 >> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- contained
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- same
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- contains
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
---
--- polygon logic
---
--- left of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- left overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
-
--- right overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' &> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- right of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' >> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- contained in
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- contains
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "false";
-
-SELECT '((0,4),(6,4),(3,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
-
-SELECT '((1,1),(1,4),(5,4),(5,3),(2,3),(2,2),(5,2),(5,1))'::polygon @> '((3,2),(3,3),(4,3),(4,2))'::polygon AS "false";
-
-SELECT '((0,0),(0,3),(3,3),(3,0))'::polygon @> '((2,1),(2,2),(3,2),(3,1))'::polygon AS "true";
-
--- same
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' && polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon && '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
-
-SELECT '((1,4),(1,1),(4,1),(4,2),(2,2),(2,4),(1,4))'::polygon && '((3,3),(4,3),(4,4),(3,4),(3,3))'::polygon AS "false";
-SELECT '((200,800),(800,800),(800,200),(200,200))' &&  '(1000,1000,0,0)'::polygon AS "true";
-
--- distance from a point
-SELECT	'(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
-	'(1,1)'::point <-> '((0,0),(2,2),(1,3))'::polygon as on_segment,
-	'(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;
-- 
2.14.3 (Apple Git-98)

#47Kyotaro HORIGUCHI
horiguchi.kyotaro@lab.ntt.co.jp
In reply to: Emre Hasegeli (#46)
Re: [HACKERS] [PATCH] Improve geometric types

At Sun, 21 Jan 2018 21:59:19 +0100, Emre Hasegeli <emre@hasegeli.com> wrote in <CAE2gYzxDYs5tcvc4uErsWaFTb3UTYS0ERt_fFyi-28Ldvs5d4A@mail.gmail.com>

New versions are attached including all changes we discussed.

Thanks for the new version.

# there's many changes from the previous version..

About 0001 and 0002.

1."COPT=-DGEODEBUG make" complains as follows.

| geo_ops.c:2445:62: error: invalid type argument of unary ‘*’ (have ‘float8 {aka double}’)
| printf("dist_ppoly_internal- segment 0/n distance is %f\n", *result);

2. line_construct_pm has been renamed to line_construct. I
noticed that the patch adds the second block for "(m == 0.0)"
(from the ealier versions) but it seems to work exactly as the
same to the "else" block. We need a comment about the reason
for the seemingly redundant second block.

3. point_sl can return -0.0 and that is a thing that this patch
intends to avoid. line_invsl has the same problem.

4. lseg_interpt_line is doing as follows.

if (FPeq(lseg->p[0].x, interpt.x) && FPeq(lseg->p[0].y, interpt.y))
*result = lseg->p[0];
else if (FPeq(lseg->p[1].x, interpt.x) && FPeq(lseg->p[1].y, interpt.y))
*result = lseg->p[1];

I suppose we can use point_pt_point for this purpose.

if (point_eq_point(&lseg->p[0], &interpt))
*result = lseg->p[0];
else if (point_eq_point(&lseg->p[1], &interpt))
*result = lseg->p[1];

However I'm not sure that adjusting the intersection to the
tips of the segment is good or not. Adjusting onto the line
can be better in another case. lseg_interpt_lseg, for
instance, checks lseg_contain_point on the line parameter of
lseg_interpt_line.

# I'll be back later..

regards

--
Kyotaro Horiguchi
NTT Open Source Software Center

#48Kyotaro HORIGUCHI
horiguchi.kyotaro@lab.ntt.co.jp
In reply to: Kyotaro HORIGUCHI (#47)
Re: [HACKERS] [PATCH] Improve geometric types

At Wed, 31 Jan 2018 13:09:09 +0900 (Tokyo Standard Time), Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp> wrote in <20180131.130909.210233873.horiguchi.kyotaro@lab.ntt.co.jp>

At Sun, 21 Jan 2018 21:59:19 +0100, Emre Hasegeli <emre@hasegeli.com> wrote in <CAE2gYzxDYs5tcvc4uErsWaFTb3UTYS0ERt_fFyi-28Ldvs5d4A@mail.gmail.com>

New versions are attached including all changes we discussed.

Thanks for the new version.

# there's many changes from the previous version..

About 0001 and 0002.

1."COPT=-DGEODEBUG make" complains as follows.

| geo_ops.c:2445:62: error: invalid type argument of unary ‘*’ (have ‘float8 {aka double}’)
| printf("dist_ppoly_internal- segment 0/n distance is %f\n", *result);

2. line_construct_pm has been renamed to line_construct. I
noticed that the patch adds the second block for "(m == 0.0)"
(from the ealier versions) but it seems to work exactly as the
same to the "else" block. We need a comment about the reason
for the seemingly redundant second block.

3. point_sl can return -0.0 and that is a thing that this patch
intends to avoid. line_invsl has the same problem.

4. lseg_interpt_line is doing as follows.

if (FPeq(lseg->p[0].x, interpt.x) && FPeq(lseg->p[0].y, interpt.y))
*result = lseg->p[0];
else if (FPeq(lseg->p[1].x, interpt.x) && FPeq(lseg->p[1].y, interpt.y))
*result = lseg->p[1];

I suppose we can use point_pt_point for this purpose.

if (point_eq_point(&lseg->p[0], &interpt))
*result = lseg->p[0];
else if (point_eq_point(&lseg->p[1], &interpt))
*result = lseg->p[1];

However I'm not sure that adjusting the intersection to the
tips of the segment is good or not. Adjusting onto the line
can be better in another case. lseg_interpt_lseg, for
instance, checks lseg_contain_point on the line parameter of
lseg_interpt_line.

# I'll be back later..

I've been back.

0003: This patch replaces "double" with float and bare arithmetic
and comparisons on double to special functions accompanied
with checking against abnormal values.

- Almost all of them are eliminated with a few safe exceptions.

- circle_recv(), circle_distance(), dist_pc(), dist_cpoint()
are using "< 0.0" comparison but it looks fine.

- pg_hypot is right to use bare arithmetics.

! circle_contain_pt() does the following comparison and it
seems to be out of our current policy.

point_dt(center, point) <= radius

I suppose this should use FPle.

FPle(point_dt(center, point), radius)

The same is true of circle_contain_pt(), pt_contained_circle .

# Sorry, that' all for today..

regards,

--
Kyotaro Horiguchi
NTT Open Source Software Center

#49Emre Hasegeli
emre@hasegeli.com
In reply to: Kyotaro HORIGUCHI (#47)
Re: [HACKERS] [PATCH] Improve geometric types

1."COPT=-DGEODEBUG make" complains as follows.

| geo_ops.c:2445:62: error: invalid type argument of unary ‘*’ (have ‘float8 {aka double}’)
| printf("dist_ppoly_internal- segment 0/n distance is %f\n", *result);

Fixing.

2. line_construct_pm has been renamed to line_construct. I
noticed that the patch adds the second block for "(m == 0.0)"
(from the ealier versions) but it seems to work exactly as the
same to the "else" block. We need a comment about the reason
for the seemingly redundant second block.

It is indeed redundant. I am removing it.

3. point_sl can return -0.0 and that is a thing that this patch
intends to avoid. line_invsl has the same problem.

The existing version of the function has the same issue. I think we
need a global solution for -0s. See the float-zero patch.

4. lseg_interpt_line is doing as follows.

if (FPeq(lseg->p[0].x, interpt.x) && FPeq(lseg->p[0].y, interpt.y))
*result = lseg->p[0];
else if (FPeq(lseg->p[1].x, interpt.x) && FPeq(lseg->p[1].y, interpt.y))
*result = lseg->p[1];

I suppose we can use point_pt_point for this purpose.

Yes, I am changing it.

if (point_eq_point(&lseg->p[0], &interpt))
*result = lseg->p[0];
else if (point_eq_point(&lseg->p[1], &interpt))
*result = lseg->p[1];

However I'm not sure that adjusting the intersection to the
tips of the segment is good or not. Adjusting onto the line
can be better in another case. lseg_interpt_lseg, for
instance, checks lseg_contain_point on the line parameter of
lseg_interpt_line.

Me neither, but it is probably better than returning a point that
extends the endpoints of the segment. I am inclined to leave it alone
for now.

#50Emre Hasegeli
emre@hasegeli.com
In reply to: Kyotaro HORIGUCHI (#48)
Re: [HACKERS] [PATCH] Improve geometric types

! circle_contain_pt() does the following comparison and it
seems to be out of our current policy.

point_dt(center, point) <= radius

I suppose this should use FPle.

FPle(point_dt(center, point), radius)

The same is true of circle_contain_pt(), pt_contained_circle .

box_contain_point() also doesn't use the macros. They are certainly
inconsistent, but I don't think it would be an improvement to make
them use the macros. As we have discussed, there are many problems
with the current application of EPSILON. I think we would be better
off not using the macros for none of the containment operators, but
this is out of my scope for now.

# Sorry, that' all for today..

I am waiting the rest of your review to post the new versions.

#51Kyotaro HORIGUCHI
horiguchi.kyotaro@lab.ntt.co.jp
In reply to: Kyotaro HORIGUCHI (#48)
Re: [HACKERS] [PATCH] Improve geometric types

Hello,

At Wed, 31 Jan 2018 17:33:42 +0900 (Tokyo Standard Time), Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp> wrote in <20180131.173342.26333067.horiguchi.kyotaro@lab.ntt.co.jp>

0003: This patch replaces "double" with float and bare arithmetic
and comparisons on double to special functions accompanied
with checking against abnormal values.

- Almost all of them are eliminated with a few safe exceptions.

- circle_recv(), circle_distance(), dist_pc(), dist_cpoint()
are using "< 0.0" comparison but it looks fine.

- pg_hypot is right to use bare arithmetics.

! circle_contain_pt() does the following comparison and it
seems to be out of our current policy.

point_dt(center, point) <= radius

I suppose this should use FPle.

FPle(point_dt(center, point), radius)

The same is true of circle_contain_pt(), pt_contained_circle .

- line_eq looks too complex in the normal (not containing NANs)
cases. We should avoid such complexity if possible.

One problem here is that comparison conceals NANness of
operands. Conversely arithmetics propagate it. We can converge
NANness into a number. The attached line_eq() doesn that. This
doesn't have almost no additional complexity when NAN is
involved. I believe it qbehaves in the same way
and shares a doubious behavior like this.

=# select '{nan, 1, nan}'::line = '{nan, 2, nan}'::line;
?column?
----------
t

But probably no point in fixing(?) it.

The attached file contains line_eq, point_eq_point and
circle_same. I expect that line_eq is fast but other two are
doubious.

0004:

- line_perp

We can detect perpendicularity without division.

The normal vecotor of Ax + Bx + C = 0 is (A, B). If two lines
are perpendicular, the inner product of the normal vectors of
v1 and v2 is 0. No point in dividing.

l1->A * l2->A + l1->B * l2->B == 0

. . . Mmm.. The function seems broken. I posted the fix for
the existing version is posted, and line_perp() in the attched
file will work fine.

regards,

--
Kyotaro Horiguchi
NTT Open Source Software Center

#52Emre Hasegeli
emre@hasegeli.com
In reply to: Kyotaro HORIGUCHI (#51)
Re: [HACKERS] [PATCH] Improve geometric types

- line_eq looks too complex in the normal (not containing NANs)
cases. We should avoid such complexity if possible.

One problem here is that comparison conceals NANness of
operands. Conversely arithmetics propagate it. We can converge
NANness into a number. The attached line_eq() doesn that. This
doesn't have almost no additional complexity when NAN is
involved. I believe it qbehaves in the same way
and shares a doubious behavior like this.

=# select '{nan, 1, nan}'::line = '{nan, 2, nan}'::line;
?column?
----------
t

But probably no point in fixing(?) it.

I think we should fix it.

The attached file contains line_eq, point_eq_point and
circle_same. I expect that line_eq is fast but other two are
doubious.

I haven't got an attachment.

. . . Mmm.. The function seems broken. I posted the fix for
the existing version is posted, and line_perp() in the attched
file will work fine.

I am incorporating the fix you have posted to the other thread to this patch.

#53Andres Freund
andres@anarazel.de
In reply to: Emre Hasegeli (#52)
Re: [HACKERS] [PATCH] Improve geometric types

Hi,

On 2018-02-07 16:46:38 +0100, Emre Hasegeli wrote:

I am incorporating the fix you have posted to the other thread to this patch.

You've not posted a version fixing the issues in the surrounding thread,
do I see that right?

I'm a bit confused how this patch has gone through several revisions
since, but has been marked as "ready for committer" since 2017-09-05. Am
I missing something?

Greetings,

Andres Freund

#54Aleksander Alekseev
a.alekseev@postgrespro.ru
In reply to: Andres Freund (#53)
Re: [PATCH] Improve geometric types

The following review has been posted through the commitfest application:
make installcheck-world: tested, failed
Implements feature: not tested
Spec compliant: not tested
Documentation: not tested

Unfortunately according to http://commitfest.cputube.org/ this patch doesn't apply anymore.

The new status of this patch is: Waiting on Author

#55Emre Hasegeli
emre@hasegeli.com
In reply to: Aleksander Alekseev (#54)
6 attachment(s)
Re: [PATCH] Improve geometric types

Unfortunately according to http://commitfest.cputube.org/ this patch doesn't apply anymore.

New versions are attached.

Attachments:

0001-geo-funcs-v08.patchapplication/octet-stream; name=0001-geo-funcs-v08.patchDownload
From 096a1e74ba77515610764ce362aa3d2ab87b7073 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 27 May 2017 11:27:18 -0400
Subject: [PATCH 1/6] geo-funcs-v08

Refactor geometric functions and operators code

Most of the geometric types were not using functions of each other's.
I believe the reason behind this is simpler types line point and line
being developed after more complicated ones.  This patch reduces
duplicate code and makes functions of different datatypes more
compatible.  The changes can be summarised as:

* Eliminate SQL level function calls
* Re-use more functions to implement others
* Unify internal function names and signatures
* Remove private functions from geo_decls.h
* Replace not-possible checks with Assert()
* Add comments to describe some functions
* Remove some unreachable code
* Define delimiter symbols of line datatype like the other ones
* Remove debugging print()s from the refactored functions

This commits aims to not cause any user visible changes, but it is
almost impossible to stay completely bug-compatible with the old code.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com
---
 src/backend/utils/adt/geo_ops.c    | 1906 +++++++++++++++++-------------------
 src/backend/utils/adt/geo_spgist.c |    3 +-
 src/include/utils/geo_decls.h      |    4 -
 src/test/regress/regress.c         |    7 +-
 4 files changed, 880 insertions(+), 1040 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index f57380a4df..4f8ac71a6b 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -31,75 +31,104 @@
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
+/* Routines for points */
+static inline void point_construct(Point *result, float8 x, float8 y);
+static inline void point_add_point(Point *result, Point *pt1, Point *pt2);
+static inline void point_sub_point(Point *result, Point *pt1, Point *pt2);
+static inline void point_mul_point(Point *result, Point *pt1, Point *pt2);
+static inline void point_div_point(Point *result, Point *pt1, Point *pt2);
+static inline bool point_eq_point(Point *pt1, Point *pt2);
+static inline float8 point_dt(Point *pt1, Point *pt2);
+static inline float8 point_sl(Point *pt1, Point *pt2);
 static int	point_inside(Point *p, int npts, Point *plist);
+
+/* Routines for lines */
+static inline void line_construct(LINE *result, Point *pt, float8 m);
+static inline float8 line_invsl(LINE *line);
+static bool	line_interpt_line(Point *result, LINE *l1, LINE *l2);
+static bool line_contain_point(LINE *line, Point *point);
+static float8 line_closept_point(Point *result, LINE *line, Point *pt);
+
+/* Routines for line segments */
+static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
+static inline float8 lseg_sl(LSEG *lseg);
+static inline float8 lseg_invsl(LSEG *lseg);
+static bool	lseg_interpt_line(Point *result, LSEG *lseg, LINE *line);
+static bool	lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2);
 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_fill(BOX *result, double x1, double x2, double y1, double y2);
+static bool	lseg_contain_point(LSEG *lseg, Point *point);
+static float8 lseg_closept_point(Point *result, LSEG *lseg, Point *pt);
+static float8 lseg_closept_line(Point *result, LSEG *lseg, LINE *line);
+static float8 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2);
+
+/* Routines for boxes */
+static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
+static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
+static double box_ar(BOX *box);
 static double box_ht(BOX *box);
 static double box_wd(BOX *box);
+static bool box_contain_point(BOX *box, Point *point);
+static bool box_contain_box(BOX *box1, BOX *box2);
+static bool box_contain_lseg(BOX *box, LSEG *lseg);
+static bool box_interpt_lseg(Point *result, BOX *box, LSEG *lseg);
+static float8 box_closept_point(Point *result, BOX *box, Point *point);
+static float8 box_closept_lseg(Point *result, BOX *box, LSEG *lseg);
+
+/* Routines for circles */
 static double circle_ar(CIRCLE *circle);
-static CIRCLE *circle_copy(CIRCLE *circle);
-static LINE *line_construct_pm(Point *pt, double m);
-static void line_construct_pts(LINE *line, Point *pt1, Point *pt2);
-static bool lseg_intersect_internal(LSEG *l1, LSEG *l2);
-static double lseg_dt(LSEG *l1, LSEG *l2);
-static bool on_ps_internal(Point *pt, LSEG *lseg);
+
+/* Routines for polygons */
 static void make_bound_box(POLYGON *poly);
+static void poly_to_circle(CIRCLE *result, POLYGON *poly);
+static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
+static bool poly_contain_poly(POLYGON *polya, POLYGON *polyb);
 static bool plist_same(int npts, Point *p1, Point *p2);
-static Point *point_construct(double x, double y);
-static Point *point_copy(Point *pt);
+static float8 dist_ppoly_internal(Point *pt, POLYGON *poly);
+
+/* Routines for encoding and decoding */
 static double single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
 static void pair_decode(char *str, double *x, double *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
 static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
-static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
-static double box_ar(BOX *box);
-static void box_cn(Point *center, BOX *box);
-static Point *interpt_sl(LSEG *lseg, LINE *line);
-static bool has_interpt_sl(LSEG *lseg, LINE *line);
-static double dist_pl_internal(Point *pt, LINE *line);
-static double dist_ps_internal(Point *pt, LSEG *lseg);
-static Point *line_interpt_internal(LINE *l1, LINE *l2);
-static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
-static Point *lseg_interpt_internal(LSEG *l1, LSEG *l2);
-static double dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 
 /*
  * Delimiters for input and output strings.
  * LDELIM, RDELIM, and DELIM are left, right, and separator delimiters, respectively.
  * LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints.
  */
 
 #define LDELIM			'('
 #define RDELIM			')'
 #define DELIM			','
 #define LDELIM_EP		'['
 #define RDELIM_EP		']'
 #define LDELIM_C		'<'
 #define RDELIM_C		'>'
+#define LDELIM_L		'{'
+#define RDELIM_L		'}'
 
 
 /*
  * Geometric data types are composed of points.
  * This code tries to support a common format throughout the data types,
  *	to allow for more predictable usage and data type conversion.
  * The fundamental unit is the point. Other units are line segments,
  *	open paths, boxes, closed paths, and polygons (which should be considered
  *	non-intersecting closed paths).
  *
@@ -229,26 +258,23 @@ path_decode(char *str, bool opentype, int npts, Point *p,
 	}
 
 	for (i = 0; i < npts; i++)
 	{
 		pair_decode(str, &(p->x), &(p->y), &str, type_name, orig_string);
 		if (*str == DELIM)
 			str++;
 		p++;
 	}
 
-	while (isspace((unsigned char) *str))
-		str++;
 	while (depth > 0)
 	{
-		if ((*str == RDELIM)
-			|| ((*str == RDELIM_EP) && (*isopen) && (depth == 1)))
+		if (*str == RDELIM || (*str == RDELIM_EP && *isopen && depth == 1))
 		{
 			depth--;
 			str++;
 			while (isspace((unsigned char) *str))
 				str++;
 		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
@@ -433,89 +459,61 @@ box_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, box->high.x);
 	pq_sendfloat8(&buf, box->high.y);
 	pq_sendfloat8(&buf, box->low.x);
 	pq_sendfloat8(&buf, box->low.y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*		box_construct	-		fill in a new box.
  */
-static BOX *
-box_construct(double x1, double x2, double y1, double y2)
+static inline void
+box_construct(BOX *result, Point *pt1, Point *pt2)
 {
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	return box_fill(result, x1, x2, y1, y2);
-}
-
-
-/*		box_fill		-		fill in a given box struct
- */
-static BOX *
-box_fill(BOX *result, double x1, double x2, double y1, double y2)
-{
-	if (x1 > x2)
+	if (pt1->x > pt2->x)
 	{
-		result->high.x = x1;
-		result->low.x = x2;
+		result->high.x = pt1->x;
+		result->low.x = pt2->x;
 	}
 	else
 	{
-		result->high.x = x2;
-		result->low.x = x1;
+		result->high.x = pt2->x;
+		result->low.x = pt1->x;
 	}
-	if (y1 > y2)
+	if (pt1->y > pt2->y)
 	{
-		result->high.y = y1;
-		result->low.y = y2;
+		result->high.y = pt1->y;
+		result->low.y = pt2->y;
 	}
 	else
 	{
-		result->high.y = y2;
-		result->low.y = y1;
+		result->high.y = pt2->y;
+		result->low.y = pt1->y;
 	}
-
-	return result;
-}
-
-
-/*		box_copy		-		copy a box
- */
-BOX *
-box_copy(BOX *box)
-{
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	memcpy((char *) result, (char *) box, sizeof(BOX));
-
-	return result;
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for BOXes.
  *		<, >, <=, >=, and == are based on box area.
  *---------------------------------------------------------*/
 
 /*		box_same		-		are two boxes identical?
  */
 Datum
 box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPeq(box1->high.x, box2->high.x) &&
-				   FPeq(box1->low.x, box2->low.x) &&
-				   FPeq(box1->high.y, box2->high.y) &&
-				   FPeq(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(point_eq_point(&box1->high, &box2->high) &&
+				   point_eq_point(&box1->low, &box2->low));
 }
 
 /*		box_overlap		-		does box1 overlap box2?
  */
 Datum
 box_overlap(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
@@ -630,38 +628,44 @@ box_overabove(PG_FUNCTION_ARGS)
 }
 
 /*		box_contained	-		is box1 contained by box2?
  */
 Datum
 box_contained(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPle(box1->high.x, box2->high.x) &&
-				   FPge(box1->low.x, box2->low.x) &&
-				   FPle(box1->high.y, box2->high.y) &&
-				   FPge(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(box_contain_box(box2, box1));
 }
 
 /*		box_contain		-		does box1 contain box2?
  */
 Datum
 box_contain(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPge(box1->high.x, box2->high.x) &&
-				   FPle(box1->low.x, box2->low.x) &&
-				   FPge(box1->high.y, box2->high.y) &&
-				   FPle(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(box_contain_box(box1, box2));
+}
+
+/*
+ * Check whether the box is in the box or on its border
+ */
+static bool
+box_contain_box(BOX *box1, BOX *box2)
+{
+	return FPge(box1->high.x, box2->high.x) &&
+		   FPle(box1->low.x, box2->low.x) &&
+		   FPge(box1->high.y, box2->high.y) &&
+		   FPle(box1->low.y, box2->low.y);
 }
 
 
 /*		box_positionop	-
  *				is box1 entirely {above,below} box2?
  *
  * box_below_eq and box_above_eq are obsolete versions that (probably
  * erroneously) accept the equal-boundaries case.  Since these are not
  * in sync with the box_left and box_right code, they are deprecated and
  * not supported in the PG 8.1 rtree operator class extension.
@@ -750,51 +754,51 @@ box_area(PG_FUNCTION_ARGS)
 
 
 /*		box_width		-		returns the width of the box
  *								  (horizontal magnitude).
  */
 Datum
 box_width(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.x - box->low.x);
+	PG_RETURN_FLOAT8(box_wd(box));
 }
 
 
 /*		box_height		-		returns the height of the box
  *								  (vertical magnitude).
  */
 Datum
 box_height(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.y - box->low.y);
+	PG_RETURN_FLOAT8(box_ht(box));
 }
 
 
 /*		box_distance	-		returns the distance between the
  *								  center points of two boxes.
  */
 Datum
 box_distance(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 	Point		a,
 				b;
 
 	box_cn(&a, box1);
 	box_cn(&b, box2);
 
-	PG_RETURN_FLOAT8(HYPOT(a.x - b.x, a.y - b.y));
+	PG_RETURN_FLOAT8(point_dt(&a, &b));
 }
 
 
 /*		box_center		-		returns the center point of the box.
  */
 Datum
 box_center(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *result = (Point *) palloc(sizeof(Point));
@@ -898,76 +902,77 @@ static bool
 line_decode(char *s, const char *str, LINE *line)
 {
 	/* s was already advanced over leading '{' */
 	line->A = single_decode(s, &s, "line", str);
 	if (*s++ != DELIM)
 		return false;
 	line->B = single_decode(s, &s, "line", str);
 	if (*s++ != DELIM)
 		return false;
 	line->C = single_decode(s, &s, "line", str);
-	if (*s++ != '}')
+	if (*s++ != RDELIM_L)
 		return false;
 	while (isspace((unsigned char) *s))
 		s++;
 	if (*s != '\0')
 		return false;
 	return true;
 }
 
 Datum
 line_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	LINE	   *line = (LINE *) palloc(sizeof(LINE));
 	LSEG		lseg;
 	bool		isopen;
 	char	   *s;
 
 	s = str;
 	while (isspace((unsigned char) *s))
 		s++;
-	if (*s == '{')
+	if (*s == LDELIM_L)
 	{
 		if (!line_decode(s + 1, str, line))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
 							"line", str)));
 		if (FPzero(line->A) && FPzero(line->B))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: A and B cannot both be zero")));
 	}
 	else
 	{
-		path_decode(s, true, 2, &(lseg.p[0]), &isopen, NULL, "line", str);
-		if (FPeq(lseg.p[0].x, lseg.p[1].x) && FPeq(lseg.p[0].y, lseg.p[1].y))
+		path_decode(s, true, 2, &lseg.p[0], &isopen, NULL, "line", str);
+		if (point_eq_point(&lseg.p[0], &lseg.p[1]))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: must be two distinct points")));
-		line_construct_pts(line, &lseg.p[0], &lseg.p[1]);
+		line_construct(line, &lseg.p[0], lseg_sl(&lseg));
 	}
 
 	PG_RETURN_LINE_P(line);
 }
 
 
 Datum
 line_out(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	char	   *astr = float8out_internal(line->A);
 	char	   *bstr = float8out_internal(line->B);
 	char	   *cstr = float8out_internal(line->C);
 
-	PG_RETURN_CSTRING(psprintf("{%s,%s,%s}", astr, bstr, cstr));
+	PG_RETURN_CSTRING(psprintf("%c%s%c%s%c%s%c", LDELIM_L, astr, DELIM, bstr,
+							   DELIM, cstr, RDELIM_L));
 }
 
 /*
  *		line_recv			- converts external binary format to line
  */
 Datum
 line_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LINE	   *line;
@@ -996,128 +1001,78 @@ line_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, line->C);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*----------------------------------------------------------
  *	Conversion routines from one line formula to internal.
  *		Internal form:	Ax+By+C=0
  *---------------------------------------------------------*/
 
-/* line_construct_pm()
- * point-slope
+/*
+ * Fill already-allocated LINE struct from the point and the slope
  */
-static LINE *
-line_construct_pm(Point *pt, double m)
+static inline void
+line_construct(LINE *result, Point *pt, float8 m)
 {
-	LINE	   *result = (LINE *) palloc(sizeof(LINE));
-
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
 		result->A = -1;
 		result->B = 0;
 		result->C = pt->x;
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
 		result->C = pt->y - m * pt->x;
 	}
-
-	return result;
-}
-
-/*
- * Fill already-allocated LINE struct from two points on the line
- */
-static void
-line_construct_pts(LINE *line, Point *pt1, Point *pt2)
-{
-	if (FPeq(pt1->x, pt2->x))
-	{							/* vertical */
-		/* use "x = C" */
-		line->A = -1;
-		line->B = 0;
-		line->C = pt1->x;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is vertical\n");
-#endif
-	}
-	else if (FPeq(pt1->y, pt2->y))
-	{							/* horizontal */
-		/* use "y = C" */
-		line->A = 0;
-		line->B = -1;
-		line->C = pt1->y;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is horizontal\n");
-#endif
-	}
-	else
-	{
-		/* use "mx - y + yinter = 0" */
-		line->A = (pt2->y - pt1->y) / (pt2->x - pt1->x);
-		line->B = -1.0;
-		line->C = pt1->y - line->A * pt1->x;
-		/* on some platforms, the preceding expression tends to produce -0 */
-		if (line->C == 0.0)
-			line->C = 0.0;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is neither vertical nor horizontal (diffs x=%.*g, y=%.*g\n",
-			   DBL_DIG, (pt2->x - pt1->x), DBL_DIG, (pt2->y - pt1->y));
-#endif
-	}
 }
 
 /* line_construct_pp()
  * two points
  */
 Datum
 line_construct_pp(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 	LINE	   *result = (LINE *) palloc(sizeof(LINE));
 
-	line_construct_pts(result, pt1, pt2);
+	line_construct(result, pt1, point_sl(pt1, pt2));
+
 	PG_RETURN_LINE_P(result);
 }
 
 
 /*----------------------------------------------------------
  *	Relative position routines.
  *---------------------------------------------------------*/
 
 Datum
 line_intersect(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(!DatumGetBool(DirectFunctionCall2(line_parallel,
-													 LinePGetDatum(l1),
-													 LinePGetDatum(l2))));
+	PG_RETURN_BOOL(line_interpt_line(NULL, l1, l2));
 }
 
 Datum
 line_parallel(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
-	if (FPzero(l1->B))
-		PG_RETURN_BOOL(FPzero(l2->B));
-
-	PG_RETURN_BOOL(FPeq(l2->A, l1->A * (l2->B / l1->B)));
+	PG_RETURN_BOOL(!line_interpt_line(NULL, l1, l2));
 }
 
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
@@ -1162,105 +1117,113 @@ line_eq(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(FPeq(l1->A, k * l2->A) &&
 				   FPeq(l1->B, k * l2->B) &&
 				   FPeq(l1->C, k * l2->C));
 }
 
 
 /*----------------------------------------------------------
  *	Line arithmetic routines.
  *---------------------------------------------------------*/
 
+/*
+ * Return inverse slope of the line
+ */
+static inline float8
+line_invsl(LINE *line)
+{
+	if (FPzero(line->A))
+		return DBL_MAX;
+	if (FPzero(line->B))
+		return 0.0;
+	return line->B / line->A;
+}
+
+
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
-	Point	   *tmp;
+	Point		tmp;
 
-	if (!DatumGetBool(DirectFunctionCall2(line_parallel,
-										  LinePGetDatum(l1),
-										  LinePGetDatum(l2))))
+	if (line_interpt_line(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
 		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
-	tmp = point_construct(0.0, l1->C);
-	result = dist_pl_internal(tmp, l2);
+	point_construct(&tmp, 0.0, l1->C);
+	result = line_closept_point(NULL, l2, &tmp);
 	PG_RETURN_FLOAT8(result);
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
-	result = line_interpt_internal(l1, l2);
+	result = (Point *) palloc(sizeof(Point));
 
-	if (result == NULL)
+	if (!line_interpt_line(result, l1, l2))
 		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
 
 /*
  * Internal version of line_interpt
  *
- * returns a NULL pointer if no intersection point
+ * This returns true if two lines intersect (they do, if they are not
+ * parallel), false if they do not.  This also sets the intersection point
+ * to *result, if it is not NULL.
+ *
+ * NOTE If the lines are identical then we will find they are parallel
+ * and report "no intersection".  This is a little weird, but since
+ * there's no *unique* intersection, maybe it's appropriate behavior.
  */
-static Point *
-line_interpt_internal(LINE *l1, LINE *l2)
+static bool
+line_interpt_line(Point *result, LINE *l1, LINE *l2)
 {
-	Point	   *result;
 	double		x,
 				y;
 
-	/*
-	 * NOTE: if the lines are identical then we will find they are parallel
-	 * and report "no intersection".  This is a little weird, but since
-	 * there's no *unique* intersection, maybe it's appropriate behavior.
-	 */
-	if (DatumGetBool(DirectFunctionCall2(line_parallel,
-										 LinePGetDatum(l1),
-										 LinePGetDatum(l2))))
-		return NULL;
-
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
+		if (FPzero(l2->B))		/* l2 vertical? */
+			return false;
+
 		x = l1->C;
 		y = (l2->A * x + l2->C);
 	}
 	else if (FPzero(l2->B))		/* l2 vertical? */
 	{
 		x = l2->C;
 		y = (l1->A * x + l1->C);
 	}
 	else
 	{
+		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+			return false;
+
 		x = (l1->C - l2->C) / (l2->A - l1->A);
 		y = (l1->A * x + l1->C);
 	}
-	result = point_construct(x, y);
+	if (result != NULL)
+		point_construct(result, x, y);
 
-#ifdef GEODEBUG
-	printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
-		   DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
-	printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
-#endif
-
-	return result;
+	return true;
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D paths (sequences of line segments, also
  **				called `polylines').
  **
  **				This is not a general package for geometric paths,
  **				which of course include polygons; the emphasis here
@@ -1555,22 +1518,21 @@ path_inter(PG_FUNCTION_ARGS)
 {
 	PATH	   *p1 = PG_GETARG_PATH_P(0);
 	PATH	   *p2 = PG_GETARG_PATH_P(1);
 	BOX			b1,
 				b2;
 	int			i,
 				j;
 	LSEG		seg1,
 				seg2;
 
-	if (p1->npts <= 0 || p2->npts <= 0)
-		PG_RETURN_BOOL(false);
+	Assert(p1->npts > 0 && p2->npts > 0);
 
 	b1.high.x = b1.low.x = p1->p[0].x;
 	b1.high.y = b1.low.y = p1->p[0].y;
 	for (i = 1; i < p1->npts; i++)
 	{
 		b1.high.x = Max(p1->p[i].x, b1.high.x);
 		b1.high.y = Max(p1->p[i].y, b1.high.y);
 		b1.low.x = Min(p1->p[i].x, b1.low.x);
 		b1.low.y = Min(p1->p[i].y, b1.low.y);
 	}
@@ -1608,21 +1570,21 @@ path_inter(PG_FUNCTION_ARGS)
 				jprev = j - 1;
 			else
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
-			if (lseg_intersect_internal(&seg1, &seg2))
+			if (lseg_interpt_lseg(NULL, &seg1, &seg2))
 				PG_RETURN_BOOL(true);
 		}
 	}
 
 	/* if we dropped through, no two segs intersected */
 	PG_RETURN_BOOL(false);
 }
 
 /* path_distance()
  * This essentially does a cartesian product of the lsegs in the
@@ -1663,23 +1625,21 @@ path_distance(PG_FUNCTION_ARGS)
 			else
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
-			tmp = DatumGetFloat8(DirectFunctionCall2(lseg_distance,
-													 LsegPGetDatum(&seg1),
-													 LsegPGetDatum(&seg2)));
+			tmp = lseg_closept_lseg(NULL, &seg1, &seg2);
 			if (!have_min || tmp < min)
 			{
 				min = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	if (!have_min)
 		PG_RETURN_NULL();
@@ -1773,44 +1733,31 @@ point_send(PG_FUNCTION_ARGS)
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	StringInfoData buf;
 
 	pq_begintypsend(&buf);
 	pq_sendfloat8(&buf, pt->x);
 	pq_sendfloat8(&buf, pt->y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
-static Point *
-point_construct(double x, double y)
+/*
+ * Initialize a point
+ *
+ * This function is over-simple, but it is, at least, useful when the new
+ * point is calculated using the existing one.
+ */
+static inline void
+point_construct(Point *result, float8 x, float8 y)
 {
-	Point	   *result = (Point *) palloc(sizeof(Point));
-
 	result->x = x;
 	result->y = y;
-	return result;
-}
-
-
-static Point *
-point_copy(Point *pt)
-{
-	Point	   *result;
-
-	if (!PointerIsValid(pt))
-		return NULL;
-
-	result = (Point *) palloc(sizeof(Point));
-
-	result->x = pt->x;
-	result->y = pt->y;
-	return result;
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for Points.
  *		Since we do have a sense of coordinates being
  *		"equal" to a given accuracy (point_vert, point_horiz),
  *		the other ops must preserve that sense.  This means
  *		that results may, strictly speaking, be a lie (unless
  *		EPSILON = 0.0).
@@ -1869,71 +1816,97 @@ point_horiz(PG_FUNCTION_ARGS)
 
 	PG_RETURN_BOOL(FPeq(pt1->y, pt2->y));
 }
 
 Datum
 point_eq(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y));
+	PG_RETURN_BOOL(point_eq_point(pt1, pt2));
 }
 
 Datum
 point_ne(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPne(pt1->x, pt2->x) || FPne(pt1->y, pt2->y));
+	PG_RETURN_BOOL(!point_eq_point(pt1, pt2));
 }
 
+static inline bool
+point_eq_point(Point *pt1, Point *pt2)
+{
+	return FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y);
+}
+
+
 /*----------------------------------------------------------
  *	"Arithmetic" operators on points.
  *---------------------------------------------------------*/
 
 Datum
 point_distance(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_FLOAT8(HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
+	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
-double
+static inline float8
 point_dt(Point *pt1, Point *pt2)
 {
-#ifdef GEODEBUG
-	printf("point_dt- segment (%f,%f),(%f,%f) length is %f\n",
-		   pt1->x, pt1->y, pt2->x, pt2->y, HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
-#endif
 	return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
 }
 
 Datum
 point_slope(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_sl(pt1, pt2));
 }
 
 
-double
+/*
+ * Return slope of two points
+ *
+ * Note that this function returns DBL_MAX when the points are the same.
+ */
+static inline float8
 point_sl(Point *pt1, Point *pt2)
 {
-	return (FPeq(pt1->x, pt2->x)
-			? (double) DBL_MAX
-			: (pt1->y - pt2->y) / (pt1->x - pt2->x));
+	if (FPeq(pt1->x, pt2->x))
+		return DBL_MAX;
+	if (FPeq(pt1->y, pt2->y))
+		return 0.0;
+	return (pt1->y - pt2->y) / (pt1->x - pt2->x);
+}
+
+
+/*
+ * Return inverse slope of two points
+ *
+ * Note that this function returns 0.0 when the points are the same.
+ */
+static inline float8
+point_invsl(Point *pt1, Point *pt2)
+{
+	if (FPeq(pt1->x, pt2->x))
+		return 0.0;
+	if (FPeq(pt1->y, pt2->y))
+		return DBL_MAX;
+	return (pt1->x - pt2->x) / (pt2->y - pt1->y);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D line segments.
  **
  ***********************************************************************/
 
 /*----------------------------------------------------------
@@ -1945,31 +1918,31 @@ point_sl(Point *pt1, Point *pt2)
  *		(old form)		"(x1, y1, x2, y2)"
  *---------------------------------------------------------*/
 
 Datum
 lseg_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	LSEG	   *lseg = (LSEG *) palloc(sizeof(LSEG));
 	bool		isopen;
 
-	path_decode(str, true, 2, &(lseg->p[0]), &isopen, NULL, "lseg", str);
+	path_decode(str, true, 2, &lseg->p[0], &isopen, NULL, "lseg", str);
 	PG_RETURN_LSEG_P(lseg);
 }
 
 
 Datum
 lseg_out(PG_FUNCTION_ARGS)
 {
 	LSEG	   *ls = PG_GETARG_LSEG_P(0);
 
-	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, (Point *) &(ls->p[0])));
+	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, &ls->p[0]));
 }
 
 /*
  *		lseg_recv			- converts external binary format to lseg
  */
 Datum
 lseg_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LSEG	   *lseg;
@@ -2005,38 +1978,56 @@ lseg_send(PG_FUNCTION_ARGS)
 /* lseg_construct -
  *		form a LSEG from two Points.
  */
 Datum
 lseg_construct(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 	LSEG	   *result = (LSEG *) palloc(sizeof(LSEG));
 
-	result->p[0].x = pt1->x;
-	result->p[0].y = pt1->y;
-	result->p[1].x = pt2->x;
-	result->p[1].y = pt2->y;
+	statlseg_construct(result, pt1, pt2);
 
 	PG_RETURN_LSEG_P(result);
 }
 
 /* like lseg_construct, but assume space already allocated */
-static void
+static inline void
 statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2)
 {
 	lseg->p[0].x = pt1->x;
 	lseg->p[0].y = pt1->y;
 	lseg->p[1].x = pt2->x;
 	lseg->p[1].y = pt2->y;
 }
 
+
+/*
+ * Return slope of the line segment
+ */
+static inline float8
+lseg_sl(LSEG *lseg)
+{
+	return point_sl(&lseg->p[0], &lseg->p[1]);
+}
+
+
+/*
+ * Return inverse slope of the line segment
+ */
+static inline float8
+lseg_invsl(LSEG *lseg)
+{
+	return point_invsl(&lseg->p[0], &lseg->p[1]);
+}
+
+
 Datum
 lseg_length(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 
 	PG_RETURN_FLOAT8(point_dt(&lseg->p[0], &lseg->p[1]));
 }
 
 /*----------------------------------------------------------
  *	Relative position routines.
@@ -2045,79 +2036,43 @@ lseg_length(PG_FUNCTION_ARGS)
 /*
  **  find intersection of the two lines, and see if it falls on
  **  both segments.
  */
 Datum
 lseg_intersect(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(lseg_intersect_internal(l1, l2));
+	PG_RETURN_BOOL(lseg_interpt_lseg(NULL, l1, l2));
 }
 
-static bool
-lseg_intersect_internal(LSEG *l1, LSEG *l2)
-{
-	LINE		ln;
-	Point	   *interpt;
-	bool		retval;
-
-	line_construct_pts(&ln, &l2->p[0], &l2->p[1]);
-	interpt = interpt_sl(l1, &ln);
-
-	if (interpt != NULL && on_ps_internal(interpt, l2))
-		retval = true;			/* interpt on l1 and l2 */
-	else
-		retval = false;
-	return retval;
-}
 
 Datum
 lseg_parallel(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPeq(point_sl(&l1->p[0], &l1->p[1]),
-						point_sl(&l2->p[0], &l2->p[1])));
+	PG_RETURN_BOOL(FPeq(lseg_sl(l1), lseg_sl(l2)));
 }
 
-/* lseg_perp()
+/*
  * Determine if two line segments are perpendicular.
- *
- * This code did not get the correct answer for
- *	'((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg
- * So, modified it to check explicitly for slope of vertical line
- *	returned by point_sl() and the results seem better.
- * - thomas 1998-01-31
  */
 Datum
 lseg_perp(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	double		m1,
-				m2;
 
-	m1 = point_sl(&(l1->p[0]), &(l1->p[1]));
-	m2 = point_sl(&(l2->p[0]), &(l2->p[1]));
-
-#ifdef GEODEBUG
-	printf("lseg_perp- slopes are %g and %g\n", m1, m2);
-#endif
-	if (FPzero(m1))
-		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
-	else if (FPzero(m2))
-		PG_RETURN_BOOL(FPeq(m1, DBL_MAX));
-
-	PG_RETURN_BOOL(FPeq(m1 / m2, -1.0));
+	PG_RETURN_BOOL(FPeq(lseg_sl(l1), lseg_invsl(l2)));
 }
 
 Datum
 lseg_vertical(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 
 	PG_RETURN_BOOL(FPeq(lseg->p[0].x, lseg->p[1].x));
 }
 
@@ -2129,36 +2084,32 @@ lseg_horizontal(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(FPeq(lseg->p[0].y, lseg->p[1].y));
 }
 
 
 Datum
 lseg_eq(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPeq(l1->p[0].x, l2->p[0].x) &&
-				   FPeq(l1->p[0].y, l2->p[0].y) &&
-				   FPeq(l1->p[1].x, l2->p[1].x) &&
-				   FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(point_eq_point(&l1->p[0], &l2->p[0]) &&
+				   point_eq_point(&l1->p[1], &l2->p[1]));
 }
 
 Datum
 lseg_ne(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(!FPeq(l1->p[0].x, l2->p[0].x) ||
-				   !FPeq(l1->p[0].y, l2->p[0].y) ||
-				   !FPeq(l1->p[1].x, l2->p[1].x) ||
-				   !FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(!point_eq_point(&l1->p[0], &l2->p[0]) ||
+				   !point_eq_point(&l1->p[1], &l2->p[1]));
 }
 
 Datum
 lseg_lt(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_BOOL(FPlt(point_dt(&l1->p[0], &l1->p[1]),
 						point_dt(&l2->p[0], &l2->p[1])));
@@ -2203,126 +2154,81 @@ lseg_ge(PG_FUNCTION_ARGS)
  *		If two segments don't intersect, then the closest
  *		point will be from one of the endpoints to the other
  *		segment.
  */
 Datum
 lseg_distance(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_FLOAT8(lseg_dt(l1, l2));
-}
-
-/* lseg_dt()
- * Distance between two line segments.
- * Must check both sets of endpoints to ensure minimum distance is found.
- * - thomas 1998-02-01
- */
-static double
-lseg_dt(LSEG *l1, LSEG *l2)
-{
-	double		result,
-				d;
-
-	if (lseg_intersect_internal(l1, l2))
-		return 0.0;
-
-	d = dist_ps_internal(&l1->p[0], l2);
-	result = d;
-	d = dist_ps_internal(&l1->p[1], l2);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[0], l1);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[1], l1);
-	result = Min(result, d);
-
-	return result;
+	PG_RETURN_FLOAT8(lseg_closept_lseg(NULL, l1, l2));
 }
 
 
 Datum
 lseg_center(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
 	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
 
 	PG_RETURN_POINT_P(result);
 }
 
-static Point *
-lseg_interpt_internal(LSEG *l1, LSEG *l2)
+
+/*
+ *		Find the intersection point of two segments (if any).
+ *
+ * This returns true if two line segments intersect, false if they do not.
+ * This also sets the intersection point to *result, if it is not NULL.
+ * This function is almost perfectly symmetric, even though it doesn't look
+ * like it.  See lseg_interpt_line() for the other half of it.
+ */
+static bool
+lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2)
 {
-	Point	   *result;
-	LINE		tmp1,
-				tmp2;
+	Point		interpt;
+	LINE		tmp;
+
+	line_construct(&tmp, &l2->p[0], lseg_sl(l2));
+	if (!lseg_interpt_line(&interpt, l1, &tmp))
+		return false;
 
 	/*
-	 * Find the intersection of the appropriate lines, if any.
+	 * If the line intersection point isn't within l2, there is no valid
+	 * segment intersection point at all.
 	 */
-	line_construct_pts(&tmp1, &l1->p[0], &l1->p[1]);
-	line_construct_pts(&tmp2, &l2->p[0], &l2->p[1]);
-	result = line_interpt_internal(&tmp1, &tmp2);
-	if (!PointerIsValid(result))
-		return NULL;
+	if (!lseg_contain_point(l2, &interpt))
+		return false;
 
-	/*
-	 * If the line intersection point isn't within l1 (or equivalently l2),
-	 * there is no valid segment intersection point at all.
-	 */
-	if (!on_ps_internal(result, l1) ||
-		!on_ps_internal(result, l2))
-	{
-		pfree(result);
-		return NULL;
-	}
+	if (result != NULL)
+		*result = interpt;
 
-	/*
-	 * If there is an intersection, then check explicitly for matching
-	 * endpoints since there may be rounding effects with annoying lsb
-	 * residue. - tgl 1997-07-09
-	 */
-	if ((FPeq(l1->p[0].x, l2->p[0].x) && FPeq(l1->p[0].y, l2->p[0].y)) ||
-		(FPeq(l1->p[0].x, l2->p[1].x) && FPeq(l1->p[0].y, l2->p[1].y)))
-	{
-		result->x = l1->p[0].x;
-		result->y = l1->p[0].y;
-	}
-	else if ((FPeq(l1->p[1].x, l2->p[0].x) && FPeq(l1->p[1].y, l2->p[0].y)) ||
-			 (FPeq(l1->p[1].x, l2->p[1].x) && FPeq(l1->p[1].y, l2->p[1].y)))
-	{
-		result->x = l1->p[1].x;
-		result->y = l1->p[1].y;
-	}
-
-	return result;
+	return true;
 }
 
-/* lseg_interpt -
- *		Find the intersection point of two segments (if any).
- */
 Datum
 lseg_interpt(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
-	result = lseg_interpt_internal(l1, l2);
-	if (!PointerIsValid(result))
-		PG_RETURN_NULL();
+	result = (Point *) palloc(sizeof(Point));
 
+	if (!lseg_interpt_lseg(result, l1, l2))
+		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
 
 /***********************************************************************
  **
  **		Routines for position comparisons of differently-typed
  **				2D objects.
  **
  ***********************************************************************/
 
@@ -2333,215 +2239,128 @@ lseg_interpt(PG_FUNCTION_ARGS)
 
 /*
  * Distance from a point to a line
  */
 Datum
 dist_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_FLOAT8(dist_pl_internal(pt, line));
+	PG_RETURN_FLOAT8(line_closept_point(NULL, line, pt));
 }
 
-static double
-dist_pl_internal(Point *pt, LINE *line)
-{
-	return fabs((line->A * pt->x + line->B * pt->y + line->C) /
-				HYPOT(line->A, line->B));
-}
 
 /*
  * Distance from a point to a lseg
  */
 Datum
 dist_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_FLOAT8(dist_ps_internal(pt, lseg));
-}
-
-static double
-dist_ps_internal(Point *pt, LSEG *lseg)
-{
-	double		m;				/* slope of perp. */
-	LINE	   *ln;
-	double		result,
-				tmpdist;
-	Point	   *ip;
-
-	/*
-	 * Construct a line perpendicular to the input segment and through the
-	 * input point
-	 */
-	if (lseg->p[1].x == lseg->p[0].x)
-		m = 0;
-	else if (lseg->p[1].y == lseg->p[0].y)
-		m = (double) DBL_MAX;	/* slope is infinite */
-	else
-		m = (lseg->p[0].x - lseg->p[1].x) / (lseg->p[1].y - lseg->p[0].y);
-	ln = line_construct_pm(pt, m);
-
-#ifdef GEODEBUG
-	printf("dist_ps- line is A=%g B=%g C=%g from (point) slope (%f,%f) %g\n",
-		   ln->A, ln->B, ln->C, pt->x, pt->y, m);
-#endif
-
-	/*
-	 * Calculate distance to the line segment or to the nearest endpoint of
-	 * the segment.
-	 */
-
-	/* intersection is on the line segment? */
-	if ((ip = interpt_sl(lseg, ln)) != NULL)
-	{
-		/* yes, so use distance to the intersection point */
-		result = point_dt(pt, ip);
-#ifdef GEODEBUG
-		printf("dist_ps- distance is %f to intersection point is (%f,%f)\n",
-			   result, ip->x, ip->y);
-#endif
-	}
-	else
-	{
-		/* no, so use distance to the nearer endpoint */
-		result = point_dt(pt, &lseg->p[0]);
-		tmpdist = point_dt(pt, &lseg->p[1]);
-		if (tmpdist < result)
-			result = tmpdist;
-	}
-
-	return result;
+	PG_RETURN_FLOAT8(lseg_closept_point(NULL, lseg, pt));
 }
 
 /*
  * Distance from a point to a path
  */
 Datum
 dist_ppath(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	PATH	   *path = PG_GETARG_PATH_P(1);
 	float8		result = 0.0;	/* keep compiler quiet */
 	bool		have_min = false;
 	float8		tmp;
 	int			i;
 	LSEG		lseg;
 
-	switch (path->npts)
+	Assert(path->npts > 0);
+
+	/*
+	 * The distance from a point to a path is the smallest distance
+	 * from the point to any of its constituent segments.
+	 */
+	for (i = 0; i < path->npts; i++)
 	{
-		case 0:
-			/* no points in path? then result is undefined... */
-			PG_RETURN_NULL();
-		case 1:
-			/* one point in path? then get distance between two points... */
-			result = point_dt(pt, &path->p[0]);
-			break;
-		default:
-			/* make sure the path makes sense... */
-			Assert(path->npts > 1);
+		int			iprev;
 
-			/*
-			 * the distance from a point to a path is the smallest distance
-			 * from the point to any of its constituent segments.
-			 */
-			for (i = 0; i < path->npts; i++)
-			{
-				int			iprev;
+		if (i > 0)
+			iprev = i - 1;
+		else
+		{
+			if (!path->closed)
+				continue;
+			iprev = path->npts - 1; /* Include the closure segment */
+		}
 
-				if (i > 0)
-					iprev = i - 1;
-				else
-				{
-					if (!path->closed)
-						continue;
-					iprev = path->npts - 1; /* include the closure segment */
-				}
-
-				statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
-				tmp = dist_ps_internal(pt, &lseg);
-				if (!have_min || tmp < result)
-				{
-					result = tmp;
-					have_min = true;
-				}
-			}
-			break;
+		statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
+		tmp = lseg_closept_point(NULL, &lseg, pt);
+		if (!have_min || tmp < result)
+		{
+			result = tmp;
+			have_min = true;
+		}
 	}
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a point to a box
  */
 Datum
 dist_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
-	float8		result;
-	Point	   *near;
 
-	near = DatumGetPointP(DirectFunctionCall2(close_pb,
-											  PointPGetDatum(pt),
-											  BoxPGetDatum(box)));
-	result = point_dt(near, pt);
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(box_closept_point(NULL, box, pt));
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	float8		result,
 				d2;
 
-	if (has_interpt_sl(lseg, line))
+	if (lseg_interpt_line(NULL, lseg, line))
 		result = 0.0;
 	else
 	{
-		result = dist_pl_internal(&lseg->p[0], line);
-		d2 = dist_pl_internal(&lseg->p[1], line);
+		result = line_closept_point(NULL, line, &lseg->p[0]);
+		d2 = line_closept_point(NULL, line, &lseg->p[1]);
 		/* XXX shouldn't we take the min not max? */
 		if (d2 > result)
 			result = d2;
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
-	Point	   *tmp;
-	Datum		result;
 
-	tmp = DatumGetPointP(DirectFunctionCall2(close_sb,
-											 LsegPGetDatum(lseg),
-											 BoxPGetDatum(box)));
-	result = DirectFunctionCall2(dist_pb,
-								 PointPGetDatum(tmp),
-								 BoxPGetDatum(box));
-
-	PG_RETURN_DATUM(result);
+	PG_RETURN_FLOAT8(box_closept_lseg(NULL, box, lseg));
 }
 
 /*
  * Distance from a line to a box
  */
 Datum
 dist_lb(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -2577,538 +2396,509 @@ dist_cpoly(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a point to a polygon
  */
 Datum
 dist_ppoly(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	POLYGON    *poly = PG_GETARG_POLYGON_P(1);
-	float8		result;
 
-	result = dist_ppoly_internal(point, poly);
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(dist_ppoly_internal(point, poly));
 }
 
 Datum
 dist_polyp(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	float8		result;
 
-	result = dist_ppoly_internal(point, poly);
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(dist_ppoly_internal(point, poly));
 }
 
-static double
+static float8
 dist_ppoly_internal(Point *pt, POLYGON *poly)
 {
 	float8		result;
 	float8		d;
 	int			i;
 	LSEG		seg;
 
 	if (point_inside(pt, poly->npts, poly->p) != 0)
 	{
 #ifdef GEODEBUG
 		printf("dist_ppoly_internal- point inside of polygon\n");
 #endif
 		return 0.0;
 	}
 
 	/* initialize distance with segment between first and last points */
 	seg.p[0].x = poly->p[0].x;
 	seg.p[0].y = poly->p[0].y;
 	seg.p[1].x = poly->p[poly->npts - 1].x;
 	seg.p[1].y = poly->p[poly->npts - 1].y;
-	result = dist_ps_internal(pt, &seg);
+	result = lseg_closept_point(NULL, &seg, pt);
 #ifdef GEODEBUG
 	printf("dist_ppoly_internal- segment 0/n distance is %f\n", result);
 #endif
 
 	/* check distances for other segments */
-	for (i = 0; (i < poly->npts - 1); i++)
+	for (i = 0; i < poly->npts - 1; i++)
 	{
 		seg.p[0].x = poly->p[i].x;
 		seg.p[0].y = poly->p[i].y;
 		seg.p[1].x = poly->p[i + 1].x;
 		seg.p[1].y = poly->p[i + 1].y;
-		d = dist_ps_internal(pt, &seg);
+		d = lseg_closept_point(NULL, &seg, pt);
 #ifdef GEODEBUG
 		printf("dist_ppoly_internal- segment %d distance is %f\n", (i + 1), d);
 #endif
 		if (d < result)
 			result = d;
 	}
 
 	return result;
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
  *				Intersection point of objects.
  *				We choose to ignore the "point" of intersection between
  *				  lines and boxes, since there are typically two.
  *-------------------------------------------------------------------*/
 
-/* Get intersection point of lseg and line; returns NULL if no intersection */
-static Point *
-interpt_sl(LSEG *lseg, LINE *line)
-{
-	LINE		tmp;
-	Point	   *p;
-
-	line_construct_pts(&tmp, &lseg->p[0], &lseg->p[1]);
-	p = line_interpt_internal(&tmp, line);
-#ifdef GEODEBUG
-	printf("interpt_sl- segment is (%.*g %.*g) (%.*g %.*g)\n",
-		   DBL_DIG, lseg->p[0].x, DBL_DIG, lseg->p[0].y, DBL_DIG, lseg->p[1].x, DBL_DIG, lseg->p[1].y);
-	printf("interpt_sl- segment becomes line A=%.*g B=%.*g C=%.*g\n",
-		   DBL_DIG, tmp.A, DBL_DIG, tmp.B, DBL_DIG, tmp.C);
-#endif
-	if (PointerIsValid(p))
-	{
-#ifdef GEODEBUG
-		printf("interpt_sl- intersection point is (%.*g %.*g)\n", DBL_DIG, p->x, DBL_DIG, p->y);
-#endif
-		if (on_ps_internal(p, lseg))
-		{
-#ifdef GEODEBUG
-			printf("interpt_sl- intersection point is on segment\n");
-#endif
-		}
-		else
-			p = NULL;
-	}
-
-	return p;
-}
-
-/* variant: just indicate if intersection point exists */
+/*
+ * Check if the line segment intersects with the line
+ *
+ * This returns true if line segment intersects with line, false if they
+ * do not.  This also sets the intersection point to *result, if it is not
+ * NULL.
+ */
 static bool
-has_interpt_sl(LSEG *lseg, LINE *line)
+lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
 {
-	Point	   *tmp;
+	Point		interpt;
+	LINE		tmp;
 
-	tmp = interpt_sl(lseg, line);
-	if (tmp)
+	line_construct(&tmp, &lseg->p[0], lseg_sl(lseg));
+	if (!line_interpt_line(&interpt, &tmp, line))
+		return false;
+
+	if (!lseg_contain_point(lseg, &interpt))
+		return false;
+
+	if (result == NULL)
 		return true;
-	return false;
+
+	/*
+	 * If there is an intersection, then check explicitly for matching
+	 * endpoints since there may be rounding effects with annoying LSB
+	 * residue.
+	 */
+	if (point_eq_point(&lseg->p[0], &interpt))
+		*result = lseg->p[0];
+	else if (point_eq_point(&lseg->p[1], &interpt))
+		*result = lseg->p[1];
+	else
+		*result = interpt;
+
+	return true;
 }
 
 /*---------------------------------------------------------------------
  *		close_
  *				Point of closest proximity between objects.
  *-------------------------------------------------------------------*/
 
-/* close_pl -
+/*
  *		The intersection point of a perpendicular of the line
  *		through the point.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
+static float8
+line_closept_point(Point *result, LINE *line, Point *point)
+{
+	bool		retval;
+	LINE		tmp;
+
+	/* Drop a perpendicular and find the intersection point */
+	line_construct(&tmp, point, line_invsl(line));
+	retval = line_interpt_line(result, line, &tmp);
+	Assert(retval);		/* XXX We need something better. */
+
+	/*
+	 * XXX We could use the distance to the closest point, but
+	 * line_interpt_line() is currently giving wrong results.
+	 */
+	return fabs((line->A * point->x + line->B * point->y + line->C) /
+				HYPOT(line->A, line->B));
+}
+
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
-	LINE	   *tmp;
-	double		invm;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	if (FPzero(line->B))		/* vertical? */
-	{
-		result->x = line->C;
-		result->y = pt->y;
-		PG_RETURN_POINT_P(result);
-	}
-	if (FPzero(line->A))		/* horizontal? */
-	{
-		result->x = pt->x;
-		result->y = line->C;
-		PG_RETURN_POINT_P(result);
-	}
-	/* drop a perpendicular and find the intersection point */
+	line_closept_point(result, line, pt);
 
-	/* invert and flip the sign on the slope to get a perpendicular */
-	invm = line->B / line->A;
-	tmp = line_construct_pm(pt, invm);
-	result = line_interpt_internal(tmp, line);
-	Assert(result != NULL);
 	PG_RETURN_POINT_P(result);
 }
 
 
-/* close_ps()
+/*
  * Closest point on line segment to specified point.
- * Take the closest endpoint if the point is left, right,
- *	above, or below the segment, otherwise find the intersection
- *	point of the segment and its perpendicular through the point.
  *
- * Some tricky code here, relying on boolean expressions
- *	evaluating to only zero or one to use as an array index.
- *		bug fixes by gthaker@atl.lmco.com; May 1, 1998
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
+static float8
+lseg_closept_point(Point *result, LSEG *lseg, Point *pt)
+{
+	Point		closept;
+	LINE		tmp;
+
+	/*
+	 * To find the closest point, we draw a perpendicular line from the point
+	 * to the line segment.
+	 */
+	line_construct(&tmp, pt, point_invsl(&lseg->p[0], &lseg->p[1]));
+	lseg_closept_line(&closept, lseg, &tmp);
+
+	if (result != NULL)
+		*result = closept;
+
+	return point_dt(&closept, pt);
+}
+
 Datum
 close_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
-	LINE	   *tmp;
-	double		invm;
-	int			xh,
-				yh;
+	Point	   *result;
 
-#ifdef GEODEBUG
-	printf("close_sp:pt->x %f pt->y %f\nlseg(0).x %f lseg(0).y %f  lseg(1).x %f lseg(1).y %f\n",
-		   pt->x, pt->y, lseg->p[0].x, lseg->p[0].y,
-		   lseg->p[1].x, lseg->p[1].y);
-#endif
+	result = (Point *) palloc(sizeof(Point));
 
-	/* xh (or yh) is the index of upper x( or y) end point of lseg */
-	/* !xh (or !yh) is the index of lower x( or y) end point of lseg */
-	xh = lseg->p[0].x < lseg->p[1].x;
-	yh = lseg->p[0].y < lseg->p[1].y;
-
-	if (FPeq(lseg->p[0].x, lseg->p[1].x))	/* vertical? */
-	{
-#ifdef GEODEBUG
-		printf("close_ps- segment is vertical\n");
-#endif
-		/* first check if point is below or above the entire lseg. */
-		if (pt->y < lseg->p[!yh].y)
-			result = point_copy(&lseg->p[!yh]); /* below the lseg */
-		else if (pt->y > lseg->p[yh].y)
-			result = point_copy(&lseg->p[yh]);	/* above the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
-
-		/* point lines along (to left or right) of the vertical lseg. */
-
-		result = (Point *) palloc(sizeof(Point));
-		result->x = lseg->p[0].x;
-		result->y = pt->y;
-		PG_RETURN_POINT_P(result);
-	}
-	else if (FPeq(lseg->p[0].y, lseg->p[1].y))	/* horizontal? */
-	{
-#ifdef GEODEBUG
-		printf("close_ps- segment is horizontal\n");
-#endif
-		/* first check if point is left or right of the entire lseg. */
-		if (pt->x < lseg->p[!xh].x)
-			result = point_copy(&lseg->p[!xh]); /* left of the lseg */
-		else if (pt->x > lseg->p[xh].x)
-			result = point_copy(&lseg->p[xh]);	/* right of the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
-
-		/* point lines along (at top or below) the horiz. lseg. */
-		result = (Point *) palloc(sizeof(Point));
-		result->x = pt->x;
-		result->y = lseg->p[0].y;
-		PG_RETURN_POINT_P(result);
-	}
-
-	/*
-	 * vert. and horiz. cases are down, now check if the closest point is one
-	 * of the end points or someplace on the lseg.
-	 */
-
-	invm = -1.0 / point_sl(&(lseg->p[0]), &(lseg->p[1]));
-	tmp = line_construct_pm(&lseg->p[!yh], invm);	/* lower edge of the
-													 * "band" */
-	if (pt->y < (tmp->A * pt->x + tmp->C))
-	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[!yh]); /* below the lseg, take lower end
-											 * pt */
-#ifdef GEODEBUG
-		printf("close_ps below: tmp A %f  B %f   C %f\n",
-			   tmp->A, tmp->B, tmp->C);
-#endif
-		PG_RETURN_POINT_P(result);
-	}
-	tmp = line_construct_pm(&lseg->p[yh], invm);	/* upper edge of the
-													 * "band" */
-	if (pt->y > (tmp->A * pt->x + tmp->C))
-	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[yh]);	/* above the lseg, take higher end
-											 * pt */
-#ifdef GEODEBUG
-		printf("close_ps above: tmp A %f  B %f   C %f\n",
-			   tmp->A, tmp->B, tmp->C);
-#endif
-		PG_RETURN_POINT_P(result);
-	}
-
-	/*
-	 * at this point the "normal" from point will hit lseg. The closest point
-	 * will be somewhere on the lseg
-	 */
-	tmp = line_construct_pm(pt, invm);
-#ifdef GEODEBUG
-	printf("close_ps- tmp A %f  B %f   C %f\n",
-		   tmp->A, tmp->B, tmp->C);
-#endif
-	result = interpt_sl(lseg, tmp);
-
-	/*
-	 * ordinarily we should always find an intersection point, but that could
-	 * fail in the presence of NaN coordinates, and perhaps even from simple
-	 * roundoff issues.  Return a SQL NULL if so.
-	 */
-	if (result == NULL)
+	if (isnan(lseg_closept_point(result, lseg, pt)))
 		PG_RETURN_NULL();
 
-#ifdef GEODEBUG
-	printf("close_ps- result.x %f  result.y %f\n", result->x, result->y);
-#endif
 	PG_RETURN_POINT_P(result);
 }
 
 
-/* close_lseg()
+/*
  * Closest point to l1 on l2.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
+ *
+ * XXX This function is wrong.  If must never set the *result to a point on
+ * the second segment.
  */
+static float8
+lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
+{
+	Point		point;
+	double		dist;
+	double		d;
+
+	d = lseg_closept_point(NULL, l1, &l2->p[0]);
+	dist = d;
+	if (result != NULL)
+		*result = l2->p[0];
+
+	d = lseg_closept_point(NULL, l1, &l2->p[1]);
+	if (d < dist)
+	{
+		dist = d;
+		if (result != NULL)
+			*result = l2->p[1];
+	}
+
+	if (lseg_closept_point(&point, l2, &l1->p[0]) < dist)
+		d = lseg_closept_point(result, l1, &point);
+
+	if (lseg_closept_point(&point, l2, &l1->p[1]) < dist)
+		d = lseg_closept_point(result, l1, &point);
+
+	if (d < dist)
+		dist = d;
+
+	return dist;
+}
+
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
-	Point		point;
-	double		dist;
-	double		d;
+	Point	   *result;
 
-	d = dist_ps_internal(&l1->p[0], l2);
-	dist = d;
-	memcpy(&point, &l1->p[0], sizeof(Point));
+	result = (Point *) palloc(sizeof(Point));
 
-	if ((d = dist_ps_internal(&l1->p[1], l2)) < dist)
-	{
-		dist = d;
-		memcpy(&point, &l1->p[1], sizeof(Point));
-	}
-
-	if (dist_ps_internal(&l2->p[0], l1) < dist)
-	{
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&l2->p[0]),
-													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
-													LsegPGetDatum(l2)));
-	}
-
-	if (dist_ps_internal(&l2->p[1], l1) < dist)
-	{
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&l2->p[1]),
-													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
-													LsegPGetDatum(l2)));
-	}
-
-	if (result == NULL)
-		result = point_copy(&point);
+	lseg_closept_lseg(result, l2, l1);
 
 	PG_RETURN_POINT_P(result);
 }
 
-/* close_pb()
+
+/*
  * Closest point on or in box to specified point.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
-Datum
-close_pb(PG_FUNCTION_ARGS)
+static float8
+box_closept_point(Point *result, BOX *box, Point *pt)
 {
-	Point	   *pt = PG_GETARG_POINT_P(0);
-	BOX		   *box = PG_GETARG_BOX_P(1);
-	LSEG		lseg,
-				seg;
-	Point		point;
+	LSEG		lseg;
+	Point		point,
+				closept;
 	double		dist,
 				d;
 
-	if (DatumGetBool(DirectFunctionCall2(on_pb,
-										 PointPGetDatum(pt),
-										 BoxPGetDatum(box))))
-		PG_RETURN_POINT_P(pt);
+	if (box_contain_point(box, pt))
+	{
+		if (result != NULL)
+			*result = *pt;
+
+		return 0.0;
+	}
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&lseg, &box->low, &point);
-	dist = dist_ps_internal(pt, &lseg);
+	dist = lseg_closept_point(result, &lseg, pt);
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	statlseg_construct(&lseg, &box->high, &point);
+	d = lseg_closept_point(&closept, &lseg, pt);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&lseg, &seg, sizeof(lseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
-	statlseg_construct(&seg, &box->low, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	statlseg_construct(&lseg, &box->low, &point);
+	d = lseg_closept_point(&closept, &lseg, pt);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&lseg, &seg, sizeof(lseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	statlseg_construct(&lseg, &box->high, &point);
+	d = lseg_closept_point(&closept, &lseg, pt);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&lseg, &seg, sizeof(lseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
-										PointPGetDatum(pt),
-										LsegPGetDatum(&lseg)));
+	return dist;
 }
 
+Datum
+close_pb(PG_FUNCTION_ARGS)
+{
+	Point	   *pt = PG_GETARG_POINT_P(0);
+	BOX		   *box = PG_GETARG_BOX_P(1);
+	Point	   *result;
+
+	result = (Point *) palloc(sizeof(Point));
+
+	box_closept_point(result, box, pt);
+
+	PG_RETURN_POINT_P(result);
+}
+
+
 /* close_sl()
  * Closest point on line to line segment.
  *
  * XXX THIS CODE IS WRONG
  * The code is actually calculating the point on the line segment
  *	which is backwards from the routine naming convention.
  * Copied code to new routine close_ls() but haven't fixed this one yet.
  * - thomas 1998-01-31
  */
 Datum
 close_sl(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 	float8		d1,
 				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
+	result = (Point *) palloc(sizeof(Point));
+
+	if (lseg_interpt_line(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
-	d1 = dist_pl_internal(&lseg->p[0], line);
-	d2 = dist_pl_internal(&lseg->p[1], line);
+	d1 = line_closept_point(NULL, line, &lseg->p[0]);
+	d2 = line_closept_point(NULL, line, &lseg->p[1]);
 	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
+		*result = lseg->p[0];
 	else
-		result = point_copy(&lseg->p[1]);
+		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
 
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_sl\" not implemented")));
 
 	PG_RETURN_NULL();
 }
 
-/* close_ls()
+/*
  * Closest point on line segment to line.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
+ *
+ * NOTE When the lines are parallel, endpoints of one of the line segment
+ * are FPeq(), in presence of NaN or Infinitive coordinates, or perhaps =
+ * even because of simple roundoff issues, there may not be a single closest
+ * point.  We are likely to set the result to the second endpoint in these
+ * cases.
  */
+static float8
+lseg_closept_line(Point *result, LSEG *lseg, LINE *line)
+{
+	float8		dist1,
+				dist2;
+
+	if (lseg_interpt_line(result, lseg, line))
+		return 0.0;
+
+	dist1 = line_closept_point(NULL, line, &lseg->p[0]);
+	dist2 = line_closept_point(NULL, line, &lseg->p[1]);
+
+	if (dist1 < dist2)
+	{
+		if (result != NULL)
+			*result = lseg->p[0];
+
+		return dist1;
+	}
+	else
+	{
+		if (result != NULL)
+			*result = lseg->p[1];
+
+		return dist2;
+	}
+}
+
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
-	float8		d1,
-				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
-		PG_RETURN_POINT_P(result);
+	result = (Point *) palloc(sizeof(Point));
 
-	d1 = dist_pl_internal(&lseg->p[0], line);
-	d2 = dist_pl_internal(&lseg->p[1], line);
-	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
-	else
-		result = point_copy(&lseg->p[1]);
+	lseg_closept_line(result, lseg, line);
 
 	PG_RETURN_POINT_P(result);
 }
 
-/* close_sb()
+
+/*
  * Closest point on or in box to line segment.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
-Datum
-close_sb(PG_FUNCTION_ARGS)
+static float8
+box_closept_lseg(Point *result, BOX *box, LSEG *lseg)
 {
-	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
-	BOX		   *box = PG_GETARG_BOX_P(1);
-	Point		point;
-	LSEG		bseg,
-				seg;
+	Point		point,
+				closept;
+	LSEG		bseg;
 	double		dist,
 				d;
 
-	/* segment intersects box? then just return closest point to center */
-	if (DatumGetBool(DirectFunctionCall2(inter_sb,
-										 LsegPGetDatum(lseg),
-										 BoxPGetDatum(box))))
-	{
-		box_cn(&point, box);
-		PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
-											PointPGetDatum(&point),
-											LsegPGetDatum(lseg)));
-	}
+	if (box_interpt_lseg(result, box, lseg))
+		return 0.0;
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	dist = lseg_dt(lseg, &bseg);
+	dist = lseg_closept_lseg(result, &bseg, lseg);
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	statlseg_construct(&bseg, &box->high, &point);
+	d = lseg_closept_lseg(&closept, &bseg, lseg);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&bseg, &seg, sizeof(bseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
-	statlseg_construct(&seg, &box->low, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	statlseg_construct(&bseg, &box->low, &point);
+	d = lseg_closept_lseg(&closept, &bseg, lseg);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&bseg, &seg, sizeof(bseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	statlseg_construct(&bseg, &box->high, &point);
+	d = lseg_closept_lseg(&closept, &bseg, lseg);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&bseg, &seg, sizeof(bseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	/* OK, we now have the closest line segment on the box boundary */
-	PG_RETURN_DATUM(DirectFunctionCall2(close_lseg,
-										LsegPGetDatum(lseg),
-										LsegPGetDatum(&bseg)));
+	return dist;
 }
 
+Datum
+close_sb(PG_FUNCTION_ARGS)
+{
+	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
+	BOX		   *box = PG_GETARG_BOX_P(1);
+	Point	   *result;
+
+	result = (Point *) palloc(sizeof(Point));
+
+	box_closept_lseg(result, box, lseg);
+
+	PG_RETURN_POINT_P(result);
+}
+
+
 Datum
 close_lb(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 #endif
 
 	/* think about this one for a while */
 	ereport(ERROR,
@@ -3116,71 +2906,87 @@ close_lb(PG_FUNCTION_ARGS)
 			 errmsg("function \"close_lb\" not implemented")));
 
 	PG_RETURN_NULL();
 }
 
 /*---------------------------------------------------------------------
  *		on_
  *				Whether one object lies completely within another.
  *-------------------------------------------------------------------*/
 
-/* on_pl -
+/*
  *		Does the point satisfy the equation?
  */
+static bool
+line_contain_point(LINE *line, Point *point)
+{
+	return FPzero(line->A * point->x + line->B * point->y + line->C);
+}
+
 Datum
 on_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(FPzero(line->A * pt->x + line->B * pt->y + line->C));
+	PG_RETURN_BOOL(line_contain_point(line, pt));
 }
 
 
-/* on_ps -
+/*
  *		Determine colinearity by detecting a triangle inequality.
  * This algorithm seems to behave nicely even with lsb residues - tgl 1997-07-09
  */
+static bool
+lseg_contain_point(LSEG *lseg, Point *pt)
+{
+	return FPeq(point_dt(pt, &lseg->p[0]) +
+				point_dt(pt, &lseg->p[1]),
+				point_dt(&lseg->p[0], &lseg->p[1]));
+}
+
 Datum
 on_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(on_ps_internal(pt, lseg));
+	PG_RETURN_BOOL(lseg_contain_point(lseg, pt));
 }
 
+
+/*
+ * Check whether the point is in the box or on its border
+ */
 static bool
-on_ps_internal(Point *pt, LSEG *lseg)
+box_contain_point(BOX *box, Point *point)
 {
-	return FPeq(point_dt(pt, &lseg->p[0]) + point_dt(pt, &lseg->p[1]),
-				point_dt(&lseg->p[0], &lseg->p[1]));
+	return box->high.x >= point->x && box->low.x <= point->x &&
+		   box->high.y >= point->y && box->low.y <= point-> y;
 }
 
 Datum
 on_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_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);
+	PG_RETURN_BOOL(box_contain_point(box, pt));
 }
 
 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);
+	PG_RETURN_BOOL(box_contain_point(box, pt));
 }
 
 /* on_ppath -
  *		Whether a point lies within (on) a polyline.
  *		If open, we have to (groan) check each segment.
  * (uses same algorithm as for point intersecting segment - tgl 1997-07-09)
  *		If closed, we use the old O(n) ray method for point-in-polygon.
  *				The ray is horizontal, from pt out to the right.
  *				Each segment that crosses the ray counts as an
  *				intersection; note that an endpoint or edge may touch
@@ -3210,158 +3016,184 @@ on_ppath(PG_FUNCTION_ARGS)
 				PG_RETURN_BOOL(true);
 			a = b;
 		}
 		PG_RETURN_BOOL(false);
 	}
 
 	/*-- CLOSED --*/
 	PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
 }
 
+
+/*
+ * Check whether the line segment is on the line or close enough
+ *
+ * It is, if both of its points are on the line or close enough.
+ */
 Datum
 on_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(DatumGetBool(DirectFunctionCall2(on_pl,
-													PointPGetDatum(&lseg->p[0]),
-													LinePGetDatum(line))) &&
-				   DatumGetBool(DirectFunctionCall2(on_pl,
-													PointPGetDatum(&lseg->p[1]),
-													LinePGetDatum(line))));
+	PG_RETURN_BOOL(line_contain_point(line, &lseg->p[0]) &&
+				   line_contain_point(line, &lseg->p[1]));
+}
+
+
+/*
+ * Check whether the line segment is in the box or on its border
+ *
+ * It is, if both of its points are in the box or on its border.
+ */
+static bool
+box_contain_lseg(BOX *box, LSEG *lseg)
+{
+	return box_contain_point(box, &lseg->p[0]) &&
+		   box_contain_point(box, &lseg->p[1]);
 }
 
 Datum
 on_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(DatumGetBool(DirectFunctionCall2(on_pb,
-													PointPGetDatum(&lseg->p[0]),
-													BoxPGetDatum(box))) &&
-				   DatumGetBool(DirectFunctionCall2(on_pb,
-													PointPGetDatum(&lseg->p[1]),
-													BoxPGetDatum(box))));
+	PG_RETURN_BOOL(box_contain_lseg(box, lseg));
 }
 
 /*---------------------------------------------------------------------
  *		inter_
  *				Whether one object intersects another.
  *-------------------------------------------------------------------*/
 
 Datum
 inter_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(has_interpt_sl(lseg, line));
+	PG_RETURN_BOOL(lseg_interpt_line(NULL, lseg, line));
 }
 
-/* inter_sb()
+
+/*
  * Do line segment and box intersect?
  *
  * Segment completely inside box counts as intersection.
  * If you want only segments crossing box boundaries,
  *	try converting box to path first.
  *
+ * This function also sets the *result to the closest point on the line
+ * segment to the center of the box when they overlap and the result is
+ * not NULL.  It is somewhat arbitrary, but maybe the best we can do as
+ * there are typically two points they intersect.
+ *
  * Optimize for non-intersection by checking for box intersection first.
  * - thomas 1998-01-30
  */
-Datum
-inter_sb(PG_FUNCTION_ARGS)
+static bool
+box_interpt_lseg(Point *result, BOX *box, LSEG *lseg)
 {
-	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
-	BOX		   *box = PG_GETARG_BOX_P(1);
 	BOX			lbox;
 	LSEG		bseg;
 	Point		point;
 
 	lbox.low.x = Min(lseg->p[0].x, lseg->p[1].x);
 	lbox.low.y = Min(lseg->p[0].y, lseg->p[1].y);
 	lbox.high.x = Max(lseg->p[0].x, lseg->p[1].x);
 	lbox.high.y = Max(lseg->p[0].y, lseg->p[1].y);
 
 	/* nothing close to overlap? then not going to intersect */
 	if (!box_ov(&lbox, box))
-		PG_RETURN_BOOL(false);
+		return false;
+
+	if (result != NULL)
+	{
+		box_cn(&point, box);
+		lseg_closept_point(result, lseg, &point);
+	}
 
 	/* an endpoint of segment is inside box? then clearly intersects */
-	if (DatumGetBool(DirectFunctionCall2(on_pb,
-										 PointPGetDatum(&lseg->p[0]),
-										 BoxPGetDatum(box))) ||
-		DatumGetBool(DirectFunctionCall2(on_pb,
-										 PointPGetDatum(&lseg->p[1]),
-										 BoxPGetDatum(box))))
-		PG_RETURN_BOOL(true);
+	if (box_contain_point(box, &lseg->p[0]) ||
+		box_contain_point(box, &lseg->p[1]))
+		return true;
 
 	/* pairwise check lseg intersections */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	/* if we dropped through, no two segs intersected */
-	PG_RETURN_BOOL(false);
+	return false;
 }
 
+Datum
+inter_sb(PG_FUNCTION_ARGS)
+{
+	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
+	BOX		   *box = PG_GETARG_BOX_P(1);
+
+	PG_RETURN_BOOL(box_interpt_lseg(NULL, box, lseg));
+}
+
+
 /* inter_lb()
  * Do line and box intersect?
  */
 Datum
 inter_lb(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	LSEG		bseg;
 	Point		p1,
 				p2;
 
 	/* pairwise check lseg intersections */
 	p1.x = box->low.x;
 	p1.y = box->low.y;
 	p2.x = box->low.x;
 	p2.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->high.x;
 	p1.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p2.x = box->high.x;
 	p2.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->low.x;
 	p1.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 
 	/* if we dropped through, no intersection */
 	PG_RETURN_BOOL(false);
 }
 
 /*------------------------------------------------------------------
  * The following routines define a data type and operator class for
  * POLYGONS .... Part of which (the polygon's bounding box) is built on
  * top of the BOX data type.
@@ -3374,42 +3206,40 @@ inter_lb(PG_FUNCTION_ARGS)
  *---------------------------------------------------------------------*/
 static void
 make_bound_box(POLYGON *poly)
 {
 	int			i;
 	double		x1,
 				y1,
 				x2,
 				y2;
 
-	if (poly->npts > 0)
-	{
-		x2 = x1 = poly->p[0].x;
-		y2 = y1 = poly->p[0].y;
-		for (i = 1; i < poly->npts; i++)
-		{
-			if (poly->p[i].x < x1)
-				x1 = poly->p[i].x;
-			if (poly->p[i].x > x2)
-				x2 = poly->p[i].x;
-			if (poly->p[i].y < y1)
-				y1 = poly->p[i].y;
-			if (poly->p[i].y > y2)
-				y2 = poly->p[i].y;
-		}
+	Assert(poly->npts > 0);
 
-		box_fill(&(poly->boundbox), x1, x2, y1, y2);
+	x1 = x2 = poly->p[0].x;
+	y2 = y1 = poly->p[0].y;
+	for (i = 1; i < poly->npts; i++)
+	{
+		if (poly->p[i].x < x1)
+			x1 = poly->p[i].x;
+		if (poly->p[i].x > x2)
+			x2 = poly->p[i].x;
+		if (poly->p[i].y < y1)
+			y1 = poly->p[i].y;
+		if (poly->p[i].y > y2)
+			y2 = poly->p[i].y;
 	}
-	else
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot create bounding box for empty polygon")));
+
+	poly->boundbox.low.x = x1;
+	poly->boundbox.high.x = x2;
+	poly->boundbox.low.y = y1;
+	poly->boundbox.high.y = y2;
 }
 
 /*------------------------------------------------------------------
  * poly_in - read in the polygon from a string specification
  *
  *		External format:
  *				"((x0,y0),...,(xn,yn))"
  *				"x0,y0,...,xn,yn"
  *				also supports the older style "(x1,...,xn,y1,...yn)"
  *------------------------------------------------------------------*/
@@ -3739,65 +3569,65 @@ poly_same(PG_FUNCTION_ARGS)
 /*-----------------------------------------------------------------
  * Determine if polygon A overlaps polygon B
  *-----------------------------------------------------------------*/
 Datum
 poly_overlap(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
+	Assert(polya->npts > 0 && polyb->npts > 0);
+
 	/* Quick check by bounding box */
-	result = (polya->npts > 0 && polyb->npts > 0 &&
-			  box_ov(&polya->boundbox, &polyb->boundbox)) ? true : false;
+	result = box_ov(&polya->boundbox, &polyb->boundbox);
 
 	/*
 	 * Brute-force algorithm - try to find intersected edges, if so then
 	 * polygons are overlapped else check is one polygon inside other or not
 	 * by testing single point of them.
 	 */
 	if (result)
 	{
 		int			ia,
 					ib;
 		LSEG		sa,
 					sb;
 
 		/* Init first of polya's edge with last point */
 		sa.p[0] = polya->p[polya->npts - 1];
 		result = false;
 
-		for (ia = 0; ia < polya->npts && result == false; ia++)
+		for (ia = 0; ia < polya->npts && !result; ia++)
 		{
 			/* Second point of polya's edge is a current one */
 			sa.p[1] = polya->p[ia];
 
 			/* Init first of polyb's edge with last point */
 			sb.p[0] = polyb->p[polyb->npts - 1];
 
-			for (ib = 0; ib < polyb->npts && result == false; ib++)
+			for (ib = 0; ib < polyb->npts && !result; ib++)
 			{
 				sb.p[1] = polyb->p[ib];
-				result = lseg_intersect_internal(&sa, &sb);
+				result = lseg_interpt_lseg(NULL, &sa, &sb);
 				sb.p[0] = sb.p[1];
 			}
 
 			/*
 			 * move current endpoint to the first point of next edge
 			 */
 			sa.p[0] = sa.p[1];
 		}
 
-		if (result == false)
+		if (!result)
 		{
-			result = (point_inside(polya->p, polyb->npts, polyb->p)
-					  ||
+			result = (point_inside(polya->p, polyb->npts, polyb->p) ||
 					  point_inside(polyb->p, polya->npts, polya->p));
 		}
 	}
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
@@ -3817,36 +3647,35 @@ poly_overlap(PG_FUNCTION_ARGS)
 
 static bool
 touched_lseg_inside_poly(Point *a, Point *b, LSEG *s, POLYGON *poly, int start)
 {
 	/* point a is on s, b is not */
 	LSEG		t;
 
 	t.p[0] = *a;
 	t.p[1] = *b;
 
-#define POINTEQ(pt1, pt2)	(FPeq((pt1)->x, (pt2)->x) && FPeq((pt1)->y, (pt2)->y))
-	if (POINTEQ(a, s->p))
+	if (point_eq_point(a, s->p))
 	{
-		if (on_ps_internal(s->p + 1, &t))
+		if (lseg_contain_point(&t, s->p + 1))
 			return lseg_inside_poly(b, s->p + 1, poly, start);
 	}
-	else if (POINTEQ(a, s->p + 1))
+	else if (point_eq_point(a, s->p + 1))
 	{
-		if (on_ps_internal(s->p, &t))
+		if (lseg_contain_point(&t, s->p))
 			return lseg_inside_poly(b, s->p, poly, start);
 	}
-	else if (on_ps_internal(s->p, &t))
+	else if (lseg_contain_point(&t, s->p))
 	{
 		return lseg_inside_poly(b, s->p, poly, start);
 	}
-	else if (on_ps_internal(s->p + 1, &t))
+	else if (lseg_contain_point(&t, s->p + 1))
 	{
 		return lseg_inside_poly(b, s->p + 1, poly, start);
 	}
 
 	return true;				/* may be not true, but that will check later */
 }
 
 /*
  * Returns true if segment (a,b) is in polygon, option
  * start is used for optimization - function checks
@@ -3860,50 +3689,49 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 	int			i;
 	bool		res = true,
 				intersection = false;
 
 	t.p[0] = *a;
 	t.p[1] = *b;
 	s.p[0] = poly->p[(start == 0) ? (poly->npts - 1) : (start - 1)];
 
 	for (i = start; i < poly->npts && res; i++)
 	{
-		Point	   *interpt;
+		Point		interpt;
 
 		CHECK_FOR_INTERRUPTS();
 
 		s.p[1] = poly->p[i];
 
-		if (on_ps_internal(t.p, &s))
+		if (lseg_contain_point(&s, t.p))
 		{
-			if (on_ps_internal(t.p + 1, &s))
+			if (lseg_contain_point(&s, t.p + 1))
 				return true;	/* t is contained by s */
 
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p, t.p + 1, &s, poly, i + 1);
 		}
-		else if (on_ps_internal(t.p + 1, &s))
+		else if (lseg_contain_point(&s, t.p + 1))
 		{
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p + 1, t.p, &s, poly, i + 1);
 		}
-		else if ((interpt = lseg_interpt_internal(&t, &s)) != NULL)
+		else if (lseg_interpt_lseg(&interpt, &t, &s))
 		{
 			/*
 			 * segments are X-crossing, go to check each subsegment
 			 */
 
 			intersection = true;
-			res = lseg_inside_poly(t.p, interpt, poly, i + 1);
+			res = lseg_inside_poly(t.p, &interpt, poly, i + 1);
 			if (res)
-				res = lseg_inside_poly(t.p + 1, interpt, poly, i + 1);
-			pfree(interpt);
+				res = lseg_inside_poly(t.p + 1, &interpt, poly, i + 1);
 		}
 
 		s.p[0] = s.p[1];
 	}
 
 	if (res && !intersection)
 	{
 		Point		p;
 
 		/*
@@ -3915,74 +3743,86 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 
 		res = point_inside(&p, poly->npts, poly->p);
 	}
 
 	return res;
 }
 
 /*-----------------------------------------------------------------
  * Determine if polygon A contains polygon B.
  *-----------------------------------------------------------------*/
+static bool
+poly_contain_poly(POLYGON *polya, POLYGON *polyb)
+{
+	int			i;
+	LSEG		s;
+
+	Assert(polya->npts > 0 && polyb->npts > 0);
+
+	/*
+	 * Quick check to see if bounding box is contained.
+	 */
+	if (!box_contain_box(&polya->boundbox, &polyb->boundbox))
+		return false;
+
+	s.p[0] = polyb->p[polyb->npts - 1];
+
+	for (i = 0; i < polyb->npts; i++)
+	{
+		s.p[1] = polyb->p[i];
+		if (!lseg_inside_poly(s.p, s.p + 1, polya, 0))
+			return false;
+		s.p[0] = s.p[1];
+	}
+
+	return true;
+}
+
 Datum
 poly_contain(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	/*
-	 * Quick check to see if bounding box is contained.
-	 */
-	if (polya->npts > 0 && polyb->npts > 0 &&
-		DatumGetBool(DirectFunctionCall2(box_contain,
-										 BoxPGetDatum(&polya->boundbox),
-										 BoxPGetDatum(&polyb->boundbox))))
-	{
-		int			i;
-		LSEG		s;
-
-		s.p[0] = polyb->p[polyb->npts - 1];
-		result = true;
-
-		for (i = 0; i < polyb->npts && result; i++)
-		{
-			s.p[1] = polyb->p[i];
-			result = lseg_inside_poly(s.p, s.p + 1, polya, 0);
-			s.p[0] = s.p[1];
-		}
-	}
-	else
-	{
-		result = false;
-	}
+	result = poly_contain_poly(polya, polyb);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
 
 /*-----------------------------------------------------------------
  * Determine if polygon A is contained by polygon B
  *-----------------------------------------------------------------*/
 Datum
 poly_contained(PG_FUNCTION_ARGS)
 {
-	Datum		polya = PG_GETARG_DATUM(0);
-	Datum		polyb = PG_GETARG_DATUM(1);
+	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
+	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
+	bool		result;
 
 	/* Just switch the arguments and pass it off to poly_contain */
-	PG_RETURN_DATUM(DirectFunctionCall2(poly_contain, polyb, polya));
+	result = poly_contain_poly(polyb, polya);
+
+	/*
+	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
+	 */
+	PG_FREE_IF_COPY(polya, 0);
+	PG_FREE_IF_COPY(polyb, 1);
+
+	PG_RETURN_BOOL(result);
 }
 
 
 Datum
 poly_contain_pt(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_BOOL(point_inside(p, poly->npts, poly->p) != 0);
@@ -4018,170 +3858,215 @@ poly_distance(PG_FUNCTION_ARGS)
  **
  **		Routines for 2D points.
  **
  ***********************************************************************/
 
 Datum
 construct_point(PG_FUNCTION_ARGS)
 {
 	float8		x = PG_GETARG_FLOAT8(0);
 	float8		y = PG_GETARG_FLOAT8(1);
+	Point	   *result;
 
-	PG_RETURN_POINT_P(point_construct(x, y));
+	result = (Point *) palloc(sizeof(Point));
+
+	point_construct(result, x, y);
+
+	PG_RETURN_POINT_P(result);
+}
+
+
+static inline void
+point_add_point(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x + pt2->x,
+					pt1->y + pt2->y);
 }
 
 Datum
 point_add(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x + p2->x);
-	result->y = (p1->y + p2->y);
+	point_add_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+
+static inline void
+point_sub_point(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x - pt2->x,
+					pt1->y - pt2->y);
+}
+
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x - p2->x);
-	result->y = (p1->y - p2->y);
+	point_sub_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+
+static inline void
+point_mul_point(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					(pt1->x * pt2->x) - (pt1->y * pt2->y),
+					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+}
+
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x * p2->x) - (p1->y * p2->y);
-	result->y = (p1->x * p2->y) + (p1->y * p2->x);
+	point_mul_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+
+static inline void
+point_div_point(Point *result, Point *pt1, Point *pt2)
+{
+	double		div;
+
+	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
+
+	if (div == 0.0)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	point_construct(result,
+					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
+					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+}
+
 Datum
 point_div(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
-	double		div;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	div = (p2->x * p2->x) + (p2->y * p2->y);
-
-	if (div == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result->x = ((p1->x * p2->x) + (p1->y * p2->y)) / div;
-	result->y = ((p2->x * p1->y) - (p2->y * p1->x)) / div;
+	point_div_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D boxes.
  **
  ***********************************************************************/
 
 Datum
 points_box(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct(p1->x, p2->x, p1->y, p2->y));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	box_construct(result, p1, p2);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_add(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct((box->high.x + p->x),
-								  (box->low.x + p->x),
-								  (box->high.y + p->y),
-								  (box->low.y + p->y)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_add_point(&result->high, &box->high, p);
+	point_add_point(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_sub(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct((box->high.x - p->x),
-								  (box->low.x - p->x),
-								  (box->high.y - p->y),
-								  (box->low.y - p->y)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_sub_point(&result->high, &box->high, p);
+	point_sub_point(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_mul(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
 
-	high = DatumGetPointP(DirectFunctionCall2(point_mul,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_mul,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	result = (BOX *) palloc(sizeof(BOX));
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	point_mul_point(&high, &box->high, p);
+	point_mul_point(&low, &box->low, p);
+
+	box_construct(result, &high, &low);
 
 	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_div(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
 
-	high = DatumGetPointP(DirectFunctionCall2(point_div,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_div,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	result = (BOX *) palloc(sizeof(BOX));
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	point_div_point(&high, &box->high, p);
+	point_div_point(&low, &box->low, p);
+
+	box_construct(result, &high, &low);
 
 	PG_RETURN_BOX_P(result);
 }
 
 /*
  * Convert point to empty box
  */
 Datum
 point_box(PG_FUNCTION_ARGS)
 {
@@ -4277,83 +4162,63 @@ path_add(PG_FUNCTION_ARGS)
  * Translation operators.
  */
 Datum
 path_add_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x += point->x;
-		path->p[i].y += point->y;
-	}
+		point_add_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_sub_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x -= point->x;
-		path->p[i].y -= point->y;
-	}
+		point_sub_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 /* path_mul_pt()
  * Rotation and scaling operators.
  */
 Datum
 path_mul_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_mul,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_mul_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_div_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_div,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_div_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 
 Datum
 path_center(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	PATH	   *path = PG_GETARG_PATH_P(0);
@@ -4414,42 +4279,40 @@ poly_npoints(PG_FUNCTION_ARGS)
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 
 	PG_RETURN_INT32(poly->npts);
 }
 
 
 Datum
 poly_center(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
-	Datum		result;
-	CIRCLE	   *circle;
+	Point	   *result;
+	CIRCLE		circle;
 
-	circle = DatumGetCircleP(DirectFunctionCall1(poly_circle,
-												 PolygonPGetDatum(poly)));
-	result = DirectFunctionCall1(circle_center,
-								 CirclePGetDatum(circle));
+	result = (Point *) palloc(sizeof(Point));
 
-	PG_RETURN_DATUM(result);
+	poly_to_circle(&circle, poly);
+	*result = circle.center;
+
+	PG_RETURN_POINT_P(result);
 }
 
 
 Datum
 poly_box(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	BOX		   *box;
 
-	if (poly->npts < 1)
-		PG_RETURN_NULL();
-
-	box = box_copy(&poly->boundbox);
+	box = (BOX *) palloc(sizeof(BOX));
+	*box = poly->boundbox;
 
 	PG_RETURN_BOX_P(box);
 }
 
 
 /* box_poly()
  * Convert a box to a polygon.
  */
 Datum
 box_poly(PG_FUNCTION_ARGS)
@@ -4467,22 +4330,21 @@ box_poly(PG_FUNCTION_ARGS)
 
 	poly->p[0].x = box->low.x;
 	poly->p[0].y = box->low.y;
 	poly->p[1].x = box->low.x;
 	poly->p[1].y = box->high.y;
 	poly->p[2].x = box->high.x;
 	poly->p[2].y = box->high.y;
 	poly->p[3].x = box->high.x;
 	poly->p[3].y = box->low.y;
 
-	box_fill(&poly->boundbox, box->high.x, box->low.x,
-			 box->high.y, box->low.y);
+	box_construct(&poly->boundbox, &box->high, &box->low);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
 
 Datum
 poly_path(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	PATH	   *path;
@@ -4557,22 +4419,21 @@ circle_in(PG_FUNCTION_ARGS)
 
 	circle->radius = single_decode(s, &s, "circle", str);
 	if (circle->radius < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
 
 	while (depth > 0)
 	{
-		if ((*s == RDELIM)
-			|| ((*s == RDELIM_C) && (depth == 1)))
+		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
 			s++;
 			while (isspace((unsigned char) *s))
 				s++;
 		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
@@ -4656,22 +4517,21 @@ circle_send(PG_FUNCTION_ARGS)
 
 /*		circles identical?
  */
 Datum
 circle_same(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPeq(circle1->radius, circle2->radius) &&
-				   FPeq(circle1->center.x, circle2->center.x) &&
-				   FPeq(circle1->center.y, circle2->center.y));
+				   point_eq_point(&circle1->center, &circle2->center));
 }
 
 /*		circle_overlap	-		does circle1 overlap circle2?
  */
 Datum
 circle_overlap(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
@@ -4730,32 +4590,34 @@ circle_overright(PG_FUNCTION_ARGS)
 }
 
 /*		circle_contained		-		is circle1 contained by circle2?
  */
 Datum
 circle_contained(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle1->radius), circle2->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						circle2->radius - circle1->radius));
 }
 
 /*		circle_contain	-		does circle1 contain circle2?
  */
 Datum
 circle_contain(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle2->radius), circle1->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						circle1->radius - circle2->radius));
 }
 
 
 /*		circle_below		-		is circle1 strictly below circle2?
  */
 Datum
 circle_below(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
@@ -4858,107 +4720,83 @@ circle_ge(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPge(circle_ar(circle1), circle_ar(circle2)));
 }
 
 
 /*----------------------------------------------------------
  *	"Arithmetic" operators on circles.
  *---------------------------------------------------------*/
 
-static CIRCLE *
-circle_copy(CIRCLE *circle)
-{
-	CIRCLE	   *result;
-
-	if (!PointerIsValid(circle))
-		return NULL;
-
-	result = (CIRCLE *) palloc(sizeof(CIRCLE));
-	memcpy((char *) result, (char *) circle, sizeof(CIRCLE));
-	return result;
-}
-
-
 /* circle_add_pt()
  * Translation operator.
  */
 Datum
 circle_add_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x += point->x;
-	result->center.y += point->y;
+	point_add_point(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_sub_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x -= point->x;
-	result->center.y -= point->y;
+	point_sub_point(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /* circle_mul_pt()
  * Rotation and scaling operators.
  */
 Datum
 circle_mul_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_mul,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
-	result->radius *= HYPOT(point->x, point->y);
+	point_mul_point(&result->center, &circle->center, point);
+	result->radius = circle->radius * HYPOT(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_div_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_div,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
-	result->radius /= HYPOT(point->x, point->y);
+	point_div_point(&result->center, &circle->center, point);
+	result->radius = circle->radius / HYPOT(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /*		circle_area		-		returns the area of the circle.
  */
 Datum
 circle_area(PG_FUNCTION_ARGS)
 {
@@ -4993,22 +4831,22 @@ circle_radius(PG_FUNCTION_ARGS)
 /*		circle_distance -		returns the distance between
  *								  two circles.
  */
 Datum
 circle_distance(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(&circle1->center, &circle2->center)
-		- (circle1->radius + circle2->radius);
+	result = point_dt(&circle1->center, &circle2->center) -
+		(circle1->radius + circle2->radius);
 	if (result < 0)
 		result = 0;
 	PG_RETURN_FLOAT8(result);
 }
 
 
 Datum
 circle_contain_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
@@ -5190,56 +5028,60 @@ circle_poly(PG_FUNCTION_ARGS)
 		angle = i * anglestep;
 		poly->p[i].x = circle->center.x - (circle->radius * cos(angle));
 		poly->p[i].y = circle->center.y + (circle->radius * sin(angle));
 	}
 
 	make_bound_box(poly);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
-/*		poly_circle		- convert polygon to circle
+/*
+ * Convert polygon to circle
+ *
+ * The result must be preallocated.
  *
  * XXX This algorithm should use weighted means of line segments
  *	rather than straight average values of points - tgl 97/01/21.
  */
+static void
+poly_to_circle(CIRCLE *result, POLYGON *poly)
+{
+	int			i;
+
+	Assert(poly->npts > 0);
+
+	result->center.x = 0;
+	result->center.y = 0;
+	result->radius = 0;
+
+	for (i = 0; i < poly->npts; i++)
+		point_add_point(&result->center, &result->center, &poly->p[i]);
+	result->center.x /= poly->npts;
+	result->center.y /= poly->npts;
+
+	for (i = 0; i < poly->npts; i++)
+		result->radius += point_dt(&poly->p[i], &result->center);
+	result->radius /= poly->npts;
+}
+
 Datum
 poly_circle(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
-	CIRCLE	   *circle;
-	int			i;
+	CIRCLE	   *result;
 
-	if (poly->npts < 1)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot convert empty polygon to circle")));
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
+	poly_to_circle(result, poly);
 
-	circle->center.x = 0;
-	circle->center.y = 0;
-	circle->radius = 0;
-
-	for (i = 0; i < poly->npts; i++)
-	{
-		circle->center.x += poly->p[i].x;
-		circle->center.y += poly->p[i].y;
-	}
-	circle->center.x /= poly->npts;
-	circle->center.y /= poly->npts;
-
-	for (i = 0; i < poly->npts; i++)
-		circle->radius += point_dt(&poly->p[i], &circle->center);
-	circle->radius /= poly->npts;
-
-	PG_RETURN_CIRCLE_P(circle);
+	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /***********************************************************************
  **
  **		Private routines for multiple types.
  **
  ***********************************************************************/
 
 /*
@@ -5261,22 +5103,21 @@ point_inside(Point *p, int npts, Point *plist)
 	double		x0,
 				y0;
 	double		prev_x,
 				prev_y;
 	int			i = 0;
 	double		x,
 				y;
 	int			cross,
 				total_cross = 0;
 
-	if (npts <= 0)
-		return 0;
+	Assert(npts > 0);
 
 	/* compute first polygon point relative to single point */
 	x0 = plist[0].x - p->x;
 	y0 = plist[0].y - p->y;
 
 	prev_x = x0;
 	prev_y = y0;
 	/* loop over polygon points and aggregate total_cross */
 	for (i = 1; i < npts; i++)
 	{
@@ -5371,51 +5212,48 @@ lseg_crossing(double x, double y, double prev_x, double prev_y)
 static bool
 plist_same(int npts, Point *p1, Point *p2)
 {
 	int			i,
 				ii,
 				j;
 
 	/* find match for first point */
 	for (i = 0; i < npts; i++)
 	{
-		if ((FPeq(p2[i].x, p1[0].x))
-			&& (FPeq(p2[i].y, p1[0].y)))
+		if (point_eq_point(&p2[i], &p1[0]))
 		{
 
 			/* match found? then look forward through remaining points */
 			for (ii = 1, j = i + 1; ii < npts; ii++, j++)
 			{
 				if (j >= npts)
 					j = 0;
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_point(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed forward match with %d\n", j, ii);
 #endif
 					break;
 				}
 			}
 #ifdef GEODEBUG
 			printf("plist_same- ii = %d/%d after forward match\n", ii, npts);
 #endif
 			if (ii == npts)
 				return true;
 
 			/* match not found forwards? then look backwards */
 			for (ii = 1, j = i - 1; ii < npts; ii++, j--)
 			{
 				if (j < 0)
 					j = (npts - 1);
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_point(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed reverse match with %d\n", j, ii);
 #endif
 					break;
 				}
 			}
 #ifdef GEODEBUG
 			printf("plist_same- ii = %d/%d after reverse match\n", ii, npts);
 #endif
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index 3f1a755cbb..0fe40499e0 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -786,14 +786,15 @@ spg_bbox_quad_config(PG_FUNCTION_ARGS)
 
 /*
  * 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);
+	box = (BOX *) palloc(sizeof(BOX));
+	*box = polygon->boundbox;
 
 	PG_RETURN_BOX_P(box);
 }
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index a589e4239f..0e066894cd 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -171,17 +171,13 @@ typedef struct
 #define DatumGetCircleP(X)	  ((CIRCLE *) DatumGetPointer(X))
 #define CirclePGetDatum(X)	  PointerGetDatum(X)
 #define PG_GETARG_CIRCLE_P(n) DatumGetCircleP(PG_GETARG_DATUM(n))
 #define PG_RETURN_CIRCLE_P(x) return CirclePGetDatum(x)
 
 
 /*
  * 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/regress.c b/src/test/regress/regress.c
index e14322c798..990a84eedc 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -171,22 +171,27 @@ widget_out(PG_FUNCTION_ARGS)
 	PG_RETURN_CSTRING(str);
 }
 
 PG_FUNCTION_INFO_V1(pt_in_widget);
 
 Datum
 pt_in_widget(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	WIDGET	   *widget = (WIDGET *) PG_GETARG_POINTER(1);
+	float8		distance;
 
-	PG_RETURN_BOOL(point_dt(point, &widget->center) < widget->radius);
+	distance = DatumGetFloat8(DirectFunctionCall2(point_distance,
+												  PointPGetDatum(point),
+											PointPGetDatum(&widget->center)));
+
+	PG_RETURN_BOOL(distance < widget->radius);
 }
 
 PG_FUNCTION_INFO_V1(reverse_name);
 
 Datum
 reverse_name(PG_FUNCTION_ARGS)
 {
 	char	   *string = PG_GETARG_CSTRING(0);
 	int			i;
 	int			len;
-- 
2.14.3 (Apple Git-98)

0002-float-header-v12.patchapplication/octet-stream; name=0002-float-header-v12.patchDownload
From 8713d5a7fb9eac91d967261f32b5203c3c710bb4 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 28 May 2016 18:16:05 +0200
Subject: [PATCH 2/6] float-header-v12

Provide header file for built-in float datatypes

Even though, some datatypes under adt/ have separate header files,
most of the simple ones do not.  Their public functions were on
the builtins.h.  We would need to make more functions of floats public
to let the geometric types built on top of them.  This is a good
opportunity to make a separate header file for floats.

1acf7572554515b99ef6e783750aaea8777524ec made _cmp functions public
to solve NaN problem locally for GiST indexes.  This patch reworks it
in favour of a more extensive API.  The API uses inline functions
instead of macros, as they are easier to use compared to macros,
and avoid double-evaluation hazards.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com
---
 contrib/btree_gin/btree_gin.c                 |   1 +
 contrib/btree_gist/btree_ts.c                 |   1 +
 contrib/cube/cube.c                           |   2 +-
 contrib/cube/cubeparse.y                      |   2 +-
 contrib/postgres_fdw/postgres_fdw.c           |   1 +
 src/backend/access/gist/gistget.c             |   2 +-
 src/backend/access/gist/gistproc.c            |  55 +--
 src/backend/access/gist/gistutil.c            |   2 +-
 src/backend/utils/adt/float.c                 | 589 ++++++--------------------
 src/backend/utils/adt/formatting.c            |   1 +
 src/backend/utils/adt/geo_ops.c               |   6 +-
 src/backend/utils/adt/geo_spgist.c            |   2 +-
 src/backend/utils/adt/numeric.c               |   1 +
 src/backend/utils/adt/rangetypes_gist.c       |   3 +-
 src/backend/utils/adt/rangetypes_selfuncs.c   |   3 +-
 src/backend/utils/adt/rangetypes_typanalyze.c |   3 +-
 src/backend/utils/adt/timestamp.c             |   1 +
 src/backend/utils/misc/guc.c                  |   1 +
 src/include/utils/builtins.h                  |  14 -
 src/include/utils/float.h                     | 376 ++++++++++++++++
 src/include/utils/geo_decls.h                 |   1 +
 21 files changed, 554 insertions(+), 513 deletions(-)
 create mode 100644 src/include/utils/float.h

diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index 2473f79ca1..301caefd47 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -3,20 +3,21 @@
  */
 #include "postgres.h"
 
 #include <limits.h>
 
 #include "access/stratnum.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/cash.h"
 #include "utils/date.h"
+#include "utils/float.h"
 #include "utils/inet.h"
 #include "utils/numeric.h"
 #include "utils/timestamp.h"
 #include "utils/varbit.h"
 
 PG_MODULE_MAGIC;
 
 typedef struct QueryInfo
 {
 	StrategyNumber strategy;
diff --git a/contrib/btree_gist/btree_ts.c b/contrib/btree_gist/btree_ts.c
index 18740cad38..49d1849d88 100644
--- a/contrib/btree_gist/btree_ts.c
+++ b/contrib/btree_gist/btree_ts.c
@@ -2,20 +2,21 @@
  * contrib/btree_gist/btree_ts.c
  */
 #include "postgres.h"
 
 #include <limits.h>
 
 #include "btree_gist.h"
 #include "btree_utils_num.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 typedef struct
 {
 	Timestamp	lower;
 	Timestamp	upper;
 } tsKEY;
 
 /*
 ** timestamp ops
 */
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c
index d96ca1ec1f..79476ed0df 100644
--- a/contrib/cube/cube.c
+++ b/contrib/cube/cube.c
@@ -7,21 +7,21 @@
 ******************************************************************************/
 
 #include "postgres.h"
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 
 #include "cubedata.h"
 
 PG_MODULE_MAGIC;
 
 /*
  * Taken from the intarray contrib header
  */
 #define ARRPTR(x)  ( (double *) ARR_DATA_PTR(x) )
 #define ARRNELEMS(x)  ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x))
diff --git a/contrib/cube/cubeparse.y b/contrib/cube/cubeparse.y
index 1b65fa967c..deb2efdc0d 100644
--- a/contrib/cube/cubeparse.y
+++ b/contrib/cube/cubeparse.y
@@ -1,20 +1,20 @@
 %{
 /* contrib/cube/cubeparse.y */
 
 /* NdBox = [(lowerleft),(upperright)] */
 /* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */
 
 #include "postgres.h"
 
 #include "cubedata.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 
 /* All grammar constructs return strings */
 #define YYSTYPE char *
 
 /*
  * Bison doesn't allocate anything that needs to live across parser calls,
  * so we can easily have it use palloc instead of malloc.  This prevents
  * memory leaks if we error out during parsing.  Note this only works with
  * bison >= 2.0.  However, in bison 1.875 the default is to use alloca()
  * if possible, so there's not really much problem anyhow, at least if
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index e8a0d5482a..af866e6e1f 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -28,20 +28,21 @@
 #include "optimizer/cost.h"
 #include "optimizer/clauses.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
 #include "optimizer/planmain.h"
 #include "optimizer/restrictinfo.h"
 #include "optimizer/var.h"
 #include "optimizer/tlist.h"
 #include "parser/parsetree.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 #include "utils/sampling.h"
 #include "utils/selfuncs.h"
 
 PG_MODULE_MAGIC;
 
 /* Default CPU cost to start up a foreign query. */
diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c
index b30b931c3b..ea992287eb 100644
--- a/src/backend/access/gist/gistget.c
+++ b/src/backend/access/gist/gistget.c
@@ -13,21 +13,21 @@
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/gist_private.h"
 #include "access/relscan.h"
 #include "catalog/pg_type.h"
 #include "miscadmin.h"
 #include "pgstat.h"
 #include "lib/pairingheap.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 
 /*
  * gistkillitems() -- set LP_DEAD state for items an indexscan caller has
  * told us were killed.
  *
  * We re-read page here, so it's important to check page LSN. If the page
  * has been modified since the last read (as determined by LSN), we cannot
  * flag any entries because it is possible that the old entry was vacuumed
diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index 97e6dc9910..4bbfdadf9f 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -27,62 +27,53 @@
 
 
 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
 						 StrategyNumber strategy);
 static bool rtree_internal_consistent(BOX *key, BOX *query,
 						  StrategyNumber strategy);
 
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
 
-/* Convenience macros for NaN-aware comparisons */
-#define FLOAT8_EQ(a,b)	(float8_cmp_internal(a, b) == 0)
-#define FLOAT8_LT(a,b)	(float8_cmp_internal(a, b) < 0)
-#define FLOAT8_LE(a,b)	(float8_cmp_internal(a, b) <= 0)
-#define FLOAT8_GT(a,b)	(float8_cmp_internal(a, b) > 0)
-#define FLOAT8_GE(a,b)	(float8_cmp_internal(a, b) >= 0)
-#define FLOAT8_MAX(a,b)  (FLOAT8_GT(a, b) ? (a) : (b))
-#define FLOAT8_MIN(a,b)  (FLOAT8_LT(a, b) ? (a) : (b))
-
 
 /**************************************************
  * Box ops
  **************************************************/
 
 /*
  * Calculates union of two boxes, a and b. The result is stored in *n.
  */
 static void
 rt_box_union(BOX *n, const BOX *a, const BOX *b)
 {
-	n->high.x = FLOAT8_MAX(a->high.x, b->high.x);
-	n->high.y = FLOAT8_MAX(a->high.y, b->high.y);
-	n->low.x = FLOAT8_MIN(a->low.x, b->low.x);
-	n->low.y = FLOAT8_MIN(a->low.y, b->low.y);
+	n->high.x = float8_max(a->high.x, b->high.x);
+	n->high.y = float8_max(a->high.y, b->high.y);
+	n->low.x = float8_min(a->low.x, b->low.x);
+	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
 static double
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
-	if (FLOAT8_LE(box->high.x, box->low.x) ||
-		FLOAT8_LE(box->high.y, box->low.y))
+	if (float8_le(box->high.x, box->low.x) ||
+		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
 	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
@@ -137,27 +128,27 @@ gist_box_consistent(PG_FUNCTION_ARGS)
 												 query,
 												 strategy));
 }
 
 /*
  * Increase BOX b to include addon.
  */
 static void
 adjustBox(BOX *b, const BOX *addon)
 {
-	if (FLOAT8_LT(b->high.x, addon->high.x))
+	if (float8_lt(b->high.x, addon->high.x))
 		b->high.x = addon->high.x;
-	if (FLOAT8_GT(b->low.x, addon->low.x))
+	if (float8_gt(b->low.x, addon->low.x))
 		b->low.x = addon->low.x;
-	if (FLOAT8_LT(b->high.y, addon->high.y))
+	if (float8_lt(b->high.y, addon->high.y))
 		b->high.y = addon->high.y;
-	if (FLOAT8_GT(b->low.y, addon->low.y))
+	if (float8_gt(b->low.y, addon->low.y))
 		b->low.y = addon->low.y;
 }
 
 /*
  * The GiST Union method for boxes
  *
  * returns the minimal bounding box that encloses all the entries in entryvec
  */
 Datum
 gist_box_union(PG_FUNCTION_ARGS)
@@ -609,36 +600,36 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		i1 = 0;
 		i2 = 0;
 		rightLower = intervalsLower[i1].lower;
 		leftUpper = intervalsUpper[i2].lower;
 		while (true)
 		{
 			/*
 			 * Find next lower bound of right group.
 			 */
 			while (i1 < nentries &&
-				   FLOAT8_EQ(rightLower, intervalsLower[i1].lower))
+				   float8_eq(rightLower, intervalsLower[i1].lower))
 			{
-				if (FLOAT8_LT(leftUpper, intervalsLower[i1].upper))
+				if (float8_lt(leftUpper, intervalsLower[i1].upper))
 					leftUpper = intervalsLower[i1].upper;
 				i1++;
 			}
 			if (i1 >= nentries)
 				break;
 			rightLower = intervalsLower[i1].lower;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * left group.
 			 */
 			while (i2 < nentries &&
-				   FLOAT8_LE(intervalsUpper[i2].upper, leftUpper))
+				   float8_le(intervalsUpper[i2].upper, leftUpper))
 				i2++;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim, rightLower, i1, leftUpper, i2);
 		}
 
 		/*
 		 * Iterate over upper bound of left group finding greatest possible
@@ -646,35 +637,35 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		 */
 		i1 = nentries - 1;
 		i2 = nentries - 1;
 		rightLower = intervalsLower[i1].upper;
 		leftUpper = intervalsUpper[i2].upper;
 		while (true)
 		{
 			/*
 			 * Find next upper bound of left group.
 			 */
-			while (i2 >= 0 && FLOAT8_EQ(leftUpper, intervalsUpper[i2].upper))
+			while (i2 >= 0 && float8_eq(leftUpper, intervalsUpper[i2].upper))
 			{
-				if (FLOAT8_GT(rightLower, intervalsUpper[i2].lower))
+				if (float8_gt(rightLower, intervalsUpper[i2].lower))
 					rightLower = intervalsUpper[i2].lower;
 				i2--;
 			}
 			if (i2 < 0)
 				break;
 			leftUpper = intervalsUpper[i2].upper;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * right group.
 			 */
-			while (i1 >= 0 && FLOAT8_GE(intervalsLower[i1].lower, rightLower))
+			while (i1 >= 0 && float8_ge(intervalsLower[i1].lower, rightLower))
 				i1--;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim,
 								 rightLower, i1 + 1, leftUpper, i2 + 1);
 		}
 	}
 
@@ -748,42 +739,42 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
 		}
 		else
 		{
 			lower = box->low.y;
 			upper = box->high.y;
 		}
 
-		if (FLOAT8_LE(upper, context.leftUpper))
+		if (float8_le(upper, context.leftUpper))
 		{
 			/* Fits to the left group */
-			if (FLOAT8_GE(lower, context.rightLower))
+			if (float8_ge(lower, context.rightLower))
 			{
 				/* Fits also to the right group, so "common entry" */
 				commonEntries[commonEntriesCount++].index = i;
 			}
 			else
 			{
 				/* Doesn't fit to the right group, so join to the left group */
 				PLACE_LEFT(box, i);
 			}
 		}
 		else
 		{
 			/*
 			 * Each entry should fit on either left or right group. Since this
 			 * entry didn't fit on the left group, it better fit in the right
 			 * group.
 			 */
-			Assert(FLOAT8_GE(lower, context.rightLower));
+			Assert(float8_ge(lower, context.rightLower));
 
 			/* Doesn't fit to the left group, so join to the right group */
 			PLACE_RIGHT(box, i);
 		}
 	}
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
@@ -853,24 +844,24 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
  * equivalent to box_same().
  */
 Datum
 gist_box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *b1 = PG_GETARG_BOX_P(0);
 	BOX		   *b2 = PG_GETARG_BOX_P(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
 	if (b1 && b2)
-		*result = (FLOAT8_EQ(b1->low.x, b2->low.x) &&
-				   FLOAT8_EQ(b1->low.y, b2->low.y) &&
-				   FLOAT8_EQ(b1->high.x, b2->high.x) &&
-				   FLOAT8_EQ(b1->high.y, b2->high.y));
+		*result = (float8_eq(b1->low.x, b2->low.x) &&
+				   float8_eq(b1->low.y, b2->low.y) &&
+				   float8_eq(b1->high.x, b2->high.x) &&
+				   float8_eq(b1->high.y, b2->high.y));
 	else
 		*result = (b1 == NULL && b2 == NULL);
 	PG_RETURN_POINTER(result);
 }
 
 /*
  * Leaf-level consistency for boxes: just apply the query operator
  */
 static bool
 gist_box_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy)
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 55cccd247a..7e43b8fc87 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -15,21 +15,21 @@
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist_private.h"
 #include "access/htup_details.h"
 #include "access/reloptions.h"
 #include "catalog/pg_opclass.h"
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/syscache.h"
 
 
 /*
  * Write itup vector to page, has no control of free space.
  */
 void
 gistfillbuffer(Page page, IndexTuple *itup, int len, OffsetNumber off)
 {
 	OffsetNumber l = InvalidOffsetNumber;
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index aadb92de66..eea8726e16 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -16,62 +16,29 @@
 
 #include <ctype.h>
 #include <float.h>
 #include <math.h>
 #include <limits.h>
 
 #include "catalog/pg_type.h"
 #include "common/int.h"
 #include "libpq/pqformat.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/sortsupport.h"
 
 
-#ifndef M_PI
-/* from my RH5.2 gcc math.h file - thomas 2000-04-03 */
-#define M_PI 3.14159265358979323846
-#endif
-
-/* Radians per degree, a.k.a. PI / 180 */
-#define RADIANS_PER_DEGREE 0.0174532925199432957692
-
-/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0.  NAN definition from
- * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfNotNumberNANItems.asp
- */
-#if defined(WIN32) && !defined(NAN)
-static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
-
-#define NAN (*(const double *) nan)
-#endif
-
 /* not sure what the following should be, but better to make it over-sufficient */
 #define MAXFLOATWIDTH	64
 #define MAXDOUBLEWIDTH	128
 
-/*
- * check to see if a float4/8 val has underflowed or overflowed
- */
-#define CHECKFLOATVAL(val, inf_is_valid, zero_is_valid)			\
-do {															\
-	if (isinf(val) && !(inf_is_valid))							\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		  errmsg("value out of range: overflow")));				\
-																\
-	if ((val) == 0.0 && !(zero_is_valid))						\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		 errmsg("value out of range: underflow")));				\
-} while(0)
-
-
 /* Configurable GUC parameter */
 int			extra_float_digits = 0; /* Added to DBL_DIG or FLT_DIG */
 
 /* Cached constants for degree-based trig functions */
 static bool degree_consts_set = false;
 static float8 sin_30 = 0;
 static float8 one_minus_cos_60 = 0;
 static float8 asin_0_5 = 0;
 static float8 acos_0_5 = 0;
 static float8 atan_1_0 = 0;
@@ -102,100 +69,20 @@ static void init_degree_constants(void);
  * function, which causes configure to not set HAVE_CBRT.  Furthermore,
  * their compilers spit up at the mismatch between extern declaration
  * and static definition.  We work around that here by the expedient
  * of a #define to make the actual name of the static function different.
  */
 #define cbrt my_cbrt
 static double cbrt(double x);
 #endif							/* HAVE_CBRT */
 
 
-/*
- * Routines to provide reasonably platform-independent handling of
- * infinity and NaN.  We assume that isinf() and isnan() are available
- * and work per spec.  (On some platforms, we have to supply our own;
- * see src/port.)  However, generating an Infinity or NaN in the first
- * place is less well standardized; pre-C99 systems tend not to have C99's
- * INFINITY and NAN macros.  We centralize our workarounds for this here.
- */
-
-double
-get_float8_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (double) INFINITY;
-#else
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (double) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-/*
-* The funny placements of the two #pragmas is necessary because of a
-* long lived bug in the Microsoft compilers.
-* See http://support.microsoft.com/kb/120968/en-us for details
-*/
-#if (_MSC_VER >= 1800)
-#pragma warning(disable:4756)
-#endif
-float
-get_float4_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (float) INFINITY;
-#else
-#if (_MSC_VER >= 1800)
-#pragma warning(default:4756)
-#endif
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (float) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-double
-get_float8_nan(void)
-{
-	/* (double) NAN doesn't work on some NetBSD/MIPS releases */
-#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
-	/* C99 standard way */
-	return (double) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (double) (0.0 / 0.0);
-#endif
-}
-
-float
-get_float4_nan(void)
-{
-#ifdef NAN
-	/* C99 standard way */
-	return (float) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (float) (0.0 / 0.0);
-#endif
-}
-
-
 /*
  * Returns -1 if 'val' represents negative infinity, 1 if 'val'
  * represents (positive) infinity, and 0 otherwise. On some platforms,
  * this is equivalent to the isinf() macro, but not everywhere: C99
  * does not specify that isinf() needs to distinguish between positive
  * and negative infinity.
  */
 int
 is_infinite(double val)
 {
@@ -340,21 +227,21 @@ float4in(PG_FUNCTION_ARGS)
 	if (*endptr != '\0')
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"real", orig_num)));
 
 	/*
 	 * if we get here, we have a legal double, still need to check to see if
 	 * it's a legal float4
 	 */
-	CHECKFLOATVAL((float4) val, isinf(val), val == 0);
+	check_float4_val((float4) val, isinf(val), val == 0);
 
 	PG_RETURN_FLOAT4((float4) val);
 }
 
 /*
  *		float4out		- converts a float4 number to a string
  *						  using a standard output format
  */
 Datum
 float4out(PG_FUNCTION_ARGS)
@@ -690,35 +577,35 @@ float4up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT4(arg);
 }
 
 Datum
 float4larger(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) > 0)
+	if (float4_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 Datum
 float4smaller(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) < 0)
+	if (float4_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 /*
  *		======================
  *		FLOAT8 BASE OPERATIONS
  *		======================
@@ -757,35 +644,35 @@ float8up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT8(arg);
 }
 
 Datum
 float8larger(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) > 0)
+	if (float8_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 Datum
 float8smaller(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) < 0)
+	if (float8_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		====================
  *		ARITHMETIC OPERATORS
@@ -796,234 +683,165 @@ float8smaller(PG_FUNCTION_ARGS)
  *		float4pl		- returns arg1 + arg2
  *		float4mi		- returns arg1 - arg2
  *		float4mul		- returns arg1 * arg2
  *		float4div		- returns arg1 / arg2
  */
 Datum
 float4pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 + arg2;
-
-	/*
-	 * There isn't any way to check for underflow of addition/subtraction
-	 * because numbers near the underflow value have already been rounded to
-	 * the point where we can't detect that the two values were originally
-	 * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
-	 * 1.4013e-45.
-	 */
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_pl(arg1, arg2));
 }
 
 Datum
 float4mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mi(arg1, arg2));
 }
 
 Datum
 float4mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mul(arg1, arg2));
 }
 
 Datum
 float4div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_div(arg1, arg2));
 }
 
 /*
  *		float8pl		- returns arg1 + arg2
  *		float8mi		- returns arg1 - arg2
  *		float8mul		- returns arg1 * arg2
  *		float8div		- returns arg1 / arg2
  */
 Datum
 float8pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 + arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, arg2));
 }
 
 Datum
 float8mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 - arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, arg2));
 }
 
 Datum
 float8mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 * arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, arg2));
 }
 
 Datum
 float8div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, arg2));
 }
 
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float4{eq,ne,lt,le,gt,ge}		- float4/float4 comparison operations
  */
 int
 float4_cmp_internal(float4 a, float4 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float4_gt(a, b))
+		return 1;
+	if (float4_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
 float4eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float4_eq(arg1, arg2));
 }
 
 Datum
 float4ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float4_ne(arg1, arg2));
 }
 
 Datum
 float4lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float4_lt(arg1, arg2));
 }
 
 Datum
 float4le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float4_le(arg1, arg2));
 }
 
 Datum
 float4gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float4_gt(arg1, arg2));
 }
 
 Datum
 float4ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float4_ge(arg1, arg2));
 }
 
 Datum
 btfloat4cmp(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
 	PG_RETURN_INT32(float4_cmp_internal(arg1, arg2));
 }
@@ -1045,99 +863,79 @@ btfloat4sortsupport(PG_FUNCTION_ARGS)
 	ssup->comparator = btfloat4fastcmp;
 	PG_RETURN_VOID();
 }
 
 /*
  *		float8{eq,ne,lt,le,gt,ge}		- float8/float8 comparison operations
  */
 int
 float8_cmp_internal(float8 a, float8 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float8_gt(a, b))
+		return 1;
+	if (float8_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
 float8eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, arg2));
 }
 
 Datum
 float8ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, arg2));
 }
 
 Datum
 float8lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, arg2));
 }
 
 Datum
 float8le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, arg2));
 }
 
 Datum
 float8gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, arg2));
 }
 
 Datum
 float8ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, arg2));
 }
 
 Datum
 btfloat8cmp(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
 	PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
 }
@@ -1290,21 +1088,21 @@ ftod(PG_FUNCTION_ARGS)
 
 
 /*
  *		dtof			- converts a float8 number to a float4 number
  */
 Datum
 dtof(PG_FUNCTION_ARGS)
 {
 	float8		num = PG_GETARG_FLOAT8(0);
 
-	CHECKFLOATVAL((float4) num, isinf(num), num == 0);
+	check_float4_val((float4) num, isinf(num), num == 0);
 
 	PG_RETURN_FLOAT4((float4) num);
 }
 
 
 /*
  *		dtoi4			- converts a float8 number to an int4 number
  */
 Datum
 dtoi4(PG_FUNCTION_ARGS)
@@ -1515,36 +1313,36 @@ dsqrt(PG_FUNCTION_ARGS)
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
 				 errmsg("cannot take square root of a negative number")));
 
 	result = sqrt(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcbrt			- returns cube root of arg1
  */
 Datum
 dcbrt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	result = cbrt(arg1);
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dpow			- returns pow(arg1,arg2)
  */
 Datum
 dpow(PG_FUNCTION_ARGS)
 {
@@ -1583,40 +1381,40 @@ dpow(PG_FUNCTION_ARGS)
 			/* The sign of Inf is not significant in this case. */
 			result = get_float8_infinity();
 		else if (fabs(arg1) != 1)
 			result = 0;
 		else
 			result = 1;
 	}
 	else if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
+	check_float8_val(result, isinf(arg1) || isinf(arg2), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dexp			- returns the exponential function of arg1
  */
 Datum
 dexp(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	errno = 0;
 	result = exp(arg1);
 	if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1), false);
+	check_float8_val(result, isinf(arg1), false);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dlog1			- returns the natural logarithm of arg1
  */
 Datum
 dlog1(PG_FUNCTION_ARGS)
 {
@@ -1631,21 +1429,21 @@ dlog1(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of zero")));
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of a negative number")));
 
 	result = log(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dlog10			- returns the base 10 logarithm of arg1
  */
 Datum
 dlog10(PG_FUNCTION_ARGS)
 {
@@ -1661,21 +1459,21 @@ dlog10(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of zero")));
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of a negative number")));
 
 	result = log10(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dacos			- returns the arccos of arg1 (radians)
  */
 Datum
 dacos(PG_FUNCTION_ARGS)
 {
@@ -1691,21 +1489,21 @@ dacos(PG_FUNCTION_ARGS)
 	 * range [-1, 1] to values in the range [0, Pi], so we should reject any
 	 * inputs outside that range and the result will always be finite.
 	 */
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = acos(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dasin			- returns the arcsin of arg1 (radians)
  */
 Datum
 dasin(PG_FUNCTION_ARGS)
 {
@@ -1721,21 +1519,21 @@ dasin(PG_FUNCTION_ARGS)
 	 * range [-1, 1] to values in the range [-Pi/2, Pi/2], so we should reject
 	 * any inputs outside that range and the result will always be finite.
 	 */
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = asin(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		datan			- returns the arctan of arg1 (radians)
  */
 Datum
 datan(PG_FUNCTION_ARGS)
 {
@@ -1746,21 +1544,21 @@ datan(PG_FUNCTION_ARGS)
 	if (isnan(arg1))
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/*
 	 * The principal branch of the inverse tangent function maps all inputs to
 	 * values in the range [-Pi/2, Pi/2], so the result should always be
 	 * finite, even if the input is infinite.
 	 */
 	result = atan(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		atan2			- returns the arctan of arg1/arg2 (radians)
  */
 Datum
 datan2(PG_FUNCTION_ARGS)
 {
@@ -1771,21 +1569,21 @@ datan2(PG_FUNCTION_ARGS)
 	/* Per the POSIX spec, return NaN if either input is NaN */
 	if (isnan(arg1) || isnan(arg2))
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/*
 	 * atan2 maps all inputs to values in the range [-Pi, Pi], so the result
 	 * should always be finite, even if the inputs are infinite.
 	 */
 	result = atan2(arg1, arg2);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcos			- returns the cosine of arg1 (radians)
  */
 Datum
 dcos(PG_FUNCTION_ARGS)
 {
@@ -1811,21 +1609,21 @@ dcos(PG_FUNCTION_ARGS)
 	 * platform reports via errno, so also explicitly test for infinite
 	 * inputs.
 	 */
 	errno = 0;
 	result = cos(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcot			- returns the cotangent of arg1 (radians)
  */
 Datum
 dcot(PG_FUNCTION_ARGS)
 {
@@ -1838,21 +1636,21 @@ dcot(PG_FUNCTION_ARGS)
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = tan(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = 1.0 / result;
-	CHECKFLOATVAL(result, true /* cot(0) == Inf */ , true);
+	check_float8_val(result, true /* cot(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dsin			- returns the sine of arg1 (radians)
  */
 Datum
 dsin(PG_FUNCTION_ARGS)
 {
@@ -1864,21 +1662,21 @@ dsin(PG_FUNCTION_ARGS)
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = sin(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dtan			- returns the tangent of arg1 (radians)
  */
 Datum
 dtan(PG_FUNCTION_ARGS)
 {
@@ -1890,21 +1688,21 @@ dtan(PG_FUNCTION_ARGS)
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = tan(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, true /* tan(pi/2) == Inf */ , true);
+	check_float8_val(result, true /* tan(pi/2) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /* ========== DEGREE-BASED TRIGONOMETRIC FUNCTIONS ========== */
 
 
 /*
  * Initialize the cached constants declared at the head of this file
  * (sin_30 etc).  The fact that we need those at all, let alone need this
@@ -2042,21 +1840,21 @@ dacosd(PG_FUNCTION_ARGS)
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	if (arg1 >= 0.0)
 		result = acosd_q1(arg1);
 	else
 		result = 90.0 + asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dasind			- returns the arcsin of arg1 (degrees)
  */
 Datum
 dasind(PG_FUNCTION_ARGS)
 {
@@ -2077,21 +1875,21 @@ dasind(PG_FUNCTION_ARGS)
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	if (arg1 >= 0.0)
 		result = asind_q1(arg1);
 	else
 		result = -asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		datand			- returns the arctan of arg1 (degrees)
  */
 Datum
 datand(PG_FUNCTION_ARGS)
 {
@@ -2107,21 +1905,21 @@ datand(PG_FUNCTION_ARGS)
 
 	/*
 	 * The principal branch of the inverse tangent function maps all inputs to
 	 * values in the range [-90, 90], so the result should always be finite,
 	 * even if the input is infinite.  Additionally, we take care to ensure
 	 * than when arg1 is 1, the result is exactly 45.
 	 */
 	atan_arg1 = atan(arg1);
 	result = (atan_arg1 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		atan2d			- returns the arctan of arg1/arg2 (degrees)
  */
 Datum
 datan2d(PG_FUNCTION_ARGS)
 {
@@ -2141,21 +1939,21 @@ datan2d(PG_FUNCTION_ARGS)
 	 * result should always be finite, even if the inputs are infinite.
 	 *
 	 * Note: this coding assumes that atan(1.0) is a suitable scaling constant
 	 * to get an exact result from atan2().  This might well fail on us at
 	 * some point, requiring us to decide exactly what inputs we think we're
 	 * going to guarantee an exact result for.
 	 */
 	atan2_arg1_arg2 = atan2(arg1, arg2);
 	result = (atan2_arg1_arg2 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		sind_0_to_30	- returns the sine of an angle that lies between 0 and
  *						  30 degrees.  This will return exactly 0 when x is 0,
  *						  and exactly 0.5 when x is 30 degrees.
  */
 static double
@@ -2262,21 +2060,21 @@ dcosd(PG_FUNCTION_ARGS)
 
 	if (arg1 > 90.0)
 	{
 		/* cosd(180-x) = -cosd(x) */
 		arg1 = 180.0 - arg1;
 		sign = -sign;
 	}
 
 	result = sign * cosd_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcotd			- returns the cotangent of arg1 (degrees)
  */
 Datum
 dcotd(PG_FUNCTION_ARGS)
 {
@@ -2327,21 +2125,21 @@ dcotd(PG_FUNCTION_ARGS)
 	result = sign * (cot_arg1 / cot_45);
 
 	/*
 	 * On some machines we get cotd(270) = minus zero, but this isn't always
 	 * true.  For portability, and because the user constituency for this
 	 * function probably doesn't want minus zero, force it to plain zero.
 	 */
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* cotd(0) == Inf */ , true);
+	check_float8_val(result, true /* cotd(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dsind			- returns the sine of arg1 (degrees)
  */
 Datum
 dsind(PG_FUNCTION_ARGS)
 {
@@ -2381,21 +2179,21 @@ dsind(PG_FUNCTION_ARGS)
 	}
 
 	if (arg1 > 90.0)
 	{
 		/* sind(180-x) = sind(x) */
 		arg1 = 180.0 - arg1;
 	}
 
 	result = sign * sind_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dtand			- returns the tangent of arg1 (degrees)
  */
 Datum
 dtand(PG_FUNCTION_ARGS)
 {
@@ -2446,64 +2244,56 @@ dtand(PG_FUNCTION_ARGS)
 	result = sign * (tan_arg1 / tan_45);
 
 	/*
 	 * On some machines we get tand(180) = minus zero, but this isn't always
 	 * true.  For portability, and because the user constituency for this
 	 * function probably doesn't want minus zero, force it to plain zero.
 	 */
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* tand(90) == Inf */ , true);
+	check_float8_val(result, true /* tand(90) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		degrees		- returns degrees converted from radians
  */
 Datum
 degrees(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
 
-	result = arg1 / RADIANS_PER_DEGREE;
-
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, RADIANS_PER_DEGREE));
 }
 
 
 /*
  *		dpi				- returns the constant PI
  */
 Datum
 dpi(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_FLOAT8(M_PI);
 }
 
 
 /*
  *		radians		- returns radians converted from degrees
  */
 Datum
 radians(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
 
-	result = arg1 * RADIANS_PER_DEGREE;
-
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, RADIANS_PER_DEGREE));
 }
 
 
 /*
  *		drandom		- returns a random number
  */
 Datum
 drandom(PG_FUNCTION_ARGS)
 {
 	float8		result;
@@ -2581,144 +2371,105 @@ check_float8_array(ArrayType *transarray, const char *caller, int n)
  * This function is used only in two stage aggregation and
  * shouldn't be called outside aggregate context.
  */
 Datum
 float8_combine(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_combine", 3);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-
 	transvalues2 = check_float8_array(transarray2, "float8_combine", 3);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
 
 Datum
 float8_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8		newval = PG_GETARG_FLOAT8(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float8_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
 	else
 	{
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
 								 sizeof(float8), FLOAT8PASSBYVAL, 'd');
 
 		PG_RETURN_ARRAYTYPE_P(result);
 	}
 }
 
 Datum
 float4_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 
 	/* do computations as float8 */
 	float8		newval = PG_GETARG_FLOAT4(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float4_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
 	else
 	{
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
 								 sizeof(float8), FLOAT8PASSBYVAL, 'd');
 
 		PG_RETURN_ARRAYTYPE_P(result);
 	}
 }
 
 Datum
@@ -2754,21 +2505,21 @@ float8_var_pop(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_var_pop", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Population variance is undefined when N is 0, so return NULL */
 	if (N == 0.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / (N * N));
 }
 
 Datum
 float8_var_samp(PG_FUNCTION_ARGS)
@@ -2783,21 +2534,21 @@ float8_var_samp(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_var_samp", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Sample variance is undefined when N is 0 or 1, so return NULL */
 	if (N <= 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
 }
 
 Datum
 float8_stddev_pop(PG_FUNCTION_ARGS)
@@ -2812,21 +2563,21 @@ float8_stddev_pop(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_stddev_pop", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Population stddev is undefined when N is 0, so return NULL */
 	if (N == 0.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(sqrt(numerator / (N * N)));
 }
 
 Datum
 float8_stddev_samp(PG_FUNCTION_ARGS)
@@ -2841,21 +2592,21 @@ float8_stddev_samp(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_stddev_samp", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Sample stddev is undefined when N is 0 or 1, so return NULL */
 	if (N <= 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(sqrt(numerator / (N * (N - 1.0))));
 }
 
 /*
  *		=========================
@@ -2890,30 +2641,30 @@ float8_regr_accum(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_accum", 6);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	N += 1.0;
 	sumX += newvalX;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
+	check_float8_val(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
 	sumX2 += newvalX * newvalX;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
+	check_float8_val(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
 	sumY += newvalY;
-	CHECKFLOATVAL(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
+	check_float8_val(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
 	sumY2 += newvalY * newvalY;
-	CHECKFLOATVAL(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
+	check_float8_val(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
 	sumXY += newvalX * newvalY;
-	CHECKFLOATVAL(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
-				  isinf(newvalY), true);
+	check_float8_val(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
+					 isinf(newvalY), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
 		transvalues[0] = N;
 		transvalues[1] = sumX;
@@ -2952,63 +2703,33 @@ float8_regr_accum(PG_FUNCTION_ARGS)
  * This function is used only in two stage aggregation and
  * shouldn't be called outside aggregate context.
  */
 Datum
 float8_regr_combine(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2,
-				sumY,
-				sumY2,
-				sumXY;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_regr_combine", 6);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-	sumY = transvalues1[3];
-	sumY2 = transvalues1[4];
-	sumXY = transvalues1[5];
-
 	transvalues2 = check_float8_array(transarray2, "float8_regr_combine", 6);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-	sumY += transvalues2[3];
-	CHECKFLOATVAL(sumY, isinf(transvalues1[3]) || isinf(transvalues2[3]),
-				  true);
-	sumY2 += transvalues2[4];
-	CHECKFLOATVAL(sumY2, isinf(transvalues1[4]) || isinf(transvalues2[4]),
-				  true);
-	sumXY += transvalues2[5];
-	CHECKFLOATVAL(sumXY, isinf(transvalues1[5]) || isinf(transvalues2[5]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
-	transvalues1[3] = sumY;
-	transvalues1[4] = sumY2;
-	transvalues1[5] = sumXY;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
+	transvalues1[3] = float8_pl(transvalues1[3], transvalues2[3]);
+	transvalues1[4] = float8_pl(transvalues1[4], transvalues2[4]);
+	transvalues1[5] = float8_pl(transvalues1[5], transvalues2[5]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
 
 
 Datum
 float8_regr_sxx(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
@@ -3020,21 +2741,21 @@ float8_regr_sxx(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_sxx", 6);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_syy(PG_FUNCTION_ARGS)
@@ -3049,21 +2770,21 @@ float8_regr_syy(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_syy", 6);
 	N = transvalues[0];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumY2) || isinf(sumY), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_sxy(PG_FUNCTION_ARGS)
@@ -3080,22 +2801,22 @@ float8_regr_sxy(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	/* A negative result is valid here */
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_avgx(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3148,22 +2869,22 @@ float8_covar_pop(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * N));
 }
 
 Datum
 float8_covar_samp(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
 	float8		N,
@@ -3176,22 +2897,22 @@ float8_covar_samp(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is <= 1 we should return NULL */
 	if (N < 2.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
 }
 
 Datum
 float8_corr(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
 	float8		N,
@@ -3210,26 +2931,26 @@ float8_corr(PG_FUNCTION_ARGS)
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0 || numeratorY <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXY / sqrt(numeratorX * numeratorY));
 }
 
 Datum
 float8_regr_r2(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3250,26 +2971,26 @@ float8_regr_r2(PG_FUNCTION_ARGS)
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 	/* per spec, horizontal line produces 1.0 */
 	if (numeratorY <= 0)
 		PG_RETURN_FLOAT8(1.0);
 
 	PG_RETURN_FLOAT8((numeratorXY * numeratorXY) /
 					 (numeratorX * numeratorY));
 }
 
@@ -3291,24 +3012,24 @@ float8_regr_slope(PG_FUNCTION_ARGS)
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXY / numeratorX);
 }
 
 Datum
 float8_regr_intercept(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3326,24 +3047,24 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXXY = sumY * sumX2 - sumX * sumXY;
-	CHECKFLOATVAL(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
-				  isinf(sumX) || isinf(sumXY), true);
+	check_float8_val(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
+					 isinf(sumX) || isinf(sumXY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXXY / numeratorX);
 }
 
 
 /*
  *		====================================
  *		MIXED-PRECISION ARITHMETIC OPERATORS
@@ -3354,251 +3075,211 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
  *		float48pl		- returns arg1 + arg2
  *		float48mi		- returns arg1 - arg2
  *		float48mul		- returns arg1 * arg2
  *		float48div		- returns arg1 / arg2
  */
 Datum
 float48pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 + arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl((float8) arg1, arg2));
 }
 
 Datum
 float48mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi((float8) arg1, arg2));
 }
 
 Datum
 float48mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul((float8) arg1, arg2));
 }
 
 Datum
 float48div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div((float8) arg1, arg2));
 }
 
 /*
  *		float84pl		- returns arg1 + arg2
  *		float84mi		- returns arg1 - arg2
  *		float84mul		- returns arg1 * arg2
  *		float84div		- returns arg1 / arg2
  */
 Datum
 float84pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 + arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, (float8) arg2));
 }
 
 Datum
 float84mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 - arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, (float8) arg2));
 }
 
 Datum
 float84mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 * arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, (float8) arg2));
 }
 
 Datum
 float84div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, (float8) arg2));
 }
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float48{eq,ne,lt,le,gt,ge}		- float4/float8 comparison operations
  */
 Datum
 float48eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq((float8) arg1, arg2));
 }
 
 Datum
 float48ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne((float8) arg1, arg2));
 }
 
 Datum
 float48lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt((float8) arg1, arg2));
 }
 
 Datum
 float48le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le((float8) arg1, arg2));
 }
 
 Datum
 float48gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt((float8) arg1, arg2));
 }
 
 Datum
 float48ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge((float8) arg1, arg2));
 }
 
 /*
  *		float84{eq,ne,lt,le,gt,ge}		- float8/float4 comparison operations
  */
 Datum
 float84eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, (float8) arg2));
 }
 
 Datum
 float84ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, (float8) arg2));
 }
 
 Datum
 float84lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, (float8) arg2));
 }
 
 Datum
 float84le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, (float8) arg2));
 }
 
 Datum
 float84gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, (float8) arg2));
 }
 
 Datum
 float84ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, (float8) arg2));
 }
 
 /*
  * Implements the float8 version of the width_bucket() function
  * defined by SQL2003. See also width_bucket_numeric().
  *
  * 'bound1' and 'bound2' are the lower and upper bounds of the
  * histogram's range, respectively. 'count' is the number of buckets
  * in the histogram. width_bucket() returns an integer indicating the
  * bucket number that 'operand' belongs to in an equiwidth histogram
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c
index b8bd4caa3e..7ecbc0b455 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -84,20 +84,21 @@
 
 #ifdef USE_ICU
 #include <unicode/ustring.h>
 #endif
 
 #include "catalog/pg_collation.h"
 #include "mb/pg_wchar.h"
 #include "utils/builtins.h"
 #include "utils/date.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 #include "utils/formatting.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/pg_locale.h"
 
 /* ----------
  * Routines type
  * ----------
  */
 #define DCH_TYPE		1		/* DATE-TIME version	*/
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 4f8ac71a6b..cdea309eeb 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -14,27 +14,23 @@
  */
 #include "postgres.h"
 
 #include <math.h>
 #include <limits.h>
 #include <float.h>
 #include <ctype.h>
 
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
-#include "utils/builtins.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index 0fe40499e0..096e59f817 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -69,21 +69,21 @@
  *			src/backend/utils/adt/geo_spgist.c
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
 
 #include "access/spgist.h"
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
  * is going only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 6f40072971..8ec44f12bc 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -29,20 +29,21 @@
 #include "access/hash.h"
 #include "catalog/pg_type.h"
 #include "common/int.h"
 #include "funcapi.h"
 #include "lib/hyperloglog.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/sortsupport.h"
 
 /* ----------
  * Uncomment the following to enable compilation of dump_numeric()
  * and dump_var() and to get a dump of any result produced by make_result().
  * ----------
 #define NUMERIC_DEBUG
diff --git a/src/backend/utils/adt/rangetypes_gist.c b/src/backend/utils/adt/rangetypes_gist.c
index 2fe61043d9..450479e31c 100644
--- a/src/backend/utils/adt/rangetypes_gist.c
+++ b/src/backend/utils/adt/rangetypes_gist.c
@@ -9,21 +9,22 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_gist.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/gist.h"
 #include "access/stratnum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/datum.h"
 #include "utils/rangetypes.h"
 
 
 /*
  * Range class properties used to segregate different classes of ranges in
  * GiST.  Each unique combination of properties is a class.  CLS_EMPTY cannot
  * be combined with anything else.
  */
 #define CLS_NORMAL			0	/* Ordinary finite range (no bits set) */
diff --git a/src/backend/utils/adt/rangetypes_selfuncs.c b/src/backend/utils/adt/rangetypes_selfuncs.c
index 59761ecf34..f9a5117492 100644
--- a/src/backend/utils/adt/rangetypes_selfuncs.c
+++ b/src/backend/utils/adt/rangetypes_selfuncs.c
@@ -14,21 +14,22 @@
  *	  src/backend/utils/adt/rangetypes_selfuncs.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/htup_details.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 #include "utils/selfuncs.h"
 #include "utils/typcache.h"
 
 static double calc_rangesel(TypeCacheEntry *typcache, VariableStatData *vardata,
 			  RangeType *constval, Oid operator);
 static double default_range_selectivity(Oid operator);
 static double calc_hist_selectivity(TypeCacheEntry *typcache,
 					  VariableStatData *vardata, RangeType *constval,
diff --git a/src/backend/utils/adt/rangetypes_typanalyze.c b/src/backend/utils/adt/rangetypes_typanalyze.c
index f2c11f54bc..9c50e4c1be 100644
--- a/src/backend/utils/adt/rangetypes_typanalyze.c
+++ b/src/backend/utils/adt/rangetypes_typanalyze.c
@@ -19,21 +19,22 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_typanalyze.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "catalog/pg_operator.h"
 #include "commands/vacuum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 
 static int	float8_qsort_cmp(const void *a1, const void *a2);
 static int	range_bound_qsort_cmp(const void *a1, const void *a2, void *arg);
 static void compute_range_stats(VacAttrStats *stats,
 					AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows);
 
 /*
  * range_typanalyze -- typanalyze function for range columns
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 103f91ae62..d1d0be164e 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -27,20 +27,21 @@
 #include "common/int128.h"
 #include "funcapi.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
 #include "parser/scansup.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 /*
  * gcc's -ffast-math switch breaks routines that expect exact results from
  * expressions like timeval / SECS_PER_HOUR, where timeval is double.
  */
 #ifdef __FAST_MATH__
 #error -ffast-math is known to break this code
 #endif
 
 #define SAMESIGN(a,b)	(((a) < 0) == ((b) < 0))
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 1db7845d5a..497e3bfdee 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -72,20 +72,21 @@
 #include "storage/fd.h"
 #include "storage/large_object.h"
 #include "storage/pg_shmem.h"
 #include "storage/proc.h"
 #include "storage/predicate.h"
 #include "tcop/tcopprot.h"
 #include "tsearch/ts_cache.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/guc_tables.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/pg_locale.h"
 #include "utils/plancache.h"
 #include "utils/portal.h"
 #include "utils/ps_status.h"
 #include "utils/rls.h"
 #include "utils/snapmgr.h"
 #include "utils/tzparser.h"
 #include "utils/varlena.h"
 #include "utils/xml.h"
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 3e462f1a9c..636c0b82d8 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -43,34 +43,20 @@ extern int	namestrcmp(Name name, const char *str);
 
 /* numutils.c */
 extern int32 pg_atoi(const char *s, int size, int c);
 extern void pg_itoa(int16 i, char *a);
 extern void pg_ltoa(int32 l, char *a);
 extern void pg_lltoa(int64 ll, char *a);
 extern char *pg_ltostr_zeropad(char *str, int32 value, int32 minwidth);
 extern char *pg_ltostr(char *str, int32 value);
 extern uint64 pg_strtouint64(const char *str, char **endptr, int base);
 
-/* float.c */
-extern PGDLLIMPORT int extra_float_digits;
-
-extern double get_float8_infinity(void);
-extern float get_float4_infinity(void);
-extern double get_float8_nan(void);
-extern float get_float4_nan(void);
-extern int	is_infinite(double val);
-extern double float8in_internal(char *num, char **endptr_p,
-				  const char *type_name, const char *orig_string);
-extern char *float8out_internal(double num);
-extern int	float4_cmp_internal(float4 a, float4 b);
-extern int	float8_cmp_internal(float8 a, float8 b);
-
 /* oid.c */
 extern oidvector *buildoidvector(const Oid *oids, int n);
 extern Oid	oidparse(Node *node);
 extern int	oid_cmp(const void *p1, const void *p2);
 
 /* regexp.c */
 extern char *regexp_fixed_prefix(text *text_re, bool case_insensitive,
 					Oid collation, bool *exact);
 
 /* ruleutils.c */
diff --git a/src/include/utils/float.h b/src/include/utils/float.h
new file mode 100644
index 0000000000..0e8483c930
--- /dev/null
+++ b/src/include/utils/float.h
@@ -0,0 +1,376 @@
+/*-------------------------------------------------------------------------
+ *
+ * float.h
+ *	  Definitions for the built-in floating-point types
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/include/utils/float.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef FLOAT_H
+#define FLOAT_H
+
+#include <math.h>
+
+#ifndef M_PI
+/* From my RH5.2 gcc math.h file - thomas 2000-04-03 */
+#define M_PI 3.14159265358979323846
+#endif
+
+/* Radians per degree, a.k.a. PI / 180 */
+#define RADIANS_PER_DEGREE 0.0174532925199432957692
+
+/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0. */
+#if defined(WIN32) && !defined(NAN)
+static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
+
+#define NAN (*(const float8 *) nan)
+#endif
+
+extern PGDLLIMPORT int extra_float_digits;
+
+/*
+ * Utility functions in float.c
+ */
+extern int	is_infinite(float8 val);
+extern float8 float8in_internal(char *num, char **endptr_p,
+				  const char *type_name, const char *orig_string);
+extern char *float8out_internal(float8 num);
+extern int	float4_cmp_internal(float4 a, float4 b);
+extern int	float8_cmp_internal(float8 a, float8 b);
+
+/*
+ * Routines to provide reasonably platform-independent handling of
+ * infinity and NaN
+ *
+ * We assume that isinf() and isnan() are available and work per spec.
+ * (On some platforms, we have to supply our own; see src/port.)  However,
+ * generating an Infinity or NaN in the first place is less well standardized;
+ * pre-C99 systems tend not to have C99's INFINITY and NaN macros.  We
+ * centralize our workarounds for this here.
+ */
+
+/*
+ * The funny placements of the two #pragmas is necessary because of a
+ * long lived bug in the Microsoft compilers.
+ * See http://support.microsoft.com/kb/120968/en-us for details
+ */
+#if (_MSC_VER >= 1800)
+#pragma warning(disable:4756)
+#endif
+static inline float4
+get_float4_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float4) INFINITY;
+#else
+#if (_MSC_VER >= 1800)
+#pragma warning(default:4756)
+#endif
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float4) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float8
+get_float8_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float8) INFINITY;
+#else
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float8) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float4
+get_float4_nan(void)
+{
+#ifdef NAN
+	/* C99 standard way */
+	return (float4) NAN;
+#else
+	/* Assume we can get a NAN via zero divide */
+	return (float4) (0.0 / 0.0);
+#endif
+}
+
+static inline float8
+get_float8_nan(void)
+{
+	/* (float8) NAN doesn't work on some NetBSD/MIPS releases */
+#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
+	/* C99 standard way */
+	return (float8) NAN;
+#else
+	/* Assume we can get a NaN via zero divide */
+	return (float8) (0.0 / 0.0);
+#endif
+}
+
+/*
+ * Checks to see if a float4/8 val has underflowed or overflowed
+ */
+
+static inline void
+check_float4_val(const float4 val, const bool inf_is_valid,
+				 const bool zero_is_valid)
+{
+	if (!inf_is_valid && unlikely(isinf(val)))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if (!zero_is_valid && unlikely(val == 0.0))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+static inline void
+check_float8_val(const float8 val, const bool inf_is_valid,
+				 const bool zero_is_valid)
+{
+	if (!inf_is_valid && unlikely(isinf(val)))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if (!zero_is_valid && unlikely(val == 0.0))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+/*
+ * Routines for operations with the checks above
+ *
+ * There isn't any way to check for underflow of addition/subtraction
+ * because numbers near the underflow value have already been rounded to
+ * the point where we can't detect that the two values were originally
+ * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
+ * 1.4013e-45.
+ */
+
+static inline float4
+float4_pl(const float4 val1, const float4 val2)
+{
+	float4		result;
+
+	result = val1 + val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_pl(const float8 val1, const float8 val2)
+{
+	float8		result;
+
+	result = val1 + val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mi(const float4 val1, const float4 val2)
+{
+	float4		result;
+
+	result = val1 - val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_mi(const float8 val1, const float8 val2)
+{
+	float8		result;
+
+	result = val1 - val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mul(const float4 val1, const float4 val2)
+{
+	float4		result;
+
+	result = val1 * val2;
+	check_float4_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0f || val2 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_mul(const float8 val1, const float8 val2)
+{
+	float8		result;
+
+	result = val1 * val2;
+	check_float8_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0 || val2 == 0.0);
+
+	return result;
+}
+
+static inline float4
+float4_div(const float4 val1, const float4 val2)
+{
+	float4		result;
+
+	if (val2 == 0.0f)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), val1 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_div(const float8 val1, const float8 val2)
+{
+	float8		result;
+
+	if (val2 == 0.0)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
+
+	return result;
+}
+
+/*
+ * Routines for NaN-aware comparisons
+ *
+ * We consider all NaNs to be equal and larger than any non-NaN. This is
+ * somewhat arbitrary; the important thing is to have a consistent sort
+ * order.
+ */
+
+static inline bool
+float4_eq(const float4 val1, const float4 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float8_eq(const float8 val1, const float8 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float4_ne(const float4 val1, const float4 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float8_ne(const float8 val1, const float8 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float4_lt(const float4 val1, const float4 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float8_lt(const float8 val1, const float8 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float4_le(const float4 val1, const float4 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float8_le(const float8 val1, const float8 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float4_gt(const float4 val1, const float4 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float8_gt(const float8 val1, const float8 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float4_ge(const float4 val1, const float4 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline bool
+float8_ge(const float8 val1, const float8 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline float4
+float4_min(const float4 val1, const float4 val2)
+{
+	return float4_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_min(const float8 val1, const float8 val2)
+{
+	return float8_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float4
+float4_max(const float4 val1, const float4 val2)
+{
+	return float4_gt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_max(const float8 val1, const float8 val2)
+{
+	return float8_gt(val1, val2) ? val1 : val2;
+}
+
+#endif							/* FLOAT_H */
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 0e066894cd..aeb31515e4 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -17,20 +17,21 @@
  *		and data types. There are still some more to do. - tgl 97/04/19
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEO_DECLS_H
 #define GEO_DECLS_H
 
 #include <math.h>
 
 #include "fmgr.h"
+#include "utils/float.h"
 
 /*--------------------------------------------------------------------
  * Useful floating point utilities and constants.
  *-------------------------------------------------------------------*/
 
 
 #define EPSILON					1.0E-06
 
 #ifdef EPSILON
 #define FPzero(A)				(fabs(A) <= EPSILON)
-- 
2.14.3 (Apple Git-98)

0003-geo-float-v09.patchapplication/octet-stream; name=0003-geo-float-v09.patchDownload
From 11eec2d91d58875f749c5800c2e85738b2edc932 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 27 May 2017 16:17:42 -0400
Subject: [PATCH 3/6] geo-float-v09

Use the built-in float datatype to implement geometric types

This patch makes the geometric operators and functions use the exported
function of the float datatype.  The main reason of doing so is to check
for underflow and overflow, and to handle NaNs consciously.

The float datatypes consider NaNs to be equal and greater than any
non-NaN.  This change considers NaNs equal only for the equality
operators.  The placement operators, contains, overlaps, left/right of
etc. continues to return false when NaNs are involved.  We don't need
to worry about them being considered greater than any-NaN because there
aren't any basic comparison operators like less/greater than for the
geometric datatypes.

All changes can be summarised as:

* Check for underflow and overflow
* Check for division by zero
* Let the objects with NaN values to be the same
* Return NULL when the distance is NaN for all closest point operators
* Don't round the slope to DBL_MAX
* Favour not-NaN over NaN where it makes sense

The patch also replaces all occurrences of "double" as "float8".  They
are the same, but were randomly spread on the same file.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com

Parallel discussions:

* https://www.postgresql.org/message-id/28685.1468246504%40sss.pgh.pa.us
---
 src/backend/access/gist/gistproc.c |  91 +++----
 src/backend/utils/adt/geo_ops.c    | 497 ++++++++++++++++++++-----------------
 src/backend/utils/adt/geo_spgist.c |  28 +--
 src/include/utils/geo_decls.h      |  17 +-
 4 files changed, 340 insertions(+), 293 deletions(-)

diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index 4bbfdadf9f..4b6233f212 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -16,20 +16,21 @@
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/geo_decls.h"
 
 
 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
 						 StrategyNumber strategy);
 static bool rtree_internal_consistent(BOX *key, BOX *query,
 						  StrategyNumber strategy);
 
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
@@ -48,55 +49,56 @@ rt_box_union(BOX *n, const BOX *a, const BOX *b)
 	n->high.x = float8_max(a->high.x, b->high.x);
 	n->high.y = float8_max(a->high.y, b->high.y);
 	n->low.x = float8_min(a->low.x, b->low.x);
 	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
 	if (float8_le(box->high.x, box->low.x) ||
 		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
-	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
+	return float8_mul(float8_mi(box->high.x, box->low.x),
+					  float8_mi(box->high.y, box->low.y));
 }
 
 /*
  * Return amount by which the union of the two boxes is larger than
  * the original BOX's area.  The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 box_penalty(const BOX *original, const BOX *new)
 {
 	BOX			unionbox;
 
 	rt_box_union(&unionbox, original, new);
-	return size_box(&unionbox) - size_box(original);
+	return float8_mi(size_box(&unionbox), size_box(original));
 }
 
 /*
  * The GiST Consistent method for boxes
  *
  * Should return false if for all data items x below entry,
  * the predicate x op query must be false, where op is the oper
  * corresponding to strategy in the pg_amop table.
  */
 Datum
@@ -256,74 +258,74 @@ fallbackSplit(GistEntryVector *entryvec, GIST_SPLITVEC *v)
 
 /*
  * Represents information about an entry that can be placed to either group
  * without affecting overlap over selected axis ("common entry").
  */
 typedef struct
 {
 	/* Index of entry in the initial array */
 	int			index;
 	/* Delta between penalties of entry insertion into different groups */
-	double		delta;
+	float8		delta;
 } CommonEntry;
 
 /*
  * Context for g_box_consider_split. Contains information about currently
  * selected split and some general information.
  */
 typedef struct
 {
 	int			entriesCount;	/* total number of entries being split */
 	BOX			boundingBox;	/* minimum bounding box across all entries */
 
 	/* Information about currently selected split follows */
 
 	bool		first;			/* true if no split was selected yet */
 
-	double		leftUpper;		/* upper bound of left interval */
-	double		rightLower;		/* lower bound of right interval */
+	float8		leftUpper;		/* upper bound of left interval */
+	float8		rightLower;		/* lower bound of right interval */
 
 	float4		ratio;
 	float4		overlap;
 	int			dim;			/* axis of this split */
-	double		range;			/* width of general MBR projection to the
+	float8		range;			/* width of general MBR projection to the
 								 * selected axis */
 } ConsiderSplitContext;
 
 /*
  * Interval represents projection of box to axis.
  */
 typedef struct
 {
-	double		lower,
+	float8		lower,
 				upper;
 } SplitInterval;
 
 /*
  * Interval comparison function by lower bound of the interval;
  */
 static int
 interval_cmp_lower(const void *i1, const void *i2)
 {
-	double		lower1 = ((const SplitInterval *) i1)->lower,
+	float8		lower1 = ((const SplitInterval *) i1)->lower,
 				lower2 = ((const SplitInterval *) i2)->lower;
 
 	return float8_cmp_internal(lower1, lower2);
 }
 
 /*
  * Interval comparison function by upper bound of the interval;
  */
 static int
 interval_cmp_upper(const void *i1, const void *i2)
 {
-	double		upper1 = ((const SplitInterval *) i1)->upper,
+	float8		upper1 = ((const SplitInterval *) i1)->upper,
 				upper2 = ((const SplitInterval *) i2)->upper;
 
 	return float8_cmp_internal(upper1, upper2);
 }
 
 /*
  * Replace negative (or NaN) value with zero.
  */
 static inline float
 non_negative(float val)
@@ -332,28 +334,28 @@ non_negative(float val)
 		return val;
 	else
 		return 0.0f;
 }
 
 /*
  * Consider replacement of currently selected split with the better one.
  */
 static inline void
 g_box_consider_split(ConsiderSplitContext *context, int dimNum,
-					 double rightLower, int minLeftCount,
-					 double leftUpper, int maxLeftCount)
+					 float8 rightLower, int minLeftCount,
+					 float8 leftUpper, int maxLeftCount)
 {
 	int			leftCount,
 				rightCount;
 	float4		ratio,
 				overlap;
-	double		range;
+	float8		range;
 
 	/*
 	 * Calculate entries distribution ratio assuming most uniform distribution
 	 * of common entries.
 	 */
 	if (minLeftCount >= (context->entriesCount + 1) / 2)
 	{
 		leftCount = minLeftCount;
 	}
 	else
@@ -362,40 +364,41 @@ g_box_consider_split(ConsiderSplitContext *context, int dimNum,
 			leftCount = maxLeftCount;
 		else
 			leftCount = context->entriesCount / 2;
 	}
 	rightCount = context->entriesCount - leftCount;
 
 	/*
 	 * Ratio of split - quotient between size of lesser group and total
 	 * entries count.
 	 */
-	ratio = ((float4) Min(leftCount, rightCount)) /
-		((float4) context->entriesCount);
+	ratio = float4_div(Min(leftCount, rightCount), context->entriesCount);
 
 	if (ratio > LIMIT_RATIO)
 	{
 		bool		selectthis = false;
 
 		/*
 		 * The ratio is acceptable, so compare current split with previously
 		 * selected one. Between splits of one dimension we search for minimal
 		 * overlap (allowing negative values) and minimal ration (between same
 		 * overlaps. We switch dimension if find less overlap (non-negative)
 		 * or less range with same overlap.
 		 */
 		if (dimNum == 0)
-			range = context->boundingBox.high.x - context->boundingBox.low.x;
+			range = float8_mi(context->boundingBox.high.x,
+							  context->boundingBox.low.x);
 		else
-			range = context->boundingBox.high.y - context->boundingBox.low.y;
+			range = float8_mi(context->boundingBox.high.y,
+							  context->boundingBox.low.y);
 
-		overlap = (leftUpper - rightLower) / range;
+		overlap = float8_div(float8_mi(leftUpper, rightLower), range);
 
 		/* If there is no previous selection, select this */
 		if (context->first)
 			selectthis = true;
 		else if (context->dim == dimNum)
 		{
 			/*
 			 * Within the same dimension, choose the new split if it has a
 			 * smaller overlap, or same overlap but better ratio.
 			 */
@@ -524,21 +527,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		else
 			adjustBox(&context.boundingBox, box);
 	}
 
 	/*
 	 * Iterate over axes for optimal split searching.
 	 */
 	context.first = true;		/* nothing selected yet */
 	for (dim = 0; dim < 2; dim++)
 	{
-		double		leftUpper,
+		float8		leftUpper,
 					rightLower;
 		int			i1,
 					i2;
 
 		/* Project each entry as an interval on the selected axis. */
 		for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 		{
 			box = DatumGetBoxP(entryvec->vector[i].key);
 			if (dim == 0)
 			{
@@ -721,21 +724,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 			*rightBox = *(box);					\
 		v->spl_right[v->spl_nright++] = off;	\
 	} while(0)
 
 	/*
 	 * Distribute entries which can be distributed unambiguously, and collect
 	 * common entries.
 	 */
 	for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 	{
-		double		lower,
+		float8		lower,
 					upper;
 
 		/*
 		 * Get upper and lower bounds along selected axis.
 		 */
 		box = DatumGetBoxP(entryvec->vector[i].key);
 		if (context.dim == 0)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
@@ -776,31 +779,31 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
 	{
 		/*
 		 * Calculate minimum number of entries that must be placed in both
 		 * groups, to reach LIMIT_RATIO.
 		 */
-		int			m = ceil(LIMIT_RATIO * (double) nentries);
+		int			m = ceil(LIMIT_RATIO * (float8) nentries);
 
 		/*
 		 * Calculate delta between penalties of join "common entries" to
 		 * different groups.
 		 */
 		for (i = 0; i < commonEntriesCount; i++)
 		{
 			box = DatumGetBoxP(entryvec->vector[commonEntries[i].index].key);
-			commonEntries[i].delta = Abs(box_penalty(leftBox, box) -
-										 box_penalty(rightBox, box));
+			commonEntries[i].delta = Abs(float8_mi(box_penalty(leftBox, box),
+												   box_penalty(rightBox, box)));
 		}
 
 		/*
 		 * Sort "common entries" by calculated deltas in order to distribute
 		 * the most ambiguous entries first.
 		 */
 		qsort(commonEntries, commonEntriesCount, sizeof(CommonEntry), common_entry_cmp);
 
 		/*
 		 * Distribute "common entries" between groups.
@@ -1100,24 +1103,24 @@ gist_circle_compress(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	GISTENTRY  *retval;
 
 	if (entry->leafkey)
 	{
 		CIRCLE	   *in = DatumGetCircleP(entry->key);
 		BOX		   *r;
 
 		r = (BOX *) palloc(sizeof(BOX));
-		r->high.x = in->center.x + in->radius;
-		r->low.x = in->center.x - in->radius;
-		r->high.y = in->center.y + in->radius;
-		r->low.y = in->center.y - in->radius;
+		r->high.x = float8_pl(in->center.x, in->radius);
+		r->low.x = float8_mi(in->center.x, in->radius);
+		r->high.y = float8_pl(in->center.y, in->radius);
+		r->low.y = float8_mi(in->center.y, in->radius);
 
 		retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
 		gistentryinit(*retval, PointerGetDatum(r),
 					  entry->rel, entry->page,
 					  entry->offset, false);
 	}
 	else
 		retval = entry;
 	PG_RETURN_POINTER(retval);
 }
@@ -1141,24 +1144,24 @@ gist_circle_consistent(PG_FUNCTION_ARGS)
 	*recheck = true;
 
 	if (DatumGetBoxP(entry->key) == NULL || query == NULL)
 		PG_RETURN_BOOL(false);
 
 	/*
 	 * Since the operators require recheck anyway, we can just use
 	 * rtree_internal_consistent even at leaf nodes.  (This works in part
 	 * because the index entries are bounding boxes not circles.)
 	 */
-	bbox.high.x = query->center.x + query->radius;
-	bbox.low.x = query->center.x - query->radius;
-	bbox.high.y = query->center.y + query->radius;
-	bbox.low.y = query->center.y - query->radius;
+	bbox.high.x = float8_pl(query->center.x, query->radius);
+	bbox.low.x = float8_mi(query->center.x, query->radius);
+	bbox.high.y = float8_pl(query->center.y, query->radius);
+	bbox.low.y = float8_mi(query->center.y, query->radius);
 
 	result = rtree_internal_consistent(DatumGetBoxP(entry->key),
 									   &bbox, strategy);
 
 	PG_RETURN_BOOL(result);
 }
 
 /**************************************************
  * Point ops
  **************************************************/
@@ -1209,63 +1212,63 @@ gist_point_fetch(PG_FUNCTION_ARGS)
 				  entry->offset, false);
 
 	PG_RETURN_POINTER(retval);
 }
 
 
 #define point_point_distance(p1,p2) \
 	DatumGetFloat8(DirectFunctionCall2(point_distance, \
 									   PointPGetDatum(p1), PointPGetDatum(p2)))
 
-static double
+static float8
 computeDistance(bool isLeaf, BOX *box, Point *point)
 {
-	double		result = 0.0;
+	float8		result = 0.0;
 
 	if (isLeaf)
 	{
 		/* simple point to point distance */
 		result = point_point_distance(point, &box->low);
 	}
 	else if (point->x <= box->high.x && point->x >= box->low.x &&
 			 point->y <= box->high.y && point->y >= box->low.y)
 	{
 		/* point inside the box */
 		result = 0.0;
 	}
 	else if (point->x <= box->high.x && point->x >= box->low.x)
 	{
 		/* point is over or below box */
 		Assert(box->low.y <= box->high.y);
 		if (point->y > box->high.y)
-			result = point->y - box->high.y;
+			result = float8_mi(point->y, box->high.y);
 		else if (point->y < box->low.y)
-			result = box->low.y - point->y;
+			result = float8_mi(box->low.y, point->y);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
 	else if (point->y <= box->high.y && point->y >= box->low.y)
 	{
 		/* point is to left or right of box */
 		Assert(box->low.x <= box->high.x);
 		if (point->x > box->high.x)
-			result = point->x - box->high.x;
+			result = float8_mi(point->x, box->high.x);
 		else if (point->x < box->low.x)
-			result = box->low.x - point->x;
+			result = float8_mi(box->low.x, point->x);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
 	else
 	{
 		/* closest point will be a vertex */
 		Point		p;
-		double		subresult;
+		float8		subresult;
 
 		result = point_point_distance(point, &box->low);
 
 		subresult = point_point_distance(point, &box->high);
 		if (result > subresult)
 			result = subresult;
 
 		p.x = box->low.x;
 		p.y = box->high.y;
 		subresult = point_point_distance(point, &p);
@@ -1442,21 +1445,21 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 	}
 
 	PG_RETURN_BOOL(result);
 }
 
 Datum
 gist_point_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(GIST_LEAF(entry),
 									   DatumGetBoxP(entry->key),
 									   PG_GETARG_POINT_P(1));
 			break;
 		default:
@@ -1471,25 +1474,25 @@ gist_point_distance(PG_FUNCTION_ARGS)
 /*
  * The inexact GiST distance method for geometric types that store bounding
  * boxes.
  *
  * Compute lossy distance from point to index entries.  The result is inexact
  * because index entries are bounding boxes, not the exact shapes of the
  * indexed geometric types.  We use distance from point to MBR of index entry.
  * This is a lower bound estimate of distance from point to indexed geometric
  * type.
  */
-static double
+static float8
 gist_bbox_distance(GISTENTRY *entry, Datum query,
 				   StrategyNumber strategy, bool *recheck)
 {
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	/* Bounding box distance is always inexact. */
 	*recheck = true;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(false,
 									   DatumGetBoxP(entry->key),
@@ -1505,32 +1508,32 @@ gist_bbox_distance(GISTENTRY *entry, Datum query,
 
 Datum
 gist_circle_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
 
 Datum
 gist_poly_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index cdea309eeb..49667b17f7 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -51,56 +51,56 @@ static inline float8 line_invsl(LINE *line);
 static bool	line_interpt_line(Point *result, LINE *l1, LINE *l2);
 static bool line_contain_point(LINE *line, Point *point);
 static float8 line_closept_point(Point *result, LINE *line, Point *pt);
 
 /* Routines for line segments */
 static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
 static inline float8 lseg_sl(LSEG *lseg);
 static inline float8 lseg_invsl(LSEG *lseg);
 static bool	lseg_interpt_line(Point *result, LSEG *lseg, LINE *line);
 static bool	lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2);
-static int	lseg_crossing(double x, double y, double px, double py);
+static int	lseg_crossing(float8 x, float8 y, float8 px, float8 py);
 static bool	lseg_contain_point(LSEG *lseg, Point *point);
 static float8 lseg_closept_point(Point *result, LSEG *lseg, Point *pt);
 static float8 lseg_closept_line(Point *result, LSEG *lseg, LINE *line);
 static float8 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2);
 
 /* Routines for boxes */
 static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
 static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
-static double box_ar(BOX *box);
-static double box_ht(BOX *box);
-static double box_wd(BOX *box);
+static float8 box_ar(BOX *box);
+static float8 box_ht(BOX *box);
+static float8 box_wd(BOX *box);
 static bool box_contain_point(BOX *box, Point *point);
 static bool box_contain_box(BOX *box1, BOX *box2);
 static bool box_contain_lseg(BOX *box, LSEG *lseg);
 static bool box_interpt_lseg(Point *result, BOX *box, LSEG *lseg);
 static float8 box_closept_point(Point *result, BOX *box, Point *point);
 static float8 box_closept_lseg(Point *result, BOX *box, LSEG *lseg);
 
 /* Routines for circles */
-static double circle_ar(CIRCLE *circle);
+static float8 circle_ar(CIRCLE *circle);
 
 /* Routines for polygons */
 static void make_bound_box(POLYGON *poly);
 static void poly_to_circle(CIRCLE *result, POLYGON *poly);
 static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
 static bool poly_contain_poly(POLYGON *polya, POLYGON *polyb);
 static bool plist_same(int npts, Point *p1, Point *p2);
 static float8 dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 /* Routines for encoding and decoding */
-static double single_decode(char *num, char **endptr_p,
+static float8 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
-static void pair_decode(char *str, double *x, double *y, char **endptr_p,
+static void pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
 static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
 
 
 /*
@@ -138,38 +138,38 @@ static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
  *
  * For boxes, the points are opposite corners with the first point at the top right.
  * For closed paths and polygons, the points should be reordered to allow
  *	fast and correct equality comparisons.
  *
  * XXX perhaps points in complex shapes should be reordered internally
  *	to allow faster internal operations, but should keep track of input order
  *	and restore that order for text output - tgl 97/01/16
  */
 
-static double
+static float8
 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string)
 {
 	return float8in_internal(num, endptr_p, type_name, orig_string);
 }								/* single_decode() */
 
 static void
 single_encode(float8 x, StringInfo str)
 {
 	char	   *xstr = float8out_internal(x);
 
 	appendStringInfoString(str, xstr);
 	pfree(xstr);
 }								/* single_encode() */
 
 static void
-pair_decode(char *str, double *x, double *y, char **endptr_p,
+pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string)
 {
 	bool		has_delim;
 
 	while (isspace((unsigned char) *str))
 		str++;
 	if ((has_delim = (*str == LDELIM)))
 		str++;
 
 	*x = float8in_internal(str, &str, type_name, orig_string);
@@ -368,33 +368,33 @@ pair_count(char *s, char delim)
  *		External format: (two corners of box)
  *				"(f8, f8), (f8, f8)"
  *				also supports the older style "(f8, f8, f8, f8)"
  */
 Datum
 box_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	BOX		   *box = (BOX *) palloc(sizeof(BOX));
 	bool		isopen;
-	double		x,
+	float8		x,
 				y;
 
 	path_decode(str, false, 2, &(box->high), &isopen, NULL, "box", str);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*		box_out -		convert a box to external form.
@@ -408,38 +408,38 @@ box_out(PG_FUNCTION_ARGS)
 }
 
 /*
  *		box_recv			- converts external binary format to box
  */
 Datum
 box_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	BOX		   *box;
-	double		x,
+	float8		x,
 				y;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
 	box->high.x = pq_getmsgfloat8(buf);
 	box->high.y = pq_getmsgfloat8(buf);
 	box->low.x = pq_getmsgfloat8(buf);
 	box->low.y = pq_getmsgfloat8(buf);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*
@@ -458,31 +458,31 @@ box_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, box->low.y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*		box_construct	-		fill in a new box.
  */
 static inline void
 box_construct(BOX *result, Point *pt1, Point *pt2)
 {
-	if (pt1->x > pt2->x)
+	if (float8_gt(pt1->x, pt2->x))
 	{
 		result->high.x = pt1->x;
 		result->low.x = pt2->x;
 	}
 	else
 	{
 		result->high.x = pt2->x;
 		result->low.x = pt1->x;
 	}
-	if (pt1->y > pt2->y)
+	if (float8_gt(pt1->y, pt2->y))
 	{
 		result->high.y = pt1->y;
 		result->low.y = pt2->y;
 	}
 	else
 	{
 		result->high.y = pt2->y;
 		result->low.y = pt1->y;
 	}
 }
@@ -800,54 +800,54 @@ box_center(PG_FUNCTION_ARGS)
 	Point	   *result = (Point *) palloc(sizeof(Point));
 
 	box_cn(result, box);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		box_ar	-		returns the area of the box.
  */
-static double
+static float8
 box_ar(BOX *box)
 {
-	return box_wd(box) * box_ht(box);
+	return float8_mul(box_wd(box), box_ht(box));
 }
 
 
 /*		box_cn	-		stores the centerpoint of the box into *center.
  */
 static void
 box_cn(Point *center, BOX *box)
 {
-	center->x = (box->high.x + box->low.x) / 2.0;
-	center->y = (box->high.y + box->low.y) / 2.0;
+	center->x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	center->y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 }
 
 
 /*		box_wd	-		returns the width (length) of the box
  *								  (horizontal magnitude).
  */
-static double
+static float8
 box_wd(BOX *box)
 {
-	return box->high.x - box->low.x;
+	return float8_mi(box->high.x, box->low.x);
 }
 
 
 /*		box_ht	-		returns the height of the box
  *								  (vertical magnitude).
  */
-static double
+static float8
 box_ht(BOX *box)
 {
-	return box->high.y - box->low.y;
+	return float8_mi(box->high.y, box->low.y);
 }
 
 
 /*----------------------------------------------------------
  *	Funky operations.
  *---------------------------------------------------------*/
 
 /*		box_intersect	-
  *				returns the overlapping portion of two boxes,
  *				  or NULL if they do not intersect.
@@ -857,24 +857,24 @@ box_intersect(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 	BOX		   *result;
 
 	if (!box_ov(box1, box2))
 		PG_RETURN_NULL();
 
 	result = (BOX *) palloc(sizeof(BOX));
 
-	result->high.x = Min(box1->high.x, box2->high.x);
-	result->low.x = Max(box1->low.x, box2->low.x);
-	result->high.y = Min(box1->high.y, box2->high.y);
-	result->low.y = Max(box1->low.y, box2->low.y);
+	result->high.x = float8_min(box1->high.x, box2->high.x);
+	result->low.x = float8_max(box1->low.x, box2->low.x);
+	result->high.y = float8_min(box1->high.y, box2->high.y);
+	result->low.y = float8_max(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(result);
 }
 
 
 /*		box_diagonal	-
  *				returns a line segment which happens to be the
  *				  positive-slope diagonal of "box".
  */
 Datum
@@ -1006,30 +1006,30 @@ line_send(PG_FUNCTION_ARGS)
 
 /*
  * Fill already-allocated LINE struct from the point and the slope
  */
 static inline void
 line_construct(LINE *result, Point *pt, float8 m)
 {
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
-		result->A = -1;
-		result->B = 0;
+		result->A = -1.0;
+		result->B = 0.0;
 		result->C = pt->x;
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
-		result->C = pt->y - m * pt->x;
+		result->C = float8_mi(pt->y, float8_mul(m, pt->x));
 	}
 }
 
 /* line_construct_pp()
  * two points
  */
 Datum
 line_construct_pp(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
@@ -1068,94 +1068,105 @@ Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
 	else if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
 
-	PG_RETURN_BOOL(FPeq(((l1->A * l2->B) / (l1->B * l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
+								   float8_mul(l1->B, l2->A)), -1.0));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
 Datum
 line_horizontal(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->A));
 }
 
+
+/*
+ * Check whether the two lines are the same
+ *
+ * We consider NaNs values to be equal to each other to let those lines
+ * to be found.
+ */
 Datum
 line_eq(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	double		k;
+	float8		ratio;
 
-	if (!FPzero(l2->A))
-		k = l1->A / l2->A;
-	else if (!FPzero(l2->B))
-		k = l1->B / l2->B;
-	else if (!FPzero(l2->C))
-		k = l1->C / l2->C;
+	if (!FPzero(l2->A) && !isnan(l2->A))
+		ratio = float8_div(l1->A, l2->A);
+	else if (!FPzero(l2->B) && !isnan(l2->B))
+		ratio = float8_div(l1->B, l2->B);
+	else if (!FPzero(l2->C) && !isnan(l2->C))
+		ratio = float8_div(l1->C, l2->C);
 	else
-		k = 1.0;
+		ratio = 1.0;
 
-	PG_RETURN_BOOL(FPeq(l1->A, k * l2->A) &&
-				   FPeq(l1->B, k * l2->B) &&
-				   FPeq(l1->C, k * l2->C));
+	PG_RETURN_BOOL((FPeq(l1->A, float8_mul(ratio, l2->A)) &&
+					FPeq(l1->B, float8_mul(ratio, l2->B)) &&
+					FPeq(l1->C, float8_mul(ratio, l2->C))) ||
+				   (float8_eq(l1->A, l2->A) &&
+					float8_eq(l1->B, l2->B) &&
+					float8_eq(l1->C, l2->C)));
 }
 
 
 /*----------------------------------------------------------
  *	Line arithmetic routines.
  *---------------------------------------------------------*/
 
 /*
  * Return inverse slope of the line
  */
 static inline float8
 line_invsl(LINE *line)
 {
 	if (FPzero(line->A))
 		return DBL_MAX;
 	if (FPzero(line->B))
 		return 0.0;
-	return line->B / line->A;
+	return float8_div(line->B, line->A);
 }
 
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
 	Point		tmp;
 
 	if (line_interpt_line(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
+		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
 	point_construct(&tmp, 0.0, l1->C);
 	result = line_closept_point(NULL, l2, &tmp);
 	PG_RETURN_FLOAT8(result);
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
@@ -1174,47 +1185,51 @@ line_interpt(PG_FUNCTION_ARGS)
 /*
  * Internal version of line_interpt
  *
  * This returns true if two lines intersect (they do, if they are not
  * parallel), false if they do not.  This also sets the intersection point
  * to *result, if it is not NULL.
  *
  * NOTE If the lines are identical then we will find they are parallel
  * and report "no intersection".  This is a little weird, but since
  * there's no *unique* intersection, maybe it's appropriate behavior.
+ *
+ * If the lines have NaN constants, we will return true, and the intersection
+ * point would have NaN coordinates.  We shouldn't return false in this case
+ * because that would mean the lines are parallel.
  */
 static bool
 line_interpt_line(Point *result, LINE *l1, LINE *l2)
 {
-	double		x,
+	float8		x,
 				y;
 
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
 		if (FPzero(l2->B))		/* l2 vertical? */
 			return false;
 
 		x = l1->C;
-		y = (l2->A * x + l2->C);
+		y = float8_pl(float8_mul(l2->A, x), l2->C);
 	}
 	else if (FPzero(l2->B))		/* l2 vertical? */
 	{
 		x = l2->C;
-		y = (l1->A * x + l1->C);
+		y = float8_pl(float8_mul(l1->A, x), l1->C);
 	}
 	else
 	{
-		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
 			return false;
 
-		x = (l1->C - l2->C) / (l2->A - l1->A);
-		y = (l1->A * x + l1->C);
+		x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
+		y = float8_pl(float8_mul(l1->A, x), l1->C);
 	}
 	if (result != NULL)
 		point_construct(result, x, y);
 
 	return true;
 }
 
 
 /***********************************************************************
  **
@@ -1235,36 +1250,35 @@ line_interpt_line(Point *result, LINE *l1, LINE *l2)
  *				"(xcoord, ycoord),... "
  *				"[xcoord, ycoord,... ]"
  *		Also support older format:
  *				"(closed, npts, xcoord, ycoord,... )"
  *---------------------------------------------------------*/
 
 Datum
 path_area(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P(0);
-	double		area = 0.0;
+	float8		area = 0.0;
 	int			i,
 				j;
 
 	if (!path->closed)
 		PG_RETURN_NULL();
 
 	for (i = 0; i < path->npts; i++)
 	{
 		j = (i + 1) % path->npts;
-		area += path->p[i].x * path->p[j].y;
-		area -= path->p[i].y * path->p[j].x;
+		area = float8_pl(area, float8_mul(path->p[i].x, path->p[j].y));
+		area = float8_mi(area, float8_mul(path->p[i].y, path->p[j].x));
 	}
 
-	area *= 0.5;
-	PG_RETURN_FLOAT8(area < 0.0 ? -area : area);
+	PG_RETURN_FLOAT8(float8_div(fabs(area), 2.0));
 }
 
 
 Datum
 path_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	PATH	   *path;
 	bool		isopen;
 	char	   *s;
@@ -1520,33 +1534,33 @@ path_inter(PG_FUNCTION_ARGS)
 				j;
 	LSEG		seg1,
 				seg2;
 
 	Assert(p1->npts > 0 && p2->npts > 0);
 
 	b1.high.x = b1.low.x = p1->p[0].x;
 	b1.high.y = b1.low.y = p1->p[0].y;
 	for (i = 1; i < p1->npts; i++)
 	{
-		b1.high.x = Max(p1->p[i].x, b1.high.x);
-		b1.high.y = Max(p1->p[i].y, b1.high.y);
-		b1.low.x = Min(p1->p[i].x, b1.low.x);
-		b1.low.y = Min(p1->p[i].y, b1.low.y);
+		b1.high.x = float8_max(p1->p[i].x, b1.high.x);
+		b1.high.y = float8_max(p1->p[i].y, b1.high.y);
+		b1.low.x = float8_min(p1->p[i].x, b1.low.x);
+		b1.low.y = float8_min(p1->p[i].y, b1.low.y);
 	}
 	b2.high.x = b2.low.x = p2->p[0].x;
 	b2.high.y = b2.low.y = p2->p[0].y;
 	for (i = 1; i < p2->npts; i++)
 	{
-		b2.high.x = Max(p2->p[i].x, b2.high.x);
-		b2.high.y = Max(p2->p[i].y, b2.high.y);
-		b2.low.x = Min(p2->p[i].x, b2.low.x);
-		b2.low.y = Min(p2->p[i].y, b2.low.y);
+		b2.high.x = float8_max(p2->p[i].x, b2.high.x);
+		b2.high.y = float8_max(p2->p[i].y, b2.high.y);
+		b2.low.x = float8_min(p2->p[i].x, b2.low.x);
+		b2.low.y = float8_min(p2->p[i].y, b2.low.y);
 	}
 	if (!box_ov(&b1, &b2))
 		PG_RETURN_BOOL(false);
 
 	/* pairwise check lseg intersections */
 	for (i = 0; i < p1->npts; i++)
 	{
 		int			iprev;
 
 		if (i > 0)
@@ -1622,21 +1636,21 @@ path_distance(PG_FUNCTION_ARGS)
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
 			tmp = lseg_closept_lseg(NULL, &seg1, &seg2);
-			if (!have_min || tmp < min)
+			if (!have_min || float8_lt(tmp, min))
 			{
 				min = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	if (!have_min)
 		PG_RETURN_NULL();
 
@@ -1661,21 +1675,21 @@ path_length(PG_FUNCTION_ARGS)
 
 		if (i > 0)
 			iprev = i - 1;
 		else
 		{
 			if (!path->closed)
 				continue;
 			iprev = path->npts - 1; /* include the closure segment */
 		}
 
-		result += point_dt(&path->p[iprev], &path->p[i]);
+		result = float8_pl(result, point_dt(&path->p[iprev], &path->p[i]));
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /***********************************************************************
  **
  **		Routines for 2D points.
  **
  ***********************************************************************/
@@ -1824,44 +1838,52 @@ point_eq(PG_FUNCTION_ARGS)
 
 Datum
 point_ne(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_BOOL(!point_eq_point(pt1, pt2));
 }
 
+
+/*
+ * Check whether the two points are the same
+ *
+ * We consider NaNs coordinates to be equal to each other to let those points
+ * to be found.
+ */
 static inline bool
 point_eq_point(Point *pt1, Point *pt2)
 {
-	return FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y);
+	return ((FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y)) ||
+			(float8_eq(pt1->x, pt2->x) && float8_eq(pt1->y, pt2->y)));
 }
 
 
 /*----------------------------------------------------------
  *	"Arithmetic" operators on points.
  *---------------------------------------------------------*/
 
 Datum
 point_distance(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
 static inline float8
 point_dt(Point *pt1, Point *pt2)
 {
-	return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
+	return HYPOT(float8_mi(pt1->x, pt2->x), float8_mi(pt1->y, pt2->y));
 }
 
 Datum
 point_slope(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_sl(pt1, pt2));
 }
@@ -1872,37 +1894,37 @@ point_slope(PG_FUNCTION_ARGS)
  *
  * Note that this function returns DBL_MAX when the points are the same.
  */
 static inline float8
 point_sl(Point *pt1, Point *pt2)
 {
 	if (FPeq(pt1->x, pt2->x))
 		return DBL_MAX;
 	if (FPeq(pt1->y, pt2->y))
 		return 0.0;
-	return (pt1->y - pt2->y) / (pt1->x - pt2->x);
+	return float8_div(float8_mi(pt1->y, pt2->y), float8_mi(pt1->x, pt2->x));
 }
 
 
 /*
  * Return inverse slope of two points
  *
  * Note that this function returns 0.0 when the points are the same.
  */
 static inline float8
 point_invsl(Point *pt1, Point *pt2)
 {
 	if (FPeq(pt1->x, pt2->x))
 		return 0.0;
 	if (FPeq(pt1->y, pt2->y))
 		return DBL_MAX;
-	return (pt1->x - pt2->x) / (pt2->y - pt1->y);
+	return float8_div(float8_mi(pt1->x, pt2->x), float8_mi(pt2->y, pt1->y));
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D line segments.
  **
  ***********************************************************************/
 
 /*----------------------------------------------------------
@@ -2162,22 +2184,22 @@ lseg_distance(PG_FUNCTION_ARGS)
 
 
 Datum
 lseg_center(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
-	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
+	result->x = float8_div(float8_pl(lseg->p[0].x, lseg->p[1].x), 2.0);
+	result->y = float8_div(float8_pl(lseg->p[0].y, lseg->p[1].y), 2.0);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  *		Find the intersection point of two segments (if any).
  *
  * This returns true if two line segments intersect, false if they do not.
  * This also sets the intersection point to *result, if it is not NULL.
@@ -2286,21 +2308,21 @@ dist_ppath(PG_FUNCTION_ARGS)
 			iprev = i - 1;
 		else
 		{
 			if (!path->closed)
 				continue;
 			iprev = path->npts - 1; /* Include the closure segment */
 		}
 
 		statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
 		tmp = lseg_closept_point(NULL, &lseg, pt);
-		if (!have_min || tmp < result)
+		if (!have_min || float8_lt(tmp, result))
 		{
 			result = tmp;
 			have_min = true;
 		}
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
@@ -2316,33 +2338,28 @@ dist_pb(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
-	float8		result,
-				d2;
+	float8		result;
 
 	if (lseg_interpt_line(NULL, lseg, line))
 		result = 0.0;
 	else
-	{
-		result = line_closept_point(NULL, line, &lseg->p[0]);
-		d2 = line_closept_point(NULL, line, &lseg->p[1]);
 		/* XXX shouldn't we take the min not max? */
-		if (d2 > result)
-			result = d2;
-	}
+		result = float8_max(line_closept_point(NULL, line, &lseg->p[0]),
+							line_closept_point(NULL, line, &lseg->p[1]));
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
@@ -2375,25 +2392,24 @@ dist_lb(PG_FUNCTION_ARGS)
  * Distance from a circle to a polygon
  */
 Datum
 dist_cpoly(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	POLYGON    *poly = PG_GETARG_POLYGON_P(1);
 	float8		result;
 
 	/* calculate distance to center, and subtract radius */
-	result = dist_ppoly_internal(&circle->center, poly);
-
-	result -= circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(dist_ppoly_internal(&circle->center, poly),
+					   circle->radius);
+	if (result < 0.0)
+		result = 0.0;
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a point to a polygon
  */
 Datum
 dist_ppoly(PG_FUNCTION_ARGS)
 {
@@ -2442,21 +2458,21 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
 	for (i = 0; i < poly->npts - 1; i++)
 	{
 		seg.p[0].x = poly->p[i].x;
 		seg.p[0].y = poly->p[i].y;
 		seg.p[1].x = poly->p[i + 1].x;
 		seg.p[1].y = poly->p[i + 1].y;
 		d = lseg_closept_point(NULL, &seg, pt);
 #ifdef GEODEBUG
 		printf("dist_ppoly_internal- segment %d distance is %f\n", (i + 1), d);
 #endif
-		if (d < result)
+		if (float8_lt(d, result))
 			result = d;
 	}
 
 	return result;
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
  *				Intersection point of objects.
@@ -2535,21 +2551,22 @@ line_closept_point(Point *result, LINE *line, Point *point)
 
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	line_closept_point(result, line, pt);
+	if (isnan(line_closept_point(result, line, pt)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point on line segment to specified point.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
@@ -2595,134 +2612,136 @@ close_ps(PG_FUNCTION_ARGS)
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  *
  * XXX This function is wrong.  If must never set the *result to a point on
  * the second segment.
  */
 static float8
 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
 {
 	Point		point;
-	double		dist;
-	double		d;
+	float8		dist,
+				d;
 
 	d = lseg_closept_point(NULL, l1, &l2->p[0]);
 	dist = d;
 	if (result != NULL)
 		*result = l2->p[0];
 
 	d = lseg_closept_point(NULL, l1, &l2->p[1]);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = l2->p[1];
 	}
 
-	if (lseg_closept_point(&point, l2, &l1->p[0]) < dist)
+	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[0]), dist))
 		d = lseg_closept_point(result, l1, &point);
 
-	if (lseg_closept_point(&point, l2, &l1->p[1]) < dist)
+	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[1]), dist))
 		d = lseg_closept_point(result, l1, &point);
 
-	if (d < dist)
+	if (float8_lt(d, dist))
 		dist = d;
 
 	return dist;
 }
 
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	lseg_closept_lseg(result, l2, l1);
+	if (isnan(lseg_closept_lseg(result, l2, l1)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point on or in box to specified point.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 box_closept_point(Point *result, BOX *box, Point *pt)
 {
-	LSEG		lseg;
+	float8		dist,
+				d;
 	Point		point,
 				closept;
-	double		dist,
-				d;
+	LSEG		lseg;
 
 	if (box_contain_point(box, pt))
 	{
 		if (result != NULL)
 			*result = *pt;
 
 		return 0.0;
 	}
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&lseg, &box->low, &point);
 	dist = lseg_closept_point(result, &lseg, pt);
 
 	statlseg_construct(&lseg, &box->high, &point);
 	d = lseg_closept_point(&closept, &lseg, pt);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&lseg, &box->low, &point);
 	d = lseg_closept_point(&closept, &lseg, pt);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	statlseg_construct(&lseg, &box->high, &point);
 	d = lseg_closept_point(&closept, &lseg, pt);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	return dist;
 }
 
 Datum
 close_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	box_closept_point(result, box, pt);
+	if (isnan(box_closept_point(result, box, pt)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_sl()
  * Closest point on line to line segment.
  *
  * XXX THIS CODE IS WRONG
  * The code is actually calculating the point on the line segment
@@ -2740,21 +2759,21 @@ close_sl(PG_FUNCTION_ARGS)
 	float8		d1,
 				d2;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (lseg_interpt_line(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = line_closept_point(NULL, line, &lseg->p[0]);
 	d2 = line_closept_point(NULL, line, &lseg->p[1]);
-	if (d1 < d2)
+	if (float8_lt(d1, d2))
 		*result = lseg->p[0];
 	else
 		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
 
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_sl\" not implemented")));
@@ -2804,92 +2823,94 @@ lseg_closept_line(Point *result, LSEG *lseg, LINE *line)
 
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	lseg_closept_line(result, lseg, line);
+	if (isnan(lseg_closept_line(result, lseg, line)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point on or in box to line segment.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 box_closept_lseg(Point *result, BOX *box, LSEG *lseg)
 {
+	float8		dist,
+				d;
 	Point		point,
 				closept;
 	LSEG		bseg;
-	double		dist,
-				d;
 
 	if (box_interpt_lseg(result, box, lseg))
 		return 0.0;
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
 	dist = lseg_closept_lseg(result, &bseg, lseg);
 
 	statlseg_construct(&bseg, &box->high, &point);
 	d = lseg_closept_lseg(&closept, &bseg, lseg);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&bseg, &box->low, &point);
 	d = lseg_closept_lseg(&closept, &bseg, lseg);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	statlseg_construct(&bseg, &box->high, &point);
 	d = lseg_closept_lseg(&closept, &bseg, lseg);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	return dist;
 }
 
 Datum
 close_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	box_closept_lseg(result, box, lseg);
+	if (isnan(box_closept_lseg(result, box, lseg)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 Datum
 close_lb(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -2908,21 +2929,23 @@ close_lb(PG_FUNCTION_ARGS)
  *		on_
  *				Whether one object lies completely within another.
  *-------------------------------------------------------------------*/
 
 /*
  *		Does the point satisfy the equation?
  */
 static bool
 line_contain_point(LINE *line, Point *point)
 {
-	return FPzero(line->A * point->x + line->B * point->y + line->C);
+	return FPzero(float8_pl(float8_pl(float8_mul(line->A, point->x),
+									  float8_mul(line->B, point->y)),
+							line->C));
 }
 
 Datum
 on_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
 	PG_RETURN_BOOL(line_contain_point(line, pt));
 }
@@ -2989,33 +3012,32 @@ box_contain_pt(PG_FUNCTION_ARGS)
  *				but not cross.
  *				(we can do p-in-p in lg(n), but it takes preprocessing)
  */
 Datum
 on_ppath(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	PATH	   *path = PG_GETARG_PATH_P(1);
 	int			i,
 				n;
-	double		a,
+	float8		a,
 				b;
 
 	/*-- OPEN --*/
 	if (!path->closed)
 	{
 		n = path->npts - 1;
 		a = point_dt(pt, &path->p[0]);
 		for (i = 0; i < n; i++)
 		{
 			b = point_dt(pt, &path->p[i + 1]);
-			if (FPeq(a + b,
-					 point_dt(&path->p[i], &path->p[i + 1])))
+			if (FPeq(float8_pl(a, b), point_dt(&path->p[i], &path->p[i + 1])))
 				PG_RETURN_BOOL(true);
 			a = b;
 		}
 		PG_RETURN_BOOL(false);
 	}
 
 	/*-- CLOSED --*/
 	PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
 }
 
@@ -3087,24 +3109,24 @@ inter_sl(PG_FUNCTION_ARGS)
  * Optimize for non-intersection by checking for box intersection first.
  * - thomas 1998-01-30
  */
 static bool
 box_interpt_lseg(Point *result, BOX *box, LSEG *lseg)
 {
 	BOX			lbox;
 	LSEG		bseg;
 	Point		point;
 
-	lbox.low.x = Min(lseg->p[0].x, lseg->p[1].x);
-	lbox.low.y = Min(lseg->p[0].y, lseg->p[1].y);
-	lbox.high.x = Max(lseg->p[0].x, lseg->p[1].x);
-	lbox.high.y = Max(lseg->p[0].y, lseg->p[1].y);
+	lbox.low.x = float8_min(lseg->p[0].x, lseg->p[1].x);
+	lbox.low.y = float8_min(lseg->p[0].y, lseg->p[1].y);
+	lbox.high.x = float8_max(lseg->p[0].x, lseg->p[1].x);
+	lbox.high.y = float8_max(lseg->p[0].y, lseg->p[1].y);
 
 	/* nothing close to overlap? then not going to intersect */
 	if (!box_ov(&lbox, box))
 		return false;
 
 	if (result != NULL)
 	{
 		box_cn(&point, box);
 		lseg_closept_point(result, lseg, &point);
 	}
@@ -3197,38 +3219,38 @@ inter_lb(PG_FUNCTION_ARGS)
  * make_bound_box - create the bounding box for the input polygon
  *------------------------------------------------------------------*/
 
 /*---------------------------------------------------------------------
  * Make the smallest bounding box for the given polygon.
  *---------------------------------------------------------------------*/
 static void
 make_bound_box(POLYGON *poly)
 {
 	int			i;
-	double		x1,
+	float8		x1,
 				y1,
 				x2,
 				y2;
 
 	Assert(poly->npts > 0);
 
 	x1 = x2 = poly->p[0].x;
 	y2 = y1 = poly->p[0].y;
 	for (i = 1; i < poly->npts; i++)
 	{
-		if (poly->p[i].x < x1)
+		if (float8_lt(poly->p[i].x, x1))
 			x1 = poly->p[i].x;
-		if (poly->p[i].x > x2)
+		if (float8_gt(poly->p[i].x, x2))
 			x2 = poly->p[i].x;
-		if (poly->p[i].y < y1)
+		if (float8_lt(poly->p[i].y, y1))
 			y1 = poly->p[i].y;
-		if (poly->p[i].y > y2)
+		if (float8_gt(poly->p[i].y, y2))
 			y2 = poly->p[i].y;
 	}
 
 	poly->boundbox.low.x = x1;
 	poly->boundbox.high.x = x2;
 	poly->boundbox.low.y = y1;
 	poly->boundbox.high.y = y2;
 }
 
 /*------------------------------------------------------------------
@@ -3727,22 +3749,22 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 	}
 
 	if (res && !intersection)
 	{
 		Point		p;
 
 		/*
 		 * if X-intersection wasn't found  then check central point of tested
 		 * segment. In opposite case we already check all subsegments
 		 */
-		p.x = (t.p[0].x + t.p[1].x) / 2.0;
-		p.y = (t.p[0].y + t.p[1].y) / 2.0;
+		p.x = float8_div(float8_pl(t.p[0].x, t.p[1].x), 2.0);
+		p.y = float8_div(float8_pl(t.p[0].y, t.p[1].y), 2.0);
 
 		res = point_inside(&p, poly->npts, poly->p);
 	}
 
 	return res;
 }
 
 /*-----------------------------------------------------------------
  * Determine if polygon A contains polygon B.
  *-----------------------------------------------------------------*/
@@ -3868,22 +3890,22 @@ construct_point(PG_FUNCTION_ARGS)
 	point_construct(result, x, y);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_add_point(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x + pt2->x,
-					pt1->y + pt2->y);
+					float8_pl(pt1->x, pt2->x),
+					float8_pl(pt1->y, pt2->y));
 }
 
 Datum
 point_add(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -3891,22 +3913,22 @@ point_add(PG_FUNCTION_ARGS)
 	point_add_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_sub_point(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x - pt2->x,
-					pt1->y - pt2->y);
+					float8_mi(pt1->x, pt2->x),
+					float8_mi(pt1->y, pt2->y));
 }
 
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -3914,54 +3936,53 @@ point_sub(PG_FUNCTION_ARGS)
 	point_sub_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_mul_point(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					(pt1->x * pt2->x) - (pt1->y * pt2->y),
-					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+					float8_mi(float8_mul(pt1->x, pt2->x),
+							  float8_mul(pt1->y, pt2->y)),
+					float8_pl(float8_mul(pt1->x, pt2->y),
+							  float8_mul(pt1->y, pt2->x)));
 }
 
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	point_mul_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_div_point(Point *result, Point *pt1, Point *pt2)
 {
-	double		div;
+	float8		div;
 
-	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
-
-	if (div == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
+	div = float8_pl(float8_mul(pt2->x, pt2->x), float8_mul(pt2->y, pt2->y));
 
 	point_construct(result,
-					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
-					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+					float8_div(float8_pl(float8_mul(pt1->x, pt2->x),
+										 float8_mul(pt1->y, pt2->y)), div),
+					float8_div(float8_mi(float8_mul(pt1->y, pt2->x),
+										 float8_mul(pt1->x, pt2->y)), div));
 }
 
 Datum
 point_div(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -4084,24 +4105,24 @@ point_box(PG_FUNCTION_ARGS)
  */
 Datum
 boxes_bound_box(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0),
 			   *box2 = PG_GETARG_BOX_P(1),
 			   *container;
 
 	container = (BOX *) palloc(sizeof(BOX));
 
-	container->high.x = Max(box1->high.x, box2->high.x);
-	container->low.x = Min(box1->low.x, box2->low.x);
-	container->high.y = Max(box1->high.y, box2->high.y);
-	container->low.y = Min(box1->low.y, box2->low.y);
+	container->high.x = float8_max(box1->high.x, box2->high.x);
+	container->low.x = float8_min(box1->low.x, box2->low.x);
+	container->high.y = float8_max(box1->high.y, box2->high.y);
+	container->low.y = float8_min(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(container);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D paths.
  **
  ***********************************************************************/
@@ -4407,21 +4428,22 @@ circle_in(PG_FUNCTION_ARGS)
 		if (*cp == LDELIM)
 			s = cp;
 	}
 
 	pair_decode(s, &circle->center.x, &circle->center.y, &s, "circle", str);
 
 	if (*s == DELIM)
 		s++;
 
 	circle->radius = single_decode(s, &s, "circle", str);
-	if (circle->radius < 0)
+	/* We have to accept NaN. */
+	if (circle->radius < 0.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
 
 	while (depth > 0)
 	{
 		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
@@ -4474,21 +4496,22 @@ circle_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	circle->center.x = pq_getmsgfloat8(buf);
 	circle->center.y = pq_getmsgfloat8(buf);
 	circle->radius = pq_getmsgfloat8(buf);
 
-	if (circle->radius < 0)
+	/* We have to accept NaN. */
+	if (circle->radius < 0.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
 				 errmsg("invalid radius in external \"circle\" value")));
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 /*
  *		circle_send			- converts circle to binary format
  */
@@ -4505,166 +4528,170 @@ circle_send(PG_FUNCTION_ARGS)
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for CIRCLEs.
  *		<, >, <=, >=, and == are based on circle area.
  *---------------------------------------------------------*/
 
 /*		circles identical?
+ *
+ * We consider NaNs values to be equal to each other to let those circles
+ * to be found.
  */
 Datum
 circle_same(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPeq(circle1->radius, circle2->radius) &&
+	PG_RETURN_BOOL(((isnan(circle1->radius) && isnan(circle1->radius)) ||
+					FPeq(circle1->radius, circle2->radius)) &&
 				   point_eq_point(&circle1->center, &circle2->center));
 }
 
 /*		circle_overlap	-		does circle1 overlap circle2?
  */
 Datum
 circle_overlap(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle1->radius + circle2->radius));
+						float8_pl(circle1->radius, circle2->radius)));
 }
 
 /*		circle_overleft -		is the right edge of circle1 at or left of
  *								the right edge of circle2?
  */
 Datum
 circle_overleft(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.x + circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_left		-		is circle1 strictly left of circle2?
  */
 Datum
 circle_left(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.x + circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_right	-		is circle1 strictly right of circle2?
  */
 Datum
 circle_right(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.x - circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_overright	-	is the left edge of circle1 at or right of
  *								the left edge of circle2?
  */
 Datum
 circle_overright(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.x - circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_contained		-		is circle1 contained by circle2?
  */
 Datum
 circle_contained(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle2->radius - circle1->radius));
+						float8_mi(circle2->radius, circle1->radius)));
 }
 
 /*		circle_contain	-		does circle1 contain circle2?
  */
 Datum
 circle_contain(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle1->radius - circle2->radius));
+						float8_mi(circle1->radius, circle2->radius)));
 }
 
 
 /*		circle_below		-		is circle1 strictly below circle2?
  */
 Datum
 circle_below(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.y + circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_above	-		is circle1 strictly above circle2?
  */
 Datum
 circle_above(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.y - circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overbelow -		is the upper edge of circle1 at or below
  *								the upper edge of circle2?
  */
 Datum
 circle_overbelow(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.y + circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overabove	-	is the lower edge of circle1 at or above
  *								the lower edge of circle2?
  */
 Datum
 circle_overabove(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.y - circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 
 /*		circle_relop	-		is area(circle1) relop area(circle2), within
  *								our accuracy constraint?
  */
 Datum
 circle_eq(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
@@ -4763,36 +4790,36 @@ circle_sub_pt(PG_FUNCTION_ARGS)
 Datum
 circle_mul_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_mul_point(&result->center, &circle->center, point);
-	result->radius = circle->radius * HYPOT(point->x, point->y);
+	result->radius = float8_mul(circle->radius, HYPOT(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_div_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_div_point(&result->center, &circle->center, point);
-	result->radius = circle->radius / HYPOT(point->x, point->y);
+	result->radius = float8_div(circle->radius, HYPOT(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /*		circle_area		-		returns the area of the circle.
  */
 Datum
 circle_area(PG_FUNCTION_ARGS)
 {
@@ -4802,21 +4829,21 @@ circle_area(PG_FUNCTION_ARGS)
 }
 
 
 /*		circle_diameter -		returns the diameter of the circle.
  */
 Datum
 circle_diameter(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
-	PG_RETURN_FLOAT8(2 * circle->radius);
+	PG_RETURN_FLOAT8(float8_mul(circle->radius, 2.0));
 }
 
 
 /*		circle_radius	-		returns the radius of the circle.
  */
 Datum
 circle_radius(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
@@ -4827,81 +4854,85 @@ circle_radius(PG_FUNCTION_ARGS)
 /*		circle_distance -		returns the distance between
  *								  two circles.
  */
 Datum
 circle_distance(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(&circle1->center, &circle2->center) -
-		(circle1->radius + circle2->radius);
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(&circle1->center, &circle2->center),
+					   float8_pl(circle1->radius, circle2->radius));
+	if (result < 0.0)
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 
 Datum
 circle_contain_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
 	PG_RETURN_BOOL(d <= circle->radius);
 }
 
 
 Datum
 pt_contained_circle(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
 	PG_RETURN_BOOL(d <= circle->radius);
 }
 
 
 /*		dist_pc -		returns the distance between
  *						  a point and a circle.
  */
 Datum
 dist_pc(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center),
+					   circle->radius);
+	if (result < 0.0)
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a circle to a point
  */
 Datum
 dist_cpoint(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center), circle->radius);
+	if (result < 0.0)
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*		circle_center	-		returns the center point of the circle.
  */
 Datum
 circle_center(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *result;
@@ -4909,24 +4940,24 @@ circle_center(PG_FUNCTION_ARGS)
 	result = (Point *) palloc(sizeof(Point));
 	result->x = circle->center.x;
 	result->y = circle->center.y;
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		circle_ar		-		returns the area of the circle.
  */
-static double
+static float8
 circle_ar(CIRCLE *circle)
 {
-	return M_PI * (circle->radius * circle->radius);
+	return float8_mul(float8_mul(circle->radius, circle->radius), M_PI);
 }
 
 
 /*----------------------------------------------------------
  *	Conversion operators.
  *---------------------------------------------------------*/
 
 Datum
 cr_circle(PG_FUNCTION_ARGS)
 {
@@ -4941,65 +4972,65 @@ cr_circle(PG_FUNCTION_ARGS)
 	result->radius = radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_box(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	BOX		   *box;
-	double		delta;
+	float8		delta;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
-	delta = circle->radius / sqrt(2.0);
+	delta = float8_div(circle->radius, sqrt(2.0));
 
-	box->high.x = circle->center.x + delta;
-	box->low.x = circle->center.x - delta;
-	box->high.y = circle->center.y + delta;
-	box->low.y = circle->center.y - delta;
+	box->high.x = float8_pl(circle->center.x, delta);
+	box->low.x = float8_mi(circle->center.x, delta);
+	box->high.y = float8_pl(circle->center.y, delta);
+	box->low.y = float8_mi(circle->center.y, delta);
 
 	PG_RETURN_BOX_P(box);
 }
 
 /* box_circle()
  * Convert a box to a circle.
  */
 Datum
 box_circle(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	circle->center.x = (box->high.x + box->low.x) / 2;
-	circle->center.y = (box->high.y + box->low.y) / 2;
+	circle->center.x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	circle->center.y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 
 	circle->radius = point_dt(&circle->center, &box->high);
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 
 Datum
 circle_poly(PG_FUNCTION_ARGS)
 {
 	int32		npts = PG_GETARG_INT32(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	POLYGON    *poly;
 	int			base_size,
 				size;
 	int			i;
-	double		angle;
-	double		anglestep;
+	float8		angle;
+	float8		anglestep;
 
 	if (FPzero(circle->radius))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("cannot convert circle with radius zero to polygon")));
 
 	if (npts < 2)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("must request at least 2 points")));
@@ -5010,27 +5041,30 @@ circle_poly(PG_FUNCTION_ARGS)
 	/* Check for integer overflow */
 	if (base_size / npts != sizeof(poly->p[0]) || size <= base_size)
 		ereport(ERROR,
 				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 				 errmsg("too many points requested")));
 
 	poly = (POLYGON *) palloc0(size);	/* zero any holes */
 	SET_VARSIZE(poly, size);
 	poly->npts = npts;
 
-	anglestep = (2.0 * M_PI) / npts;
+	anglestep = float8_div(2.0 * M_PI, npts);
 
 	for (i = 0; i < npts; i++)
 	{
-		angle = i * anglestep;
-		poly->p[i].x = circle->center.x - (circle->radius * cos(angle));
-		poly->p[i].y = circle->center.y + (circle->radius * sin(angle));
+		angle = float8_mul(anglestep, i);
+
+		poly->p[i].x = float8_mi(circle->center.x,
+								 float8_mul(circle->radius, cos(angle)));
+		poly->p[i].y = float8_pl(circle->center.y,
+								 float8_mul(circle->radius, sin(angle)));
 	}
 
 	make_bound_box(poly);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
 /*
  * Convert polygon to circle
  *
@@ -5045,26 +5079,27 @@ poly_to_circle(CIRCLE *result, POLYGON *poly)
 	int			i;
 
 	Assert(poly->npts > 0);
 
 	result->center.x = 0;
 	result->center.y = 0;
 	result->radius = 0;
 
 	for (i = 0; i < poly->npts; i++)
 		point_add_point(&result->center, &result->center, &poly->p[i]);
-	result->center.x /= poly->npts;
-	result->center.y /= poly->npts;
+	result->center.x = float8_div(result->center.x, poly->npts);
+	result->center.y = float8_div(result->center.y, poly->npts);
 
 	for (i = 0; i < poly->npts; i++)
-		result->radius += point_dt(&poly->p[i], &result->center);
-	result->radius /= poly->npts;
+		result->radius = float8_pl(result->radius,
+								   point_dt(&poly->p[i], &result->center));
+	result->radius = float8_div(result->radius, poly->npts);
 }
 
 Datum
 poly_circle(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
@@ -5089,44 +5124,44 @@ poly_circle(PG_FUNCTION_ARGS)
  *	http://hopf.math.northwestern.edu/index.html
  *	Description of algorithm:  http://www.linuxjournal.com/article/2197
  *							   http://www.linuxjournal.com/article/2029
  */
 
 #define POINT_ON_POLYGON INT_MAX
 
 static int
 point_inside(Point *p, int npts, Point *plist)
 {
-	double		x0,
+	float8		x0,
 				y0;
-	double		prev_x,
+	float8		prev_x,
 				prev_y;
 	int			i = 0;
-	double		x,
+	float8		x,
 				y;
 	int			cross,
 				total_cross = 0;
 
 	Assert(npts > 0);
 
 	/* compute first polygon point relative to single point */
-	x0 = plist[0].x - p->x;
-	y0 = plist[0].y - p->y;
+	x0 = float8_mi(plist[0].x, p->x);
+	y0 = float8_mi(plist[0].y, p->y);
 
 	prev_x = x0;
 	prev_y = y0;
 	/* loop over polygon points and aggregate total_cross */
 	for (i = 1; i < npts; i++)
 	{
 		/* compute next polygon point relative to single point */
-		x = plist[i].x - p->x;
-		y = plist[i].y - p->y;
+		x = float8_mi(plist[i].x, p->x);
+		y = float8_mi(plist[i].y, p->y);
 
 		/* compute previous to current point crossing */
 		if ((cross = lseg_crossing(x, y, prev_x, prev_y)) == POINT_ON_POLYGON)
 			return 2;
 		total_cross += cross;
 
 		prev_x = x;
 		prev_y = y;
 	}
 
@@ -5144,69 +5179,74 @@ point_inside(Point *p, int npts, Point *plist)
 /* lseg_crossing()
  * Returns +/-2 if line segment crosses the positive X-axis in a +/- direction.
  * Returns +/-1 if one point is on the positive X-axis.
  * Returns 0 if both points are on the positive X-axis, or there is no crossing.
  * Returns POINT_ON_POLYGON if the segment contains (0,0).
  * Wow, that is one confusing API, but it is used above, and when summed,
  * can tell is if a point is in a polygon.
  */
 
 static int
-lseg_crossing(double x, double y, double prev_x, double prev_y)
+lseg_crossing(float8 x, float8 y, float8 prev_x, float8 prev_y)
 {
-	double		z;
+	float8		z;
 	int			y_sign;
 
 	if (FPzero(y))
 	{							/* y == 0, on X axis */
 		if (FPzero(x))			/* (x,y) is (0,0)? */
 			return POINT_ON_POLYGON;
 		else if (FPgt(x, 0))
 		{						/* x > 0 */
 			if (FPzero(prev_y)) /* y and prev_y are zero */
 				/* prev_x > 0? */
-				return FPgt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
-			return FPlt(prev_y, 0) ? 1 : -1;
+				return FPgt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
+			return FPlt(prev_y, 0.0) ? 1 : -1;
 		}
 		else
 		{						/* x < 0, x not on positive X axis */
 			if (FPzero(prev_y))
 				/* prev_x < 0? */
-				return FPlt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
+				return FPlt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
 			return 0;
 		}
 	}
 	else
 	{							/* y != 0 */
 		/* compute y crossing direction from previous point */
-		y_sign = FPgt(y, 0) ? 1 : -1;
+		y_sign = FPgt(y, 0.0) ? 1 : -1;
 
 		if (FPzero(prev_y))
 			/* previous point was on X axis, so new point is either off or on */
-			return FPlt(prev_x, 0) ? 0 : y_sign;
-		else if (FPgt(y_sign * prev_y, 0))
+			return FPlt(prev_x, 0.0) ? 0 : y_sign;
+		else if ((y_sign < 0 && FPlt(prev_y, 0.0)) ||
+				 (y_sign > 0 && FPgt(prev_y, 0.0)))
 			/* both above or below X axis */
 			return 0;			/* same sign */
 		else
 		{						/* y and prev_y cross X-axis */
-			if (FPge(x, 0) && FPgt(prev_x, 0))
+			if (FPge(x, 0.0) && FPgt(prev_x, 0.0))
 				/* both non-negative so cross positive X-axis */
 				return 2 * y_sign;
-			if (FPlt(x, 0) && FPle(prev_x, 0))
+			if (FPlt(x, 0.0) && FPle(prev_x, 0.0))
 				/* both non-positive so do not cross positive X-axis */
 				return 0;
 
 			/* x and y cross axises, see URL above point_inside() */
-			z = (x - prev_x) * y - (y - prev_y) * x;
+			z = float8_mi(float8_mul(float8_mi(x, prev_x), y),
+						  float8_mul(float8_mi(y, prev_y), x));
 			if (FPzero(z))
 				return POINT_ON_POLYGON;
-			return FPgt((y_sign * z), 0) ? 0 : 2 * y_sign;
+			if ((y_sign < 0 && FPlt(z, 0.0)) ||
+				(y_sign > 0 && FPgt(z, 0.0)))
+				return 0;
+			return 2 * y_sign;
 		}
 	}
 }
 
 
 static bool
 plist_same(int npts, Point *p1, Point *p2)
 {
 	int			i,
 				ii,
@@ -5276,47 +5316,52 @@ plist_same(int npts, Point *p1, Point *p2)
  *					 = x * sqrt( 1 + y^2/x^2 )
  *					 = x * sqrt( 1 + y/x * y/x )
  *
  * It is expected that this routine will eventually be replaced with the
  * C99 hypot() function.
  *
  * This implementation conforms to IEEE Std 1003.1 and GLIBC, in that the
  * case of hypot(inf,nan) results in INF, and not NAN.
  *-----------------------------------------------------------------------
  */
-double
-pg_hypot(double x, double y)
+float8
+pg_hypot(float8 x, float8 y)
 {
-	double		yx;
+	float8		yx,
+				result;
 
 	/* Handle INF and NaN properly */
 	if (isinf(x) || isinf(y))
 		return get_float8_infinity();
 
 	if (isnan(x) || isnan(y))
 		return get_float8_nan();
 
 	/* Else, drop any minus signs */
 	x = fabs(x);
 	y = fabs(y);
 
 	/* Swap x and y if needed to make x the larger one */
 	if (x < y)
 	{
-		double		temp = x;
+		float8		temp = x;
 
 		x = y;
 		y = temp;
 	}
 
 	/*
 	 * If y is zero, the hypotenuse is x.  This test saves a few cycles in
 	 * such cases, but more importantly it also protects against
 	 * divide-by-zero errors, since now x >= y.
 	 */
 	if (y == 0.0)
 		return x;
 
 	/* Determine the hypotenuse */
 	yx = y / x;
-	return x * sqrt(1.0 + (yx * yx));
+	result = x * sqrt(1.0 + (yx * yx));
+
+	check_float8_val(result, false, false);
+
+	return result;
 }
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index 096e59f817..b4008d7423 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -76,38 +76,38 @@
 #include "access/spgist.h"
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
 #include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
- * is going only going to be used in a place to effect the performance
+ * is only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
 compareDoubles(const void *a, const void *b)
 {
-	double		x = *(double *) a;
-	double		y = *(double *) b;
+	float8		x = *(float8 *) a;
+	float8		y = *(float8 *) b;
 
 	if (x == y)
 		return 0;
 	return (x > y) ? 1 : -1;
 }
 
 typedef struct
 {
-	double		low;
-	double		high;
+	float8		low;
+	float8		high;
 } Range;
 
 typedef struct
 {
 	Range		left;
 	Range		right;
 } RangeBox;
 
 typedef struct
 {
@@ -167,21 +167,21 @@ getRangeBox(BOX *box)
 /*
  * Initialize the traversal value
  *
  * In the beginning, we don't have any restrictions.  We have to
  * initialize the struct to cover the whole 4D space.
  */
 static RectBox *
 initRectBox(void)
 {
 	RectBox    *rect_box = (RectBox *) palloc(sizeof(RectBox));
-	double		infinity = get_float8_infinity();
+	float8		infinity = get_float8_infinity();
 
 	rect_box->range_box_x.left.low = -infinity;
 	rect_box->range_box_x.left.high = infinity;
 
 	rect_box->range_box_x.right.low = -infinity;
 	rect_box->range_box_x.right.high = infinity;
 
 	rect_box->range_box_y.left.low = -infinity;
 	rect_box->range_box_y.left.high = infinity;
 
@@ -410,40 +410,40 @@ spg_box_quad_choose(PG_FUNCTION_ARGS)
  * point as the median of the coordinates of the boxes.
  */
 Datum
 spg_box_quad_picksplit(PG_FUNCTION_ARGS)
 {
 	spgPickSplitIn *in = (spgPickSplitIn *) PG_GETARG_POINTER(0);
 	spgPickSplitOut *out = (spgPickSplitOut *) PG_GETARG_POINTER(1);
 	BOX		   *centroid;
 	int			median,
 				i;
-	double	   *lowXs = palloc(sizeof(double) * in->nTuples);
-	double	   *highXs = palloc(sizeof(double) * in->nTuples);
-	double	   *lowYs = palloc(sizeof(double) * in->nTuples);
-	double	   *highYs = palloc(sizeof(double) * in->nTuples);
+	float8	   *lowXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *lowYs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highYs = palloc(sizeof(float8) * in->nTuples);
 
 	/* Calculate median of all 4D coordinates */
 	for (i = 0; i < in->nTuples; i++)
 	{
 		BOX		   *box = DatumGetBoxP(in->datums[i]);
 
 		lowXs[i] = box->low.x;
 		highXs[i] = box->high.x;
 		lowYs[i] = box->low.y;
 		highYs[i] = box->high.y;
 	}
 
-	qsort(lowXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(lowYs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highYs, in->nTuples, sizeof(double), compareDoubles);
+	qsort(lowXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(lowYs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highYs, in->nTuples, sizeof(float8), compareDoubles);
 
 	median = in->nTuples / 2;
 
 	centroid = palloc(sizeof(BOX));
 
 	centroid->low.x = lowXs[median];
 	centroid->high.x = highXs[median];
 	centroid->low.y = lowYs[median];
 	centroid->high.y = highYs[median];
 
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index aeb31515e4..d14e8c8f72 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -1,42 +1,41 @@
 /*-------------------------------------------------------------------------
  *
  * geo_decls.h - Declarations for various 2D constructs.
  *
  *
  * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * src/include/utils/geo_decls.h
  *
- * NOTE
- *	  These routines do *not* use the float types from adt/.
- *
  *	  XXX These routines were not written by a numerical analyst.
  *
  *	  XXX I have made some attempt to flesh out the operators
  *		and data types. There are still some more to do. - tgl 97/04/19
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEO_DECLS_H
 #define GEO_DECLS_H
 
 #include <math.h>
 
 #include "fmgr.h"
 #include "utils/float.h"
 
 /*--------------------------------------------------------------------
  * Useful floating point utilities and constants.
- *-------------------------------------------------------------------*/
-
+ *-------------------------------------------------------------------
+ *
+ * XXX They are not NaN-aware.
+ */
 
 #define EPSILON					1.0E-06
 
 #ifdef EPSILON
 #define FPzero(A)				(fabs(A) <= EPSILON)
 #define FPeq(A,B)				(fabs((A) - (B)) <= EPSILON)
 #define FPne(A,B)				(fabs((A) - (B)) > EPSILON)
 #define FPlt(A,B)				((B) - (A) > EPSILON)
 #define FPle(A,B)				((A) - (B) <= EPSILON)
 #define FPgt(A,B)				((A) - (B) > EPSILON)
@@ -51,21 +50,21 @@
 #define FPge(A,B)				((A) >= (B))
 #endif
 
 #define HYPOT(A, B)				pg_hypot(A, B)
 
 /*---------------------------------------------------------------------
  * Point - (x,y)
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		x,
+	float8		x,
 				y;
 } Point;
 
 
 /*---------------------------------------------------------------------
  * LSEG - A straight line, specified by endpoints.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		p[2];
@@ -83,21 +82,21 @@ typedef struct
 	int32		dummy;			/* padding to make it double align */
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } PATH;
 
 
 /*---------------------------------------------------------------------
  * LINE - Specified by its general equation (Ax+By+C=0).
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		A,
+	float8		A,
 				B,
 				C;
 } LINE;
 
 
 /*---------------------------------------------------------------------
  * BOX	- Specified by two corner points, which are
  *		 sorted to save calculation time later.
  *-------------------------------------------------------------------*/
 typedef struct
@@ -118,21 +117,21 @@ typedef struct
 	BOX			boundbox;
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } POLYGON;
 
 /*---------------------------------------------------------------------
  * CIRCLE - Specified by a center point and radius.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		center;
-	double		radius;
+	float8		radius;
 } CIRCLE;
 
 /*
  * fmgr interface macros
  *
  * Path and Polygon are toastable varlena types, the others are just
  * fixed-size pass-by-reference types.
  */
 
 #define DatumGetPointP(X)	 ((Point *) DatumGetPointer(X))
@@ -172,13 +171,13 @@ typedef struct
 #define DatumGetCircleP(X)	  ((CIRCLE *) DatumGetPointer(X))
 #define CirclePGetDatum(X)	  PointerGetDatum(X)
 #define PG_GETARG_CIRCLE_P(n) DatumGetCircleP(PG_GETARG_DATUM(n))
 #define PG_RETURN_CIRCLE_P(x) return CirclePGetDatum(x)
 
 
 /*
  * in geo_ops.c
  */
 
-extern double pg_hypot(double x, double y);
+extern float8 pg_hypot(float8 x, float8 y);
 
 #endif							/* GEO_DECLS_H */
-- 
2.14.3 (Apple Git-98)

0004-line-fixes-v08.patchapplication/octet-stream; name=0004-line-fixes-v08.patchDownload
From 2b6274cd332119a9398511e490411e04b7704e86 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sun, 28 May 2017 11:35:17 +0200
Subject: [PATCH 4/6] line-fixes-v08

Fix obvious problems around the line datatype

I have noticed some line operators retuning wrong results, and Tom Lane
spotted similar problems on more places.  Source history reveals that
during 1990s, the internal format of the line datatype is changed, but
most functions haven't got the hint.  The fixes include:

* Reject invalid specification A=B=0 on receive
* Reject same points on line_construct_pp()
* Fix perpendicular operator when negative values are involved
* Avoid division by zero on perpendicular operator
* Fix intersection and distance operators when neither A nor B are 1
* Return NULL for closest point when objects are parallel
* Check whether closest point of line segments is the intersection point
* Fix closest point of line segments being on the wrong segment

The changes are also aiming make line operators more symmetric and less
sensitive to floating point precision loss.  The EPSILON interferes with
every minor change in different ways.  It is hard to guess which
behaviour is more expected, but we can assume threating both sides of
the operators more equally is more expected.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com

Parallel discussions:

* https://www.postgresql.org/message-id/CAE2gYzw_-z%3DV2kh8QqFjenu%3D8MJXzOP44wRW%3DAzzeamrmTT1%3DQ%40mail.gmail.com
* https://www.postgresql.org/message-id/20180201.205138.34583581.horiguchi.kyotaro@lab.ntt.co.jp
---
 src/backend/utils/adt/geo_ops.c | 148 ++++++++++++++++++++++++++--------------
 1 file changed, 96 insertions(+), 52 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 49667b17f7..853d483e69 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -40,20 +40,21 @@ static inline void point_add_point(Point *result, Point *pt1, Point *pt2);
 static inline void point_sub_point(Point *result, Point *pt1, Point *pt2);
 static inline void point_mul_point(Point *result, Point *pt1, Point *pt2);
 static inline void point_div_point(Point *result, Point *pt1, Point *pt2);
 static inline bool point_eq_point(Point *pt1, Point *pt2);
 static inline float8 point_dt(Point *pt1, Point *pt2);
 static inline float8 point_sl(Point *pt1, Point *pt2);
 static int	point_inside(Point *p, int npts, Point *plist);
 
 /* Routines for lines */
 static inline void line_construct(LINE *result, Point *pt, float8 m);
+static inline float8 line_sl(LINE *line);
 static inline float8 line_invsl(LINE *line);
 static bool	line_interpt_line(Point *result, LINE *l1, LINE *l2);
 static bool line_contain_point(LINE *line, Point *point);
 static float8 line_closept_point(Point *result, LINE *line, Point *pt);
 
 /* Routines for line segments */
 static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
 static inline float8 lseg_sl(LSEG *lseg);
 static inline float8 lseg_invsl(LSEG *lseg);
 static bool	lseg_interpt_line(Point *result, LSEG *lseg, LINE *line);
@@ -972,20 +973,25 @@ line_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LINE	   *line;
 
 	line = (LINE *) palloc(sizeof(LINE));
 
 	line->A = pq_getmsgfloat8(buf);
 	line->B = pq_getmsgfloat8(buf);
 	line->C = pq_getmsgfloat8(buf);
 
+	if (FPzero(line->A) && FPzero(line->B))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("invalid line specification: A and B cannot both be zero")));
+
 	PG_RETURN_LINE_P(line);
 }
 
 /*
  *		line_send			- converts line to binary format
  */
 Datum
 line_send(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -1029,20 +1035,25 @@ line_construct(LINE *result, Point *pt, float8 m)
 /* line_construct_pp()
  * two points
  */
 Datum
 line_construct_pp(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 	LINE	   *result = (LINE *) palloc(sizeof(LINE));
 
+	if (point_eq_point(pt1, pt2))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("invalid line specification: must be two distinct points")));
+
 	line_construct(result, pt1, point_sl(pt1, pt2));
 
 	PG_RETURN_LINE_P(result);
 }
 
 
 /*----------------------------------------------------------
  *	Relative position routines.
  *---------------------------------------------------------*/
 
@@ -1063,27 +1074,22 @@ line_parallel(PG_FUNCTION_ARGS)
 
 	PG_RETURN_BOOL(!line_interpt_line(NULL, l1, l2));
 }
 
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
-	if (FPzero(l1->A))
-		PG_RETURN_BOOL(FPzero(l2->B));
-	else if (FPzero(l1->B))
-		PG_RETURN_BOOL(FPzero(l2->A));
-
-	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
-								   float8_mul(l1->B, l2->A)), -1.0));
+	PG_RETURN_BOOL(FPzero(float8_pl(float8_mul(l1->A, l2->A),
+									float8_mul(l1->B, l2->B))));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
@@ -1124,20 +1130,34 @@ line_eq(PG_FUNCTION_ARGS)
 				   (float8_eq(l1->A, l2->A) &&
 					float8_eq(l1->B, l2->B) &&
 					float8_eq(l1->C, l2->C)));
 }
 
 
 /*----------------------------------------------------------
  *	Line arithmetic routines.
  *---------------------------------------------------------*/
 
+/*
+ * Return slope of the line
+ */
+static inline float8
+line_sl(LINE *line)
+{
+	if (FPzero(line->A))
+		return 0.0;
+	if (FPzero(line->B))
+		return DBL_MAX;
+	return float8_div(line->A, -line->B);
+}
+
+
 /*
  * Return inverse slope of the line
  */
 static inline float8
 line_invsl(LINE *line)
 {
 	if (FPzero(line->A))
 		return DBL_MAX;
 	if (FPzero(line->B))
 		return 0.0;
@@ -1146,30 +1166,35 @@ line_invsl(LINE *line)
 
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	float8		result;
-	Point		tmp;
+	float8		ratio;
 
 	if (line_interpt_line(NULL, l1, l2))
 		PG_RETURN_FLOAT8(0.0);
-	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
-	point_construct(&tmp, 0.0, l1->C);
-	result = line_closept_point(NULL, l2, &tmp);
-	PG_RETURN_FLOAT8(result);
+
+	if (!FPzero(l1->A) && !isnan(l1->A) && !FPzero(l2->A) && !isnan(l2->A))
+		ratio = float8_div(l1->A, l2->A);
+	else if (!FPzero(l1->B) && !isnan(l1->B) && !FPzero(l2->B) && !isnan(l2->B))
+		ratio = float8_div(l1->B, l2->B);
+	else
+		ratio = 1.0;
+
+	PG_RETURN_FLOAT8(float8_div(fabs(float8_mi(l1->C,
+											   float8_mul(ratio, l2->C))),
+								HYPOT(l1->A, l1->B)));
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
@@ -1201,35 +1226,39 @@ static bool
 line_interpt_line(Point *result, LINE *l1, LINE *l2)
 {
 	float8		x,
 				y;
 
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
 		if (FPzero(l2->B))		/* l2 vertical? */
 			return false;
 
-		x = l1->C;
-		y = float8_pl(float8_mul(l2->A, x), l2->C);
+		x = float8_div(-l1->C, l1->A);
+		y = float8_div(-float8_pl(float8_mul(l2->A, x), l2->C), l2->B);
 	}
 	else if (FPzero(l2->B))		/* l2 vertical? */
 	{
-		x = l2->C;
-		y = float8_pl(float8_mul(l1->A, x), l1->C);
+		x = float8_div(-l2->C, l2->A);
+		y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
 	}
 	else
 	{
+		/* XXX This check break commutative property. */
 		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
 			return false;
 
-		x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
-		y = float8_pl(float8_mul(l1->A, x), l1->C);
+		x = float8_div(float8_mi(float8_mul(l1->B, l2->C),
+								 float8_mul(l2->B, l1->C)),
+					   float8_mi(float8_mul(l1->A, l2->B),
+								 float8_mul(l2->A, l1->B)));
+		y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
 	}
 	if (result != NULL)
 		point_construct(result, x, y);
 
 	return true;
 }
 
 
 /***********************************************************************
  **
@@ -2338,30 +2367,22 @@ dist_pb(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
-	float8		result;
 
-	if (lseg_interpt_line(NULL, lseg, line))
-		result = 0.0;
-	else
-		/* XXX shouldn't we take the min not max? */
-		result = float8_max(line_closept_point(NULL, line, &lseg->p[0]),
-							line_closept_point(NULL, line, &lseg->p[1]));
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(lseg_closept_line(NULL, lseg, line));
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
@@ -2526,34 +2547,43 @@ lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
 /*
  *		The intersection point of a perpendicular of the line
  *		through the point.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 line_closept_point(Point *result, LINE *line, Point *point)
 {
-	bool		retval;
+	Point		closept;
 	LINE		tmp;
 
 	/* Drop a perpendicular and find the intersection point */
 	line_construct(&tmp, point, line_invsl(line));
-	retval = line_interpt_line(result, line, &tmp);
-	Assert(retval);		/* XXX We need something better. */
 
 	/*
-	 * XXX We could use the distance to the closest point, but
-	 * line_interpt_line() is currently giving wrong results.
+	 * Ordinarily we should always find an intersection point, but that could
+	 * fail in the presence of NaN coordinates, and perhaps even from simple
+	 * roundoff issues.
 	 */
-	return fabs((line->A * point->x + line->B * point->y + line->C) /
-				HYPOT(line->A, line->B));
+	if (!line_interpt_line(&closept, &tmp, line))
+	{
+		if (result != NULL)
+			*result = *point;
+
+		return get_float8_nan();
+	}
+
+	if (result != NULL)
+		*result = closept;
+
+	return point_dt(&closept, point);
 }
 
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -2603,64 +2633,75 @@ close_ps(PG_FUNCTION_ARGS)
 		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point to l1 on l2.
  *
  * This sets the closest point to the *result if it is not NULL and returns
- * the distance to the closest point.
- *
- * XXX This function is wrong.  If must never set the *result to a point on
- * the second segment.
+ * the distance to the closest point.  We first eliminate the case
+ * the segments intersecting with each other.  Then we try to find
+ * the closest point on the first segment by trying the endpoints of
+ * the second.  Though, it is still possible for the closest point to be
+ * one of the endpoints, so we test them.
  */
 static float8
 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
 {
 	Point		point;
 	float8		dist,
 				d;
 
-	d = lseg_closept_point(NULL, l1, &l2->p[0]);
-	dist = d;
-	if (result != NULL)
-		*result = l2->p[0];
+	if (lseg_interpt_lseg(result, l1, l2))
+		return 0.0;
 
-	d = lseg_closept_point(NULL, l1, &l2->p[1]);
+	dist = lseg_closept_point(result, l1, &l2->p[0]);
+
+	d = lseg_closept_point(&point, l1, &l2->p[1]);
 	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
-			*result = l2->p[1];
+			*result = point;
 	}
 
-	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[0]), dist))
-		d = lseg_closept_point(result, l1, &point);
-
-	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[1]), dist))
-		d = lseg_closept_point(result, l1, &point);
-
+	d = lseg_closept_point(NULL, l2, &l1->p[0]);
 	if (float8_lt(d, dist))
+	{
 		dist = d;
+		if (result != NULL)
+			*result = l1->p[0];
+	}
+
+	d = lseg_closept_point(NULL, l2, &l1->p[1]);
+	if (float8_lt(d, dist))
+	{
+		dist = d;
+		if (result != NULL)
+			*result = l1->p[1];
+	}
 
 	return dist;
 }
 
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
+	if (lseg_sl(l1) == lseg_sl(l2))
+		PG_RETURN_NULL();
+
 	result = (Point *) palloc(sizeof(Point));
 
 	if (isnan(lseg_closept_lseg(result, l2, l1)))
 		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
@@ -2821,20 +2862,23 @@ lseg_closept_line(Point *result, LSEG *lseg, LINE *line)
 	}
 }
 
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
+	if (lseg_sl(lseg) == line_sl(line))
+		PG_RETURN_NULL();
+
 	result = (Point *) palloc(sizeof(Point));
 
 	if (isnan(lseg_closept_line(result, lseg, line)))
 		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
-- 
2.14.3 (Apple Git-98)

0005-float-zero-v04.patchapplication/octet-stream; name=0005-float-zero-v04.patchDownload
From 45e68ada40aea4403a50ce57d39345d7ccc9f27d Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Thu, 2 Nov 2017 12:21:19 +0100
Subject: [PATCH 5/6] float-zero-v04

Check for float -0 after multiplications and divisions

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com
---
 src/include/utils/float.h | 26 ++++++++++++++++++++------
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/src/include/utils/float.h b/src/include/utils/float.h
index 0e8483c930..e359d8a3d4 100644
--- a/src/include/utils/float.h
+++ b/src/include/utils/float.h
@@ -209,69 +209,83 @@ float8_mi(const float8 val1, const float8 val2)
 
 	result = val1 - val2;
 	check_float8_val(result, isinf(val1) || isinf(val2), true);
 
 	return result;
 }
 
 static inline float4
 float4_mul(const float4 val1, const float4 val2)
 {
+	const bool	zero_is_valid = val1 == 0.0f || val2 == 0.0f;
 	float4		result;
 
 	result = val1 * val2;
-	check_float4_val(result, isinf(val1) || isinf(val2),
-					 val1 == 0.0f || val2 == 0.0f);
+	check_float4_val(result, isinf(val1) || isinf(val2), zero_is_valid);
+
+	if (zero_is_valid && unlikely(result == -0.0f))
+		result = 0.0f;
 
 	return result;
 }
 
 static inline float8
 float8_mul(const float8 val1, const float8 val2)
 {
+	const bool	zero_is_valid = val1 == 0.0 || val2 == 0.0;
 	float8		result;
 
 	result = val1 * val2;
-	check_float8_val(result, isinf(val1) || isinf(val2),
-					 val1 == 0.0 || val2 == 0.0);
+	check_float8_val(result, isinf(val1) || isinf(val2), zero_is_valid);
+
+	if (zero_is_valid && unlikely(result == -0.0))
+		result = 0.0;
 
 	return result;
 }
 
 static inline float4
 float4_div(const float4 val1, const float4 val2)
 {
+	const bool	zero_is_valid = val1 == 0.0f;
 	float4		result;
 
 	if (val2 == 0.0f)
 		ereport(ERROR,
 				(errcode(ERRCODE_DIVISION_BY_ZERO),
 				 errmsg("division by zero")));
 
 	result = val1 / val2;
-	check_float4_val(result, isinf(val1) || isinf(val2), val1 == 0.0f);
+	check_float4_val(result, isinf(val1) || isinf(val2), zero_is_valid);
+
+	if (zero_is_valid && unlikely(result == -0.0f))
+		result = 0.0f;
 
 	return result;
 }
 
 static inline float8
 float8_div(const float8 val1, const float8 val2)
 {
+	const bool	zero_is_valid = val1 == 0.0;
 	float8		result;
 
 	if (val2 == 0.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_DIVISION_BY_ZERO),
 				 errmsg("division by zero")));
 
 	result = val1 / val2;
-	check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
+	check_float8_val(result, isinf(val1) || isinf(val2), zero_is_valid);
+
+	if (zero_is_valid && unlikely(result == -0.0))
+		result = 0.0;
 
 	return result;
 }
 
 /*
  * Routines for NaN-aware comparisons
  *
  * We consider all NaNs to be equal and larger than any non-NaN. This is
  * somewhat arbitrary; the important thing is to have a consistent sort
  * order.
-- 
2.14.3 (Apple Git-98)

0006-geo-tests-v04.patchapplication/octet-stream; name=0006-geo-tests-v04.patchDownload
From f03b8d1f6bfb9a5fae59cd2661d16c3f86a99d6b Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Tue, 24 Oct 2017 11:28:21 +0200
Subject: [PATCH 6/6] geo-tests-v04

Improve test coverage of geometric types

The tests for the geometric functions and operators were in sad state.
This commit increases test coverage of geo_ops.c significantly.  It
removes the alternative results to expect -0 on some platforms.  We
better try to return the same results on different platforms, but if we
can't we can add them back using the results from build farm.

The tests are added to geometric.sql file.  It is not clear where to
put them as there are many cross datatype operators.  Organising them
on a single file sorted by the left hand side of the operators appear
to be a simple solution.  We may take this further and remove the other
tests later.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com
---
 src/test/regress/expected/box.out          |   44 +-
 src/test/regress/expected/circle.out       |   39 +-
 src/test/regress/expected/create_index.out |   73 +-
 src/test/regress/expected/geometry.out     | 4879 ++++++++++++++++++++++++++--
 src/test/regress/expected/geometry_1.out   |  563 ----
 src/test/regress/expected/geometry_2.out   |  563 ----
 src/test/regress/expected/line.out         |  272 +-
 src/test/regress/expected/lseg.out         |   24 +-
 src/test/regress/expected/path.out         |   49 +-
 src/test/regress/expected/point.out        |  358 +-
 src/test/regress/expected/polygon.out      |  200 +-
 src/test/regress/sql/box.sql               |    9 +
 src/test/regress/sql/circle.sql            |   10 +-
 src/test/regress/sql/geometry.sql          |  400 ++-
 src/test/regress/sql/line.sql              |   79 +-
 src/test/regress/sql/lseg.sql              |    9 +-
 src/test/regress/sql/path.sql              |   22 +-
 src/test/regress/sql/point.sql             |   10 +
 src/test/regress/sql/polygon.sql           |   91 +-
 19 files changed, 5483 insertions(+), 2211 deletions(-)
 delete mode 100644 src/test/regress/expected/geometry_1.out
 delete mode 100644 src/test/regress/expected/geometry_2.out

diff --git a/src/test/regress/expected/box.out b/src/test/regress/expected/box.out
index 49af242c8c..998b52223c 100644
--- a/src/test/regress/expected/box.out
+++ b/src/test/regress/expected/box.out
@@ -11,92 +11,109 @@
 -- 1	| o-+-o
 --	|   |
 -- 0	+---+
 --
 --	0 1 2 3
 --
 -- boxes are specified by two points, given by four floats x1,y1,x2,y2
 CREATE TABLE BOX_TBL (f1 box);
 INSERT INTO BOX_TBL (f1) VALUES ('(2.0,2.0,0.0,0.0)');
 INSERT INTO BOX_TBL (f1) VALUES ('(1.0,1.0,3.0,3.0)');
+INSERT INTO BOX_TBL (f1) VALUES ('((-8, 2), (-2, -10))');
 -- degenerate cases where the box is a line or a point
 -- note that lines and points boxes all have zero area
 INSERT INTO BOX_TBL (f1) VALUES ('(2.5, 2.5, 2.5,3.5)');
 INSERT INTO BOX_TBL (f1) VALUES ('(3.0, 3.0,3.0,3.0)');
 -- badly formatted box inputs
 INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
 ERROR:  invalid input syntax for type box: "(2.3, 4.5)"
 LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
                                          ^
+INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+ERROR:  invalid input syntax for type box: "[1, 2, 3, 4)"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+                                         ^
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+ERROR:  invalid input syntax for type box: "(1, 2, 3, 4]"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+                                         ^
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+ERROR:  invalid input syntax for type box: "(1, 2, 3, 4) x"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+                                         ^
 INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
 ERROR:  invalid input syntax for type box: "asdfasdf(ad"
 LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
                                          ^
 SELECT '' AS four, * FROM BOX_TBL;
  four |         f1          
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
+      | (-2,2),(-8,-10)
       | (2.5,3.5),(2.5,2.5)
       | (3,3),(3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, b.*, area(b.f1) as barea
    FROM BOX_TBL b;
  four |         f1          | barea 
 ------+---------------------+-------
       | (2,2),(0,0)         |     4
       | (3,3),(1,1)         |     4
+      | (-2,2),(-8,-10)     |    72
       | (2.5,3.5),(2.5,2.5) |     0
       | (3,3),(3,3)         |     0
-(4 rows)
+(5 rows)
 
 -- overlap
 SELECT '' AS three, b.f1
    FROM BOX_TBL b
    WHERE b.f1 && box '(2.5,2.5,1.0,1.0)';
  three |         f1          
 -------+---------------------
        | (2,2),(0,0)
        | (3,3),(1,1)
        | (2.5,3.5),(2.5,2.5)
 (3 rows)
 
 -- left-or-overlap (x only)
 SELECT '' AS two, b1.*
    FROM BOX_TBL b1
    WHERE b1.f1 &< box '(2.0,2.0,2.5,2.5)';
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- right-or-overlap (x only)
 SELECT '' AS two, b1.*
    FROM BOX_TBL b1
    WHERE b1.f1 &> box '(2.0,2.0,2.5,2.5)';
  two |         f1          
 -----+---------------------
      | (2.5,3.5),(2.5,2.5)
      | (3,3),(3,3)
 (2 rows)
 
 -- left of
 SELECT '' AS two, b.f1
    FROM BOX_TBL b
    WHERE b.f1 << box '(3.0,3.0,5.0,5.0)';
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- area <=
 SELECT '' AS four, b.f1
    FROM BOX_TBL b
    WHERE b.f1 <= box '(3.0,3.0,5.0,5.0)';
  four |         f1          
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
       | (2.5,3.5),(2.5,2.5)
@@ -120,47 +137,50 @@ SELECT '' AS two, b.f1
  two |     f1      
 -----+-------------
      | (2,2),(0,0)
      | (3,3),(1,1)
 (2 rows)
 
 -- area >
 SELECT '' AS two, b.f1
    FROM BOX_TBL b				-- zero area
    WHERE b.f1 > box '(3.5,3.0,4.5,3.0)';
- two |     f1      
------+-------------
+ two |       f1        
+-----+-----------------
      | (2,2),(0,0)
      | (3,3),(1,1)
-(2 rows)
+     | (-2,2),(-8,-10)
+(3 rows)
 
 -- area >=
 SELECT '' AS four, b.f1
    FROM BOX_TBL b				-- zero area
    WHERE b.f1 >= box '(3.5,3.0,4.5,3.0)';
  four |         f1          
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
+      | (-2,2),(-8,-10)
       | (2.5,3.5),(2.5,2.5)
       | (3,3),(3,3)
-(4 rows)
+(5 rows)
 
 -- right of
 SELECT '' AS two, b.f1
    FROM BOX_TBL b
    WHERE box '(3.0,3.0,5.0,5.0)' >> b.f1;
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- contained in
 SELECT '' AS three, b.f1
    FROM BOX_TBL b
    WHERE b.f1 <@ box '(0,0,3,3)';
  three |     f1      
 -------+-------------
        | (2,2),(0,0)
        | (3,3),(1,1)
        | (3,3),(3,3)
@@ -186,41 +206,43 @@ SELECT '' AS one, b.f1
      | (3,3),(1,1)
 (1 row)
 
 -- center of box, left unary operator
 SELECT '' AS four, @@(b1.f1) AS p
    FROM BOX_TBL b1;
  four |    p    
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 -- wholly-contained
 SELECT '' AS one, b1.*, b2.*
    FROM BOX_TBL b1, BOX_TBL b2
    WHERE b1.f1 @> b2.f1 and not b1.f1 ~= b2.f1;
  one |     f1      |     f1      
 -----+-------------+-------------
      | (3,3),(1,1) | (3,3),(3,3)
 (1 row)
 
 SELECT '' AS four, height(f1), width(f1) FROM BOX_TBL;
  four | height | width 
 ------+--------+-------
       |      2 |     2
       |      2 |     2
+      |     12 |     6
       |      1 |     0
       |      0 |     0
-(4 rows)
+(5 rows)
 
 --
 -- Test the SP-GiST index
 --
 CREATE TEMPORARY TABLE box_temp (f1 box);
 INSERT INTO box_temp
 	SELECT box(point(i, i), point(i * 2, i * 2))
 	FROM generate_series(1, 50) AS i;
 CREATE INDEX box_spgist ON box_temp USING spgist (f1);
 INSERT INTO box_temp
diff --git a/src/test/regress/expected/circle.out b/src/test/regress/expected/circle.out
index 9ba4a0495d..2ed74cc6aa 100644
--- a/src/test/regress/expected/circle.out
+++ b/src/test/regress/expected/circle.out
@@ -1,99 +1,122 @@
 --
 -- CIRCLE
 --
 CREATE TABLE CIRCLE_TBL (f1 circle);
 INSERT INTO CIRCLE_TBL VALUES ('<(5,1),3>');
 INSERT INTO CIRCLE_TBL VALUES ('<(1,2),100>');
 INSERT INTO CIRCLE_TBL VALUES ('1,3,5');
 INSERT INTO CIRCLE_TBL VALUES ('((1,2),3)');
 INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10>');
-INSERT INTO CIRCLE_TBL VALUES ('<(100,1),115>');
+INSERT INTO CIRCLE_TBL VALUES (' < ( 100 , 1 ) , 115 > ');
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),0>');	-- Zero radius
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),NaN>');	-- NaN radius
 -- bad values
 INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
 ERROR:  invalid input syntax for type circle: "<(-100,0),-100>"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
                                        ^
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+ERROR:  invalid input syntax for type circle: "<(100,200),10"
+LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+                                       ^
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+ERROR:  invalid input syntax for type circle: "<(100,200),10> x"
+LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+                                       ^
 INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
 ERROR:  invalid input syntax for type circle: "1abc,3,5"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
                                        ^
 INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
 ERROR:  invalid input syntax for type circle: "(3,(1,2),3)"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
                                        ^
 SELECT * FROM CIRCLE_TBL;
        f1       
 ----------------
  <(5,1),3>
  <(1,2),100>
  <(1,3),5>
  <(1,2),3>
  <(100,200),10>
  <(100,1),115>
-(6 rows)
+ <(3,5),0>
+ <(3,5),NaN>
+(8 rows)
 
 SELECT '' AS six, center(f1) AS center
   FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS six, radius(f1) AS radius
   FROM CIRCLE_TBL;
  six | radius 
 -----+--------
      |      3
      |    100
      |      5
      |      3
      |     10
      |    115
-(6 rows)
+     |      0
+     |    NaN
+(8 rows)
 
 SELECT '' AS six, diameter(f1) AS diameter
   FROM CIRCLE_TBL;
  six | diameter 
 -----+----------
      |        6
      |      200
      |       10
      |        6
      |       20
      |      230
-(6 rows)
+     |        0
+     |      NaN
+(8 rows)
 
 SELECT '' AS two, f1 FROM CIRCLE_TBL WHERE radius(f1) < 5;
  two |    f1     
 -----+-----------
      | <(5,1),3>
      | <(1,2),3>
-(2 rows)
+     | <(3,5),0>
+(3 rows)
 
 SELECT '' AS four, f1 FROM CIRCLE_TBL WHERE diameter(f1) >= 10;
  four |       f1       
 ------+----------------
       | <(1,2),100>
       | <(1,3),5>
       | <(100,200),10>
       | <(100,1),115>
-(4 rows)
+      | <(3,5),NaN>
+(5 rows)
 
 SELECT '' as five, c1.f1 AS one, c2.f1 AS two, (c1.f1 <-> c2.f1) AS distance
   FROM CIRCLE_TBL c1, CIRCLE_TBL c2
   WHERE (c1.f1 < c2.f1) AND ((c1.f1 <-> c2.f1) > 0)
   ORDER BY distance, area(c1.f1), area(c2.f1);
  five |      one       |      two       |     distance     
 ------+----------------+----------------+------------------
+      | <(3,5),0>      | <(1,2),3>      | 0.60555127546399
+      | <(3,5),0>      | <(5,1),3>      | 1.47213595499958
       | <(100,200),10> | <(100,1),115>  |               74
       | <(100,200),10> | <(1,2),100>    | 111.370729772479
       | <(1,3),5>      | <(100,200),10> | 205.476756144497
       | <(5,1),3>      | <(100,200),10> |  207.51303816328
+      | <(3,5),0>      | <(100,200),10> | 207.793480159531
       | <(1,2),3>      | <(100,200),10> | 208.370729772479
-(5 rows)
+(8 rows)
 
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 057faff2e5..3c0db6016f 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -150,96 +150,103 @@ SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)';
 
 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
+     5
 (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
+     3
 (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
+     4
 (1 row)
 
 SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
  count 
 -------
      1
 (1 row)
 
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
  (-5,-12)
  (5.1,34.5)
+ (1e+300,Infinity)
+ (NaN,NaN)
  
-(7 rows)
+(10 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NULL;
  f1 
 ----
  
 (1 row)
 
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (1e-300,-1e-300)
  (0,0)
  (-3,4)
  (-10,0)
  (10,10)
  (-5,-12)
  (5.1,34.5)
-(6 rows)
+ (1e+300,Infinity)
+ (NaN,NaN)
+(9 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
  count 
 -------
      3
 (1 row)
 
 SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
  count 
 -------
@@ -561,21 +568,21 @@ SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,
                                        QUERY PLAN                                       
 ----------------------------------------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     4
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>';
                      QUERY PLAN                     
 ----------------------------------------------------
  Aggregate
    ->  Index Only Scan using gpointind on point_tbl
          Index Cond: (f1 <@ '<(50,50),50>'::circle)
 (3 rows)
@@ -606,21 +613,21 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     3
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl p WHERE p.f1 <^ '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only Scan using gpointind on point_tbl p
          Index Cond: (f1 <^ '(0,0)'::point)
 (3 rows)
@@ -636,21 +643,21 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 >^ '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     4
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only Scan using gpointind on point_tbl p
          Index Cond: (f1 ~= '(-5,-12)'::point)
 (3 rows)
@@ -663,30 +670,33 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
                   QUERY PLAN                  
 ----------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Order By: (f1 <-> '(0,1)'::point)
 (2 rows)
 
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (10,10)
+ (NaN,NaN)
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
- (10,10)
  (-5,-12)
  (5.1,34.5)
  
-(7 rows)
+ (1e+300,Infinity)
+(10 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 IS NULL;
                   QUERY PLAN                  
 ----------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Index Cond: (f1 IS NULL)
 (2 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NULL;
@@ -698,47 +708,51 @@ SELECT * FROM point_tbl WHERE f1 IS NULL;
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
                   QUERY PLAN                  
 ----------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Index Cond: (f1 IS NOT NULL)
    Order By: (f1 <-> '(0,1)'::point)
 (3 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (10,10)
+ (NaN,NaN)
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
- (10,10)
  (-5,-12)
  (5.1,34.5)
-(6 rows)
+ (1e+300,Infinity)
+(9 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
                    QUERY PLAN                   
 ------------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Index Cond: (f1 <@ '(10,10),(-10,-10)'::box)
    Order By: (f1 <-> '(0,1)'::point)
 (3 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
                         QUERY PLAN                         
 -----------------------------------------------------------
  Aggregate
    ->  Index Only Scan using sp_quad_ind on quad_point_tbl
          Index Cond: (p IS NULL)
 (3 rows)
 
@@ -1240,27 +1254,28 @@ SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0
 ------------------------------------------------------------
  Sort
    Sort Key: ((f1 <-> '(0,1)'::point))
    ->  Bitmap Heap Scan on point_tbl
          Recheck Cond: (f1 <@ '(10,10),(-10,-10)'::box)
          ->  Bitmap Index Scan on gpointind
                Index Cond: (f1 <@ '(10,10),(-10,-10)'::box)
 (6 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
                   QUERY PLAN                  
 ----------------------------------------------
  Aggregate
    ->  Bitmap Heap Scan on quad_point_tbl
          Recheck Cond: (p IS NULL)
          ->  Bitmap Index Scan on sp_quad_ind
                Index Cond: (p IS NULL)
diff --git a/src/test/regress/expected/geometry.out b/src/test/regress/expected/geometry.out
index e4c0039040..58051b8946 100644
--- a/src/test/regress/expected/geometry.out
+++ b/src/test/regress/expected/geometry.out
@@ -6,558 +6,4885 @@
 SET extra_float_digits TO -3;
 --
 -- Points
 --
 SELECT '' AS four, center(f1) AS center
    FROM BOX_TBL;
  four | center  
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, (@@ f1) AS center
    FROM BOX_TBL;
  four | center  
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS six, point(f1) AS center
    FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS six, (@@ f1) AS center
    FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS two, (@@ f1) AS center
    FROM POLYGON_TBL
    WHERE (# f1) > 2;
  two |            center             
 -----+-------------------------------
      | (1.33333333333,1.33333333333)
      | (2.33333333333,1.33333333333)
-(2 rows)
+     | (4,5)
+     | (4,5)
+     | (4,3)
+(5 rows)
 
 -- "is horizontal" function
 SELECT '' AS two, p1.f1
    FROM POINT_TBL p1
    WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 -- "is horizontal" operator
 SELECT '' AS two, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 -- "is vertical" function
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE isvertical(p1.f1, point '(5.1,34.5)');
  one |     f1     
 -----+------------
      | (5.1,34.5)
 (1 row)
 
 -- "is vertical" operator
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?| point '(5.1,34.5)';
  one |     f1     
 -----+------------
      | (5.1,34.5)
 (1 row)
 
+-- Slope
+SELECT p1.f1, p2.f1, slope(p1.f1, p2.f1) FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |       slope        
+-------------------+-------------------+--------------------
+ (0,0)             | (0,0)             | 1.79769313486e+308
+ (0,0)             | (-10,0)           |                  0
+ (0,0)             | (-3,4)            |     -1.33333333333
+ (0,0)             | (5.1,34.5)        |      6.76470588235
+ (0,0)             | (-5,-12)          |                2.4
+ (0,0)             | (1e-300,-1e-300)  | 1.79769313486e+308
+ (0,0)             | (1e+300,Infinity) |           Infinity
+ (0,0)             | (NaN,NaN)         |                NaN
+ (0,0)             | (10,10)           |                  1
+ (-10,0)           | (0,0)             |                  0
+ (-10,0)           | (-10,0)           | 1.79769313486e+308
+ (-10,0)           | (-3,4)            |     0.571428571429
+ (-10,0)           | (5.1,34.5)        |      2.28476821192
+ (-10,0)           | (-5,-12)          |               -2.4
+ (-10,0)           | (1e-300,-1e-300)  |                  0
+ (-10,0)           | (1e+300,Infinity) |           Infinity
+ (-10,0)           | (NaN,NaN)         |                NaN
+ (-10,0)           | (10,10)           |                0.5
+ (-3,4)            | (0,0)             |     -1.33333333333
+ (-3,4)            | (-10,0)           |     0.571428571429
+ (-3,4)            | (-3,4)            | 1.79769313486e+308
+ (-3,4)            | (5.1,34.5)        |      3.76543209877
+ (-3,4)            | (-5,-12)          |                  8
+ (-3,4)            | (1e-300,-1e-300)  |     -1.33333333333
+ (-3,4)            | (1e+300,Infinity) |           Infinity
+ (-3,4)            | (NaN,NaN)         |                NaN
+ (-3,4)            | (10,10)           |     0.461538461538
+ (5.1,34.5)        | (0,0)             |      6.76470588235
+ (5.1,34.5)        | (-10,0)           |      2.28476821192
+ (5.1,34.5)        | (-3,4)            |      3.76543209877
+ (5.1,34.5)        | (5.1,34.5)        | 1.79769313486e+308
+ (5.1,34.5)        | (-5,-12)          |      4.60396039604
+ (5.1,34.5)        | (1e-300,-1e-300)  |      6.76470588235
+ (5.1,34.5)        | (1e+300,Infinity) |           Infinity
+ (5.1,34.5)        | (NaN,NaN)         |                NaN
+ (5.1,34.5)        | (10,10)           |                 -5
+ (-5,-12)          | (0,0)             |                2.4
+ (-5,-12)          | (-10,0)           |               -2.4
+ (-5,-12)          | (-3,4)            |                  8
+ (-5,-12)          | (5.1,34.5)        |      4.60396039604
+ (-5,-12)          | (-5,-12)          | 1.79769313486e+308
+ (-5,-12)          | (1e-300,-1e-300)  |                2.4
+ (-5,-12)          | (1e+300,Infinity) |           Infinity
+ (-5,-12)          | (NaN,NaN)         |                NaN
+ (-5,-12)          | (10,10)           |      1.46666666667
+ (1e-300,-1e-300)  | (0,0)             | 1.79769313486e+308
+ (1e-300,-1e-300)  | (-10,0)           |                  0
+ (1e-300,-1e-300)  | (-3,4)            |     -1.33333333333
+ (1e-300,-1e-300)  | (5.1,34.5)        |      6.76470588235
+ (1e-300,-1e-300)  | (-5,-12)          |                2.4
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | 1.79769313486e+308
+ (1e-300,-1e-300)  | (1e+300,Infinity) |           Infinity
+ (1e-300,-1e-300)  | (NaN,NaN)         |                NaN
+ (1e-300,-1e-300)  | (10,10)           |                  1
+ (1e+300,Infinity) | (0,0)             |           Infinity
+ (1e+300,Infinity) | (-10,0)           |           Infinity
+ (1e+300,Infinity) | (-3,4)            |           Infinity
+ (1e+300,Infinity) | (5.1,34.5)        |           Infinity
+ (1e+300,Infinity) | (-5,-12)          |           Infinity
+ (1e+300,Infinity) | (1e-300,-1e-300)  |           Infinity
+ (1e+300,Infinity) | (1e+300,Infinity) | 1.79769313486e+308
+ (1e+300,Infinity) | (NaN,NaN)         |                NaN
+ (1e+300,Infinity) | (10,10)           |           Infinity
+ (NaN,NaN)         | (0,0)             |                NaN
+ (NaN,NaN)         | (-10,0)           |                NaN
+ (NaN,NaN)         | (-3,4)            |                NaN
+ (NaN,NaN)         | (5.1,34.5)        |                NaN
+ (NaN,NaN)         | (-5,-12)          |                NaN
+ (NaN,NaN)         | (1e-300,-1e-300)  |                NaN
+ (NaN,NaN)         | (1e+300,Infinity) |                NaN
+ (NaN,NaN)         | (NaN,NaN)         |                NaN
+ (NaN,NaN)         | (10,10)           |                NaN
+ (10,10)           | (0,0)             |                  1
+ (10,10)           | (-10,0)           |                0.5
+ (10,10)           | (-3,4)            |     0.461538461538
+ (10,10)           | (5.1,34.5)        |                 -5
+ (10,10)           | (-5,-12)          |      1.46666666667
+ (10,10)           | (1e-300,-1e-300)  |                  1
+ (10,10)           | (1e+300,Infinity) |           Infinity
+ (10,10)           | (NaN,NaN)         |                NaN
+ (10,10)           | (10,10)           | 1.79769313486e+308
+(81 rows)
+
+-- Add point
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |     ?column?      
+-------------------+-------------------+-------------------
+ (0,0)             | (0,0)             | (0,0)
+ (0,0)             | (-10,0)           | (-10,0)
+ (0,0)             | (-3,4)            | (-3,4)
+ (0,0)             | (5.1,34.5)        | (5.1,34.5)
+ (0,0)             | (-5,-12)          | (-5,-12)
+ (0,0)             | (1e-300,-1e-300)  | (1e-300,-1e-300)
+ (0,0)             | (1e+300,Infinity) | (1e+300,Infinity)
+ (0,0)             | (NaN,NaN)         | (NaN,NaN)
+ (0,0)             | (10,10)           | (10,10)
+ (-10,0)           | (0,0)             | (-10,0)
+ (-10,0)           | (-10,0)           | (-20,0)
+ (-10,0)           | (-3,4)            | (-13,4)
+ (-10,0)           | (5.1,34.5)        | (-4.9,34.5)
+ (-10,0)           | (-5,-12)          | (-15,-12)
+ (-10,0)           | (1e-300,-1e-300)  | (-10,-1e-300)
+ (-10,0)           | (1e+300,Infinity) | (1e+300,Infinity)
+ (-10,0)           | (NaN,NaN)         | (NaN,NaN)
+ (-10,0)           | (10,10)           | (0,10)
+ (-3,4)            | (0,0)             | (-3,4)
+ (-3,4)            | (-10,0)           | (-13,4)
+ (-3,4)            | (-3,4)            | (-6,8)
+ (-3,4)            | (5.1,34.5)        | (2.1,38.5)
+ (-3,4)            | (-5,-12)          | (-8,-8)
+ (-3,4)            | (1e-300,-1e-300)  | (-3,4)
+ (-3,4)            | (1e+300,Infinity) | (1e+300,Infinity)
+ (-3,4)            | (NaN,NaN)         | (NaN,NaN)
+ (-3,4)            | (10,10)           | (7,14)
+ (5.1,34.5)        | (0,0)             | (5.1,34.5)
+ (5.1,34.5)        | (-10,0)           | (-4.9,34.5)
+ (5.1,34.5)        | (-3,4)            | (2.1,38.5)
+ (5.1,34.5)        | (5.1,34.5)        | (10.2,69)
+ (5.1,34.5)        | (-5,-12)          | (0.1,22.5)
+ (5.1,34.5)        | (1e-300,-1e-300)  | (5.1,34.5)
+ (5.1,34.5)        | (1e+300,Infinity) | (1e+300,Infinity)
+ (5.1,34.5)        | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5)        | (10,10)           | (15.1,44.5)
+ (-5,-12)          | (0,0)             | (-5,-12)
+ (-5,-12)          | (-10,0)           | (-15,-12)
+ (-5,-12)          | (-3,4)            | (-8,-8)
+ (-5,-12)          | (5.1,34.5)        | (0.1,22.5)
+ (-5,-12)          | (-5,-12)          | (-10,-24)
+ (-5,-12)          | (1e-300,-1e-300)  | (-5,-12)
+ (-5,-12)          | (1e+300,Infinity) | (1e+300,Infinity)
+ (-5,-12)          | (NaN,NaN)         | (NaN,NaN)
+ (-5,-12)          | (10,10)           | (5,-2)
+ (1e-300,-1e-300)  | (0,0)             | (1e-300,-1e-300)
+ (1e-300,-1e-300)  | (-10,0)           | (-10,-1e-300)
+ (1e-300,-1e-300)  | (-3,4)            | (-3,4)
+ (1e-300,-1e-300)  | (5.1,34.5)        | (5.1,34.5)
+ (1e-300,-1e-300)  | (-5,-12)          | (-5,-12)
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | (2e-300,-2e-300)
+ (1e-300,-1e-300)  | (1e+300,Infinity) | (1e+300,Infinity)
+ (1e-300,-1e-300)  | (NaN,NaN)         | (NaN,NaN)
+ (1e-300,-1e-300)  | (10,10)           | (10,10)
+ (1e+300,Infinity) | (0,0)             | (1e+300,Infinity)
+ (1e+300,Infinity) | (-10,0)           | (1e+300,Infinity)
+ (1e+300,Infinity) | (-3,4)            | (1e+300,Infinity)
+ (1e+300,Infinity) | (5.1,34.5)        | (1e+300,Infinity)
+ (1e+300,Infinity) | (-5,-12)          | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e-300,-1e-300)  | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e+300,Infinity) | (2e+300,Infinity)
+ (1e+300,Infinity) | (NaN,NaN)         | (NaN,NaN)
+ (1e+300,Infinity) | (10,10)           | (1e+300,Infinity)
+ (NaN,NaN)         | (0,0)             | (NaN,NaN)
+ (NaN,NaN)         | (-10,0)           | (NaN,NaN)
+ (NaN,NaN)         | (-3,4)            | (NaN,NaN)
+ (NaN,NaN)         | (5.1,34.5)        | (NaN,NaN)
+ (NaN,NaN)         | (-5,-12)          | (NaN,NaN)
+ (NaN,NaN)         | (1e-300,-1e-300)  | (NaN,NaN)
+ (NaN,NaN)         | (1e+300,Infinity) | (NaN,NaN)
+ (NaN,NaN)         | (NaN,NaN)         | (NaN,NaN)
+ (NaN,NaN)         | (10,10)           | (NaN,NaN)
+ (10,10)           | (0,0)             | (10,10)
+ (10,10)           | (-10,0)           | (0,10)
+ (10,10)           | (-3,4)            | (7,14)
+ (10,10)           | (5.1,34.5)        | (15.1,44.5)
+ (10,10)           | (-5,-12)          | (5,-2)
+ (10,10)           | (1e-300,-1e-300)  | (10,10)
+ (10,10)           | (1e+300,Infinity) | (1e+300,Infinity)
+ (10,10)           | (NaN,NaN)         | (NaN,NaN)
+ (10,10)           | (10,10)           | (20,20)
+(81 rows)
+
+-- Subtract point
+SELECT p1.f1, p2.f1, p1.f1 - p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |      ?column?       
+-------------------+-------------------+---------------------
+ (0,0)             | (0,0)             | (0,0)
+ (0,0)             | (-10,0)           | (10,0)
+ (0,0)             | (-3,4)            | (3,-4)
+ (0,0)             | (5.1,34.5)        | (-5.1,-34.5)
+ (0,0)             | (-5,-12)          | (5,12)
+ (0,0)             | (1e-300,-1e-300)  | (-1e-300,1e-300)
+ (0,0)             | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (0,0)             | (NaN,NaN)         | (NaN,NaN)
+ (0,0)             | (10,10)           | (-10,-10)
+ (-10,0)           | (0,0)             | (-10,0)
+ (-10,0)           | (-10,0)           | (0,0)
+ (-10,0)           | (-3,4)            | (-7,-4)
+ (-10,0)           | (5.1,34.5)        | (-15.1,-34.5)
+ (-10,0)           | (-5,-12)          | (-5,12)
+ (-10,0)           | (1e-300,-1e-300)  | (-10,1e-300)
+ (-10,0)           | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-10,0)           | (NaN,NaN)         | (NaN,NaN)
+ (-10,0)           | (10,10)           | (-20,-10)
+ (-3,4)            | (0,0)             | (-3,4)
+ (-3,4)            | (-10,0)           | (7,4)
+ (-3,4)            | (-3,4)            | (0,0)
+ (-3,4)            | (5.1,34.5)        | (-8.1,-30.5)
+ (-3,4)            | (-5,-12)          | (2,16)
+ (-3,4)            | (1e-300,-1e-300)  | (-3,4)
+ (-3,4)            | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-3,4)            | (NaN,NaN)         | (NaN,NaN)
+ (-3,4)            | (10,10)           | (-13,-6)
+ (5.1,34.5)        | (0,0)             | (5.1,34.5)
+ (5.1,34.5)        | (-10,0)           | (15.1,34.5)
+ (5.1,34.5)        | (-3,4)            | (8.1,30.5)
+ (5.1,34.5)        | (5.1,34.5)        | (0,0)
+ (5.1,34.5)        | (-5,-12)          | (10.1,46.5)
+ (5.1,34.5)        | (1e-300,-1e-300)  | (5.1,34.5)
+ (5.1,34.5)        | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (5.1,34.5)        | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5)        | (10,10)           | (-4.9,24.5)
+ (-5,-12)          | (0,0)             | (-5,-12)
+ (-5,-12)          | (-10,0)           | (5,-12)
+ (-5,-12)          | (-3,4)            | (-2,-16)
+ (-5,-12)          | (5.1,34.5)        | (-10.1,-46.5)
+ (-5,-12)          | (-5,-12)          | (0,0)
+ (-5,-12)          | (1e-300,-1e-300)  | (-5,-12)
+ (-5,-12)          | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-5,-12)          | (NaN,NaN)         | (NaN,NaN)
+ (-5,-12)          | (10,10)           | (-15,-22)
+ (1e-300,-1e-300)  | (0,0)             | (1e-300,-1e-300)
+ (1e-300,-1e-300)  | (-10,0)           | (10,-1e-300)
+ (1e-300,-1e-300)  | (-3,4)            | (3,-4)
+ (1e-300,-1e-300)  | (5.1,34.5)        | (-5.1,-34.5)
+ (1e-300,-1e-300)  | (-5,-12)          | (5,12)
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | (0,0)
+ (1e-300,-1e-300)  | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (1e-300,-1e-300)  | (NaN,NaN)         | (NaN,NaN)
+ (1e-300,-1e-300)  | (10,10)           | (-10,-10)
+ (1e+300,Infinity) | (0,0)             | (1e+300,Infinity)
+ (1e+300,Infinity) | (-10,0)           | (1e+300,Infinity)
+ (1e+300,Infinity) | (-3,4)            | (1e+300,Infinity)
+ (1e+300,Infinity) | (5.1,34.5)        | (1e+300,Infinity)
+ (1e+300,Infinity) | (-5,-12)          | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e-300,-1e-300)  | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e+300,Infinity) | (0,NaN)
+ (1e+300,Infinity) | (NaN,NaN)         | (NaN,NaN)
+ (1e+300,Infinity) | (10,10)           | (1e+300,Infinity)
+ (NaN,NaN)         | (0,0)             | (NaN,NaN)
+ (NaN,NaN)         | (-10,0)           | (NaN,NaN)
+ (NaN,NaN)         | (-3,4)            | (NaN,NaN)
+ (NaN,NaN)         | (5.1,34.5)        | (NaN,NaN)
+ (NaN,NaN)         | (-5,-12)          | (NaN,NaN)
+ (NaN,NaN)         | (1e-300,-1e-300)  | (NaN,NaN)
+ (NaN,NaN)         | (1e+300,Infinity) | (NaN,NaN)
+ (NaN,NaN)         | (NaN,NaN)         | (NaN,NaN)
+ (NaN,NaN)         | (10,10)           | (NaN,NaN)
+ (10,10)           | (0,0)             | (10,10)
+ (10,10)           | (-10,0)           | (20,10)
+ (10,10)           | (-3,4)            | (13,6)
+ (10,10)           | (5.1,34.5)        | (4.9,-24.5)
+ (10,10)           | (-5,-12)          | (15,22)
+ (10,10)           | (1e-300,-1e-300)  | (10,10)
+ (10,10)           | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (10,10)           | (NaN,NaN)         | (NaN,NaN)
+ (10,10)           | (10,10)           | (0,0)
+(81 rows)
+
+-- Multiply with point
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+     f1     |        f1         |       ?column?        
+------------+-------------------+-----------------------
+ (5.1,34.5) | (0,0)             | (0,0)
+ (10,10)    | (0,0)             | (0,0)
+ (5.1,34.5) | (-10,0)           | (-51,-345)
+ (10,10)    | (-10,0)           | (-100,-100)
+ (5.1,34.5) | (-3,4)            | (-153.3,-83.1)
+ (10,10)    | (-3,4)            | (-70,10)
+ (5.1,34.5) | (5.1,34.5)        | (-1164.24,351.9)
+ (10,10)    | (5.1,34.5)        | (-294,396)
+ (5.1,34.5) | (-5,-12)          | (388.5,-233.7)
+ (10,10)    | (-5,-12)          | (70,-170)
+ (5.1,34.5) | (1e-300,-1e-300)  | (3.96e-299,2.94e-299)
+ (10,10)    | (1e-300,-1e-300)  | (2e-299,0)
+ (5.1,34.5) | (1e+300,Infinity) | (-Infinity,Infinity)
+ (10,10)    | (1e+300,Infinity) | (-Infinity,Infinity)
+ (5.1,34.5) | (NaN,NaN)         | (NaN,NaN)
+ (10,10)    | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5) | (10,10)           | (-294,396)
+ (10,10)    | (10,10)           | (0,200)
+(18 rows)
+
+-- Underflow error
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] < 1;
+ERROR:  value out of range: underflow
+-- Divide by point
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] BETWEEN 1 AND 1000;
+        f1         |     f1     |                 ?column?                  
+-------------------+------------+-------------------------------------------
+ (0,0)             | (5.1,34.5) | (0,0)
+ (0,0)             | (10,10)    | (0,0)
+ (-10,0)           | (5.1,34.5) | (-0.0419318237877,0.283656455034)
+ (-10,0)           | (10,10)    | (-0.5,0.5)
+ (-3,4)            | (5.1,34.5) | (0.100883034877,0.101869666025)
+ (-3,4)            | (10,10)    | (0.05,0.35)
+ (5.1,34.5)        | (5.1,34.5) | (1,0)
+ (5.1,34.5)        | (10,10)    | (1.98,1.47)
+ (-5,-12)          | (5.1,34.5) | (-0.361353657935,0.0915100389719)
+ (-5,-12)          | (10,10)    | (-0.85,-0.35)
+ (1e-300,-1e-300)  | (5.1,34.5) | (-2.41724631247e-302,-3.25588278822e-302)
+ (1e-300,-1e-300)  | (10,10)    | (0,-1e-301)
+ (1e+300,Infinity) | (5.1,34.5) | (Infinity,Infinity)
+ (1e+300,Infinity) | (10,10)    | (Infinity,Infinity)
+ (NaN,NaN)         | (5.1,34.5) | (NaN,NaN)
+ (NaN,NaN)         | (10,10)    | (NaN,NaN)
+ (10,10)           | (5.1,34.5) | (0.325588278822,-0.241724631247)
+ (10,10)           | (10,10)    | (1,0)
+(18 rows)
+
+-- Overflow error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] > 1000;
+ERROR:  value out of range: overflow
+-- Division by 0 error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to line
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LINE_TBL l;
+        f1         |                   s                   |      ?column?      
+-------------------+---------------------------------------+--------------------
+ (0,0)             | {0,-1,5}                              |                  5
+ (0,0)             | {1,0,5}                               |                  5
+ (0,0)             | {0,3,0}                               |                  0
+ (0,0)             | {1,-1,0}                              |                  0
+ (0,0)             | {-0.4,-1,-6}                          |      5.57086014531
+ (0,0)             | {-0.000184615384615,-1,15.3846153846} |      15.3846151224
+ (0,0)             | {3,NaN,5}                             |                NaN
+ (0,0)             | {NaN,NaN,NaN}                         |                NaN
+ (0,0)             | {0,-1,3}                              |                  3
+ (0,0)             | {-1,0,3}                              |                  3
+ (-10,0)           | {0,-1,5}                              |                  5
+ (-10,0)           | {1,0,5}                               |                  5
+ (-10,0)           | {0,3,0}                               |                  0
+ (-10,0)           | {1,-1,0}                              |      7.07106781187
+ (-10,0)           | {-0.4,-1,-6}                          |      1.85695338177
+ (-10,0)           | {-0.000184615384615,-1,15.3846153846} |      15.3864612763
+ (-10,0)           | {3,NaN,5}                             |                NaN
+ (-10,0)           | {NaN,NaN,NaN}                         |                NaN
+ (-10,0)           | {0,-1,3}                              |                  3
+ (-10,0)           | {-1,0,3}                              |                 13
+ (-3,4)            | {0,-1,5}                              |                  1
+ (-3,4)            | {1,0,5}                               |                  2
+ (-3,4)            | {0,3,0}                               |                  4
+ (-3,4)            | {1,-1,0}                              |      4.94974746831
+ (-3,4)            | {-0.4,-1,-6}                          |      8.17059487979
+ (-3,4)            | {-0.000184615384615,-1,15.3846153846} |      11.3851690368
+ (-3,4)            | {3,NaN,5}                             |                NaN
+ (-3,4)            | {NaN,NaN,NaN}                         |                NaN
+ (-3,4)            | {0,-1,3}                              |                  1
+ (-3,4)            | {-1,0,3}                              |                  6
+ (5.1,34.5)        | {0,-1,5}                              |               29.5
+ (5.1,34.5)        | {1,0,5}                               |               10.1
+ (5.1,34.5)        | {0,3,0}                               |               34.5
+ (5.1,34.5)        | {1,-1,0}                              |      20.7889393669
+ (5.1,34.5)        | {-0.4,-1,-6}                          |      39.4973984303
+ (5.1,34.5)        | {-0.000184615384615,-1,15.3846153846} |      19.1163258281
+ (5.1,34.5)        | {3,NaN,5}                             |                NaN
+ (5.1,34.5)        | {NaN,NaN,NaN}                         |                NaN
+ (5.1,34.5)        | {0,-1,3}                              |               31.5
+ (5.1,34.5)        | {-1,0,3}                              |                2.1
+ (-5,-12)          | {0,-1,5}                              |                 17
+ (-5,-12)          | {1,0,5}                               |                  0
+ (-5,-12)          | {0,3,0}                               |                 12
+ (-5,-12)          | {1,-1,0}                              |      4.94974746831
+ (-5,-12)          | {-0.4,-1,-6}                          |      7.42781352708
+ (-5,-12)          | {-0.000184615384615,-1,15.3846153846} |      27.3855379948
+ (-5,-12)          | {3,NaN,5}                             |                NaN
+ (-5,-12)          | {NaN,NaN,NaN}                         |                NaN
+ (-5,-12)          | {0,-1,3}                              |                 15
+ (-5,-12)          | {-1,0,3}                              |                  8
+ (1e-300,-1e-300)  | {0,-1,5}                              |                  5
+ (1e-300,-1e-300)  | {1,0,5}                               |                  5
+ (1e-300,-1e-300)  | {0,3,0}                               |             1e-300
+ (1e-300,-1e-300)  | {1,-1,0}                              | 1.41421356237e-300
+ (1e-300,-1e-300)  | {-0.4,-1,-6}                          |      5.57086014531
+ (1e-300,-1e-300)  | {-0.000184615384615,-1,15.3846153846} |      15.3846151224
+ (1e-300,-1e-300)  | {3,NaN,5}                             |                NaN
+ (1e-300,-1e-300)  | {NaN,NaN,NaN}                         |                NaN
+ (1e-300,-1e-300)  | {0,-1,3}                              |                  3
+ (1e-300,-1e-300)  | {-1,0,3}                              |                  3
+ (1e+300,Infinity) | {0,-1,5}                              |           Infinity
+ (1e+300,Infinity) | {1,0,5}                               |                NaN
+ (1e+300,Infinity) | {0,3,0}                               |           Infinity
+ (1e+300,Infinity) | {1,-1,0}                              |           Infinity
+ (1e+300,Infinity) | {-0.4,-1,-6}                          |           Infinity
+ (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} |           Infinity
+ (1e+300,Infinity) | {3,NaN,5}                             |                NaN
+ (1e+300,Infinity) | {NaN,NaN,NaN}                         |                NaN
+ (1e+300,Infinity) | {0,-1,3}                              |           Infinity
+ (1e+300,Infinity) | {-1,0,3}                              |                NaN
+ (NaN,NaN)         | {0,-1,5}                              |                NaN
+ (NaN,NaN)         | {1,0,5}                               |                NaN
+ (NaN,NaN)         | {0,3,0}                               |                NaN
+ (NaN,NaN)         | {1,-1,0}                              |                NaN
+ (NaN,NaN)         | {-0.4,-1,-6}                          |                NaN
+ (NaN,NaN)         | {-0.000184615384615,-1,15.3846153846} |                NaN
+ (NaN,NaN)         | {3,NaN,5}                             |                NaN
+ (NaN,NaN)         | {NaN,NaN,NaN}                         |                NaN
+ (NaN,NaN)         | {0,-1,3}                              |                NaN
+ (NaN,NaN)         | {-1,0,3}                              |                NaN
+ (10,10)           | {0,-1,5}                              |                  5
+ (10,10)           | {1,0,5}                               |                 15
+ (10,10)           | {0,3,0}                               |                 10
+ (10,10)           | {1,-1,0}                              |                  0
+ (10,10)           | {-0.4,-1,-6}                          |      18.5695338177
+ (10,10)           | {-0.000184615384615,-1,15.3846153846} |      5.38276913903
+ (10,10)           | {3,NaN,5}                             |                NaN
+ (10,10)           | {NaN,NaN,NaN}                         |                NaN
+ (10,10)           | {0,-1,3}                              |                  7
+ (10,10)           | {-1,0,3}                              |                  7
+(90 rows)
+
+-- Distance to line segment
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LSEG_TBL l;
+        f1         |               s               |      ?column?      
+-------------------+-------------------------------+--------------------
+ (0,0)             | [(1,2),(3,4)]                 |       2.2360679775
+ (0,0)             | [(0,0),(6,6)]                 |                  0
+ (0,0)             | [(10,-10),(-3,-4)]            |      4.88901207039
+ (0,0)             | [(-1000000,200),(300000,-40)] |      15.3846151224
+ (0,0)             | [(11,22),(33,44)]             |      24.5967477525
+ (0,0)             | [(-10,2),(-10,3)]             |      10.1980390272
+ (0,0)             | [(0,-20),(30,-20)]            |                 20
+ (0,0)             | [(NaN,1),(NaN,90)]            |                NaN
+ (-10,0)           | [(1,2),(3,4)]                 |      11.1803398875
+ (-10,0)           | [(0,0),(6,6)]                 |                 10
+ (-10,0)           | [(10,-10),(-3,-4)]            |       8.0622577483
+ (-10,0)           | [(-1000000,200),(300000,-40)] |      15.3864612763
+ (-10,0)           | [(11,22),(33,44)]             |      30.4138126515
+ (-10,0)           | [(-10,2),(-10,3)]             |                  2
+ (-10,0)           | [(0,-20),(30,-20)]            |       22.360679775
+ (-10,0)           | [(NaN,1),(NaN,90)]            |                NaN
+ (-3,4)            | [(1,2),(3,4)]                 |        4.472135955
+ (-3,4)            | [(0,0),(6,6)]                 |      4.94974746831
+ (-3,4)            | [(10,-10),(-3,-4)]            |                  8
+ (-3,4)            | [(-1000000,200),(300000,-40)] |      11.3851690367
+ (-3,4)            | [(11,22),(33,44)]             |       22.803508502
+ (-3,4)            | [(-10,2),(-10,3)]             |      7.07106781187
+ (-3,4)            | [(0,-20),(30,-20)]            |      24.1867732449
+ (-3,4)            | [(NaN,1),(NaN,90)]            |                NaN
+ (5.1,34.5)        | [(1,2),(3,4)]                 |      30.5722096028
+ (5.1,34.5)        | [(0,0),(6,6)]                 |      28.5142069853
+ (5.1,34.5)        | [(10,-10),(-3,-4)]            |      39.3428519556
+ (5.1,34.5)        | [(-1000000,200),(300000,-40)] |      19.1163258281
+ (5.1,34.5)        | [(11,22),(33,44)]             |      13.0107647738
+ (5.1,34.5)        | [(-10,2),(-10,3)]             |       34.932220084
+ (5.1,34.5)        | [(0,-20),(30,-20)]            |               54.5
+ (5.1,34.5)        | [(NaN,1),(NaN,90)]            |                NaN
+ (-5,-12)          | [(1,2),(3,4)]                 |      15.2315462117
+ (-5,-12)          | [(0,0),(6,6)]                 |                 13
+ (-5,-12)          | [(10,-10),(-3,-4)]            |      8.10179143093
+ (-5,-12)          | [(-1000000,200),(300000,-40)] |      27.3855379949
+ (-5,-12)          | [(11,22),(33,44)]             |      37.5765884561
+ (-5,-12)          | [(-10,2),(-10,3)]             |      14.8660687473
+ (-5,-12)          | [(0,-20),(30,-20)]            |      9.43398113206
+ (-5,-12)          | [(NaN,1),(NaN,90)]            |                NaN
+ (1e-300,-1e-300)  | [(1,2),(3,4)]                 |       2.2360679775
+ (1e-300,-1e-300)  | [(0,0),(6,6)]                 | 1.41421356237e-300
+ (1e-300,-1e-300)  | [(10,-10),(-3,-4)]            |      4.88901207039
+ (1e-300,-1e-300)  | [(-1000000,200),(300000,-40)] |      15.3846151224
+ (1e-300,-1e-300)  | [(11,22),(33,44)]             |      24.5967477525
+ (1e-300,-1e-300)  | [(-10,2),(-10,3)]             |      10.1980390272
+ (1e-300,-1e-300)  | [(0,-20),(30,-20)]            |                 20
+ (1e-300,-1e-300)  | [(NaN,1),(NaN,90)]            |                NaN
+ (1e+300,Infinity) | [(1,2),(3,4)]                 |           Infinity
+ (1e+300,Infinity) | [(0,0),(6,6)]                 |           Infinity
+ (1e+300,Infinity) | [(10,-10),(-3,-4)]            |           Infinity
+ (1e+300,Infinity) | [(-1000000,200),(300000,-40)] |           Infinity
+ (1e+300,Infinity) | [(11,22),(33,44)]             |           Infinity
+ (1e+300,Infinity) | [(-10,2),(-10,3)]             |           Infinity
+ (1e+300,Infinity) | [(0,-20),(30,-20)]            |           Infinity
+ (1e+300,Infinity) | [(NaN,1),(NaN,90)]            |           Infinity
+ (NaN,NaN)         | [(1,2),(3,4)]                 |                NaN
+ (NaN,NaN)         | [(0,0),(6,6)]                 |                NaN
+ (NaN,NaN)         | [(10,-10),(-3,-4)]            |                NaN
+ (NaN,NaN)         | [(-1000000,200),(300000,-40)] |                NaN
+ (NaN,NaN)         | [(11,22),(33,44)]             |                NaN
+ (NaN,NaN)         | [(-10,2),(-10,3)]             |                NaN
+ (NaN,NaN)         | [(0,-20),(30,-20)]            |                NaN
+ (NaN,NaN)         | [(NaN,1),(NaN,90)]            |                NaN
+ (10,10)           | [(1,2),(3,4)]                 |      9.21954445729
+ (10,10)           | [(0,0),(6,6)]                 |      5.65685424949
+ (10,10)           | [(10,-10),(-3,-4)]            |        18.15918769
+ (10,10)           | [(-1000000,200),(300000,-40)] |      5.38276913904
+ (10,10)           | [(11,22),(33,44)]             |      12.0415945788
+ (10,10)           | [(-10,2),(-10,3)]             |      21.1896201004
+ (10,10)           | [(0,-20),(30,-20)]            |                 30
+ (10,10)           | [(NaN,1),(NaN,90)]            |                NaN
+(72 rows)
+
+-- Distance to box
+SELECT p.f1, b.f1, p.f1 <-> b.f1 FROM POINT_TBL p, BOX_TBL b;
+        f1         |         f1          |      ?column?      
+-------------------+---------------------+--------------------
+ (0,0)             | (2,2),(0,0)         |                  0
+ (0,0)             | (3,3),(1,1)         |      1.41421356237
+ (0,0)             | (-2,2),(-8,-10)     |                  2
+ (0,0)             | (2.5,3.5),(2.5,2.5) |      3.53553390593
+ (0,0)             | (3,3),(3,3)         |      4.24264068712
+ (-10,0)           | (2,2),(0,0)         |                 10
+ (-10,0)           | (3,3),(1,1)         |      11.0453610172
+ (-10,0)           | (-2,2),(-8,-10)     |                  2
+ (-10,0)           | (2.5,3.5),(2.5,2.5) |       12.747548784
+ (-10,0)           | (3,3),(3,3)         |      13.3416640641
+ (-3,4)            | (2,2),(0,0)         |      3.60555127546
+ (-3,4)            | (3,3),(1,1)         |      4.12310562562
+ (-3,4)            | (-2,2),(-8,-10)     |                  2
+ (-3,4)            | (2.5,3.5),(2.5,2.5) |      5.52268050859
+ (-3,4)            | (3,3),(3,3)         |       6.0827625303
+ (5.1,34.5)        | (2,2),(0,0)         |      32.6475113906
+ (5.1,34.5)        | (3,3),(1,1)         |      31.5699223946
+ (5.1,34.5)        | (-2,2),(-8,-10)     |      33.2664996656
+ (5.1,34.5)        | (2.5,3.5),(2.5,2.5) |       31.108841187
+ (5.1,34.5)        | (3,3),(3,3)         |      31.5699223946
+ (-5,-12)          | (2,2),(0,0)         |                 13
+ (-5,-12)          | (3,3),(1,1)         |      14.3178210633
+ (-5,-12)          | (-2,2),(-8,-10)     |                  2
+ (-5,-12)          | (2.5,3.5),(2.5,2.5) |      16.3248277173
+ (-5,-12)          | (3,3),(3,3)         |                 17
+ (1e-300,-1e-300)  | (2,2),(0,0)         | 1.41421356237e-300
+ (1e-300,-1e-300)  | (3,3),(1,1)         |      1.41421356237
+ (1e-300,-1e-300)  | (-2,2),(-8,-10)     |                  2
+ (1e-300,-1e-300)  | (2.5,3.5),(2.5,2.5) |      3.53553390593
+ (1e-300,-1e-300)  | (3,3),(3,3)         |      4.24264068712
+ (1e+300,Infinity) | (2,2),(0,0)         |           Infinity
+ (1e+300,Infinity) | (3,3),(1,1)         |           Infinity
+ (1e+300,Infinity) | (-2,2),(-8,-10)     |           Infinity
+ (1e+300,Infinity) | (2.5,3.5),(2.5,2.5) |           Infinity
+ (1e+300,Infinity) | (3,3),(3,3)         |           Infinity
+ (NaN,NaN)         | (2,2),(0,0)         |                NaN
+ (NaN,NaN)         | (3,3),(1,1)         |                NaN
+ (NaN,NaN)         | (-2,2),(-8,-10)     |                NaN
+ (NaN,NaN)         | (2.5,3.5),(2.5,2.5) |                NaN
+ (NaN,NaN)         | (3,3),(3,3)         |                NaN
+ (10,10)           | (2,2),(0,0)         |       11.313708499
+ (10,10)           | (3,3),(1,1)         |      9.89949493661
+ (10,10)           | (-2,2),(-8,-10)     |      14.4222051019
+ (10,10)           | (2.5,3.5),(2.5,2.5) |      9.92471662064
+ (10,10)           | (3,3),(3,3)         |      9.89949493661
+(45 rows)
+
+-- Distance to path
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, PATH_TBL p1;
+        f1         |            f1             |      ?column?      
+-------------------+---------------------------+--------------------
+ (0,0)             | [(1,2),(3,4)]             |       2.2360679775
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | [(0,0),(3,0),(4,5),(1,6)] |                  0
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | [(1,2),(3,4)]             |       2.2360679775
+ (0,0)             | ((10,20))                 |       22.360679775
+ (0,0)             | [(11,12),(13,14)]         |      16.2788205961
+ (0,0)             | ((11,12),(13,14))         |      16.2788205961
+ (-10,0)           | [(1,2),(3,4)]             |      11.1803398875
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | [(0,0),(3,0),(4,5),(1,6)] |                 10
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | [(1,2),(3,4)]             |      11.1803398875
+ (-10,0)           | ((10,20))                 |      28.2842712475
+ (-10,0)           | [(11,12),(13,14)]         |      24.1867732449
+ (-10,0)           | ((11,12),(13,14))         |      24.1867732449
+ (-3,4)            | [(1,2),(3,4)]             |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | [(0,0),(3,0),(4,5),(1,6)] |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | [(1,2),(3,4)]             |        4.472135955
+ (-3,4)            | ((10,20))                 |      20.6155281281
+ (-3,4)            | [(11,12),(13,14)]         |      16.1245154966
+ (-3,4)            | ((11,12),(13,14))         |      16.1245154966
+ (5.1,34.5)        | [(1,2),(3,4)]             |      30.5722096028
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | [(0,0),(3,0),(4,5),(1,6)] |       28.793402022
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | [(1,2),(3,4)]             |      30.5722096028
+ (5.1,34.5)        | ((10,20))                 |      15.3055545473
+ (5.1,34.5)        | [(11,12),(13,14)]         |      21.9695243462
+ (5.1,34.5)        | ((11,12),(13,14))         |      21.9695243462
+ (-5,-12)          | [(1,2),(3,4)]             |      15.2315462117
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | [(0,0),(3,0),(4,5),(1,6)] |                 13
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | [(1,2),(3,4)]             |      15.2315462117
+ (-5,-12)          | ((10,20))                 |      35.3411940941
+ (-5,-12)          | [(11,12),(13,14)]         |      28.8444102037
+ (-5,-12)          | ((11,12),(13,14))         |      28.8444102037
+ (1e-300,-1e-300)  | [(1,2),(3,4)]             |       2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | [(0,0),(3,0),(4,5),(1,6)] | 1.41421356237e-300
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | [(1,2),(3,4)]             |       2.2360679775
+ (1e-300,-1e-300)  | ((10,20))                 |       22.360679775
+ (1e-300,-1e-300)  | [(11,12),(13,14)]         |      16.2788205961
+ (1e-300,-1e-300)  | ((11,12),(13,14))         |      16.2788205961
+ (1e+300,Infinity) | [(1,2),(3,4)]             |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | [(0,0),(3,0),(4,5),(1,6)] |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | [(1,2),(3,4)]             |           Infinity
+ (1e+300,Infinity) | ((10,20))                 |           Infinity
+ (1e+300,Infinity) | [(11,12),(13,14)]         |           Infinity
+ (1e+300,Infinity) | ((11,12),(13,14))         |           Infinity
+ (NaN,NaN)         | [(1,2),(3,4)]             |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | [(0,0),(3,0),(4,5),(1,6)] |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | [(1,2),(3,4)]             |                NaN
+ (NaN,NaN)         | ((10,20))                 |                NaN
+ (NaN,NaN)         | [(11,12),(13,14)]         |                NaN
+ (NaN,NaN)         | ((11,12),(13,14))         |                NaN
+ (10,10)           | [(1,2),(3,4)]             |      9.21954445729
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | [(0,0),(3,0),(4,5),(1,6)] |      7.81024967591
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | [(1,2),(3,4)]             |      9.21954445729
+ (10,10)           | ((10,20))                 |                 10
+ (10,10)           | [(11,12),(13,14)]         |       2.2360679775
+ (10,10)           | ((11,12),(13,14))         |       2.2360679775
+(81 rows)
+
+-- Distance to polygon
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, POLYGON_TBL p1;
+        f1         |             f1             |   ?column?    
+-------------------+----------------------------+---------------
+ (0,0)             | ((2,0),(2,4),(0,0))        |             0
+ (0,0)             | ((3,1),(3,3),(1,0))        |             1
+ (0,0)             | ((1,2),(3,4),(5,6),(7,8))  |  2.2360679775
+ (0,0)             | ((7,8),(5,6),(3,4),(1,2))  |  2.2360679775
+ (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | 1.58113883008
+ (0,0)             | ((0,0))                    |             0
+ (0,0)             | ((0,1),(0,1))              |             1
+ (-10,0)           | ((2,0),(2,4),(0,0))        |            10
+ (-10,0)           | ((3,1),(3,3),(1,0))        |            11
+ (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | 11.1803398875
+ (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | 11.1803398875
+ (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | 11.1803398875
+ (-10,0)           | ((0,0))                    |            10
+ (-10,0)           | ((0,1),(0,1))              | 10.0498756211
+ (-3,4)            | ((2,0),(2,4),(0,0))        |   4.472135955
+ (-3,4)            | ((3,1),(3,3),(1,0))        | 5.54700196225
+ (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  |   4.472135955
+ (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  |   4.472135955
+ (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) |   4.472135955
+ (-3,4)            | ((0,0))                    |             5
+ (-3,4)            | ((0,1),(0,1))              | 4.24264068712
+ (5.1,34.5)        | ((2,0),(2,4),(0,0))        | 30.6571362002
+ (5.1,34.5)        | ((3,1),(3,3),(1,0))        | 31.5699223946
+ (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | 26.5680258958
+ (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | 26.5680258958
+ (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | 26.5680258958
+ (5.1,34.5)        | ((0,0))                    | 34.8749193547
+ (5.1,34.5)        | ((0,1),(0,1))              | 33.8859853037
+ (-5,-12)          | ((2,0),(2,4),(0,0))        |            13
+ (-5,-12)          | ((3,1),(3,3),(1,0))        |  13.416407865
+ (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | 15.2315462117
+ (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | 15.2315462117
+ (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) |  11.313708499
+ (-5,-12)          | ((0,0))                    |            13
+ (-5,-12)          | ((0,1),(0,1))              | 13.9283882772
+ (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        |             0
+ (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        |             1
+ (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  |  2.2360679775
+ (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  |  2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | 1.58113883008
+ (1e-300,-1e-300)  | ((0,0))                    |             0
+ (1e-300,-1e-300)  | ((0,1),(0,1))              |             1
+ (1e+300,Infinity) | ((2,0),(2,4),(0,0))        |      Infinity
+ (1e+300,Infinity) | ((3,1),(3,3),(1,0))        |      Infinity
+ (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  |      Infinity
+ (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  |      Infinity
+ (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) |      Infinity
+ (1e+300,Infinity) | ((0,0))                    |      Infinity
+ (1e+300,Infinity) | ((0,1),(0,1))              |      Infinity
+ (NaN,NaN)         | ((2,0),(2,4),(0,0))        |             0
+ (NaN,NaN)         | ((3,1),(3,3),(1,0))        |             0
+ (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  |             0
+ (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  |             0
+ (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) |             0
+ (NaN,NaN)         | ((0,0))                    |             0
+ (NaN,NaN)         | ((0,1),(0,1))              |             0
+ (10,10)           | ((2,0),(2,4),(0,0))        |            10
+ (10,10)           | ((3,1),(3,3),(1,0))        | 9.89949493661
+ (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | 3.60555127546
+ (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | 3.60555127546
+ (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | 3.60555127546
+ (10,10)           | ((0,0))                    | 14.1421356237
+ (10,10)           | ((0,1),(0,1))              | 13.4536240471
+(63 rows)
+
+-- Closest point to line
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LINE_TBL l;
+        f1         |                   s                   |             ?column?             
+-------------------+---------------------------------------+----------------------------------
+ (0,0)             | {0,-1,5}                              | (0,5)
+ (0,0)             | {1,0,5}                               | (-5,0)
+ (0,0)             | {0,3,0}                               | (0,0)
+ (0,0)             | {1,-1,0}                              | (0,0)
+ (0,0)             | {-0.4,-1,-6}                          | (-2.06896551724,-5.1724137931)
+ (0,0)             | {-0.000184615384615,-1,15.3846153846} | (0.00284023658959,15.3846148603)
+ (0,0)             | {3,NaN,5}                             | 
+ (0,0)             | {NaN,NaN,NaN}                         | 
+ (0,0)             | {0,-1,3}                              | (0,3)
+ (0,0)             | {-1,0,3}                              | (3,0)
+ (-10,0)           | {0,-1,5}                              | (-10,5)
+ (-10,0)           | {1,0,5}                               | (-5,0)
+ (-10,0)           | {0,3,0}                               | (-10,0)
+ (-10,0)           | {1,-1,0}                              | (-5,-5)
+ (-10,0)           | {-0.4,-1,-6}                          | (-10.6896551724,-1.72413793103)
+ (-10,0)           | {-0.000184615384615,-1,15.3846153846} | (-9.99715942258,15.386461014)
+ (-10,0)           | {3,NaN,5}                             | 
+ (-10,0)           | {NaN,NaN,NaN}                         | 
+ (-10,0)           | {0,-1,3}                              | (-10,3)
+ (-10,0)           | {-1,0,3}                              | (3,0)
+ (-3,4)            | {0,-1,5}                              | (-3,5)
+ (-3,4)            | {1,0,5}                               | (-5,4)
+ (-3,4)            | {0,3,0}                               | (-3,0)
+ (-3,4)            | {1,-1,0}                              | (0.5,0.5)
+ (-3,4)            | {-0.4,-1,-6}                          | (-6.03448275862,-3.58620689655)
+ (-3,4)            | {-0.000184615384615,-1,15.3846153846} | (-2.99789812268,15.3851688427)
+ (-3,4)            | {3,NaN,5}                             | 
+ (-3,4)            | {NaN,NaN,NaN}                         | 
+ (-3,4)            | {0,-1,3}                              | (-3,3)
+ (-3,4)            | {-1,0,3}                              | (3,4)
+ (5.1,34.5)        | {0,-1,5}                              | (5.1,5)
+ (5.1,34.5)        | {1,0,5}                               | (-5,34.5)
+ (5.1,34.5)        | {0,3,0}                               | (5.1,0)
+ (5.1,34.5)        | {1,-1,0}                              | (19.8,19.8)
+ (5.1,34.5)        | {-0.4,-1,-6}                          | (-9.56896551724,-2.1724137931)
+ (5.1,34.5)        | {-0.000184615384615,-1,15.3846153846} | (5.09647083221,15.3836744977)
+ (5.1,34.5)        | {3,NaN,5}                             | 
+ (5.1,34.5)        | {NaN,NaN,NaN}                         | 
+ (5.1,34.5)        | {0,-1,3}                              | (5.1,3)
+ (5.1,34.5)        | {-1,0,3}                              | (3,34.5)
+ (-5,-12)          | {0,-1,5}                              | (-5,5)
+ (-5,-12)          | {1,0,5}                               | (-5,-12)
+ (-5,-12)          | {0,3,0}                               | (-5,0)
+ (-5,-12)          | {1,-1,0}                              | (-8.5,-8.5)
+ (-5,-12)          | {-0.4,-1,-6}                          | (-2.24137931034,-5.10344827586)
+ (-5,-12)          | {-0.000184615384615,-1,15.3846153846} | (-4.99494420846,15.3855375282)
+ (-5,-12)          | {3,NaN,5}                             | 
+ (-5,-12)          | {NaN,NaN,NaN}                         | 
+ (-5,-12)          | {0,-1,3}                              | (-5,3)
+ (-5,-12)          | {-1,0,3}                              | (3,-12)
+ (1e-300,-1e-300)  | {0,-1,5}                              | (1e-300,5)
+ (1e-300,-1e-300)  | {1,0,5}                               | (-5,-1e-300)
+ (1e-300,-1e-300)  | {0,3,0}                               | (1e-300,0)
+ (1e-300,-1e-300)  | {1,-1,0}                              | (0,0)
+ (1e-300,-1e-300)  | {-0.4,-1,-6}                          | (-2.06896551724,-5.1724137931)
+ (1e-300,-1e-300)  | {-0.000184615384615,-1,15.3846153846} | (0.00284023658959,15.3846148603)
+ (1e-300,-1e-300)  | {3,NaN,5}                             | 
+ (1e-300,-1e-300)  | {NaN,NaN,NaN}                         | 
+ (1e-300,-1e-300)  | {0,-1,3}                              | (1e-300,3)
+ (1e-300,-1e-300)  | {-1,0,3}                              | (3,-1e-300)
+ (1e+300,Infinity) | {0,-1,5}                              | (1e+300,5)
+ (1e+300,Infinity) | {1,0,5}                               | 
+ (1e+300,Infinity) | {0,3,0}                               | (1e+300,0)
+ (1e+300,Infinity) | {1,-1,0}                              | (Infinity,NaN)
+ (1e+300,Infinity) | {-0.4,-1,-6}                          | (-Infinity,NaN)
+ (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} | (-Infinity,NaN)
+ (1e+300,Infinity) | {3,NaN,5}                             | 
+ (1e+300,Infinity) | {NaN,NaN,NaN}                         | 
+ (1e+300,Infinity) | {0,-1,3}                              | (1e+300,3)
+ (1e+300,Infinity) | {-1,0,3}                              | 
+ (NaN,NaN)         | {0,-1,5}                              | 
+ (NaN,NaN)         | {1,0,5}                               | 
+ (NaN,NaN)         | {0,3,0}                               | 
+ (NaN,NaN)         | {1,-1,0}                              | 
+ (NaN,NaN)         | {-0.4,-1,-6}                          | 
+ (NaN,NaN)         | {-0.000184615384615,-1,15.3846153846} | 
+ (NaN,NaN)         | {3,NaN,5}                             | 
+ (NaN,NaN)         | {NaN,NaN,NaN}                         | 
+ (NaN,NaN)         | {0,-1,3}                              | 
+ (NaN,NaN)         | {-1,0,3}                              | 
+ (10,10)           | {0,-1,5}                              | (10,5)
+ (10,10)           | {1,0,5}                               | (-5,10)
+ (10,10)           | {0,3,0}                               | (10,0)
+ (10,10)           | {1,-1,0}                              | (10,10)
+ (10,10)           | {-0.4,-1,-6}                          | (3.10344827586,-7.24137931034)
+ (10,10)           | {-0.000184615384615,-1,15.3846153846} | (10.000993742,15.3827690473)
+ (10,10)           | {3,NaN,5}                             | 
+ (10,10)           | {NaN,NaN,NaN}                         | 
+ (10,10)           | {0,-1,3}                              | (10,3)
+ (10,10)           | {-1,0,3}                              | (3,10)
+(90 rows)
+
+-- Closest point to line segment
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LSEG_TBL l;
+        f1         |               s               |             ?column?             
+-------------------+-------------------------------+----------------------------------
+ (0,0)             | [(1,2),(3,4)]                 | (1,2)
+ (0,0)             | [(0,0),(6,6)]                 | (0,0)
+ (0,0)             | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ (0,0)             | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
+ (0,0)             | [(11,22),(33,44)]             | (11,22)
+ (0,0)             | [(-10,2),(-10,3)]             | (-10,2)
+ (0,0)             | [(0,-20),(30,-20)]            | (0,-20)
+ (0,0)             | [(NaN,1),(NaN,90)]            | 
+ (-10,0)           | [(1,2),(3,4)]                 | (1,2)
+ (-10,0)           | [(0,0),(6,6)]                 | (0,0)
+ (-10,0)           | [(10,-10),(-3,-4)]            | (-3,-4)
+ (-10,0)           | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
+ (-10,0)           | [(11,22),(33,44)]             | (11,22)
+ (-10,0)           | [(-10,2),(-10,3)]             | (-10,2)
+ (-10,0)           | [(0,-20),(30,-20)]            | (0,-20)
+ (-10,0)           | [(NaN,1),(NaN,90)]            | 
+ (-3,4)            | [(1,2),(3,4)]                 | (1,2)
+ (-3,4)            | [(0,0),(6,6)]                 | (0.5,0.5)
+ (-3,4)            | [(10,-10),(-3,-4)]            | (-3,-4)
+ (-3,4)            | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
+ (-3,4)            | [(11,22),(33,44)]             | (11,22)
+ (-3,4)            | [(-10,2),(-10,3)]             | (-10,3)
+ (-3,4)            | [(0,-20),(30,-20)]            | (0,-20)
+ (-3,4)            | [(NaN,1),(NaN,90)]            | 
+ (5.1,34.5)        | [(1,2),(3,4)]                 | (3,4)
+ (5.1,34.5)        | [(0,0),(6,6)]                 | (6,6)
+ (5.1,34.5)        | [(10,-10),(-3,-4)]            | (-3,-4)
+ (5.1,34.5)        | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
+ (5.1,34.5)        | [(11,22),(33,44)]             | (14.3,25.3)
+ (5.1,34.5)        | [(-10,2),(-10,3)]             | (-10,3)
+ (5.1,34.5)        | [(0,-20),(30,-20)]            | (5.1,-20)
+ (5.1,34.5)        | [(NaN,1),(NaN,90)]            | 
+ (-5,-12)          | [(1,2),(3,4)]                 | (1,2)
+ (-5,-12)          | [(0,0),(6,6)]                 | (0,0)
+ (-5,-12)          | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
+ (-5,-12)          | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
+ (-5,-12)          | [(11,22),(33,44)]             | (11,22)
+ (-5,-12)          | [(-10,2),(-10,3)]             | (-10,2)
+ (-5,-12)          | [(0,-20),(30,-20)]            | (0,-20)
+ (-5,-12)          | [(NaN,1),(NaN,90)]            | 
+ (1e-300,-1e-300)  | [(1,2),(3,4)]                 | (1,2)
+ (1e-300,-1e-300)  | [(0,0),(6,6)]                 | (0,0)
+ (1e-300,-1e-300)  | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ (1e-300,-1e-300)  | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
+ (1e-300,-1e-300)  | [(11,22),(33,44)]             | (11,22)
+ (1e-300,-1e-300)  | [(-10,2),(-10,3)]             | (-10,2)
+ (1e-300,-1e-300)  | [(0,-20),(30,-20)]            | (0,-20)
+ (1e-300,-1e-300)  | [(NaN,1),(NaN,90)]            | 
+ (1e+300,Infinity) | [(1,2),(3,4)]                 | (3,4)
+ (1e+300,Infinity) | [(0,0),(6,6)]                 | (6,6)
+ (1e+300,Infinity) | [(10,-10),(-3,-4)]            | (-3,-4)
+ (1e+300,Infinity) | [(-1000000,200),(300000,-40)] | (300000,-40)
+ (1e+300,Infinity) | [(11,22),(33,44)]             | (33,44)
+ (1e+300,Infinity) | [(-10,2),(-10,3)]             | (-10,3)
+ (1e+300,Infinity) | [(0,-20),(30,-20)]            | (30,-20)
+ (1e+300,Infinity) | [(NaN,1),(NaN,90)]            | (NaN,90)
+ (NaN,NaN)         | [(1,2),(3,4)]                 | 
+ (NaN,NaN)         | [(0,0),(6,6)]                 | 
+ (NaN,NaN)         | [(10,-10),(-3,-4)]            | 
+ (NaN,NaN)         | [(-1000000,200),(300000,-40)] | 
+ (NaN,NaN)         | [(11,22),(33,44)]             | 
+ (NaN,NaN)         | [(-10,2),(-10,3)]             | 
+ (NaN,NaN)         | [(0,-20),(30,-20)]            | 
+ (NaN,NaN)         | [(NaN,1),(NaN,90)]            | 
+ (10,10)           | [(1,2),(3,4)]                 | (3,4)
+ (10,10)           | [(0,0),(6,6)]                 | (6,6)
+ (10,10)           | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
+ (10,10)           | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
+ (10,10)           | [(11,22),(33,44)]             | (11,22)
+ (10,10)           | [(-10,2),(-10,3)]             | (-10,3)
+ (10,10)           | [(0,-20),(30,-20)]            | (10,-20)
+ (10,10)           | [(NaN,1),(NaN,90)]            | 
+(72 rows)
+
+-- Closest point to box
+SELECT p.f1, b.f1, p.f1 ## b.f1 FROM POINT_TBL p, BOX_TBL b;
+        f1         |         f1          |   ?column?   
+-------------------+---------------------+--------------
+ (0,0)             | (2,2),(0,0)         | (0,0)
+ (0,0)             | (3,3),(1,1)         | (1,1)
+ (0,0)             | (-2,2),(-8,-10)     | (-2,0)
+ (0,0)             | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (0,0)             | (3,3),(3,3)         | (3,3)
+ (-10,0)           | (2,2),(0,0)         | (0,0)
+ (-10,0)           | (3,3),(1,1)         | (1,1)
+ (-10,0)           | (-2,2),(-8,-10)     | (-8,0)
+ (-10,0)           | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (-10,0)           | (3,3),(3,3)         | (3,3)
+ (-3,4)            | (2,2),(0,0)         | (0,2)
+ (-3,4)            | (3,3),(1,1)         | (1,3)
+ (-3,4)            | (-2,2),(-8,-10)     | (-3,2)
+ (-3,4)            | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (-3,4)            | (3,3),(3,3)         | (3,3)
+ (5.1,34.5)        | (2,2),(0,0)         | (2,2)
+ (5.1,34.5)        | (3,3),(1,1)         | (3,3)
+ (5.1,34.5)        | (-2,2),(-8,-10)     | (-2,2)
+ (5.1,34.5)        | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (5.1,34.5)        | (3,3),(3,3)         | (3,3)
+ (-5,-12)          | (2,2),(0,0)         | (0,0)
+ (-5,-12)          | (3,3),(1,1)         | (1,1)
+ (-5,-12)          | (-2,2),(-8,-10)     | (-5,-10)
+ (-5,-12)          | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (-5,-12)          | (3,3),(3,3)         | (3,3)
+ (1e-300,-1e-300)  | (2,2),(0,0)         | (0,0)
+ (1e-300,-1e-300)  | (3,3),(1,1)         | (1,1)
+ (1e-300,-1e-300)  | (-2,2),(-8,-10)     | (-2,-1e-300)
+ (1e-300,-1e-300)  | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (1e-300,-1e-300)  | (3,3),(3,3)         | (3,3)
+ (1e+300,Infinity) | (2,2),(0,0)         | (0,2)
+ (1e+300,Infinity) | (3,3),(1,1)         | (1,3)
+ (1e+300,Infinity) | (-2,2),(-8,-10)     | (-8,2)
+ (1e+300,Infinity) | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (1e+300,Infinity) | (3,3),(3,3)         | (3,3)
+ (NaN,NaN)         | (2,2),(0,0)         | 
+ (NaN,NaN)         | (3,3),(1,1)         | 
+ (NaN,NaN)         | (-2,2),(-8,-10)     | 
+ (NaN,NaN)         | (2.5,3.5),(2.5,2.5) | 
+ (NaN,NaN)         | (3,3),(3,3)         | 
+ (10,10)           | (2,2),(0,0)         | (2,2)
+ (10,10)           | (3,3),(1,1)         | (3,3)
+ (10,10)           | (-2,2),(-8,-10)     | (-2,2)
+ (10,10)           | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (10,10)           | (3,3),(3,3)         | (3,3)
+(45 rows)
+
+-- On line
+SELECT p.f1, l.s FROM POINT_TBL p, LINE_TBL l WHERE p.f1 <@ l.s;
+        f1        |    s     
+------------------+----------
+ (0,0)            | {0,3,0}
+ (0,0)            | {1,-1,0}
+ (-10,0)          | {0,3,0}
+ (-5,-12)         | {1,0,5}
+ (1e-300,-1e-300) | {0,3,0}
+ (1e-300,-1e-300) | {1,-1,0}
+ (10,10)          | {1,-1,0}
+(7 rows)
+
+-- On line segment
+SELECT p.f1, l.s FROM POINT_TBL p, LSEG_TBL l WHERE p.f1 <@ l.s;
+        f1        |       s       
+------------------+---------------
+ (0,0)            | [(0,0),(6,6)]
+ (1e-300,-1e-300) | [(0,0),(6,6)]
+(2 rows)
+
+-- On path
+SELECT p.f1, p1.f1 FROM POINT_TBL p, PATH_TBL p1 WHERE p.f1 <@ p1.f1;
+        f1        |            f1             
+------------------+---------------------------
+ (0,0)            | [(0,0),(3,0),(4,5),(1,6)]
+ (1e-300,-1e-300) | [(0,0),(3,0),(4,5),(1,6)]
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((10,20))
+ (NaN,NaN)        | ((11,12),(13,14))
+(7 rows)
+
+--
+-- Lines
+--
+-- Vertical
+SELECT s FROM LINE_TBL WHERE ?| s;
+    s     
+----------
+ {1,0,5}
+ {-1,0,3}
+(2 rows)
+
+-- Horizontal
+SELECT s FROM LINE_TBL WHERE ?- s;
+    s     
+----------
+ {0,-1,5}
+ {0,3,0}
+ {0,-1,3}
+(3 rows)
+
+-- Same as line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s = l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {0,-1,5}
+ {1,0,5}                               | {1,0,5}
+ {0,3,0}                               | {0,3,0}
+ {1,-1,0}                              | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846}
+ {3,NaN,5}                             | {3,NaN,5}
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}
+ {0,-1,3}                              | {0,-1,3}
+ {-1,0,3}                              | {-1,0,3}
+(10 rows)
+
+-- Parallel to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?|| l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {0,-1,5}
+ {0,-1,5}                              | {0,3,0}
+ {0,-1,5}                              | {0,-1,3}
+ {1,0,5}                               | {1,0,5}
+ {1,0,5}                               | {-1,0,3}
+ {0,3,0}                               | {0,-1,5}
+ {0,3,0}                               | {0,3,0}
+ {0,3,0}                               | {0,-1,3}
+ {1,-1,0}                              | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,3}                              | {0,-1,5}
+ {0,-1,3}                              | {0,3,0}
+ {0,-1,3}                              | {0,-1,3}
+ {-1,0,3}                              | {1,0,5}
+ {-1,0,3}                              | {-1,0,3}
+(16 rows)
+
+-- Perpendicular to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?-| l2.s;
+    s     |    s     
+----------+----------
+ {0,-1,5} | {1,0,5}
+ {0,-1,5} | {-1,0,3}
+ {1,0,5}  | {0,-1,5}
+ {1,0,5}  | {0,3,0}
+ {1,0,5}  | {0,-1,3}
+ {0,3,0}  | {1,0,5}
+ {0,3,0}  | {-1,0,3}
+ {0,-1,3} | {1,0,5}
+ {0,-1,3} | {-1,0,3}
+ {-1,0,3} | {0,-1,5}
+ {-1,0,3} | {0,3,0}
+ {-1,0,3} | {0,-1,3}
+(12 rows)
+
+-- Distance to line
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2;
+                   s                   |                   s                   | ?column? 
+---------------------------------------+---------------------------------------+----------
+ {0,-1,5}                              | {0,-1,5}                              |        0
+ {0,-1,5}                              | {1,0,5}                               |        0
+ {0,-1,5}                              | {0,3,0}                               |        5
+ {0,-1,5}                              | {1,-1,0}                              |        0
+ {0,-1,5}                              | {-0.4,-1,-6}                          |        0
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,-1,5}                              | {3,NaN,5}                             |        0
+ {0,-1,5}                              | {NaN,NaN,NaN}                         |        0
+ {0,-1,5}                              | {0,-1,3}                              |        2
+ {0,-1,5}                              | {-1,0,3}                              |        0
+ {1,0,5}                               | {0,-1,5}                              |        0
+ {1,0,5}                               | {1,0,5}                               |        0
+ {1,0,5}                               | {0,3,0}                               |        0
+ {1,0,5}                               | {1,-1,0}                              |        0
+ {1,0,5}                               | {-0.4,-1,-6}                          |        0
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846} |        0
+ {1,0,5}                               | {3,NaN,5}                             |        0
+ {1,0,5}                               | {NaN,NaN,NaN}                         |        0
+ {1,0,5}                               | {0,-1,3}                              |        0
+ {1,0,5}                               | {-1,0,3}                              |        8
+ {0,3,0}                               | {0,-1,5}                              |        5
+ {0,3,0}                               | {1,0,5}                               |        0
+ {0,3,0}                               | {0,3,0}                               |        0
+ {0,3,0}                               | {1,-1,0}                              |        0
+ {0,3,0}                               | {-0.4,-1,-6}                          |        0
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,3,0}                               | {3,NaN,5}                             |        0
+ {0,3,0}                               | {NaN,NaN,NaN}                         |        0
+ {0,3,0}                               | {0,-1,3}                              |        3
+ {0,3,0}                               | {-1,0,3}                              |        0
+ {1,-1,0}                              | {0,-1,5}                              |        0
+ {1,-1,0}                              | {1,0,5}                               |        0
+ {1,-1,0}                              | {0,3,0}                               |        0
+ {1,-1,0}                              | {1,-1,0}                              |        0
+ {1,-1,0}                              | {-0.4,-1,-6}                          |        0
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {1,-1,0}                              | {3,NaN,5}                             |        0
+ {1,-1,0}                              | {NaN,NaN,NaN}                         |        0
+ {1,-1,0}                              | {0,-1,3}                              |        0
+ {1,-1,0}                              | {-1,0,3}                              |        0
+ {-0.4,-1,-6}                          | {0,-1,5}                              |        0
+ {-0.4,-1,-6}                          | {1,0,5}                               |        0
+ {-0.4,-1,-6}                          | {0,3,0}                               |        0
+ {-0.4,-1,-6}                          | {1,-1,0}                              |        0
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}                          |        0
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846} |        0
+ {-0.4,-1,-6}                          | {3,NaN,5}                             |        0
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}                         |        0
+ {-0.4,-1,-6}                          | {0,-1,3}                              |        0
+ {-0.4,-1,-6}                          | {-1,0,3}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}                               |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}                               |        0
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}                          |        0
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} |        0
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}                             |        0
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}                         |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}                              |        0
+ {3,NaN,5}                             | {0,-1,5}                              |        0
+ {3,NaN,5}                             | {1,0,5}                               |        0
+ {3,NaN,5}                             | {0,3,0}                               |        0
+ {3,NaN,5}                             | {1,-1,0}                              |        0
+ {3,NaN,5}                             | {-0.4,-1,-6}                          |        0
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846} |        0
+ {3,NaN,5}                             | {3,NaN,5}                             |        0
+ {3,NaN,5}                             | {NaN,NaN,NaN}                         |        0
+ {3,NaN,5}                             | {0,-1,3}                              |        0
+ {3,NaN,5}                             | {-1,0,3}                              |        0
+ {NaN,NaN,NaN}                         | {0,-1,5}                              |        0
+ {NaN,NaN,NaN}                         | {1,0,5}                               |        0
+ {NaN,NaN,NaN}                         | {0,3,0}                               |        0
+ {NaN,NaN,NaN}                         | {1,-1,0}                              |        0
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}                          |        0
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846} |        0
+ {NaN,NaN,NaN}                         | {3,NaN,5}                             |        0
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}                         |        0
+ {NaN,NaN,NaN}                         | {0,-1,3}                              |        0
+ {NaN,NaN,NaN}                         | {-1,0,3}                              |        0
+ {0,-1,3}                              | {0,-1,5}                              |        2
+ {0,-1,3}                              | {1,0,5}                               |        0
+ {0,-1,3}                              | {0,3,0}                               |        3
+ {0,-1,3}                              | {1,-1,0}                              |        0
+ {0,-1,3}                              | {-0.4,-1,-6}                          |        0
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,-1,3}                              | {3,NaN,5}                             |        0
+ {0,-1,3}                              | {NaN,NaN,NaN}                         |        0
+ {0,-1,3}                              | {0,-1,3}                              |        0
+ {0,-1,3}                              | {-1,0,3}                              |        0
+ {-1,0,3}                              | {0,-1,5}                              |        0
+ {-1,0,3}                              | {1,0,5}                               |        8
+ {-1,0,3}                              | {0,3,0}                               |        0
+ {-1,0,3}                              | {1,-1,0}                              |        0
+ {-1,0,3}                              | {-0.4,-1,-6}                          |        0
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {-1,0,3}                              | {3,NaN,5}                             |        0
+ {-1,0,3}                              | {NaN,NaN,NaN}                         |        0
+ {-1,0,3}                              | {0,-1,3}                              |        0
+ {-1,0,3}                              | {-1,0,3}                              |        0
+(100 rows)
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LINE_TBL l, BOX_TBL b;
+ERROR:  function "dist_lb" not implemented
+-- Intersect with line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?# l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {1,0,5}
+ {0,-1,5}                              | {1,-1,0}
+ {0,-1,5}                              | {-0.4,-1,-6}
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,5}                              | {3,NaN,5}
+ {0,-1,5}                              | {NaN,NaN,NaN}
+ {0,-1,5}                              | {-1,0,3}
+ {1,0,5}                               | {0,-1,5}
+ {1,0,5}                               | {0,3,0}
+ {1,0,5}                               | {1,-1,0}
+ {1,0,5}                               | {-0.4,-1,-6}
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846}
+ {1,0,5}                               | {3,NaN,5}
+ {1,0,5}                               | {NaN,NaN,NaN}
+ {1,0,5}                               | {0,-1,3}
+ {0,3,0}                               | {1,0,5}
+ {0,3,0}                               | {1,-1,0}
+ {0,3,0}                               | {-0.4,-1,-6}
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846}
+ {0,3,0}                               | {3,NaN,5}
+ {0,3,0}                               | {NaN,NaN,NaN}
+ {0,3,0}                               | {-1,0,3}
+ {1,-1,0}                              | {0,-1,5}
+ {1,-1,0}                              | {1,0,5}
+ {1,-1,0}                              | {0,3,0}
+ {1,-1,0}                              | {-0.4,-1,-6}
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846}
+ {1,-1,0}                              | {3,NaN,5}
+ {1,-1,0}                              | {NaN,NaN,NaN}
+ {1,-1,0}                              | {0,-1,3}
+ {1,-1,0}                              | {-1,0,3}
+ {-0.4,-1,-6}                          | {0,-1,5}
+ {-0.4,-1,-6}                          | {1,0,5}
+ {-0.4,-1,-6}                          | {0,3,0}
+ {-0.4,-1,-6}                          | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846}
+ {-0.4,-1,-6}                          | {3,NaN,5}
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}
+ {-0.4,-1,-6}                          | {0,-1,3}
+ {-0.4,-1,-6}                          | {-1,0,3}
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}
+ {3,NaN,5}                             | {0,-1,5}
+ {3,NaN,5}                             | {1,0,5}
+ {3,NaN,5}                             | {0,3,0}
+ {3,NaN,5}                             | {1,-1,0}
+ {3,NaN,5}                             | {-0.4,-1,-6}
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846}
+ {3,NaN,5}                             | {3,NaN,5}
+ {3,NaN,5}                             | {NaN,NaN,NaN}
+ {3,NaN,5}                             | {0,-1,3}
+ {3,NaN,5}                             | {-1,0,3}
+ {NaN,NaN,NaN}                         | {0,-1,5}
+ {NaN,NaN,NaN}                         | {1,0,5}
+ {NaN,NaN,NaN}                         | {0,3,0}
+ {NaN,NaN,NaN}                         | {1,-1,0}
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846}
+ {NaN,NaN,NaN}                         | {3,NaN,5}
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}
+ {NaN,NaN,NaN}                         | {0,-1,3}
+ {NaN,NaN,NaN}                         | {-1,0,3}
+ {0,-1,3}                              | {1,0,5}
+ {0,-1,3}                              | {1,-1,0}
+ {0,-1,3}                              | {-0.4,-1,-6}
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,3}                              | {3,NaN,5}
+ {0,-1,3}                              | {NaN,NaN,NaN}
+ {0,-1,3}                              | {-1,0,3}
+ {-1,0,3}                              | {0,-1,5}
+ {-1,0,3}                              | {0,3,0}
+ {-1,0,3}                              | {1,-1,0}
+ {-1,0,3}                              | {-0.4,-1,-6}
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846}
+ {-1,0,3}                              | {3,NaN,5}
+ {-1,0,3}                              | {NaN,NaN,NaN}
+ {-1,0,3}                              | {0,-1,3}
+(84 rows)
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LINE_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+      s       |         f1          
+--------------+---------------------
+ {1,0,5}      | (-2,2),(-8,-10)
+ {0,3,0}      | (2,2),(0,0)
+ {0,3,0}      | (-2,2),(-8,-10)
+ {1,-1,0}     | (2,2),(0,0)
+ {1,-1,0}     | (3,3),(1,1)
+ {1,-1,0}     | (-2,2),(-8,-10)
+ {1,-1,0}     | (2.5,3.5),(2.5,2.5)
+ {1,-1,0}     | (3,3),(3,3)
+ {-0.4,-1,-6} | (-2,2),(-8,-10)
+ {0,-1,3}     | (3,3),(1,1)
+ {0,-1,3}     | (2.5,3.5),(2.5,2.5)
+ {0,-1,3}     | (3,3),(3,3)
+ {-1,0,3}     | (3,3),(1,1)
+(13 rows)
+
+-- Intersection point with line
+SELECT l1.s, l2.s, l1.s # l2.s FROM LINE_TBL l1, LINE_TBL l2;
+                   s                   |                   s                   |             ?column?              
+---------------------------------------+---------------------------------------+-----------------------------------
+ {0,-1,5}                              | {0,-1,5}                              | 
+ {0,-1,5}                              | {1,0,5}                               | (-5,5)
+ {0,-1,5}                              | {0,3,0}                               | 
+ {0,-1,5}                              | {1,-1,0}                              | (5,5)
+ {0,-1,5}                              | {-0.4,-1,-6}                          | (-27.5,5)
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846} | (56250,5)
+ {0,-1,5}                              | {3,NaN,5}                             | (NaN,NaN)
+ {0,-1,5}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,-1,5}                              | {0,-1,3}                              | 
+ {0,-1,5}                              | {-1,0,3}                              | (3,5)
+ {1,0,5}                               | {0,-1,5}                              | (-5,5)
+ {1,0,5}                               | {1,0,5}                               | 
+ {1,0,5}                               | {0,3,0}                               | (-5,0)
+ {1,0,5}                               | {1,-1,0}                              | (-5,-5)
+ {1,0,5}                               | {-0.4,-1,-6}                          | (-5,-4)
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846} | (-5,15.3855384615)
+ {1,0,5}                               | {3,NaN,5}                             | (-5,NaN)
+ {1,0,5}                               | {NaN,NaN,NaN}                         | (-5,NaN)
+ {1,0,5}                               | {0,-1,3}                              | (-5,3)
+ {1,0,5}                               | {-1,0,3}                              | 
+ {0,3,0}                               | {0,-1,5}                              | 
+ {0,3,0}                               | {1,0,5}                               | (-5,0)
+ {0,3,0}                               | {0,3,0}                               | 
+ {0,3,0}                               | {1,-1,0}                              | (0,0)
+ {0,3,0}                               | {-0.4,-1,-6}                          | (-15,0)
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846} | (83333.3333333,0)
+ {0,3,0}                               | {3,NaN,5}                             | (NaN,NaN)
+ {0,3,0}                               | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,3,0}                               | {0,-1,3}                              | 
+ {0,3,0}                               | {-1,0,3}                              | (3,0)
+ {1,-1,0}                              | {0,-1,5}                              | (5,5)
+ {1,-1,0}                              | {1,0,5}                               | (-5,-5)
+ {1,-1,0}                              | {0,3,0}                               | (0,0)
+ {1,-1,0}                              | {1,-1,0}                              | 
+ {1,-1,0}                              | {-0.4,-1,-6}                          | (-4.28571428571,-4.28571428571)
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846} | (15.3817756722,15.3817756722)
+ {1,-1,0}                              | {3,NaN,5}                             | (NaN,NaN)
+ {1,-1,0}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {1,-1,0}                              | {0,-1,3}                              | (3,3)
+ {1,-1,0}                              | {-1,0,3}                              | (3,3)
+ {-0.4,-1,-6}                          | {0,-1,5}                              | (-27.5,5)
+ {-0.4,-1,-6}                          | {1,0,5}                               | (-5,-4)
+ {-0.4,-1,-6}                          | {0,3,0}                               | (-15,0)
+ {-0.4,-1,-6}                          | {1,-1,0}                              | (-4.28571428571,-4.28571428571)
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}                          | 
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846} | (-53.4862244113,15.3944897645)
+ {-0.4,-1,-6}                          | {3,NaN,5}                             | (NaN,NaN)
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-0.4,-1,-6}                          | {0,-1,3}                              | (-22.5,3)
+ {-0.4,-1,-6}                          | {-1,0,3}                              | (3,-7.2)
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}                              | (56250,5)
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}                               | (-5,15.3855384615)
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}                               | (83333.3333333,-1.7763568394e-15)
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}                              | (15.3817756722,15.3817756722)
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}                          | (-53.4862244113,15.3944897645)
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} | 
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}                             | (NaN,NaN)
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}                              | (67083.3333333,3)
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}                              | (3,15.3840615385)
+ {3,NaN,5}                             | {0,-1,5}                              | (NaN,NaN)
+ {3,NaN,5}                             | {1,0,5}                               | (-5,NaN)
+ {3,NaN,5}                             | {0,3,0}                               | (NaN,NaN)
+ {3,NaN,5}                             | {1,-1,0}                              | (NaN,NaN)
+ {3,NaN,5}                             | {-0.4,-1,-6}                          | (NaN,NaN)
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ {3,NaN,5}                             | {3,NaN,5}                             | (NaN,NaN)
+ {3,NaN,5}                             | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {3,NaN,5}                             | {0,-1,3}                              | (NaN,NaN)
+ {3,NaN,5}                             | {-1,0,3}                              | (3,NaN)
+ {NaN,NaN,NaN}                         | {0,-1,5}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {1,0,5}                               | (-5,NaN)
+ {NaN,NaN,NaN}                         | {0,3,0}                               | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {1,-1,0}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}                          | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {3,NaN,5}                             | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,-1,3}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-1,0,3}                              | (3,NaN)
+ {0,-1,3}                              | {0,-1,5}                              | 
+ {0,-1,3}                              | {1,0,5}                               | (-5,3)
+ {0,-1,3}                              | {0,3,0}                               | 
+ {0,-1,3}                              | {1,-1,0}                              | (3,3)
+ {0,-1,3}                              | {-0.4,-1,-6}                          | (-22.5,3)
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846} | (67083.3333333,3)
+ {0,-1,3}                              | {3,NaN,5}                             | (NaN,NaN)
+ {0,-1,3}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,-1,3}                              | {0,-1,3}                              | 
+ {0,-1,3}                              | {-1,0,3}                              | (3,3)
+ {-1,0,3}                              | {0,-1,5}                              | (3,5)
+ {-1,0,3}                              | {1,0,5}                               | 
+ {-1,0,3}                              | {0,3,0}                               | (3,0)
+ {-1,0,3}                              | {1,-1,0}                              | (3,3)
+ {-1,0,3}                              | {-0.4,-1,-6}                          | (3,-7.2)
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846} | (3,15.3840615385)
+ {-1,0,3}                              | {3,NaN,5}                             | (3,NaN)
+ {-1,0,3}                              | {NaN,NaN,NaN}                         | (3,NaN)
+ {-1,0,3}                              | {0,-1,3}                              | (3,3)
+ {-1,0,3}                              | {-1,0,3}                              | 
+(100 rows)
+
+-- Closest point to line segment
+SELECT l.s, l1.s, l.s ## l1.s FROM LINE_TBL l, LSEG_TBL l1;
+                   s                   |               s               |             ?column?              
+---------------------------------------+-------------------------------+-----------------------------------
+ {0,-1,5}                              | [(1,2),(3,4)]                 | (3,4)
+ {0,-1,5}                              | [(0,0),(6,6)]                 | (5,5)
+ {0,-1,5}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,-1,5}                              | [(-1000000,200),(300000,-40)] | (56250,5)
+ {0,-1,5}                              | [(11,22),(33,44)]             | (11,22)
+ {0,-1,5}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {0,-1,5}                              | [(0,-20),(30,-20)]            | 
+ {0,-1,5}                              | [(NaN,1),(NaN,90)]            | 
+ {1,0,5}                               | [(1,2),(3,4)]                 | (1,2)
+ {1,0,5}                               | [(0,0),(6,6)]                 | (0,0)
+ {1,0,5}                               | [(10,-10),(-3,-4)]            | (-3,-4)
+ {1,0,5}                               | [(-1000000,200),(300000,-40)] | (-5,15.3855384615)
+ {1,0,5}                               | [(11,22),(33,44)]             | (11,22)
+ {1,0,5}                               | [(-10,2),(-10,3)]             | 
+ {1,0,5}                               | [(0,-20),(30,-20)]            | (0,-20)
+ {1,0,5}                               | [(NaN,1),(NaN,90)]            | 
+ {0,3,0}                               | [(1,2),(3,4)]                 | (1,2)
+ {0,3,0}                               | [(0,0),(6,6)]                 | (0,0)
+ {0,3,0}                               | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,3,0}                               | [(-1000000,200),(300000,-40)] | (83333.3333333,-1.7763568394e-15)
+ {0,3,0}                               | [(11,22),(33,44)]             | (11,22)
+ {0,3,0}                               | [(-10,2),(-10,3)]             | (-10,2)
+ {0,3,0}                               | [(0,-20),(30,-20)]            | 
+ {0,3,0}                               | [(NaN,1),(NaN,90)]            | 
+ {1,-1,0}                              | [(1,2),(3,4)]                 | 
+ {1,-1,0}                              | [(0,0),(6,6)]                 | 
+ {1,-1,0}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {1,-1,0}                              | [(-1000000,200),(300000,-40)] | (15.3817756722,15.3817756722)
+ {1,-1,0}                              | [(11,22),(33,44)]             | 
+ {1,-1,0}                              | [(-10,2),(-10,3)]             | (-10,2)
+ {1,-1,0}                              | [(0,-20),(30,-20)]            | (0,-20)
+ {1,-1,0}                              | [(NaN,1),(NaN,90)]            | 
+ {-0.4,-1,-6}                          | [(1,2),(3,4)]                 | (1,2)
+ {-0.4,-1,-6}                          | [(0,0),(6,6)]                 | (0,0)
+ {-0.4,-1,-6}                          | [(10,-10),(-3,-4)]            | (10,-10)
+ {-0.4,-1,-6}                          | [(-1000000,200),(300000,-40)] | (-53.4862244113,15.3944897645)
+ {-0.4,-1,-6}                          | [(11,22),(33,44)]             | (11,22)
+ {-0.4,-1,-6}                          | [(-10,2),(-10,3)]             | (-10,2)
+ {-0.4,-1,-6}                          | [(0,-20),(30,-20)]            | (30,-20)
+ {-0.4,-1,-6}                          | [(NaN,1),(NaN,90)]            | 
+ {-0.000184615384615,-1,15.3846153846} | [(1,2),(3,4)]                 | (3,4)
+ {-0.000184615384615,-1,15.3846153846} | [(0,0),(6,6)]                 | (6,6)
+ {-0.000184615384615,-1,15.3846153846} | [(10,-10),(-3,-4)]            | (-3,-4)
+ {-0.000184615384615,-1,15.3846153846} | [(-1000000,200),(300000,-40)] | 
+ {-0.000184615384615,-1,15.3846153846} | [(11,22),(33,44)]             | (11,22)
+ {-0.000184615384615,-1,15.3846153846} | [(-10,2),(-10,3)]             | (-10,3)
+ {-0.000184615384615,-1,15.3846153846} | [(0,-20),(30,-20)]            | (30,-20)
+ {-0.000184615384615,-1,15.3846153846} | [(NaN,1),(NaN,90)]            | 
+ {3,NaN,5}                             | [(1,2),(3,4)]                 | 
+ {3,NaN,5}                             | [(0,0),(6,6)]                 | 
+ {3,NaN,5}                             | [(10,-10),(-3,-4)]            | 
+ {3,NaN,5}                             | [(-1000000,200),(300000,-40)] | 
+ {3,NaN,5}                             | [(11,22),(33,44)]             | 
+ {3,NaN,5}                             | [(-10,2),(-10,3)]             | 
+ {3,NaN,5}                             | [(0,-20),(30,-20)]            | 
+ {3,NaN,5}                             | [(NaN,1),(NaN,90)]            | 
+ {NaN,NaN,NaN}                         | [(1,2),(3,4)]                 | 
+ {NaN,NaN,NaN}                         | [(0,0),(6,6)]                 | 
+ {NaN,NaN,NaN}                         | [(10,-10),(-3,-4)]            | 
+ {NaN,NaN,NaN}                         | [(-1000000,200),(300000,-40)] | 
+ {NaN,NaN,NaN}                         | [(11,22),(33,44)]             | 
+ {NaN,NaN,NaN}                         | [(-10,2),(-10,3)]             | 
+ {NaN,NaN,NaN}                         | [(0,-20),(30,-20)]            | 
+ {NaN,NaN,NaN}                         | [(NaN,1),(NaN,90)]            | 
+ {0,-1,3}                              | [(1,2),(3,4)]                 | (2,3)
+ {0,-1,3}                              | [(0,0),(6,6)]                 | (3,3)
+ {0,-1,3}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,-1,3}                              | [(-1000000,200),(300000,-40)] | (67083.3333333,3)
+ {0,-1,3}                              | [(11,22),(33,44)]             | (11,22)
+ {0,-1,3}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {0,-1,3}                              | [(0,-20),(30,-20)]            | 
+ {0,-1,3}                              | [(NaN,1),(NaN,90)]            | 
+ {-1,0,3}                              | [(1,2),(3,4)]                 | (3,4)
+ {-1,0,3}                              | [(0,0),(6,6)]                 | (3,3)
+ {-1,0,3}                              | [(10,-10),(-3,-4)]            | (3,-6.76923076923)
+ {-1,0,3}                              | [(-1000000,200),(300000,-40)] | (3,15.3840615385)
+ {-1,0,3}                              | [(11,22),(33,44)]             | (11,22)
+ {-1,0,3}                              | [(-10,2),(-10,3)]             | 
+ {-1,0,3}                              | [(0,-20),(30,-20)]            | (3,-20)
+ {-1,0,3}                              | [(NaN,1),(NaN,90)]            | 
+(80 rows)
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LINE_TBL l, BOX_TBL b;
+ERROR:  function "close_lb" not implemented
 --
 -- Line segments
 --
 -- intersection
 SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
    FROM LSEG_TBL l, POINT_TBL p;
 ERROR:  operator does not exist: lseg # point
 LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
                                            ^
 HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (-0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
+-- Length
+SELECT s, @-@ s FROM LSEG_TBL;
+               s               |   ?column?    
+-------------------------------+---------------
+ [(1,2),(3,4)]                 | 2.82842712475
+ [(0,0),(6,6)]                 | 8.48528137424
+ [(10,-10),(-3,-4)]            | 14.3178210633
+ [(-1000000,200),(300000,-40)] | 1300000.02215
+ [(11,22),(33,44)]             | 31.1126983722
+ [(-10,2),(-10,3)]             |             1
+ [(0,-20),(30,-20)]            |            30
+ [(NaN,1),(NaN,90)]            |           NaN
+(8 rows)
+
+-- Vertical
+SELECT s FROM LSEG_TBL WHERE ?| s;
+         s         
+-------------------
+ [(-10,2),(-10,3)]
+(1 row)
+
+-- Horizontal
+SELECT s FROM LSEG_TBL WHERE ?- s;
+         s          
+--------------------
+ [(0,-20),(30,-20)]
+(1 row)
+
+-- Center
+SELECT s, @@ s FROM LSEG_TBL;
+               s               |   ?column?   
+-------------------------------+--------------
+ [(1,2),(3,4)]                 | (2,3)
+ [(0,0),(6,6)]                 | (3,3)
+ [(10,-10),(-3,-4)]            | (3.5,-7)
+ [(-1000000,200),(300000,-40)] | (-350000,80)
+ [(11,22),(33,44)]             | (22,33)
+ [(-10,2),(-10,3)]             | (-10,2.5)
+ [(0,-20),(30,-20)]            | (15,-20)
+ [(NaN,1),(NaN,90)]            | (NaN,45.5)
+(8 rows)
+
+-- To point
+SELECT s, s::point FROM LSEG_TBL;
+               s               |      s       
+-------------------------------+--------------
+ [(1,2),(3,4)]                 | (2,3)
+ [(0,0),(6,6)]                 | (3,3)
+ [(10,-10),(-3,-4)]            | (3.5,-7)
+ [(-1000000,200),(300000,-40)] | (-350000,80)
+ [(11,22),(33,44)]             | (22,33)
+ [(-10,2),(-10,3)]             | (-10,2.5)
+ [(0,-20),(30,-20)]            | (15,-20)
+ [(NaN,1),(NaN,90)]            | (NaN,45.5)
+(8 rows)
+
+-- Has points less than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s < l2.s;
+         s          |               s               
+--------------------+-------------------------------
+ [(1,2),(3,4)]      | [(0,0),(6,6)]
+ [(1,2),(3,4)]      | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]      | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]      | [(11,22),(33,44)]
+ [(1,2),(3,4)]      | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]      | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]      | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]      | [(11,22),(33,44)]
+ [(0,0),(6,6)]      | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)] | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)] | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]  | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]  | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]  | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]  | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]  | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]  | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]  | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)] | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)] | [(11,22),(33,44)]
+(21 rows)
+
+-- Has points less than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s <= l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(28 rows)
+
+-- Has points equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s = l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]
+(8 rows)
+
+-- Has points greater than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s >= l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(28 rows)
+
+-- Has points greater than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s > l2.s;
+               s               |         s          
+-------------------------------+--------------------
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+(21 rows)
+
+-- Has points not equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s != l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)]
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]
+(56 rows)
+
+-- Parallel with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?|| l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(13 rows)
+
+-- Perpendicular with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?-| l2.s;
+         s          |         s          
+--------------------+--------------------
+ [(-10,2),(-10,3)]  | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)] | [(-10,2),(-10,3)]
+(2 rows)
+
+-- Distance to line
+SELECT l.s, l1.s, l.s <-> l1.s FROM LSEG_TBL l, LINE_TBL l1;
+               s               |                   s                   |    ?column?    
+-------------------------------+---------------------------------------+----------------
+ [(1,2),(3,4)]                 | {0,-1,5}                              |              1
+ [(0,0),(6,6)]                 | {0,-1,5}                              |              0
+ [(10,-10),(-3,-4)]            | {0,-1,5}                              |              9
+ [(-1000000,200),(300000,-40)] | {0,-1,5}                              |              0
+ [(11,22),(33,44)]             | {0,-1,5}                              |             17
+ [(-10,2),(-10,3)]             | {0,-1,5}                              |              2
+ [(0,-20),(30,-20)]            | {0,-1,5}                              |             25
+ [(NaN,1),(NaN,90)]            | {0,-1,5}                              |            NaN
+ [(1,2),(3,4)]                 | {1,0,5}                               |              6
+ [(0,0),(6,6)]                 | {1,0,5}                               |              5
+ [(10,-10),(-3,-4)]            | {1,0,5}                               |              2
+ [(-1000000,200),(300000,-40)] | {1,0,5}                               |              0
+ [(11,22),(33,44)]             | {1,0,5}                               |             16
+ [(-10,2),(-10,3)]             | {1,0,5}                               |              5
+ [(0,-20),(30,-20)]            | {1,0,5}                               |              5
+ [(NaN,1),(NaN,90)]            | {1,0,5}                               |            NaN
+ [(1,2),(3,4)]                 | {0,3,0}                               |              2
+ [(0,0),(6,6)]                 | {0,3,0}                               |              0
+ [(10,-10),(-3,-4)]            | {0,3,0}                               |              4
+ [(-1000000,200),(300000,-40)] | {0,3,0}                               |              0
+ [(11,22),(33,44)]             | {0,3,0}                               |             22
+ [(-10,2),(-10,3)]             | {0,3,0}                               |              2
+ [(0,-20),(30,-20)]            | {0,3,0}                               |             20
+ [(NaN,1),(NaN,90)]            | {0,3,0}                               |            NaN
+ [(1,2),(3,4)]                 | {1,-1,0}                              | 0.707106781187
+ [(0,0),(6,6)]                 | {1,-1,0}                              |              0
+ [(10,-10),(-3,-4)]            | {1,-1,0}                              | 0.707106781187
+ [(-1000000,200),(300000,-40)] | {1,-1,0}                              |              0
+ [(11,22),(33,44)]             | {1,-1,0}                              |  7.77817459305
+ [(-10,2),(-10,3)]             | {1,-1,0}                              |  8.48528137424
+ [(0,-20),(30,-20)]            | {1,-1,0}                              |  14.1421356237
+ [(NaN,1),(NaN,90)]            | {1,-1,0}                              |            NaN
+ [(1,2),(3,4)]                 | {-0.4,-1,-6}                          |  7.79920420344
+ [(0,0),(6,6)]                 | {-0.4,-1,-6}                          |  5.57086014531
+ [(10,-10),(-3,-4)]            | {-0.4,-1,-6}                          |              0
+ [(-1000000,200),(300000,-40)] | {-0.4,-1,-6}                          |              0
+ [(11,22),(33,44)]             | {-0.4,-1,-6}                          |  30.0826447847
+ [(-10,2),(-10,3)]             | {-0.4,-1,-6}                          |  3.71390676354
+ [(0,-20),(30,-20)]            | {-0.4,-1,-6}                          |  1.85695338177
+ [(NaN,1),(NaN,90)]            | {-0.4,-1,-6}                          |            NaN
+ [(1,2),(3,4)]                 | {-0.000184615384615,-1,15.3846153846} |  11.3840613445
+ [(0,0),(6,6)]                 | {-0.000184615384615,-1,15.3846153846} |   9.3835075324
+ [(10,-10),(-3,-4)]            | {-0.000184615384615,-1,15.3846153846} |  19.3851689004
+ [(-1000000,200),(300000,-40)] | {-0.000184615384615,-1,15.3846153846} |              0
+ [(11,22),(33,44)]             | {-0.000184615384615,-1,15.3846153846} |  6.61741527185
+ [(-10,2),(-10,3)]             | {-0.000184615384615,-1,15.3846153846} |  12.3864613274
+ [(0,-20),(30,-20)]            | {-0.000184615384615,-1,15.3846153846} |  35.3790763202
+ [(NaN,1),(NaN,90)]            | {-0.000184615384615,-1,15.3846153846} |            NaN
+ [(1,2),(3,4)]                 | {3,NaN,5}                             |            NaN
+ [(0,0),(6,6)]                 | {3,NaN,5}                             |            NaN
+ [(10,-10),(-3,-4)]            | {3,NaN,5}                             |            NaN
+ [(-1000000,200),(300000,-40)] | {3,NaN,5}                             |            NaN
+ [(11,22),(33,44)]             | {3,NaN,5}                             |            NaN
+ [(-10,2),(-10,3)]             | {3,NaN,5}                             |            NaN
+ [(0,-20),(30,-20)]            | {3,NaN,5}                             |            NaN
+ [(NaN,1),(NaN,90)]            | {3,NaN,5}                             |            NaN
+ [(1,2),(3,4)]                 | {NaN,NaN,NaN}                         |            NaN
+ [(0,0),(6,6)]                 | {NaN,NaN,NaN}                         |            NaN
+ [(10,-10),(-3,-4)]            | {NaN,NaN,NaN}                         |            NaN
+ [(-1000000,200),(300000,-40)] | {NaN,NaN,NaN}                         |            NaN
+ [(11,22),(33,44)]             | {NaN,NaN,NaN}                         |            NaN
+ [(-10,2),(-10,3)]             | {NaN,NaN,NaN}                         |            NaN
+ [(0,-20),(30,-20)]            | {NaN,NaN,NaN}                         |            NaN
+ [(NaN,1),(NaN,90)]            | {NaN,NaN,NaN}                         |            NaN
+ [(1,2),(3,4)]                 | {0,-1,3}                              |              0
+ [(0,0),(6,6)]                 | {0,-1,3}                              |              0
+ [(10,-10),(-3,-4)]            | {0,-1,3}                              |              7
+ [(-1000000,200),(300000,-40)] | {0,-1,3}                              |              0
+ [(11,22),(33,44)]             | {0,-1,3}                              |             19
+ [(-10,2),(-10,3)]             | {0,-1,3}                              |              0
+ [(0,-20),(30,-20)]            | {0,-1,3}                              |             23
+ [(NaN,1),(NaN,90)]            | {0,-1,3}                              |            NaN
+ [(1,2),(3,4)]                 | {-1,0,3}                              |              0
+ [(0,0),(6,6)]                 | {-1,0,3}                              |              0
+ [(10,-10),(-3,-4)]            | {-1,0,3}                              |              0
+ [(-1000000,200),(300000,-40)] | {-1,0,3}                              |              0
+ [(11,22),(33,44)]             | {-1,0,3}                              |              8
+ [(-10,2),(-10,3)]             | {-1,0,3}                              |             13
+ [(0,-20),(30,-20)]            | {-1,0,3}                              |              0
+ [(NaN,1),(NaN,90)]            | {-1,0,3}                              |            NaN
+(80 rows)
+
+-- Distance to line segment
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               |    ?column?    
+-------------------------------+-------------------------------+----------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 |              0
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 0.707106781187
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            |  7.12398901685
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] |  11.3840613445
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             |  19.6977156036
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             |             11
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            |             22
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            |            NaN
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 0.707106781187
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 |              0
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            |  4.88901207039
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] |   9.3835075324
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             |  16.7630546142
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             |  10.1980390272
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            |             20
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            |            NaN
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 |  7.12398901685
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 |  4.88901207039
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            |              0
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] |  19.3851689004
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             |  29.4737584815
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             |  9.21954445729
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            |             10
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            |            NaN
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 |  11.3840613445
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 |   9.3835075324
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            |  19.3851689004
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] |              0
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             |  6.61741527185
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             |  12.3864613274
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            |  35.3790763202
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            |            NaN
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 |  19.6977156036
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 |  16.7630546142
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            |  29.4737584815
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] |  6.61741527185
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             |              0
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             |   28.319604517
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            |             42
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            |            NaN
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 |             11
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 |  10.1980390272
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            |  9.21954445729
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] |  12.3864613274
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             |   28.319604517
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             |              0
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            |  24.1660919472
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            |            NaN
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 |             22
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 |             20
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            |             10
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] |  35.3790763202
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             |             42
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             |  24.1660919472
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            |              0
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 |            NaN
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 |            NaN
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] |            NaN
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             |            NaN
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             |            NaN
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            |            NaN
+(64 rows)
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LSEG_TBL l, BOX_TBL b;
+               s               |         f1          |    ?column?    
+-------------------------------+---------------------+----------------
+ [(1,2),(3,4)]                 | (2,2),(0,0)         |              0
+ [(1,2),(3,4)]                 | (3,3),(1,1)         |              0
+ [(1,2),(3,4)]                 | (-2,2),(-8,-10)     |              3
+ [(1,2),(3,4)]                 | (2.5,3.5),(2.5,2.5) |              0
+ [(1,2),(3,4)]                 | (3,3),(3,3)         | 0.707106781187
+ [(0,0),(6,6)]                 | (2,2),(0,0)         |              0
+ [(0,0),(6,6)]                 | (3,3),(1,1)         |              0
+ [(0,0),(6,6)]                 | (-2,2),(-8,-10)     |              2
+ [(0,0),(6,6)]                 | (2.5,3.5),(2.5,2.5) |              0
+ [(0,0),(6,6)]                 | (3,3),(3,3)         |              0
+ [(10,-10),(-3,-4)]            | (2,2),(0,0)         |  4.88901207039
+ [(10,-10),(-3,-4)]            | (3,3),(1,1)         |  6.21602963235
+ [(10,-10),(-3,-4)]            | (-2,2),(-8,-10)     |              0
+ [(10,-10),(-3,-4)]            | (2.5,3.5),(2.5,2.5) |  8.20655597529
+ [(10,-10),(-3,-4)]            | (3,3),(3,3)         |  8.87006475627
+ [(-1000000,200),(300000,-40)] | (2,2),(0,0)         |  13.3842459258
+ [(-1000000,200),(300000,-40)] | (3,3),(1,1)         |  12.3840613274
+ [(-1000000,200),(300000,-40)] | (-2,2),(-8,-10)     |  13.3849843873
+ [(-1000000,200),(300000,-40)] | (2.5,3.5),(2.5,2.5) |  11.8841536436
+ [(-1000000,200),(300000,-40)] | (3,3),(3,3)         |  12.3840613274
+ [(11,22),(33,44)]             | (2,2),(0,0)         |  21.9317121995
+ [(11,22),(33,44)]             | (3,3),(1,1)         |  20.6155281281
+ [(11,22),(33,44)]             | (-2,2),(-8,-10)     |  23.8537208838
+ [(11,22),(33,44)]             | (2.5,3.5),(2.5,2.5) |  20.3592730715
+ [(11,22),(33,44)]             | (3,3),(3,3)         |  20.6155281281
+ [(-10,2),(-10,3)]             | (2,2),(0,0)         |             10
+ [(-10,2),(-10,3)]             | (3,3),(1,1)         |             11
+ [(-10,2),(-10,3)]             | (-2,2),(-8,-10)     |              2
+ [(-10,2),(-10,3)]             | (2.5,3.5),(2.5,2.5) |           12.5
+ [(-10,2),(-10,3)]             | (3,3),(3,3)         |             13
+ [(0,-20),(30,-20)]            | (2,2),(0,0)         |             20
+ [(0,-20),(30,-20)]            | (3,3),(1,1)         |             21
+ [(0,-20),(30,-20)]            | (-2,2),(-8,-10)     |  10.1980390272
+ [(0,-20),(30,-20)]            | (2.5,3.5),(2.5,2.5) |           22.5
+ [(0,-20),(30,-20)]            | (3,3),(3,3)         |             23
+ [(NaN,1),(NaN,90)]            | (2,2),(0,0)         |            NaN
+ [(NaN,1),(NaN,90)]            | (3,3),(1,1)         |            NaN
+ [(NaN,1),(NaN,90)]            | (-2,2),(-8,-10)     |            NaN
+ [(NaN,1),(NaN,90)]            | (2.5,3.5),(2.5,2.5) |            NaN
+ [(NaN,1),(NaN,90)]            | (3,3),(3,3)         |            NaN
+(40 rows)
+
+-- Intersect with line segment
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s ?# l1.s;
+               s               |      s       
+-------------------------------+--------------
+ [(0,0),(6,6)]                 | {0,-1,5}
+ [(-1000000,200),(300000,-40)] | {0,-1,5}
+ [(-1000000,200),(300000,-40)] | {1,0,5}
+ [(0,0),(6,6)]                 | {0,3,0}
+ [(-1000000,200),(300000,-40)] | {0,3,0}
+ [(-1000000,200),(300000,-40)] | {1,-1,0}
+ [(10,-10),(-3,-4)]            | {-0.4,-1,-6}
+ [(-1000000,200),(300000,-40)] | {-0.4,-1,-6}
+ [(1,2),(3,4)]                 | {0,-1,3}
+ [(0,0),(6,6)]                 | {0,-1,3}
+ [(-1000000,200),(300000,-40)] | {0,-1,3}
+ [(-10,2),(-10,3)]             | {0,-1,3}
+ [(1,2),(3,4)]                 | {-1,0,3}
+ [(0,0),(6,6)]                 | {-1,0,3}
+ [(10,-10),(-3,-4)]            | {-1,0,3}
+ [(-1000000,200),(300000,-40)] | {-1,0,3}
+ [(0,-20),(30,-20)]            | {-1,0,3}
+(17 rows)
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+         s          |         f1          
+--------------------+---------------------
+ [(1,2),(3,4)]      | (2,2),(0,0)
+ [(1,2),(3,4)]      | (3,3),(1,1)
+ [(1,2),(3,4)]      | (2.5,3.5),(2.5,2.5)
+ [(0,0),(6,6)]      | (2,2),(0,0)
+ [(0,0),(6,6)]      | (3,3),(1,1)
+ [(0,0),(6,6)]      | (2.5,3.5),(2.5,2.5)
+ [(0,0),(6,6)]      | (3,3),(3,3)
+ [(10,-10),(-3,-4)] | (-2,2),(-8,-10)
+(8 rows)
+
+-- Intersection point with line segment
+SELECT l1.s, l2.s, l1.s # l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               | ?column? 
+-------------------------------+-------------------------------+----------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 | 
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            | 
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] | 
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             | 
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             | 
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            | 
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            | 
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 | 
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            | 
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] | 
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             | 
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             | 
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            | 
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            | 
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 | 
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 | 
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            | 
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] | 
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             | 
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             | 
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            | 
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            | 
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 | 
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 | 
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            | 
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] | 
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             | 
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             | 
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            | 
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            | 
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 | 
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 | 
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            | 
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] | 
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             | 
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             | 
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            | 
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            | 
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 | 
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 | 
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            | 
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] | 
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             | 
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             | 
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            | 
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            | 
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 | 
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 | 
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            | 
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] | 
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             | 
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             | 
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            | 
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            | 
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 | 
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 | 
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            | 
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] | 
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             | 
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             | 
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            | 
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            | 
+(64 rows)
+
+-- Closest point to line
+SELECT l.s, l1.s, l.s ## l1.s FROM LSEG_TBL l, LINE_TBL l1;
+ERROR:  function "close_sl" not implemented
+-- Closest point to line segment
+SELECT l1.s, l2.s, l1.s ## l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               |            ?column?             
+-------------------------------+-------------------------------+---------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 | 
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            | (-1.98536585366,-4.46829268293)
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] | (3.00210167283,15.3840611505)
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             | 
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             | (-10,2)
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            | (1,-20)
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            | 
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 | 
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] | (6.00173233982,15.3835073725)
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             | 
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             | (-10,2)
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            | (0,-20)
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            | 
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 | (1,2)
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 | (0,0)
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            | 
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] | (-2.99642119965,15.3851685701)
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             | (11,22)
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             | (-10,2)
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            | (10,-20)
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            | 
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 | (3,4)
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 | (6,6)
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            | (-3,-4)
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] | 
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             | (11,22)
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             | (-10,3)
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            | (30,-20)
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            | 
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 | 
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 | 
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            | (-1.3512195122,-4.76097560976)
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] | (10.9987783234,15.3825848409)
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             | 
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             | (-10,3)
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            | (11,-20)
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            | 
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 | (1,2)
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 | (0,0)
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            | (-3,-4)
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] | (-9.99771326872,15.3864611163)
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             | (11,22)
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             | 
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            | (0,-20)
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            | 
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 | (1,2)
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 | (0,0)
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            | (10,-10)
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] | (30.0065315217,15.3790757173)
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             | (11,22)
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             | (-10,2)
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            | 
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            | 
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 | 
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 | 
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            | 
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] | 
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             | 
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             | 
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            | 
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            | 
+(64 rows)
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LSEG_TBL l, BOX_TBL b;
+               s               |         f1          |  ?column?   
+-------------------------------+---------------------+-------------
+ [(1,2),(3,4)]                 | (2,2),(0,0)         | (1,2)
+ [(1,2),(3,4)]                 | (3,3),(1,1)         | (1.5,2.5)
+ [(1,2),(3,4)]                 | (-2,2),(-8,-10)     | (-2,2)
+ [(1,2),(3,4)]                 | (2.5,3.5),(2.5,2.5) | (2.25,3.25)
+ [(1,2),(3,4)]                 | (3,3),(3,3)         | (3,3)
+ [(0,0),(6,6)]                 | (2,2),(0,0)         | (1,1)
+ [(0,0),(6,6)]                 | (3,3),(1,1)         | (2,2)
+ [(0,0),(6,6)]                 | (-2,2),(-8,-10)     | (-2,0)
+ [(0,0),(6,6)]                 | (2.5,3.5),(2.5,2.5) | (2.75,2.75)
+ [(0,0),(6,6)]                 | (3,3),(3,3)         | (3,3)
+ [(10,-10),(-3,-4)]            | (2,2),(0,0)         | (0,0)
+ [(10,-10),(-3,-4)]            | (3,3),(1,1)         | (1,1)
+ [(10,-10),(-3,-4)]            | (-2,2),(-8,-10)     | (-3,-4)
+ [(10,-10),(-3,-4)]            | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ [(10,-10),(-3,-4)]            | (3,3),(3,3)         | (3,3)
+ [(-1000000,200),(300000,-40)] | (2,2),(0,0)         | (2,2)
+ [(-1000000,200),(300000,-40)] | (3,3),(1,1)         | (3,3)
+ [(-1000000,200),(300000,-40)] | (-2,2),(-8,-10)     | (-2,2)
+ [(-1000000,200),(300000,-40)] | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ [(-1000000,200),(300000,-40)] | (3,3),(3,3)         | (3,3)
+ [(11,22),(33,44)]             | (2,2),(0,0)         | (2,2)
+ [(11,22),(33,44)]             | (3,3),(1,1)         | (3,3)
+ [(11,22),(33,44)]             | (-2,2),(-8,-10)     | (-2,2)
+ [(11,22),(33,44)]             | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ [(11,22),(33,44)]             | (3,3),(3,3)         | (3,3)
+ [(-10,2),(-10,3)]             | (2,2),(0,0)         | (0,2)
+ [(-10,2),(-10,3)]             | (3,3),(1,1)         | (1,2)
+ [(-10,2),(-10,3)]             | (-2,2),(-8,-10)     | (-8,2)
+ [(-10,2),(-10,3)]             | (2.5,3.5),(2.5,2.5) | (2.5,3)
+ [(-10,2),(-10,3)]             | (3,3),(3,3)         | (3,3)
+ [(0,-20),(30,-20)]            | (2,2),(0,0)         | (0,0)
+ [(0,-20),(30,-20)]            | (3,3),(1,1)         | (1,1)
+ [(0,-20),(30,-20)]            | (-2,2),(-8,-10)     | (-2,-10)
+ [(0,-20),(30,-20)]            | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ [(0,-20),(30,-20)]            | (3,3),(3,3)         | (3,3)
+ [(NaN,1),(NaN,90)]            | (2,2),(0,0)         | 
+ [(NaN,1),(NaN,90)]            | (3,3),(1,1)         | 
+ [(NaN,1),(NaN,90)]            | (-2,2),(-8,-10)     | 
+ [(NaN,1),(NaN,90)]            | (2.5,3.5),(2.5,2.5) | 
+ [(NaN,1),(NaN,90)]            | (3,3),(3,3)         | 
+(40 rows)
+
+-- On line
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s <@ l1.s;
+               s               |                   s                   
+-------------------------------+---------------------------------------
+ [(0,0),(6,6)]                 | {1,-1,0}
+ [(-1000000,200),(300000,-40)] | {-0.000184615384615,-1,15.3846153846}
+(2 rows)
+
+-- On box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s <@ b.f1;
+ s | f1 
+---+----
+(0 rows)
 
 --
 -- Boxes
 --
 SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
  six |                              box                               
 -----+----------------------------------------------------------------
      | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
      | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
      | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
      | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
      | (107.071067812,207.071067812),(92.9289321881,192.928932188)
      | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
+     | (3,5),(3,5)
+     | (NaN,NaN),(NaN,NaN)
+(8 rows)
 
 -- translation
 SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
+ twentyfour |             translation             
+------------+-------------------------------------
             | (2,2),(0,0)
             | (3,3),(1,1)
+            | (-2,2),(-8,-10)
             | (2.5,3.5),(2.5,2.5)
             | (3,3),(3,3)
             | (-8,2),(-10,0)
             | (-7,3),(-9,1)
+            | (-12,2),(-18,-10)
             | (-7.5,3.5),(-7.5,2.5)
             | (-7,3),(-7,3)
             | (-1,6),(-3,4)
             | (0,7),(-2,5)
+            | (-5,6),(-11,-6)
             | (-0.5,7.5),(-0.5,6.5)
             | (0,7),(0,7)
             | (7.1,36.5),(5.1,34.5)
             | (8.1,37.5),(6.1,35.5)
+            | (3.1,36.5),(-2.9,24.5)
             | (7.6,38),(7.6,37)
             | (8.1,37.5),(8.1,37.5)
             | (-3,-10),(-5,-12)
             | (-2,-9),(-4,-11)
+            | (-7,-10),(-13,-22)
             | (-2.5,-8.5),(-2.5,-9.5)
             | (-2,-9),(-2,-9)
+            | (2,2),(1e-300,-1e-300)
+            | (3,3),(1,1)
+            | (-2,2),(-8,-10)
+            | (2.5,3.5),(2.5,2.5)
+            | (3,3),(3,3)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
             | (12,12),(10,10)
             | (13,13),(11,11)
+            | (8,12),(2,0)
             | (12.5,13.5),(12.5,12.5)
             | (13,13),(13,13)
-(24 rows)
+(45 rows)
 
 SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
+ twentyfour |               translation               
+------------+-----------------------------------------
             | (2,2),(0,0)
             | (3,3),(1,1)
+            | (-2,2),(-8,-10)
             | (2.5,3.5),(2.5,2.5)
             | (3,3),(3,3)
             | (12,2),(10,0)
             | (13,3),(11,1)
+            | (8,2),(2,-10)
             | (12.5,3.5),(12.5,2.5)
             | (13,3),(13,3)
             | (5,-2),(3,-4)
             | (6,-1),(4,-3)
+            | (1,-2),(-5,-14)
             | (5.5,-0.5),(5.5,-1.5)
             | (6,-1),(6,-1)
             | (-3.1,-32.5),(-5.1,-34.5)
             | (-2.1,-31.5),(-4.1,-33.5)
+            | (-7.1,-32.5),(-13.1,-44.5)
             | (-2.6,-31),(-2.6,-32)
             | (-2.1,-31.5),(-2.1,-31.5)
             | (7,14),(5,12)
             | (8,15),(6,13)
+            | (3,14),(-3,2)
             | (7.5,15.5),(7.5,14.5)
             | (8,15),(8,15)
+            | (2,2),(-1e-300,1e-300)
+            | (3,3),(1,1)
+            | (-2,2),(-8,-10)
+            | (2.5,3.5),(2.5,2.5)
+            | (3,3),(3,3)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
             | (-8,-8),(-10,-10)
             | (-7,-7),(-9,-9)
+            | (-12,-8),(-18,-20)
             | (-7.5,-6.5),(-7.5,-7.5)
             | (-7,-7),(-7,-7)
-(24 rows)
+(45 rows)
 
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (-0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (-0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,-0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
+-- Multiply with point
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+         f1          |     f1     |          ?column?           
+---------------------+------------+-----------------------------
+ (2,2),(0,0)         | (5.1,34.5) | (0,79.2),(-58.8,0)
+ (2,2),(0,0)         | (10,10)    | (0,40),(0,0)
+ (3,3),(1,1)         | (5.1,34.5) | (-29.4,118.8),(-88.2,39.6)
+ (3,3),(1,1)         | (10,10)    | (0,60),(0,20)
+ (-2,2),(-8,-10)     | (5.1,34.5) | (304.2,-58.8),(-79.2,-327)
+ (-2,2),(-8,-10)     | (10,10)    | (20,0),(-40,-180)
+ (2.5,3.5),(2.5,2.5) | (5.1,34.5) | (-73.5,104.1),(-108,99)
+ (2.5,3.5),(2.5,2.5) | (10,10)    | (0,60),(-10,50)
+ (3,3),(3,3)         | (5.1,34.5) | (-88.2,118.8),(-88.2,118.8)
+ (3,3),(3,3)         | (10,10)    | (0,60),(0,60)
+(10 rows)
 
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,-0),(-0.2,-0.2)
-        | (0.08,-0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (-0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
+-- Overflow error
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] > 1000;
+         f1          |        f1         |                  ?column?                  
+---------------------+-------------------+--------------------------------------------
+ (2,2),(0,0)         | (1e+300,Infinity) | (NaN,NaN),(-Infinity,Infinity)
+ (2,2),(0,0)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (3,3),(1,1)         | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (3,3),(1,1)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (-2,2),(-8,-10)     | (1e+300,Infinity) | (Infinity,-Infinity),(-Infinity,-Infinity)
+ (-2,2),(-8,-10)     | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (2.5,3.5),(2.5,2.5) | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (2.5,3.5),(2.5,2.5) | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (3,3),(3,3)         | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (3,3),(3,3)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+(10 rows)
 
+-- Divide by point
+SELECT b.f1, p.f1, b.f1 / p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+         f1          |     f1     |                               ?column?                               
+---------------------+------------+----------------------------------------------------------------------
+ (2,2),(0,0)         | (5.1,34.5) | (0.0651176557644,0),(0,-0.0483449262493)
+ (2,2),(0,0)         | (10,10)    | (0.2,0),(0,0)
+ (3,3),(1,1)         | (5.1,34.5) | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
+ (3,3),(1,1)         | (10,10)    | (0.3,0),(0.1,0)
+ (-2,2),(-8,-10)     | (5.1,34.5) | (0.0483449262493,0.18499334024),(-0.317201914064,0.0651176557644)
+ (-2,2),(-8,-10)     | (10,10)    | (0,0.2),(-0.9,-0.1)
+ (2.5,3.5),(2.5,2.5) | (5.1,34.5) | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
+ (2.5,3.5),(2.5,2.5) | (10,10)    | (0.3,0.05),(0.25,0)
+ (3,3),(3,3)         | (5.1,34.5) | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
+ (3,3),(3,3)         | (10,10)    | (0.3,0),(0.3,0)
+(10 rows)
+
+-- To box
 SELECT f1::box
 	FROM POINT_TBL;
-          f1           
------------------------
+                 f1                  
+-------------------------------------
  (0,0),(0,0)
  (-10,0),(-10,0)
  (-3,4),(-3,4)
  (5.1,34.5),(5.1,34.5)
  (-5,-12),(-5,-12)
+ (1e-300,-1e-300),(1e-300,-1e-300)
+ (1e+300,Infinity),(1e+300,Infinity)
+ (NaN,NaN),(NaN,NaN)
  (10,10),(10,10)
-(6 rows)
+(9 rows)
 
 SELECT bound_box(a.f1, b.f1)
 	FROM BOX_TBL a, BOX_TBL b;
       bound_box      
 ---------------------
  (2,2),(0,0)
  (3,3),(0,0)
+ (2,2),(-8,-10)
  (2.5,3.5),(0,0)
  (3,3),(0,0)
  (3,3),(0,0)
  (3,3),(1,1)
+ (3,3),(-8,-10)
  (3,3.5),(1,1)
  (3,3),(1,1)
+ (2,2),(-8,-10)
+ (3,3),(-8,-10)
+ (-2,2),(-8,-10)
+ (2.5,3.5),(-8,-10)
+ (3,3),(-8,-10)
  (2.5,3.5),(0,0)
  (3,3.5),(1,1)
+ (2.5,3.5),(-8,-10)
  (2.5,3.5),(2.5,2.5)
  (3,3.5),(2.5,2.5)
  (3,3),(0,0)
  (3,3),(1,1)
+ (3,3),(-8,-10)
  (3,3.5),(2.5,2.5)
  (3,3),(3,3)
-(16 rows)
+(25 rows)
+
+-- Below box
+SELECT b1.f1, b2.f1, b1.f1 <^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          | ?column? 
+---------------------+---------------------+----------
+ (2,2),(0,0)         | (2,2),(0,0)         | f
+ (2,2),(0,0)         | (3,3),(1,1)         | f
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | f
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | t
+ (2,2),(0,0)         | (3,3),(3,3)         | t
+ (3,3),(1,1)         | (2,2),(0,0)         | f
+ (3,3),(1,1)         | (3,3),(1,1)         | f
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | f
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(1,1)         | (3,3),(3,3)         | t
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | f
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | f
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | f
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | t
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | t
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | f
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | f
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | f
+ (3,3),(3,3)         | (2,2),(0,0)         | f
+ (3,3),(3,3)         | (3,3),(1,1)         | f
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | f
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(3,3)         | (3,3),(3,3)         | t
+(25 rows)
+
+-- Above box
+SELECT b1.f1, b2.f1, b1.f1 >^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          | ?column? 
+---------------------+---------------------+----------
+ (2,2),(0,0)         | (2,2),(0,0)         | f
+ (2,2),(0,0)         | (3,3),(1,1)         | f
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | f
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | f
+ (2,2),(0,0)         | (3,3),(3,3)         | f
+ (3,3),(1,1)         | (2,2),(0,0)         | f
+ (3,3),(1,1)         | (3,3),(1,1)         | f
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | f
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(1,1)         | (3,3),(3,3)         | f
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | f
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | f
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | f
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | f
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | f
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | t
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | f
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | t
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | f
+ (3,3),(3,3)         | (2,2),(0,0)         | t
+ (3,3),(3,3)         | (3,3),(1,1)         | t
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | t
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(3,3)         | (3,3),(3,3)         | t
+(25 rows)
+
+-- Intersection point with box
+SELECT b1.f1, b2.f1, b1.f1 # b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          |      ?column?       
+---------------------+---------------------+---------------------
+ (2,2),(0,0)         | (2,2),(0,0)         | (2,2),(0,0)
+ (2,2),(0,0)         | (3,3),(1,1)         | (2,2),(1,1)
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | 
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | 
+ (2,2),(0,0)         | (3,3),(3,3)         | 
+ (3,3),(1,1)         | (2,2),(0,0)         | (2,2),(1,1)
+ (3,3),(1,1)         | (3,3),(1,1)         | (3,3),(1,1)
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | 
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | (2.5,3),(2.5,2.5)
+ (3,3),(1,1)         | (3,3),(3,3)         | (3,3),(3,3)
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | 
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | 
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | (-2,2),(-8,-10)
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | 
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | 
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | 
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | (2.5,3),(2.5,2.5)
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | 
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5)
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | 
+ (3,3),(3,3)         | (2,2),(0,0)         | 
+ (3,3),(3,3)         | (3,3),(1,1)         | (3,3),(3,3)
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | 
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | 
+ (3,3),(3,3)         | (3,3),(3,3)         | (3,3),(3,3)
+(25 rows)
+
+-- Diagonal
+SELECT f1, diagonal(f1) FROM BOX_TBL;
+         f1          |       diagonal        
+---------------------+-----------------------
+ (2,2),(0,0)         | [(2,2),(0,0)]
+ (3,3),(1,1)         | [(3,3),(1,1)]
+ (-2,2),(-8,-10)     | [(-2,2),(-8,-10)]
+ (2.5,3.5),(2.5,2.5) | [(2.5,3.5),(2.5,2.5)]
+ (3,3),(3,3)         | [(3,3),(3,3)]
+(5 rows)
+
+-- Distance to box
+SELECT b1.f1, b2.f1, b1.f1 <-> b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          |   ?column?    
+---------------------+---------------------+---------------
+ (2,2),(0,0)         | (2,2),(0,0)         |             0
+ (2,2),(0,0)         | (3,3),(1,1)         | 1.41421356237
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | 7.81024967591
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) |           2.5
+ (2,2),(0,0)         | (3,3),(3,3)         | 2.82842712475
+ (3,3),(1,1)         | (2,2),(0,0)         | 1.41421356237
+ (3,3),(1,1)         | (3,3),(1,1)         |             0
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | 9.21954445729
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | 1.11803398875
+ (3,3),(1,1)         | (3,3),(3,3)         | 1.41421356237
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | 7.81024967591
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | 9.21954445729
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     |             0
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | 10.2591422643
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | 10.6301458127
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         |           2.5
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | 1.11803398875
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | 10.2591422643
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) |             0
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         |           0.5
+ (3,3),(3,3)         | (2,2),(0,0)         | 2.82842712475
+ (3,3),(3,3)         | (3,3),(1,1)         | 1.41421356237
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | 10.6301458127
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) |           0.5
+ (3,3),(3,3)         | (3,3),(3,3)         |             0
+(25 rows)
 
 --
 -- Paths
 --
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
+-- Points
+SELECT f1, npoints(f1) FROM PATH_TBL;
+            f1             | npoints 
+---------------------------+---------
+ [(1,2),(3,4)]             |       2
+ ((1,2),(3,4))             |       2
+ [(0,0),(3,0),(4,5),(1,6)] |       4
+ ((1,2),(3,4))             |       2
+ ((1,2),(3,4))             |       2
+ [(1,2),(3,4)]             |       2
+ ((10,20))                 |       1
+ [(11,12),(13,14)]         |       2
+ ((11,12),(13,14))         |       2
+(9 rows)
 
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
+-- Area
+SELECT f1, area(f1) FROM PATH_TBL;
+            f1             | area 
+---------------------------+------
+ [(1,2),(3,4)]             |     
+ ((1,2),(3,4))             |    0
+ [(0,0),(3,0),(4,5),(1,6)] |     
+ ((1,2),(3,4))             |    0
+ ((1,2),(3,4))             |    0
+ [(1,2),(3,4)]             |     
+ ((10,20))                 |    0
+ [(11,12),(13,14)]         |     
+ ((11,12),(13,14))         |    0
+(9 rows)
 
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
+-- Length
+SELECT f1, @-@ f1 FROM PATH_TBL;
+            f1             |   ?column?    
+---------------------------+---------------
+ [(1,2),(3,4)]             | 2.82842712475
+ ((1,2),(3,4))             | 5.65685424949
+ [(0,0),(3,0),(4,5),(1,6)] | 11.2612971738
+ ((1,2),(3,4))             | 5.65685424949
+ ((1,2),(3,4))             | 5.65685424949
+ [(1,2),(3,4)]             | 2.82842712475
+ ((10,20))                 |             0
+ [(11,12),(13,14)]         | 2.82842712475
+ ((11,12),(13,14))         | 5.65685424949
+(9 rows)
 
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
+-- Center
+SELECT f1, @@ f1 FROM PATH_TBL;
+ERROR:  function "path_center" not implemented
+-- To polygon
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isclosed(f1);
+        f1         |        f1         
+-------------------+-------------------
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((10,20))         | ((10,20))
+ ((11,12),(13,14)) | ((11,12),(13,14))
+(5 rows)
+
+-- Open path cannot be converted to polygon error
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isopen(f1);
+ERROR:  open path cannot be converted to polygon
+-- Has points less than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 < p2.f1;
+        f1         |            f1             
+-------------------+---------------------------
+ [(1,2),(3,4)]     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]     | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))         | [(1,2),(3,4)]
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | [(1,2),(3,4)]
+ ((10,20))         | [(11,12),(13,14)]
+ ((10,20))         | ((11,12),(13,14))
+ [(11,12),(13,14)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((11,12),(13,14)) | [(0,0),(3,0),(4,5),(1,6)]
+(15 rows)
+
+-- Has points less than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 <= p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | [(1,2),(3,4)]
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | [(1,2),(3,4)]
+ ((10,20))                 | ((10,20))
+ ((10,20))                 | [(11,12),(13,14)]
+ ((10,20))                 | ((11,12),(13,14))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(66 rows)
+
+-- Has points equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 = p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | ((10,20))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(51 rows)
+
+-- Has points greater than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 >= p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | ((10,20))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((10,20))
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((10,20))
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(66 rows)
+
+-- Has points greater than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 > p2.f1;
+            f1             |        f1         
+---------------------------+-------------------
+ [(1,2),(3,4)]             | ((10,20))
+ ((1,2),(3,4))             | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | ((10,20))
+ [(1,2),(3,4)]             | ((10,20))
+ [(11,12),(13,14)]         | ((10,20))
+ ((11,12),(13,14))         | ((10,20))
+(15 rows)
+
+-- Add path
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+            f1             |            f1             |                     ?column?                      
+---------------------------+---------------------------+---------------------------------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4),(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))                 | 
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         | [(1,2),(3,4),(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6),(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6),(0,0),(3,0),(4,5),(1,6)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6),(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))                 | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6),(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4),(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))                 | 
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         | [(1,2),(3,4),(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))         | 
+ ((10,20))                 | [(1,2),(3,4)]             | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | [(1,2),(3,4)]             | 
+ ((10,20))                 | ((10,20))                 | 
+ ((10,20))                 | [(11,12),(13,14)]         | 
+ ((10,20))                 | ((11,12),(13,14))         | 
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             | [(11,12),(13,14),(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14),(0,0),(3,0),(4,5),(1,6)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             | [(11,12),(13,14),(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((10,20))                 | 
+ [(11,12),(13,14)]         | [(11,12),(13,14)]         | [(11,12),(13,14),(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))         | 
+ ((11,12),(13,14))         | [(1,2),(3,4)]             | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | [(1,2),(3,4)]             | 
+ ((11,12),(13,14))         | ((10,20))                 | 
+ ((11,12),(13,14))         | [(11,12),(13,14)]         | 
+ ((11,12),(13,14))         | ((11,12),(13,14))         | 
+(81 rows)
+
+-- Add point
+SELECT p.f1, p1.f1, p.f1 + p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                                 ?column?                                  
+---------------------------+-------------------+---------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((10,20))                 | (0,0)             | ((10,20))
+ [(11,12),(13,14)]         | (0,0)             | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (0,0)             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (-10,0)           | [(-9,2),(-7,4)]
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(-10,0),(-7,0),(-6,5),(-9,6)]
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ [(1,2),(3,4)]             | (-10,0)           | [(-9,2),(-7,4)]
+ ((10,20))                 | (-10,0)           | ((0,20))
+ [(11,12),(13,14)]         | (-10,0)           | [(1,12),(3,14)]
+ ((11,12),(13,14))         | (-10,0)           | ((1,12),(3,14))
+ [(1,2),(3,4)]             | (-3,4)            | [(-2,6),(0,8)]
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(-3,4),(0,4),(1,9),(-2,10)]
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ [(1,2),(3,4)]             | (-3,4)            | [(-2,6),(0,8)]
+ ((10,20))                 | (-3,4)            | ((7,24))
+ [(11,12),(13,14)]         | (-3,4)            | [(8,16),(10,18)]
+ ((11,12),(13,14))         | (-3,4)            | ((8,16),(10,18))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(6.1,36.5),(8.1,38.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(5.1,34.5),(8.1,34.5),(9.1,39.5),(6.1,40.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(6.1,36.5),(8.1,38.5)]
+ ((10,20))                 | (5.1,34.5)        | ((15.1,54.5))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(16.1,46.5),(18.1,48.5)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((16.1,46.5),(18.1,48.5))
+ [(1,2),(3,4)]             | (-5,-12)          | [(-4,-10),(-2,-8)]
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(-5,-12),(-2,-12),(-1,-7),(-4,-6)]
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ [(1,2),(3,4)]             | (-5,-12)          | [(-4,-10),(-2,-8)]
+ ((10,20))                 | (-5,-12)          | ((5,8))
+ [(11,12),(13,14)]         | (-5,-12)          | [(6,0),(8,2)]
+ ((11,12),(13,14))         | (-5,-12)          | ((6,0),(8,2))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(1e-300,-1e-300),(3,-1e-300),(4,5),(1,6)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((10,20))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity),(1e+300,Infinity),(1e+300,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((1e+300,Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(11,12),(13,14)]
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(10,10),(13,10),(14,15),(11,16)]
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (10,10)           | [(11,12),(13,14)]
+ ((10,20))                 | (10,10)           | ((20,30))
+ [(11,12),(13,14)]         | (10,10)           | [(21,22),(23,24)]
+ ((11,12),(13,14))         | (10,10)           | ((21,22),(23,24))
+(81 rows)
+
+-- Subtract point
+SELECT p.f1, p1.f1, p.f1 - p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                                     ?column?                                      
+---------------------------+-------------------+-----------------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((10,20))                 | (0,0)             | ((10,20))
+ [(11,12),(13,14)]         | (0,0)             | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (0,0)             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (-10,0)           | [(11,2),(13,4)]
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(10,0),(13,0),(14,5),(11,6)]
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ [(1,2),(3,4)]             | (-10,0)           | [(11,2),(13,4)]
+ ((10,20))                 | (-10,0)           | ((20,20))
+ [(11,12),(13,14)]         | (-10,0)           | [(21,12),(23,14)]
+ ((11,12),(13,14))         | (-10,0)           | ((21,12),(23,14))
+ [(1,2),(3,4)]             | (-3,4)            | [(4,-2),(6,0)]
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(3,-4),(6,-4),(7,1),(4,2)]
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ [(1,2),(3,4)]             | (-3,4)            | [(4,-2),(6,0)]
+ ((10,20))                 | (-3,4)            | ((13,16))
+ [(11,12),(13,14)]         | (-3,4)            | [(14,8),(16,10)]
+ ((11,12),(13,14))         | (-3,4)            | ((14,8),(16,10))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-4.1,-32.5),(-2.1,-30.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(-5.1,-34.5),(-2.1,-34.5),(-1.1,-29.5),(-4.1,-28.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-4.1,-32.5),(-2.1,-30.5)]
+ ((10,20))                 | (5.1,34.5)        | ((4.9,-14.5))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(5.9,-22.5),(7.9,-20.5)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((5.9,-22.5),(7.9,-20.5))
+ [(1,2),(3,4)]             | (-5,-12)          | [(6,14),(8,16)]
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(5,12),(8,12),(9,17),(6,18)]
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ [(1,2),(3,4)]             | (-5,-12)          | [(6,14),(8,16)]
+ ((10,20))                 | (-5,-12)          | ((15,32))
+ [(11,12),(13,14)]         | (-5,-12)          | [(16,24),(18,26)]
+ ((11,12),(13,14))         | (-5,-12)          | ((16,24),(18,26))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(-1e-300,1e-300),(3,1e-300),(4,5),(1,6)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((10,20))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity),(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((-1e+300,-Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(-9,-8),(-7,-6)]
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(-10,-10),(-7,-10),(-6,-5),(-9,-4)]
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ [(1,2),(3,4)]             | (10,10)           | [(-9,-8),(-7,-6)]
+ ((10,20))                 | (10,10)           | ((0,10))
+ [(11,12),(13,14)]         | (10,10)           | [(1,2),(3,4)]
+ ((11,12),(13,14))         | (10,10)           | ((1,2),(3,4))
+(81 rows)
+
+-- Multiply with point
+SELECT p.f1, p1.f1, p.f1 * p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                               ?column?                               
+---------------------------+-------------------+----------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(0,0),(0,0)]
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(0,0),(0,0),(0,0)]
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ [(1,2),(3,4)]             | (0,0)             | [(0,0),(0,0)]
+ ((10,20))                 | (0,0)             | ((0,0))
+ [(11,12),(13,14)]         | (0,0)             | [(0,0),(0,0)]
+ ((11,12),(13,14))         | (0,0)             | ((0,0),(0,0))
+ [(1,2),(3,4)]             | (-10,0)           | [(-10,-20),(-30,-40)]
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(0,0),(-30,0),(-40,-50),(-10,-60)]
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ [(1,2),(3,4)]             | (-10,0)           | [(-10,-20),(-30,-40)]
+ ((10,20))                 | (-10,0)           | ((-100,-200))
+ [(11,12),(13,14)]         | (-10,0)           | [(-110,-120),(-130,-140)]
+ ((11,12),(13,14))         | (-10,0)           | ((-110,-120),(-130,-140))
+ [(1,2),(3,4)]             | (-3,4)            | [(-11,-2),(-25,0)]
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(0,0),(-9,12),(-32,1),(-27,-14)]
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ [(1,2),(3,4)]             | (-3,4)            | [(-11,-2),(-25,0)]
+ ((10,20))                 | (-3,4)            | ((-110,-20))
+ [(11,12),(13,14)]         | (-3,4)            | [(-81,8),(-95,10)]
+ ((11,12),(13,14))         | (-3,4)            | ((-81,8),(-95,10))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-63.9,44.7),(-122.7,123.9)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(0,0),(15.3,103.5),(-152.1,163.5),(-201.9,65.1)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-63.9,44.7),(-122.7,123.9)]
+ ((10,20))                 | (5.1,34.5)        | ((-639,447))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(-357.9,440.7),(-416.7,519.9)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((-357.9,440.7),(-416.7,519.9))
+ [(1,2),(3,4)]             | (-5,-12)          | [(19,-22),(33,-56)]
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(0,0),(-15,-36),(40,-73),(67,-42)]
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ [(1,2),(3,4)]             | (-5,-12)          | [(19,-22),(33,-56)]
+ ((10,20))                 | (-5,-12)          | ((190,-220))
+ [(11,12),(13,14)]         | (-5,-12)          | [(89,-192),(103,-226)]
+ ((11,12),(13,14))         | (-5,-12)          | ((89,-192),(103,-226))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(3e-300,1e-300),(7e-300,1e-300)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(0,0),(3e-300,-3e-300),(9e-300,1e-300),(7e-300,5e-300)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(3e-300,1e-300),(7e-300,1e-300)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((3e-299,1e-299))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(2.3e-299,1e-300),(2.7e-299,1e-300)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((2.3e-299,1e-300),(2.7e-299,1e-300))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(NaN,NaN),(NaN,Infinity),(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((-Infinity,Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(-10,30),(-10,70)]
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(0,0),(30,30),(-10,90),(-50,70)]
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ [(1,2),(3,4)]             | (10,10)           | [(-10,30),(-10,70)]
+ ((10,20))                 | (10,10)           | ((-100,300))
+ [(11,12),(13,14)]         | (10,10)           | [(-10,230),(-10,270)]
+ ((11,12),(13,14))         | (10,10)           | ((-10,230),(-10,270))
+(81 rows)
+
+-- Divide by point
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+            f1             |     f1     |                                                    ?column?                                                     
+---------------------------+------------+-----------------------------------------------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (5.1,34.5) | [(0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952)]
+ [(1,2),(3,4)]             | (10,10)    | [(0.15,0.05),(0.35,0.05)]
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5) | [(0,0),(0.0125795471363,-0.0850969365103),(0.158600957032,-0.0924966701199),(0.174387055399,-0.00320655123082)]
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)    | [(0,0),(0.15,-0.15),(0.45,0.05),(0.35,0.25)]
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ [(1,2),(3,4)]             | (5.1,34.5) | [(0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952)]
+ [(1,2),(3,4)]             | (10,10)    | [(0.15,0.05),(0.35,0.05)]
+ ((10,20))                 | (5.1,34.5) | ((0.609244733856,-0.199792807459))
+ ((10,20))                 | (10,10)    | ((1.5,0.5))
+ [(11,12),(13,14)]         | (5.1,34.5) | [(0.386512752208,-0.261703911993),(0.451630407972,-0.310048838242)]
+ [(11,12),(13,14)]         | (10,10)    | [(1.15,0.05),(1.35,0.05)]
+ ((11,12),(13,14))         | (5.1,34.5) | ((0.386512752208,-0.261703911993),(0.451630407972,-0.310048838242))
+ ((11,12),(13,14))         | (10,10)    | ((1.15,0.05),(1.35,0.05))
+(18 rows)
+
+-- Division by 0 error
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to path
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+            f1             |            f1             |    ?column?    
+---------------------------+---------------------------+----------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((10,20))                 |  17.4642491966
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         |   11.313708499
+ [(1,2),(3,4)]             | ((11,12),(13,14))         |   11.313708499
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)] |              0
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))                 |  16.1554944214
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]         |  9.89949493661
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))         |  9.89949493661
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((10,20))                 |  17.4642491966
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         |   11.313708499
+ [(1,2),(3,4)]             | ((11,12),(13,14))         |   11.313708499
+ ((10,20))                 | [(1,2),(3,4)]             |  17.4642491966
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)] |  16.1554944214
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | [(1,2),(3,4)]             |  17.4642491966
+ ((10,20))                 | ((10,20))                 |              0
+ ((10,20))                 | [(11,12),(13,14)]         |   6.7082039325
+ ((10,20))                 | ((11,12),(13,14))         |   6.7082039325
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             |   11.313708499
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)] |  9.89949493661
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             |   11.313708499
+ [(11,12),(13,14)]         | ((10,20))                 |   6.7082039325
+ [(11,12),(13,14)]         | [(11,12),(13,14)]         |              0
+ [(11,12),(13,14)]         | ((11,12),(13,14))         |              0
+ ((11,12),(13,14))         | [(1,2),(3,4)]             |   11.313708499
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)] |  9.89949493661
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | [(1,2),(3,4)]             |   11.313708499
+ ((11,12),(13,14))         | ((10,20))                 |   6.7082039325
+ ((11,12),(13,14))         | [(11,12),(13,14)]         |              0
+ ((11,12),(13,14))         | ((11,12),(13,14))         |              0
+(81 rows)
 
 --
 -- Polygons
 --
 -- containment
 SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
    FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
+ twentyfour |        f1         |             f1             | contains 
+------------+-------------------+----------------------------+----------
+            | (0,0)             | ((2,0),(2,4),(0,0))        | t
+            | (0,0)             | ((3,1),(3,3),(1,0))        | f
+            | (0,0)             | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (0,0)             | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (0,0)             | ((0,0))                    | t
+            | (0,0)             | ((0,1),(0,1))              | f
+            | (-10,0)           | ((2,0),(2,4),(0,0))        | f
+            | (-10,0)           | ((3,1),(3,3),(1,0))        | f
+            | (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-10,0)           | ((0,0))                    | f
+            | (-10,0)           | ((0,1),(0,1))              | f
+            | (-3,4)            | ((2,0),(2,4),(0,0))        | f
+            | (-3,4)            | ((3,1),(3,3),(1,0))        | f
+            | (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-3,4)            | ((0,0))                    | f
+            | (-3,4)            | ((0,1),(0,1))              | f
+            | (5.1,34.5)        | ((2,0),(2,4),(0,0))        | f
+            | (5.1,34.5)        | ((3,1),(3,3),(1,0))        | f
+            | (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (5.1,34.5)        | ((0,0))                    | f
+            | (5.1,34.5)        | ((0,1),(0,1))              | f
+            | (-5,-12)          | ((2,0),(2,4),(0,0))        | f
+            | (-5,-12)          | ((3,1),(3,3),(1,0))        | f
+            | (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-5,-12)          | ((0,0))                    | f
+            | (-5,-12)          | ((0,1),(0,1))              | f
+            | (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        | t
+            | (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        | f
+            | (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e-300,-1e-300)  | ((0,0))                    | t
+            | (1e-300,-1e-300)  | ((0,1),(0,1))              | f
+            | (1e+300,Infinity) | ((2,0),(2,4),(0,0))        | f
+            | (1e+300,Infinity) | ((3,1),(3,3),(1,0))        | f
+            | (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e+300,Infinity) | ((0,0))                    | f
+            | (1e+300,Infinity) | ((0,1),(0,1))              | f
+            | (NaN,NaN)         | ((2,0),(2,4),(0,0))        | t
+            | (NaN,NaN)         | ((3,1),(3,3),(1,0))        | t
+            | (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  | t
+            | (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  | t
+            | (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) | t
+            | (NaN,NaN)         | ((0,0))                    | t
+            | (NaN,NaN)         | ((0,1),(0,1))              | t
+            | (10,10)           | ((2,0),(2,4),(0,0))        | f
+            | (10,10)           | ((3,1),(3,3),(1,0))        | f
+            | (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (10,10)           | ((0,0))                    | f
+            | (10,10)           | ((0,1),(0,1))              | f
+(63 rows)
 
 SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
    FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
+ twentyfour |        f1         |             f1             | contained 
+------------+-------------------+----------------------------+-----------
+            | (0,0)             | ((2,0),(2,4),(0,0))        | t
+            | (0,0)             | ((3,1),(3,3),(1,0))        | f
+            | (0,0)             | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (0,0)             | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (0,0)             | ((0,0))                    | t
+            | (0,0)             | ((0,1),(0,1))              | f
+            | (-10,0)           | ((2,0),(2,4),(0,0))        | f
+            | (-10,0)           | ((3,1),(3,3),(1,0))        | f
+            | (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-10,0)           | ((0,0))                    | f
+            | (-10,0)           | ((0,1),(0,1))              | f
+            | (-3,4)            | ((2,0),(2,4),(0,0))        | f
+            | (-3,4)            | ((3,1),(3,3),(1,0))        | f
+            | (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-3,4)            | ((0,0))                    | f
+            | (-3,4)            | ((0,1),(0,1))              | f
+            | (5.1,34.5)        | ((2,0),(2,4),(0,0))        | f
+            | (5.1,34.5)        | ((3,1),(3,3),(1,0))        | f
+            | (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (5.1,34.5)        | ((0,0))                    | f
+            | (5.1,34.5)        | ((0,1),(0,1))              | f
+            | (-5,-12)          | ((2,0),(2,4),(0,0))        | f
+            | (-5,-12)          | ((3,1),(3,3),(1,0))        | f
+            | (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-5,-12)          | ((0,0))                    | f
+            | (-5,-12)          | ((0,1),(0,1))              | f
+            | (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        | t
+            | (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        | f
+            | (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e-300,-1e-300)  | ((0,0))                    | t
+            | (1e-300,-1e-300)  | ((0,1),(0,1))              | f
+            | (1e+300,Infinity) | ((2,0),(2,4),(0,0))        | f
+            | (1e+300,Infinity) | ((3,1),(3,3),(1,0))        | f
+            | (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e+300,Infinity) | ((0,0))                    | f
+            | (1e+300,Infinity) | ((0,1),(0,1))              | f
+            | (NaN,NaN)         | ((2,0),(2,4),(0,0))        | t
+            | (NaN,NaN)         | ((3,1),(3,3),(1,0))        | t
+            | (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  | t
+            | (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  | t
+            | (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) | t
+            | (NaN,NaN)         | ((0,0))                    | t
+            | (NaN,NaN)         | ((0,1),(0,1))              | t
+            | (10,10)           | ((2,0),(2,4),(0,0))        | f
+            | (10,10)           | ((3,1),(3,3),(1,0))        | f
+            | (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (10,10)           | ((0,0))                    | f
+            | (10,10)           | ((0,1),(0,1))              | f
+(63 rows)
 
 SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
    FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
+ four | npoints |          polygon           
+------+---------+----------------------------
       |       3 | ((2,0),(2,4),(0,0))
       |       3 | ((3,1),(3,3),(1,0))
+      |       4 | ((1,2),(3,4),(5,6),(7,8))
+      |       4 | ((7,8),(5,6),(3,4),(1,2))
+      |       4 | ((1,2),(7,8),(5,6),(3,-4))
       |       1 | ((0,0))
       |       2 | ((0,1),(0,1))
-(4 rows)
+(7 rows)
 
 SELECT '' AS four, polygon(f1)
    FROM BOX_TBL;
  four |                  polygon                  
 ------+-------------------------------------------
       | ((0,0),(0,2),(2,2),(2,0))
       | ((1,1),(1,3),(3,3),(3,1))
+      | ((-8,-10),(-8,2),(-2,2),(-2,-10))
       | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
       | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, polygon(f1)
    FROM PATH_TBL WHERE isclosed(f1);
  four |      polygon      
 ------+-------------------
       | ((1,2),(3,4))
       | ((1,2),(3,4))
       | ((1,2),(3,4))
+      | ((10,20))
       | ((11,12),(13,14))
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
    FROM PATH_TBL
    WHERE isopen(f1);
  four |         open_path         |          polygon          
 ------+---------------------------+---------------------------
       | [(1,2),(3,4)]             | ((1,2),(3,4))
       | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
       | [(1,2),(3,4)]             | ((1,2),(3,4))
       | [(11,12),(13,14)]         | ((11,12),(13,14))
 (4 rows)
 
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
+-- To box
+SELECT f1, f1::box FROM POLYGON_TBL;
+             f1             |      f1      
+----------------------------+--------------
+ ((2,0),(2,4),(0,0))        | (2,4),(0,0)
+ ((3,1),(3,3),(1,0))        | (3,3),(1,0)
+ ((1,2),(3,4),(5,6),(7,8))  | (7,8),(1,2)
+ ((7,8),(5,6),(3,4),(1,2))  | (7,8),(1,2)
+ ((1,2),(7,8),(5,6),(3,-4)) | (7,8),(1,-4)
+ ((0,0))                    | (0,0),(0,0)
+ ((0,1),(0,1))              | (0,1),(0,1)
+(7 rows)
 
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
+-- To path
+SELECT f1, f1::path FROM POLYGON_TBL;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(7 rows)
 
+-- Same as polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 ~= p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(9 rows)
+
+-- Contained by polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <@ p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(12 rows)
+
+-- Contains polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 @> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(12 rows)
+
+-- Overlap with polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 && p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(25 rows)
+
+-- Left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 << p2.f1;
+      f1       |             f1             
+---------------+----------------------------
+ ((0,0))       | ((3,1),(3,3),(1,0))
+ ((0,0))       | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))       | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))       | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1)) | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1)) | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1)) | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1)) | ((1,2),(7,8),(5,6),(3,-4))
+(8 rows)
+
+-- Overlap of left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &< p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))                    | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1))              | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(32 rows)
+
+-- Right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 >> p2.f1;
+             f1             |      f1       
+----------------------------+---------------
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((0,1),(0,1))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1))
+(8 rows)
+
+-- Overlap of right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((2,0),(2,4),(0,0))        | ((0,1),(0,1))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((0,1),(0,1))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((3,1),(3,3),(1,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(37 rows)
+
+-- Below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <<| p2.f1;
+      f1       |            f1             
+---------------+---------------------------
+ ((0,0))       | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))       | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))       | ((0,1),(0,1))
+ ((0,1),(0,1)) | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1)) | ((7,8),(5,6),(3,4),(1,2))
+(5 rows)
+
+-- Overlap or below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &<| p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))                    | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1))              | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(31 rows)
+
+-- Above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |>> p2.f1;
+            f1             |      f1       
+---------------------------+---------------
+ ((1,2),(3,4),(5,6),(7,8)) | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8)) | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2)) | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2)) | ((0,1),(0,1))
+ ((0,1),(0,1))             | ((0,0))
+(5 rows)
+
+-- Overlap or above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |&> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((3,1),(3,3),(1,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(32 rows)
+
+-- Distance to polygon
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2;
+ERROR:  function "poly_distance" not implemented
 --
 -- Circles
 --
 SELECT '' AS six, circle(f1, 50.0)
    FROM POINT_TBL;
- six |     circle      
------+-----------------
+ six |         circle         
+-----+------------------------
      | <(0,0),50>
      | <(-10,0),50>
      | <(-3,4),50>
      | <(5.1,34.5),50>
      | <(-5,-12),50>
+     | <(1e-300,-1e-300),50>
+     | <(1e+300,Infinity),50>
+     | <(NaN,NaN),50>
      | <(10,10),50>
-(6 rows)
+(9 rows)
 
 SELECT '' AS four, circle(f1)
    FROM BOX_TBL;
- four |        circle         
-------+-----------------------
+ four |         circle         
+------+------------------------
       | <(1,1),1.41421356237>
       | <(2,2),1.41421356237>
+      | <(-5,-4),6.7082039325>
       | <(2.5,3),0.5>
       | <(3,3),0>
-(4 rows)
+(5 rows)
 
 SELECT '' AS two, circle(f1)
    FROM POLYGON_TBL
    WHERE (# f1) >= 3;
  two |                    circle                     
 -----+-----------------------------------------------
      | <(1.33333333333,1.33333333333),2.04168905064>
      | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
+     | <(4,5),2.82842712475>
+     | <(4,5),2.82842712475>
+     | <(4,3),4.80664375676>
+(5 rows)
 
 SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
    FROM CIRCLE_TBL c1, POINT_TBL p1
    WHERE (p1.f1 <-> c1.f1) > 0
    ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
+ twentyfour |     circle     |       point       |   distance    
+------------+----------------+-------------------+---------------
+            | <(1,2),3>      | (-3,4)            |   1.472135955
+            | <(5,1),3>      | (0,0)             | 2.09901951359
+            | <(5,1),3>      | (1e-300,-1e-300)  | 2.09901951359
+            | <(5,1),3>      | (-3,4)            | 5.54400374532
+            | <(3,5),0>      | (0,0)             | 5.83095189485
+            | <(3,5),0>      | (1e-300,-1e-300)  | 5.83095189485
+            | <(3,5),0>      | (-3,4)            |  6.0827625303
+            | <(1,3),5>      | (-10,0)           | 6.40175425099
+            | <(1,3),5>      | (10,10)           | 6.40175425099
+            | <(5,1),3>      | (10,10)           | 7.29563014099
+            | <(1,2),3>      | (-10,0)           |  8.1803398875
+            | <(3,5),0>      | (10,10)           | 8.60232526704
+            | <(1,2),3>      | (10,10)           | 9.04159457879
+            | <(1,3),5>      | (-5,-12)          | 11.1554944214
+            | <(5,1),3>      | (-10,0)           | 12.0332963784
+            | <(1,2),3>      | (-5,-12)          | 12.2315462117
+            | <(5,1),3>      | (-5,-12)          | 13.4012194669
+            | <(3,5),0>      | (-10,0)           | 13.9283882772
+            | <(3,5),0>      | (-5,-12)          | 18.7882942281
+            | <(1,3),5>      | (5.1,34.5)        | 26.7657047773
+            | <(3,5),0>      | (5.1,34.5)        | 29.5746513082
+            | <(1,2),3>      | (5.1,34.5)        | 29.7575945393
+            | <(5,1),3>      | (5.1,34.5)        | 30.5001492534
+            | <(100,200),10> | (5.1,34.5)        | 180.778038568
+            | <(100,200),10> | (10,10)           | 200.237960416
+            | <(100,200),10> | (-3,4)            | 211.415898255
+            | <(100,200),10> | (0,0)             |  213.60679775
+            | <(100,200),10> | (1e-300,-1e-300)  |  213.60679775
+            | <(100,200),10> | (-10,0)           |  218.25424421
+            | <(100,200),10> | (-5,-12)          | 226.577682802
+            | <(3,5),0>      | (1e+300,Infinity) |      Infinity
+            | <(1,2),3>      | (1e+300,Infinity) |      Infinity
+            | <(5,1),3>      | (1e+300,Infinity) |      Infinity
+            | <(1,3),5>      | (1e+300,Infinity) |      Infinity
+            | <(100,200),10> | (1e+300,Infinity) |      Infinity
+            | <(1,2),100>    | (1e+300,Infinity) |      Infinity
+            | <(100,1),115>  | (1e+300,Infinity) |      Infinity
+            | <(3,5),0>      | (NaN,NaN)         |           NaN
+            | <(1,2),3>      | (NaN,NaN)         |           NaN
+            | <(5,1),3>      | (NaN,NaN)         |           NaN
+            | <(1,3),5>      | (NaN,NaN)         |           NaN
+            | <(100,200),10> | (NaN,NaN)         |           NaN
+            | <(1,2),100>    | (NaN,NaN)         |           NaN
+            | <(100,1),115>  | (NaN,NaN)         |           NaN
+            | <(3,5),NaN>    | (-10,0)           |           NaN
+            | <(3,5),NaN>    | (-5,-12)          |           NaN
+            | <(3,5),NaN>    | (-3,4)            |           NaN
+            | <(3,5),NaN>    | (0,0)             |           NaN
+            | <(3,5),NaN>    | (1e-300,-1e-300)  |           NaN
+            | <(3,5),NaN>    | (5.1,34.5)        |           NaN
+            | <(3,5),NaN>    | (10,10)           |           NaN
+            | <(3,5),NaN>    | (1e+300,Infinity) |           NaN
+            | <(3,5),NaN>    | (NaN,NaN)         |           NaN
+(53 rows)
+
+-- To polygon
+SELECT f1, f1::polygon FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+       f1       |                                                                                                          f1                                                                                                          
+----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ <(5,1),3>      | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
+ <(1,2),100>    | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
+ <(1,3),5>      | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
+ <(1,2),3>      | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
+ <(100,200),10> | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
+ <(100,1),115>  | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
+(6 rows)
+
+-- To polygon with less points
+SELECT f1, polygon(8, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+       f1       |                                                                             polygon                                                                              
+----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ <(5,1),3>      | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
+ <(1,2),100>    | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
+ <(1,3),5>      | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
+ <(1,2),3>      | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
+ <(100,200),10> | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
+ <(100,1),115>  | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
+(6 rows)
+
+-- Too less points error
+SELECT f1, polygon(1, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+ERROR:  must request at least 2 points
+-- Zero radius error
+SELECT f1, polygon(10, f1) FROM CIRCLE_TBL WHERE f1 < '<(0,0),1>';
+ERROR:  cannot convert circle with radius zero to polygon
+-- Same as circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 ~= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+ <(3,5),NaN>    | <(3,5),0>
+ <(3,5),NaN>    | <(3,5),NaN>
+(9 rows)
+
+-- Overlap with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 && c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,1),115>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(100,1),115>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(33 rows)
+
+-- Overlap or left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &< c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(28 rows)
+
+-- Left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 << c2.f1;
+    f1     |       f1       
+-----------+----------------
+ <(5,1),3> | <(100,200),10>
+ <(1,3),5> | <(100,200),10>
+ <(1,2),3> | <(100,200),10>
+ <(3,5),0> | <(100,200),10>
+(4 rows)
+
+-- Right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >> c2.f1;
+       f1       |    f1     
+----------------+-----------
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(3,5),0>
+(4 rows)
+
+-- Overlap or right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(28 rows)
+
+-- Contained by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <@ c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(17 rows)
+
+-- Contain by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 @> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(3,5),0>
+(17 rows)
+
+-- Below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <<| c2.f1;
+      f1       |       f1       
+---------------+----------------
+ <(5,1),3>     | <(100,200),10>
+ <(5,1),3>     | <(3,5),0>
+ <(1,2),100>   | <(100,200),10>
+ <(1,3),5>     | <(100,200),10>
+ <(1,2),3>     | <(100,200),10>
+ <(100,1),115> | <(100,200),10>
+ <(3,5),0>     | <(100,200),10>
+(7 rows)
+
+-- Above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |>> c2.f1;
+       f1       |      f1       
+----------------+---------------
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(3,5),0>      | <(5,1),3>
+(7 rows)
+
+-- Overlap or below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &<| c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Overlap or above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |&> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 = c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(9 rows)
+
+-- Area not equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 != c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(40 rows)
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 > c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(3,5),0>
+(20 rows)
+
+-- Area less than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area greater than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Add point
+SELECT c.f1, p.f1, c.f1 + p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |        ?column?         
+----------------+-------------------+-------------------------
+ <(5,1),3>      | (0,0)             | <(5,1),3>
+ <(1,2),100>    | (0,0)             | <(1,2),100>
+ <(1,3),5>      | (0,0)             | <(1,3),5>
+ <(1,2),3>      | (0,0)             | <(1,2),3>
+ <(100,200),10> | (0,0)             | <(100,200),10>
+ <(100,1),115>  | (0,0)             | <(100,1),115>
+ <(3,5),0>      | (0,0)             | <(3,5),0>
+ <(3,5),NaN>    | (0,0)             | <(3,5),NaN>
+ <(5,1),3>      | (-10,0)           | <(-5,1),3>
+ <(1,2),100>    | (-10,0)           | <(-9,2),100>
+ <(1,3),5>      | (-10,0)           | <(-9,3),5>
+ <(1,2),3>      | (-10,0)           | <(-9,2),3>
+ <(100,200),10> | (-10,0)           | <(90,200),10>
+ <(100,1),115>  | (-10,0)           | <(90,1),115>
+ <(3,5),0>      | (-10,0)           | <(-7,5),0>
+ <(3,5),NaN>    | (-10,0)           | <(-7,5),NaN>
+ <(5,1),3>      | (-3,4)            | <(2,5),3>
+ <(1,2),100>    | (-3,4)            | <(-2,6),100>
+ <(1,3),5>      | (-3,4)            | <(-2,7),5>
+ <(1,2),3>      | (-3,4)            | <(-2,6),3>
+ <(100,200),10> | (-3,4)            | <(97,204),10>
+ <(100,1),115>  | (-3,4)            | <(97,5),115>
+ <(3,5),0>      | (-3,4)            | <(0,9),0>
+ <(3,5),NaN>    | (-3,4)            | <(0,9),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(10.1,35.5),3>
+ <(1,2),100>    | (5.1,34.5)        | <(6.1,36.5),100>
+ <(1,3),5>      | (5.1,34.5)        | <(6.1,37.5),5>
+ <(1,2),3>      | (5.1,34.5)        | <(6.1,36.5),3>
+ <(100,200),10> | (5.1,34.5)        | <(105.1,234.5),10>
+ <(100,1),115>  | (5.1,34.5)        | <(105.1,35.5),115>
+ <(3,5),0>      | (5.1,34.5)        | <(8.1,39.5),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(8.1,39.5),NaN>
+ <(5,1),3>      | (-5,-12)          | <(0,-11),3>
+ <(1,2),100>    | (-5,-12)          | <(-4,-10),100>
+ <(1,3),5>      | (-5,-12)          | <(-4,-9),5>
+ <(1,2),3>      | (-5,-12)          | <(-4,-10),3>
+ <(100,200),10> | (-5,-12)          | <(95,188),10>
+ <(100,1),115>  | (-5,-12)          | <(95,-11),115>
+ <(3,5),0>      | (-5,-12)          | <(-2,-7),0>
+ <(3,5),NaN>    | (-5,-12)          | <(-2,-7),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(5,1),3>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(1,2),100>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(1,3),5>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(1,2),3>
+ <(100,200),10> | (1e-300,-1e-300)  | <(100,200),10>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(100,1),115>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(3,5),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(3,5),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(1e+300,Infinity),3>
+ <(1,2),100>    | (1e+300,Infinity) | <(1e+300,Infinity),100>
+ <(1,3),5>      | (1e+300,Infinity) | <(1e+300,Infinity),5>
+ <(1,2),3>      | (1e+300,Infinity) | <(1e+300,Infinity),3>
+ <(100,200),10> | (1e+300,Infinity) | <(1e+300,Infinity),10>
+ <(100,1),115>  | (1e+300,Infinity) | <(1e+300,Infinity),115>
+ <(3,5),0>      | (1e+300,Infinity) | <(1e+300,Infinity),0>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(1e+300,Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),100>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),5>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),10>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),115>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),0>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(15,11),3>
+ <(1,2),100>    | (10,10)           | <(11,12),100>
+ <(1,3),5>      | (10,10)           | <(11,13),5>
+ <(1,2),3>      | (10,10)           | <(11,12),3>
+ <(100,200),10> | (10,10)           | <(110,210),10>
+ <(100,1),115>  | (10,10)           | <(110,11),115>
+ <(3,5),0>      | (10,10)           | <(13,15),0>
+ <(3,5),NaN>    | (10,10)           | <(13,15),NaN>
+(72 rows)
+
+-- Subtract point
+SELECT c.f1, p.f1, c.f1 - p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |         ?column?          
+----------------+-------------------+---------------------------
+ <(5,1),3>      | (0,0)             | <(5,1),3>
+ <(1,2),100>    | (0,0)             | <(1,2),100>
+ <(1,3),5>      | (0,0)             | <(1,3),5>
+ <(1,2),3>      | (0,0)             | <(1,2),3>
+ <(100,200),10> | (0,0)             | <(100,200),10>
+ <(100,1),115>  | (0,0)             | <(100,1),115>
+ <(3,5),0>      | (0,0)             | <(3,5),0>
+ <(3,5),NaN>    | (0,0)             | <(3,5),NaN>
+ <(5,1),3>      | (-10,0)           | <(15,1),3>
+ <(1,2),100>    | (-10,0)           | <(11,2),100>
+ <(1,3),5>      | (-10,0)           | <(11,3),5>
+ <(1,2),3>      | (-10,0)           | <(11,2),3>
+ <(100,200),10> | (-10,0)           | <(110,200),10>
+ <(100,1),115>  | (-10,0)           | <(110,1),115>
+ <(3,5),0>      | (-10,0)           | <(13,5),0>
+ <(3,5),NaN>    | (-10,0)           | <(13,5),NaN>
+ <(5,1),3>      | (-3,4)            | <(8,-3),3>
+ <(1,2),100>    | (-3,4)            | <(4,-2),100>
+ <(1,3),5>      | (-3,4)            | <(4,-1),5>
+ <(1,2),3>      | (-3,4)            | <(4,-2),3>
+ <(100,200),10> | (-3,4)            | <(103,196),10>
+ <(100,1),115>  | (-3,4)            | <(103,-3),115>
+ <(3,5),0>      | (-3,4)            | <(6,1),0>
+ <(3,5),NaN>    | (-3,4)            | <(6,1),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(-0.1,-33.5),3>
+ <(1,2),100>    | (5.1,34.5)        | <(-4.1,-32.5),100>
+ <(1,3),5>      | (5.1,34.5)        | <(-4.1,-31.5),5>
+ <(1,2),3>      | (5.1,34.5)        | <(-4.1,-32.5),3>
+ <(100,200),10> | (5.1,34.5)        | <(94.9,165.5),10>
+ <(100,1),115>  | (5.1,34.5)        | <(94.9,-33.5),115>
+ <(3,5),0>      | (5.1,34.5)        | <(-2.1,-29.5),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(-2.1,-29.5),NaN>
+ <(5,1),3>      | (-5,-12)          | <(10,13),3>
+ <(1,2),100>    | (-5,-12)          | <(6,14),100>
+ <(1,3),5>      | (-5,-12)          | <(6,15),5>
+ <(1,2),3>      | (-5,-12)          | <(6,14),3>
+ <(100,200),10> | (-5,-12)          | <(105,212),10>
+ <(100,1),115>  | (-5,-12)          | <(105,13),115>
+ <(3,5),0>      | (-5,-12)          | <(8,17),0>
+ <(3,5),NaN>    | (-5,-12)          | <(8,17),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(5,1),3>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(1,2),100>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(1,3),5>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(1,2),3>
+ <(100,200),10> | (1e-300,-1e-300)  | <(100,200),10>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(100,1),115>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(3,5),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(3,5),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(-1e+300,-Infinity),3>
+ <(1,2),100>    | (1e+300,Infinity) | <(-1e+300,-Infinity),100>
+ <(1,3),5>      | (1e+300,Infinity) | <(-1e+300,-Infinity),5>
+ <(1,2),3>      | (1e+300,Infinity) | <(-1e+300,-Infinity),3>
+ <(100,200),10> | (1e+300,Infinity) | <(-1e+300,-Infinity),10>
+ <(100,1),115>  | (1e+300,Infinity) | <(-1e+300,-Infinity),115>
+ <(3,5),0>      | (1e+300,Infinity) | <(-1e+300,-Infinity),0>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(-1e+300,-Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),100>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),5>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),10>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),115>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),0>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(-5,-9),3>
+ <(1,2),100>    | (10,10)           | <(-9,-8),100>
+ <(1,3),5>      | (10,10)           | <(-9,-7),5>
+ <(1,2),3>      | (10,10)           | <(-9,-8),3>
+ <(100,200),10> | (10,10)           | <(90,190),10>
+ <(100,1),115>  | (10,10)           | <(90,-9),115>
+ <(3,5),0>      | (10,10)           | <(-7,-5),0>
+ <(3,5),NaN>    | (10,10)           | <(-7,-5),NaN>
+(72 rows)
+
+-- Multiply with point
+SELECT c.f1, p.f1, c.f1 * p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |                  ?column?                  
+----------------+-------------------+--------------------------------------------
+ <(5,1),3>      | (0,0)             | <(0,0),0>
+ <(1,2),100>    | (0,0)             | <(0,0),0>
+ <(1,3),5>      | (0,0)             | <(0,0),0>
+ <(1,2),3>      | (0,0)             | <(0,0),0>
+ <(100,200),10> | (0,0)             | <(0,0),0>
+ <(100,1),115>  | (0,0)             | <(0,0),0>
+ <(3,5),0>      | (0,0)             | <(0,0),0>
+ <(3,5),NaN>    | (0,0)             | <(0,0),NaN>
+ <(5,1),3>      | (-10,0)           | <(-50,-10),30>
+ <(1,2),100>    | (-10,0)           | <(-10,-20),1000>
+ <(1,3),5>      | (-10,0)           | <(-10,-30),50>
+ <(1,2),3>      | (-10,0)           | <(-10,-20),30>
+ <(100,200),10> | (-10,0)           | <(-1000,-2000),100>
+ <(100,1),115>  | (-10,0)           | <(-1000,-10),1150>
+ <(3,5),0>      | (-10,0)           | <(-30,-50),0>
+ <(3,5),NaN>    | (-10,0)           | <(-30,-50),NaN>
+ <(5,1),3>      | (-3,4)            | <(-19,17),15>
+ <(1,2),100>    | (-3,4)            | <(-11,-2),500>
+ <(1,3),5>      | (-3,4)            | <(-15,-5),25>
+ <(1,2),3>      | (-3,4)            | <(-11,-2),15>
+ <(100,200),10> | (-3,4)            | <(-1100,-200),50>
+ <(100,1),115>  | (-3,4)            | <(-304,397),575>
+ <(3,5),0>      | (-3,4)            | <(-29,-3),0>
+ <(3,5),NaN>    | (-3,4)            | <(-29,-3),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(-9,177.6),104.624758064>
+ <(1,2),100>    | (5.1,34.5)        | <(-63.9,44.7),3487.49193547>
+ <(1,3),5>      | (5.1,34.5)        | <(-98.4,49.8),174.374596774>
+ <(1,2),3>      | (5.1,34.5)        | <(-63.9,44.7),104.624758064>
+ <(100,200),10> | (5.1,34.5)        | <(-6390,4470),348.749193547>
+ <(100,1),115>  | (5.1,34.5)        | <(475.5,3455.1),4010.6157258>
+ <(3,5),0>      | (5.1,34.5)        | <(-157.2,129),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(-157.2,129),NaN>
+ <(5,1),3>      | (-5,-12)          | <(-13,-65),39>
+ <(1,2),100>    | (-5,-12)          | <(19,-22),1300>
+ <(1,3),5>      | (-5,-12)          | <(31,-27),65>
+ <(1,2),3>      | (-5,-12)          | <(19,-22),39>
+ <(100,200),10> | (-5,-12)          | <(1900,-2200),130>
+ <(100,1),115>  | (-5,-12)          | <(-488,-1205),1495>
+ <(3,5),0>      | (-5,-12)          | <(45,-61),0>
+ <(3,5),NaN>    | (-5,-12)          | <(45,-61),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(6e-300,-4e-300),4.24264068712e-300>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(3e-300,1e-300),1.41421356237e-298>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(4e-300,2e-300),7.07106781187e-300>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(3e-300,1e-300),4.24264068712e-300>
+ <(100,200),10> | (1e-300,-1e-300)  | <(3e-298,1e-298),1.41421356237e-299>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(1.01e-298,-9.9e-299),1.62634559673e-298>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(8e-300,2e-300),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(8e-300,2e-300),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,2),100>    | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,3),5>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,2),3>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(100,200),10> | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(100,1),115>  | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(3,5),0>      | (1e+300,Infinity) | <(-Infinity,Infinity),NaN>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(-Infinity,Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(40,60),42.4264068712>
+ <(1,2),100>    | (10,10)           | <(-10,30),1414.21356237>
+ <(1,3),5>      | (10,10)           | <(-20,40),70.7106781187>
+ <(1,2),3>      | (10,10)           | <(-10,30),42.4264068712>
+ <(100,200),10> | (10,10)           | <(-1000,3000),141.421356237>
+ <(100,1),115>  | (10,10)           | <(990,1010),1626.34559673>
+ <(3,5),0>      | (10,10)           | <(-20,80),0>
+ <(3,5),NaN>    | (10,10)           | <(-20,80),NaN>
+(72 rows)
+
+-- Divide by point
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+       f1       |     f1     |                       ?column?                       
+----------------+------------+------------------------------------------------------
+ <(5,1),3>      | (5.1,34.5) | <(0.0493315573973,-0.137635045138),0.0860217042937>
+ <(5,1),3>      | (10,10)    | <(0.3,-0.2),0.212132034356>
+ <(1,2),100>    | (5.1,34.5) | <(0.0609244733856,-0.0199792807459),2.86739014312>
+ <(1,2),100>    | (10,10)    | <(0.15,0.05),7.07106781187>
+ <(1,3),5>      | (5.1,34.5) | <(0.0892901188891,-0.0157860983671),0.143369507156>
+ <(1,3),5>      | (10,10)    | <(0.2,0.1),0.353553390593>
+ <(1,2),3>      | (5.1,34.5) | <(0.0609244733856,-0.0199792807459),0.0860217042937>
+ <(1,2),3>      | (10,10)    | <(0.15,0.05),0.212132034356>
+ <(100,200),10> | (5.1,34.5) | <(6.09244733856,-1.99792807459),0.286739014312>
+ <(100,200),10> | (10,10)    | <(15,5),0.707106781187>
+ <(100,1),115>  | (5.1,34.5) | <(0.44768388338,-2.83237136796),3.29749866459>
+ <(100,1),115>  | (10,10)    | <(5.05,-4.95),8.13172798365>
+ <(3,5),0>      | (5.1,34.5) | <(0.154407774653,-0.0641310246164),0>
+ <(3,5),0>      | (10,10)    | <(0.4,0.1),0>
+ <(3,5),NaN>    | (5.1,34.5) | <(0.154407774653,-0.0641310246164),NaN>
+ <(3,5),NaN>    | (10,10)    | <(0.4,0.1),NaN>
+(16 rows)
+
+-- Overflow error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] > 1000;
+ERROR:  value out of range: overflow
+-- Division by 0 error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to polygon
+SELECT c.f1, p.f1, c.f1 <-> p.f1 FROM CIRCLE_TBL c, POLYGON_TBL p;
+       f1       |             f1             |    ?column?    
+----------------+----------------------------+----------------
+ <(5,1),3>      | ((2,0),(2,4),(0,0))        |              0
+ <(5,1),3>      | ((3,1),(3,3),(1,0))        |              0
+ <(5,1),3>      | ((1,2),(3,4),(5,6),(7,8))  | 0.535533905933
+ <(5,1),3>      | ((7,8),(5,6),(3,4),(1,2))  | 0.535533905933
+ <(5,1),3>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(5,1),3>      | ((0,0))                    |  2.09901951359
+ <(5,1),3>      | ((0,1),(0,1))              |              2
+ <(1,2),100>    | ((2,0),(2,4),(0,0))        |              0
+ <(1,2),100>    | ((3,1),(3,3),(1,0))        |              0
+ <(1,2),100>    | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,2),100>    | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,2),100>    | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,2),100>    | ((0,0))                    |              0
+ <(1,2),100>    | ((0,1),(0,1))              |              0
+ <(1,3),5>      | ((2,0),(2,4),(0,0))        |              0
+ <(1,3),5>      | ((3,1),(3,3),(1,0))        |              0
+ <(1,3),5>      | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,3),5>      | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,3),5>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,3),5>      | ((0,0))                    |              0
+ <(1,3),5>      | ((0,1),(0,1))              |              0
+ <(1,2),3>      | ((2,0),(2,4),(0,0))        |              0
+ <(1,2),3>      | ((3,1),(3,3),(1,0))        |              0
+ <(1,2),3>      | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,2),3>      | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,2),3>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,2),3>      | ((0,0))                    |              0
+ <(1,2),3>      | ((0,1),(0,1))              |              0
+ <(100,200),10> | ((2,0),(2,4),(0,0))        |  209.134661795
+ <(100,200),10> | ((3,1),(3,3),(1,0))        |  209.585974051
+ <(100,200),10> | ((1,2),(3,4),(5,6),(7,8))  |  203.337760371
+ <(100,200),10> | ((7,8),(5,6),(3,4),(1,2))  |  203.337760371
+ <(100,200),10> | ((1,2),(7,8),(5,6),(3,-4)) |  203.337760371
+ <(100,200),10> | ((0,0))                    |   213.60679775
+ <(100,200),10> | ((0,1),(0,1))              |  212.712819568
+ <(100,1),115>  | ((2,0),(2,4),(0,0))        |              0
+ <(100,1),115>  | ((3,1),(3,3),(1,0))        |              0
+ <(100,1),115>  | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(100,1),115>  | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(100,1),115>  | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(100,1),115>  | ((0,0))                    |              0
+ <(100,1),115>  | ((0,1),(0,1))              |              0
+ <(3,5),0>      | ((2,0),(2,4),(0,0))        |  1.41421356237
+ <(3,5),0>      | ((3,1),(3,3),(1,0))        |              2
+ <(3,5),0>      | ((1,2),(3,4),(5,6),(7,8))  | 0.707106781187
+ <(3,5),0>      | ((7,8),(5,6),(3,4),(1,2))  | 0.707106781187
+ <(3,5),0>      | ((1,2),(7,8),(5,6),(3,-4)) | 0.707106781187
+ <(3,5),0>      | ((0,0))                    |  5.83095189485
+ <(3,5),0>      | ((0,1),(0,1))              |              5
+ <(3,5),NaN>    | ((2,0),(2,4),(0,0))        |            NaN
+ <(3,5),NaN>    | ((3,1),(3,3),(1,0))        |            NaN
+ <(3,5),NaN>    | ((1,2),(3,4),(5,6),(7,8))  |            NaN
+ <(3,5),NaN>    | ((7,8),(5,6),(3,4),(1,2))  |            NaN
+ <(3,5),NaN>    | ((1,2),(7,8),(5,6),(3,-4)) |            NaN
+ <(3,5),NaN>    | ((0,0))                    |            NaN
+ <(3,5),NaN>    | ((0,1),(0,1))              |            NaN
+(56 rows)
 
diff --git a/src/test/regress/expected/geometry_1.out b/src/test/regress/expected/geometry_1.out
deleted file mode 100644
index 3b92e23059..0000000000
--- a/src/test/regress/expected/geometry_1.out
+++ /dev/null
@@ -1,563 +0,0 @@
---
--- GEOMETRY
---
--- Back off displayed precision a little bit to reduce platform-to-platform
--- variation in results.
-SET extra_float_digits TO -3;
---
--- Points
---
-SELECT '' AS four, center(f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS four, (@@ f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS six, point(f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS six, (@@ f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS two, (@@ f1) AS center
-   FROM POLYGON_TBL
-   WHERE (# f1) > 2;
- two |            center             
------+-------------------------------
-     | (1.33333333333,1.33333333333)
-     | (2.33333333333,1.33333333333)
-(2 rows)
-
--- "is horizontal" function
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is horizontal" operator
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is vertical" function
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE isvertical(p1.f1, point '(5.1,34.5)');
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
--- "is vertical" operator
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?| point '(5.1,34.5)';
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
---
--- Line segments
---
--- intersection
-SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-   FROM LSEG_TBL l, POINT_TBL p;
-ERROR:  operator does not exist: lseg # point
-LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-                                           ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
-
---
--- Boxes
---
-SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
- six |                              box                               
------+----------------------------------------------------------------
-     | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
-     | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
-     | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
-     | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
-     | (107.071067812,207.071067812),(92.9289321881,192.928932188)
-     | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
-
--- translation
-SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (-8,2),(-10,0)
-            | (-7,3),(-9,1)
-            | (-7.5,3.5),(-7.5,2.5)
-            | (-7,3),(-7,3)
-            | (-1,6),(-3,4)
-            | (0,7),(-2,5)
-            | (-0.5,7.5),(-0.5,6.5)
-            | (0,7),(0,7)
-            | (7.1,36.5),(5.1,34.5)
-            | (8.1,37.5),(6.1,35.5)
-            | (7.6,38),(7.6,37)
-            | (8.1,37.5),(8.1,37.5)
-            | (-3,-10),(-5,-12)
-            | (-2,-9),(-4,-11)
-            | (-2.5,-8.5),(-2.5,-9.5)
-            | (-2,-9),(-2,-9)
-            | (12,12),(10,10)
-            | (13,13),(11,11)
-            | (12.5,13.5),(12.5,12.5)
-            | (13,13),(13,13)
-(24 rows)
-
-SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (12,2),(10,0)
-            | (13,3),(11,1)
-            | (12.5,3.5),(12.5,2.5)
-            | (13,3),(13,3)
-            | (5,-2),(3,-4)
-            | (6,-1),(4,-3)
-            | (5.5,-0.5),(5.5,-1.5)
-            | (6,-1),(6,-1)
-            | (-3.1,-32.5),(-5.1,-34.5)
-            | (-2.1,-31.5),(-4.1,-33.5)
-            | (-2.6,-31),(-2.6,-32)
-            | (-2.1,-31.5),(-2.1,-31.5)
-            | (7,14),(5,12)
-            | (8,15),(6,13)
-            | (7.5,15.5),(7.5,14.5)
-            | (8,15),(8,15)
-            | (-8,-8),(-10,-10)
-            | (-7,-7),(-9,-9)
-            | (-7.5,-6.5),(-7.5,-7.5)
-            | (-7,-7),(-7,-7)
-(24 rows)
-
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
-
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,0),(-0.2,-0.2)
-        | (0.08,0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
-
-SELECT f1::box
-	FROM POINT_TBL;
-          f1           
------------------------
- (0,0),(0,0)
- (-10,0),(-10,0)
- (-3,4),(-3,4)
- (5.1,34.5),(5.1,34.5)
- (-5,-12),(-5,-12)
- (10,10),(10,10)
-(6 rows)
-
-SELECT bound_box(a.f1, b.f1)
-	FROM BOX_TBL a, BOX_TBL b;
-      bound_box      
----------------------
- (2,2),(0,0)
- (3,3),(0,0)
- (2.5,3.5),(0,0)
- (3,3),(0,0)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(1,1)
- (3,3),(1,1)
- (2.5,3.5),(0,0)
- (3,3.5),(1,1)
- (2.5,3.5),(2.5,2.5)
- (3,3.5),(2.5,2.5)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(2.5,2.5)
- (3,3),(3,3)
-(16 rows)
-
---
--- Paths
---
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
-
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
-
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
-
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
-
---
--- Polygons
---
--- containment
-SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
-   FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
-      |       3 | ((2,0),(2,4),(0,0))
-      |       3 | ((3,1),(3,3),(1,0))
-      |       1 | ((0,0))
-      |       2 | ((0,1),(0,1))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM BOX_TBL;
- four |                  polygon                  
-------+-------------------------------------------
-      | ((0,0),(0,2),(2,2),(2,0))
-      | ((1,1),(1,3),(3,3),(3,1))
-      | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
-      | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM PATH_TBL WHERE isclosed(f1);
- four |      polygon      
-------+-------------------
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((11,12),(13,14))
-(4 rows)
-
-SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
-   FROM PATH_TBL
-   WHERE isopen(f1);
- four |         open_path         |          polygon          
-------+---------------------------+---------------------------
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(11,12),(13,14)]         | ((11,12),(13,14))
-(4 rows)
-
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
-
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
-
---
--- Circles
---
-SELECT '' AS six, circle(f1, 50.0)
-   FROM POINT_TBL;
- six |     circle      
------+-----------------
-     | <(0,0),50>
-     | <(-10,0),50>
-     | <(-3,4),50>
-     | <(5.1,34.5),50>
-     | <(-5,-12),50>
-     | <(10,10),50>
-(6 rows)
-
-SELECT '' AS four, circle(f1)
-   FROM BOX_TBL;
- four |        circle         
-------+-----------------------
-      | <(1,1),1.41421356237>
-      | <(2,2),1.41421356237>
-      | <(2.5,3),0.5>
-      | <(3,3),0>
-(4 rows)
-
-SELECT '' AS two, circle(f1)
-   FROM POLYGON_TBL
-   WHERE (# f1) >= 3;
- two |                    circle                     
------+-----------------------------------------------
-     | <(1.33333333333,1.33333333333),2.04168905064>
-     | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
-
-SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
-   FROM CIRCLE_TBL c1, POINT_TBL p1
-   WHERE (p1.f1 <-> c1.f1) > 0
-   ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
-
diff --git a/src/test/regress/expected/geometry_2.out b/src/test/regress/expected/geometry_2.out
deleted file mode 100644
index 5a922bcd3f..0000000000
--- a/src/test/regress/expected/geometry_2.out
+++ /dev/null
@@ -1,563 +0,0 @@
---
--- GEOMETRY
---
--- Back off displayed precision a little bit to reduce platform-to-platform
--- variation in results.
-SET extra_float_digits TO -3;
---
--- Points
---
-SELECT '' AS four, center(f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS four, (@@ f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS six, point(f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS six, (@@ f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS two, (@@ f1) AS center
-   FROM POLYGON_TBL
-   WHERE (# f1) > 2;
- two |            center             
------+-------------------------------
-     | (1.33333333333,1.33333333333)
-     | (2.33333333333,1.33333333333)
-(2 rows)
-
--- "is horizontal" function
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is horizontal" operator
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is vertical" function
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE isvertical(p1.f1, point '(5.1,34.5)');
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
--- "is vertical" operator
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?| point '(5.1,34.5)';
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
---
--- Line segments
---
--- intersection
-SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-   FROM LSEG_TBL l, POINT_TBL p;
-ERROR:  operator does not exist: lseg # point
-LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-                                           ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
-
---
--- Boxes
---
-SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
- six |                              box                               
------+----------------------------------------------------------------
-     | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
-     | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
-     | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
-     | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
-     | (107.071067812,207.071067812),(92.9289321881,192.928932188)
-     | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
-
--- translation
-SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (-8,2),(-10,0)
-            | (-7,3),(-9,1)
-            | (-7.5,3.5),(-7.5,2.5)
-            | (-7,3),(-7,3)
-            | (-1,6),(-3,4)
-            | (0,7),(-2,5)
-            | (-0.5,7.5),(-0.5,6.5)
-            | (0,7),(0,7)
-            | (7.1,36.5),(5.1,34.5)
-            | (8.1,37.5),(6.1,35.5)
-            | (7.6,38),(7.6,37)
-            | (8.1,37.5),(8.1,37.5)
-            | (-3,-10),(-5,-12)
-            | (-2,-9),(-4,-11)
-            | (-2.5,-8.5),(-2.5,-9.5)
-            | (-2,-9),(-2,-9)
-            | (12,12),(10,10)
-            | (13,13),(11,11)
-            | (12.5,13.5),(12.5,12.5)
-            | (13,13),(13,13)
-(24 rows)
-
-SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (12,2),(10,0)
-            | (13,3),(11,1)
-            | (12.5,3.5),(12.5,2.5)
-            | (13,3),(13,3)
-            | (5,-2),(3,-4)
-            | (6,-1),(4,-3)
-            | (5.5,-0.5),(5.5,-1.5)
-            | (6,-1),(6,-1)
-            | (-3.1,-32.5),(-5.1,-34.5)
-            | (-2.1,-31.5),(-4.1,-33.5)
-            | (-2.6,-31),(-2.6,-32)
-            | (-2.1,-31.5),(-2.1,-31.5)
-            | (7,14),(5,12)
-            | (8,15),(6,13)
-            | (7.5,15.5),(7.5,14.5)
-            | (8,15),(8,15)
-            | (-8,-8),(-10,-10)
-            | (-7,-7),(-9,-9)
-            | (-7.5,-6.5),(-7.5,-7.5)
-            | (-7,-7),(-7,-7)
-(24 rows)
-
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (-0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (-0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,-0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
-
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,-0),(-0.2,-0.2)
-        | (0.08,-0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (-0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
-
-SELECT f1::box
-	FROM POINT_TBL;
-          f1           
------------------------
- (0,0),(0,0)
- (-10,0),(-10,0)
- (-3,4),(-3,4)
- (5.1,34.5),(5.1,34.5)
- (-5,-12),(-5,-12)
- (10,10),(10,10)
-(6 rows)
-
-SELECT bound_box(a.f1, b.f1)
-	FROM BOX_TBL a, BOX_TBL b;
-      bound_box      
----------------------
- (2,2),(0,0)
- (3,3),(0,0)
- (2.5,3.5),(0,0)
- (3,3),(0,0)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(1,1)
- (3,3),(1,1)
- (2.5,3.5),(0,0)
- (3,3.5),(1,1)
- (2.5,3.5),(2.5,2.5)
- (3,3.5),(2.5,2.5)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(2.5,2.5)
- (3,3),(3,3)
-(16 rows)
-
---
--- Paths
---
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
-
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
-
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
-
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
-
---
--- Polygons
---
--- containment
-SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
-   FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
-      |       3 | ((2,0),(2,4),(0,0))
-      |       3 | ((3,1),(3,3),(1,0))
-      |       1 | ((0,0))
-      |       2 | ((0,1),(0,1))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM BOX_TBL;
- four |                  polygon                  
-------+-------------------------------------------
-      | ((0,0),(0,2),(2,2),(2,0))
-      | ((1,1),(1,3),(3,3),(3,1))
-      | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
-      | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM PATH_TBL WHERE isclosed(f1);
- four |      polygon      
-------+-------------------
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((11,12),(13,14))
-(4 rows)
-
-SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
-   FROM PATH_TBL
-   WHERE isopen(f1);
- four |         open_path         |          polygon          
-------+---------------------------+---------------------------
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(11,12),(13,14)]         | ((11,12),(13,14))
-(4 rows)
-
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
-
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
-
---
--- Circles
---
-SELECT '' AS six, circle(f1, 50.0)
-   FROM POINT_TBL;
- six |     circle      
------+-----------------
-     | <(0,0),50>
-     | <(-10,0),50>
-     | <(-3,4),50>
-     | <(5.1,34.5),50>
-     | <(-5,-12),50>
-     | <(10,10),50>
-(6 rows)
-
-SELECT '' AS four, circle(f1)
-   FROM BOX_TBL;
- four |        circle         
-------+-----------------------
-      | <(1,1),1.41421356237>
-      | <(2,2),1.41421356237>
-      | <(2.5,3),0.5>
-      | <(3,3),0>
-(4 rows)
-
-SELECT '' AS two, circle(f1)
-   FROM POLYGON_TBL
-   WHERE (# f1) >= 3;
- two |                    circle                     
------+-----------------------------------------------
-     | <(1.33333333333,1.33333333333),2.04168905064>
-     | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
-
-SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
-   FROM CIRCLE_TBL c1, POINT_TBL p1
-   WHERE (p1.f1 <-> c1.f1) > 0
-   ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
-
diff --git a/src/test/regress/expected/line.out b/src/test/regress/expected/line.out
index f20abdc430..bf780daa2c 100644
--- a/src/test/regress/expected/line.out
+++ b/src/test/regress/expected/line.out
@@ -1,271 +1,87 @@
 --
 -- LINE
 -- Infinite lines
 --
 --DROP TABLE LINE_TBL;
 CREATE TABLE LINE_TBL (s line);
-INSERT INTO LINE_TBL VALUES ('{1,-1,1}');
-INSERT INTO LINE_TBL VALUES ('(0,0),(6,6)');
+INSERT INTO LINE_TBL VALUES ('{0,-1,5}');	-- A == 0
+INSERT INTO LINE_TBL VALUES ('{1,0,5}');	-- B == 0
+INSERT INTO LINE_TBL VALUES ('{0,3,0}');	-- A == C == 0
+INSERT INTO LINE_TBL VALUES (' (0,0), (6,6)');
 INSERT INTO LINE_TBL VALUES ('10,-10 ,-5,-4');
 INSERT INTO LINE_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LINE_TBL VALUES ('(11,22,33,44)');
-INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
-ERROR:  invalid line specification: must be two distinct points
-LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
-                                     ^
+INSERT INTO LINE_TBL VALUES ('{3,NaN,5}');
+INSERT INTO LINE_TBL VALUES ('{NaN,NaN,NaN}');
 -- horizontal
 INSERT INTO LINE_TBL VALUES ('[(1,3),(2,3)]');
 -- vertical
-INSERT INTO LINE_TBL VALUES ('[(3,1),(3,2)]');
+INSERT INTO LINE_TBL VALUES (line(point '(3,1)', point '(3,2)'));
 -- bad values for parser testing
+INSERT INTO LINE_TBL VALUES ('{}');
+ERROR:  invalid input syntax for type line: "{}"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{}');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0');
+ERROR:  invalid input syntax for type line: "{0"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0,0}');
+ERROR:  invalid input syntax for type line: "{0,0}"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0}');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0,0,1');
+ERROR:  invalid input syntax for type line: "{0,0,1"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1');
+                                     ^
 INSERT INTO LINE_TBL VALUES ('{0,0,1}');
 ERROR:  invalid line specification: A and B cannot both be zero
 LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1}');
                                      ^
+INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
+ERROR:  invalid input syntax for type line: "{0,0,1} x"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
+                                     ^
 INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
 ERROR:  invalid input syntax for type line: "(3asdf,2 ,3,4r2)"
 LINE 1: INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
                                      ^
 INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
 ERROR:  invalid input syntax for type line: "[1,2,3, 4"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
                                      ^
 INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
 ERROR:  invalid input syntax for type line: "[(,2),(3,4)]"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
                                      ^
 INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
 ERROR:  invalid input syntax for type line: "[(1,2),(3,4)"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
                                      ^
+INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
+ERROR:  invalid line specification: must be two distinct points
+LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
+                                     ^
+INSERT INTO LINE_TBL VALUES (line(point '(1,0)', point '(1,0)'));
+ERROR:  invalid line specification: must be two distinct points
 select * from LINE_TBL;
                       s                      
 ---------------------------------------------
- {1,-1,1}
+ {0,-1,5}
+ {1,0,5}
+ {0,3,0}
  {1,-1,0}
  {-0.4,-1,-6}
  {-0.000184615384615385,-1,15.3846153846154}
- {1,-1,11}
+ {3,NaN,5}
+ {NaN,NaN,NaN}
  {0,-1,3}
  {-1,0,3}
-(7 rows)
+(10 rows)
 
--- functions and operators
-SELECT * FROM LINE_TBL WHERE (s <-> line '[(1,2),(3,4)]') < 10;
-                      s                      
----------------------------------------------
- {1,-1,1}
- {1,-1,0}
- {-0.4,-1,-6}
- {-0.000184615384615385,-1,15.3846153846154}
- {1,-1,11}
- {0,-1,3}
- {-1,0,3}
-(7 rows)
-
-SELECT * FROM LINE_TBL WHERE (point '(0.1,0.1)' <-> s) < 1;
-    s     
-----------
- {1,-1,1}
- {1,-1,0}
-(2 rows)
-
-SELECT * FROM LINE_TBL WHERE (lseg '[(0.1,0.1),(0.2,0.2)]' <-> s) < 1;
-    s     
-----------
- {1,-1,1}
- {1,-1,0}
-(2 rows)
-
-SELECT line '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
- ?column? 
-----------
-        2
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
- ?column? 
-----------
-        2
-(1 row)
-
-SELECT point '(-1,1)' <-> line '[(-3,0),(-4,0)]';
- ?column? 
-----------
-        1
-(1 row)
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(2,0),(0,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# box '(0,0,2,2)';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(3,0),(4,1)]' ?# box '(0,0,2,2)';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(1,1)' <@ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT point '(1,1)' <@ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(1,1)' @ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT point '(1,1)' @ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT lseg '[(1,1),(2,2)]' <@ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' <@ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT lseg '[(1,1),(2,2)]' @ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' @ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(0,1)' ## line '[(0,0),(1,1)]';
- ?column?  
------------
- (0.5,0.5)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ## lseg '[(1,0),(2,0)]';
- ?column? 
-----------
- (1,0)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(2,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(1,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(2,1)]';
- ?column? 
-----------
- 
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(1,1)]';
- ?column? 
-----------
- (1,1)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(2,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,0)]' ?-| line '[(0,0),(0,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?-| line '[(1,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT ?- line '[(0,0),(1,0)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT ?- line '[(0,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT ?| line '[(0,0),(0,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT ?| line '[(0,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line(point '(1,2)', point '(3,4)');
-   line   
-----------
- {1,-1,1}
-(1 row)
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,5)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,4)]';  -- false
- ?column? 
-----------
- f
+select '{nan, 1, nan}'::line = '{nan, 1, nan}'::line as true,
+	   '{nan, 1, nan}'::line = '{nan, 2, nan}'::line as false;
+ true | false 
+------+-------
+ t    | f
 (1 row)
 
diff --git a/src/test/regress/expected/lseg.out b/src/test/regress/expected/lseg.out
index bba1f3ee80..7e878b5577 100644
--- a/src/test/regress/expected/lseg.out
+++ b/src/test/regress/expected/lseg.out
@@ -1,21 +1,24 @@
 --
 -- LSEG
 -- Line segments
 --
 --DROP TABLE LSEG_TBL;
 CREATE TABLE LSEG_TBL (s lseg);
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('(0,0),(6,6)');
 INSERT INTO LSEG_TBL VALUES ('10,-10 ,-3,-4');
 INSERT INTO LSEG_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LSEG_TBL VALUES ('(11,22,33,44)');
+INSERT INTO LSEG_TBL VALUES (lseg(point(11, 22), point(33,44)));
+INSERT INTO LSEG_TBL VALUES ('[(-10,2),(-10,3)]');	-- vertical
+INSERT INTO LSEG_TBL VALUES ('[(0,-20),(30,-20)]');	-- horizontal
+INSERT INTO LSEG_TBL VALUES ('[(NaN,1),(NaN,90)]');	-- NaN
 -- bad values for parser testing
 INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
 ERROR:  invalid input syntax for type lseg: "(3asdf,2 ,3,4r2)"
 LINE 1: INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
                                      ^
 INSERT INTO LSEG_TBL VALUES ('[1,2,3, 4');
 ERROR:  invalid input syntax for type lseg: "[1,2,3, 4"
 LINE 1: INSERT INTO LSEG_TBL VALUES ('[1,2,3, 4');
                                      ^
 INSERT INTO LSEG_TBL VALUES ('[(,2),(3,4)]');
@@ -27,26 +30,15 @@ ERROR:  invalid input syntax for type lseg: "[(1,2),(3,4)"
 LINE 1: INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)');
                                      ^
 select * from LSEG_TBL;
                s               
 -------------------------------
  [(1,2),(3,4)]
  [(0,0),(6,6)]
  [(10,-10),(-3,-4)]
  [(-1000000,200),(300000,-40)]
  [(11,22),(33,44)]
-(5 rows)
-
-SELECT * FROM LSEG_TBL WHERE s <= lseg '[(1,2),(3,4)]';
-       s       
----------------
- [(1,2),(3,4)]
-(1 row)
-
-SELECT * FROM LSEG_TBL WHERE (s <-> lseg '[(1,2),(3,4)]') < 10;
-         s          
---------------------
- [(1,2),(3,4)]
- [(0,0),(6,6)]
- [(10,-10),(-3,-4)]
-(3 rows)
+ [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]
+ [(NaN,1),(NaN,90)]
+(8 rows)
 
diff --git a/src/test/regress/expected/path.out b/src/test/regress/expected/path.out
index 08d6d61dda..bd6e467752 100644
--- a/src/test/regress/expected/path.out
+++ b/src/test/regress/expected/path.out
@@ -1,79 +1,82 @@
 --
 -- PATH
 --
 --DROP TABLE PATH_TBL;
 CREATE TABLE PATH_TBL (f1 path);
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)]');
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
-INSERT INTO PATH_TBL VALUES ('[(0,0),(3,0),(4,5),(1,6)]');
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
-INSERT INTO PATH_TBL VALUES ('1,2 ,3,4');
-INSERT INTO PATH_TBL VALUES ('[1,2,3, 4]');
-INSERT INTO PATH_TBL VALUES ('[11,12,13,14]');
-INSERT INTO PATH_TBL VALUES ('(11,12,13,14)');
+INSERT INTO PATH_TBL VALUES (' ( ( 1 , 2 ) , ( 3 , 4 ) ) ');
+INSERT INTO PATH_TBL VALUES ('[ (0,0),(3,0),(4,5),(1,6) ]');
+INSERT INTO PATH_TBL VALUES ('((1,2) ,(3,4 ))');
+INSERT INTO PATH_TBL VALUES ('1,2 ,3,4 ');
+INSERT INTO PATH_TBL VALUES (' [1,2,3, 4] ');
+INSERT INTO PATH_TBL VALUES ('((10,20))');	-- Only one point
+INSERT INTO PATH_TBL VALUES ('[ 11,12,13,14 ]');
+INSERT INTO PATH_TBL VALUES ('( 11,12,13,14) ');
 -- bad values for parser testing
+INSERT INTO PATH_TBL VALUES ('[]');
+ERROR:  invalid input syntax for type path: "[]"
+LINE 1: INSERT INTO PATH_TBL VALUES ('[]');
+                                     ^
 INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
 ERROR:  invalid input syntax for type path: "[(,2),(3,4)]"
 LINE 1: INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
                                      ^
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
 ERROR:  invalid input syntax for type path: "[(1,2),(3,4)"
 LINE 1: INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
                                      ^
-SELECT f1 FROM PATH_TBL;
-            f1             
----------------------------
- [(1,2),(3,4)]
- ((1,2),(3,4))
- [(0,0),(3,0),(4,5),(1,6)]
- ((1,2),(3,4))
- ((1,2),(3,4))
- [(1,2),(3,4)]
- [(11,12),(13,14)]
- ((11,12),(13,14))
-(8 rows)
-
+INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+ERROR:  invalid input syntax for type path: "(1,2,3,4"
+LINE 1: INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+                                     ^
+INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
+ERROR:  invalid input syntax for type path: "(1,2),(3,4)]"
+LINE 1: INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
+                                     ^
 SELECT '' AS count, f1 AS open_path FROM PATH_TBL WHERE isopen(f1);
  count |         open_path         
 -------+---------------------------
        | [(1,2),(3,4)]
        | [(0,0),(3,0),(4,5),(1,6)]
        | [(1,2),(3,4)]
        | [(11,12),(13,14)]
 (4 rows)
 
 SELECT '' AS count, f1 AS closed_path FROM PATH_TBL WHERE isclosed(f1);
  count |    closed_path    
 -------+-------------------
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
+       | ((10,20))
        | ((11,12),(13,14))
-(4 rows)
+(5 rows)
 
 SELECT '' AS count, pclose(f1) AS closed_path FROM PATH_TBL;
  count |        closed_path        
 -------+---------------------------
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((0,0),(3,0),(4,5),(1,6))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
+       | ((10,20))
        | ((11,12),(13,14))
        | ((11,12),(13,14))
-(8 rows)
+(9 rows)
 
 SELECT '' AS count, popen(f1) AS open_path FROM PATH_TBL;
  count |         open_path         
 -------+---------------------------
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
        | [(0,0),(3,0),(4,5),(1,6)]
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
+       | [(10,20)]
        | [(11,12),(13,14)]
        | [(11,12),(13,14)]
-(8 rows)
+(9 rows)
 
diff --git a/src/test/regress/expected/point.out b/src/test/regress/expected/point.out
index bfc0962749..c18e865370 100644
--- a/src/test/regress/expected/point.out
+++ b/src/test/regress/expected/point.out
@@ -1,43 +1,57 @@
 --
 -- POINT
 --
 CREATE TABLE POINT_TBL(f1 point);
 INSERT INTO POINT_TBL(f1) VALUES ('(0.0,0.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-10.0,0.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-3.0,4.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(5.1, 34.5)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-5.0,-12.0)');
+INSERT INTO POINT_TBL(f1) VALUES ('(1e-300,-1e-300)');	-- To underflow
+INSERT INTO POINT_TBL(f1) VALUES ('(1e+300,Inf)');		-- To overflow
+INSERT INTO POINT_TBL(f1) VALUES (' ( Nan , NaN ) ');
 -- bad format points
 INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
 ERROR:  invalid input syntax for type point: "asdfasdf"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
                                           ^
 INSERT INTO POINT_TBL(f1) VALUES ('10.0,10.0');
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
 ERROR:  invalid input syntax for type point: "(10.0 10.0)"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
                                           ^
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+ERROR:  invalid input syntax for type point: "(10.0, 10.0) x"
+LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+                                          ^
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
 ERROR:  invalid input syntax for type point: "(10.0,10.0"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
                                           ^
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');	-- Out of range
+ERROR:  "1e+500" is out of range for type double precision
+LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');
+                                          ^
 SELECT '' AS six, * FROM POINT_TBL;
- six |     f1     
------+------------
+ six |        f1         
+-----+-------------------
      | (0,0)
      | (-10,0)
      | (-3,4)
      | (5.1,34.5)
      | (-5,-12)
+     | (1e-300,-1e-300)
+     | (1e+300,Infinity)
+     | (NaN,NaN)
      | (10,10)
-(6 rows)
+(9 rows)
 
 -- left of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE p.f1 << '(0.0, 0.0)';
  three |    f1    
 -------+----------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
 (3 rows)
 
@@ -85,172 +99,282 @@ 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    
--------+----------
+ three |        f1         
+-------+-------------------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
-(3 rows)
+       | (1e-300,-1e-300)
+       | (1e+300,Infinity)
+       | (NaN,NaN)
+(6 rows)
 
 SELECT '' AS two, p.* FROM POINT_TBL p
    WHERE p.f1 <@ path '[(0,0),(-10,0),(-10,10)]';
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 SELECT '' AS three, p.* FROM POINT_TBL p
    WHERE not box '(0,0,100,100)' @> p.f1;
- three |    f1    
--------+----------
+ three |        f1         
+-------+-------------------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
-(3 rows)
+       | (1e-300,-1e-300)
+       | (1e+300,Infinity)
+       | (NaN,NaN)
+(6 rows)
 
 SELECT '' AS six, p.f1, p.f1 <-> point '(0,0)' AS dist
    FROM POINT_TBL p
    ORDER BY dist;
- six |     f1     |       dist       
------+------------+------------------
-     | (0,0)      |                0
-     | (-3,4)     |                5
-     | (-10,0)    |               10
-     | (-5,-12)   |               13
-     | (10,10)    |  14.142135623731
-     | (5.1,34.5) | 34.8749193547455
-(6 rows)
+ six |        f1         |         dist         
+-----+-------------------+----------------------
+     | (0,0)             |                    0
+     | (1e-300,-1e-300)  | 1.4142135623731e-300
+     | (-3,4)            |                    5
+     | (-10,0)           |                   10
+     | (-5,-12)          |                   13
+     | (10,10)           |      14.142135623731
+     | (5.1,34.5)        |     34.8749193547455
+     | (1e+300,Infinity) |             Infinity
+     | (NaN,NaN)         |                  NaN
+(9 rows)
 
 SELECT '' AS thirtysix, p1.f1 AS point1, p2.f1 AS point2, p1.f1 <-> p2.f1 AS dist
    FROM POINT_TBL p1, POINT_TBL p2
    ORDER BY dist, p1.f1[0], p2.f1[0];
- thirtysix |   point1   |   point2   |       dist       
------------+------------+------------+------------------
-           | (-10,0)    | (-10,0)    |                0
-           | (-5,-12)   | (-5,-12)   |                0
-           | (-3,4)     | (-3,4)     |                0
-           | (0,0)      | (0,0)      |                0
-           | (5.1,34.5) | (5.1,34.5) |                0
-           | (10,10)    | (10,10)    |                0
-           | (-3,4)     | (0,0)      |                5
-           | (0,0)      | (-3,4)     |                5
-           | (-10,0)    | (-3,4)     | 8.06225774829855
-           | (-3,4)     | (-10,0)    | 8.06225774829855
-           | (-10,0)    | (0,0)      |               10
-           | (0,0)      | (-10,0)    |               10
-           | (-10,0)    | (-5,-12)   |               13
-           | (-5,-12)   | (-10,0)    |               13
-           | (-5,-12)   | (0,0)      |               13
-           | (0,0)      | (-5,-12)   |               13
-           | (0,0)      | (10,10)    |  14.142135623731
-           | (10,10)    | (0,0)      |  14.142135623731
-           | (-3,4)     | (10,10)    | 14.3178210632764
-           | (10,10)    | (-3,4)     | 14.3178210632764
-           | (-5,-12)   | (-3,4)     | 16.1245154965971
-           | (-3,4)     | (-5,-12)   | 16.1245154965971
-           | (-10,0)    | (10,10)    | 22.3606797749979
-           | (10,10)    | (-10,0)    | 22.3606797749979
-           | (5.1,34.5) | (10,10)    | 24.9851956166046
-           | (10,10)    | (5.1,34.5) | 24.9851956166046
-           | (-5,-12)   | (10,10)    | 26.6270539113887
-           | (10,10)    | (-5,-12)   | 26.6270539113887
-           | (-3,4)     | (5.1,34.5) | 31.5572495632937
-           | (5.1,34.5) | (-3,4)     | 31.5572495632937
-           | (0,0)      | (5.1,34.5) | 34.8749193547455
-           | (5.1,34.5) | (0,0)      | 34.8749193547455
-           | (-10,0)    | (5.1,34.5) | 37.6597928831267
-           | (5.1,34.5) | (-10,0)    | 37.6597928831267
-           | (-5,-12)   | (5.1,34.5) | 47.5842410888311
-           | (5.1,34.5) | (-5,-12)   | 47.5842410888311
-(36 rows)
+ thirtysix |      point1       |      point2       |         dist         
+-----------+-------------------+-------------------+----------------------
+           | (-10,0)           | (-10,0)           |                    0
+           | (-5,-12)          | (-5,-12)          |                    0
+           | (-3,4)            | (-3,4)            |                    0
+           | (0,0)             | (0,0)             |                    0
+           | (1e-300,-1e-300)  | (1e-300,-1e-300)  |                    0
+           | (5.1,34.5)        | (5.1,34.5)        |                    0
+           | (10,10)           | (10,10)           |                    0
+           | (0,0)             | (1e-300,-1e-300)  | 1.4142135623731e-300
+           | (1e-300,-1e-300)  | (0,0)             | 1.4142135623731e-300
+           | (-3,4)            | (0,0)             |                    5
+           | (-3,4)            | (1e-300,-1e-300)  |                    5
+           | (0,0)             | (-3,4)            |                    5
+           | (1e-300,-1e-300)  | (-3,4)            |                    5
+           | (-10,0)           | (-3,4)            |     8.06225774829855
+           | (-3,4)            | (-10,0)           |     8.06225774829855
+           | (-10,0)           | (0,0)             |                   10
+           | (-10,0)           | (1e-300,-1e-300)  |                   10
+           | (0,0)             | (-10,0)           |                   10
+           | (1e-300,-1e-300)  | (-10,0)           |                   10
+           | (-10,0)           | (-5,-12)          |                   13
+           | (-5,-12)          | (-10,0)           |                   13
+           | (-5,-12)          | (0,0)             |                   13
+           | (-5,-12)          | (1e-300,-1e-300)  |                   13
+           | (0,0)             | (-5,-12)          |                   13
+           | (1e-300,-1e-300)  | (-5,-12)          |                   13
+           | (0,0)             | (10,10)           |      14.142135623731
+           | (1e-300,-1e-300)  | (10,10)           |      14.142135623731
+           | (10,10)           | (0,0)             |      14.142135623731
+           | (10,10)           | (1e-300,-1e-300)  |      14.142135623731
+           | (-3,4)            | (10,10)           |     14.3178210632764
+           | (10,10)           | (-3,4)            |     14.3178210632764
+           | (-5,-12)          | (-3,4)            |     16.1245154965971
+           | (-3,4)            | (-5,-12)          |     16.1245154965971
+           | (-10,0)           | (10,10)           |     22.3606797749979
+           | (10,10)           | (-10,0)           |     22.3606797749979
+           | (5.1,34.5)        | (10,10)           |     24.9851956166046
+           | (10,10)           | (5.1,34.5)        |     24.9851956166046
+           | (-5,-12)          | (10,10)           |     26.6270539113887
+           | (10,10)           | (-5,-12)          |     26.6270539113887
+           | (-3,4)            | (5.1,34.5)        |     31.5572495632937
+           | (5.1,34.5)        | (-3,4)            |     31.5572495632937
+           | (0,0)             | (5.1,34.5)        |     34.8749193547455
+           | (1e-300,-1e-300)  | (5.1,34.5)        |     34.8749193547455
+           | (5.1,34.5)        | (0,0)             |     34.8749193547455
+           | (5.1,34.5)        | (1e-300,-1e-300)  |     34.8749193547455
+           | (-10,0)           | (5.1,34.5)        |     37.6597928831267
+           | (5.1,34.5)        | (-10,0)           |     37.6597928831267
+           | (-5,-12)          | (5.1,34.5)        |     47.5842410888311
+           | (5.1,34.5)        | (-5,-12)          |     47.5842410888311
+           | (-10,0)           | (1e+300,Infinity) |             Infinity
+           | (-5,-12)          | (1e+300,Infinity) |             Infinity
+           | (-3,4)            | (1e+300,Infinity) |             Infinity
+           | (0,0)             | (1e+300,Infinity) |             Infinity
+           | (1e-300,-1e-300)  | (1e+300,Infinity) |             Infinity
+           | (5.1,34.5)        | (1e+300,Infinity) |             Infinity
+           | (10,10)           | (1e+300,Infinity) |             Infinity
+           | (1e+300,Infinity) | (-10,0)           |             Infinity
+           | (1e+300,Infinity) | (-5,-12)          |             Infinity
+           | (1e+300,Infinity) | (-3,4)            |             Infinity
+           | (1e+300,Infinity) | (0,0)             |             Infinity
+           | (1e+300,Infinity) | (1e-300,-1e-300)  |             Infinity
+           | (1e+300,Infinity) | (5.1,34.5)        |             Infinity
+           | (1e+300,Infinity) | (10,10)           |             Infinity
+           | (-10,0)           | (NaN,NaN)         |                  NaN
+           | (-5,-12)          | (NaN,NaN)         |                  NaN
+           | (-3,4)            | (NaN,NaN)         |                  NaN
+           | (0,0)             | (NaN,NaN)         |                  NaN
+           | (1e-300,-1e-300)  | (NaN,NaN)         |                  NaN
+           | (5.1,34.5)        | (NaN,NaN)         |                  NaN
+           | (10,10)           | (NaN,NaN)         |                  NaN
+           | (1e+300,Infinity) | (1e+300,Infinity) |                  NaN
+           | (1e+300,Infinity) | (NaN,NaN)         |                  NaN
+           | (NaN,NaN)         | (-10,0)           |                  NaN
+           | (NaN,NaN)         | (-5,-12)          |                  NaN
+           | (NaN,NaN)         | (-3,4)            |                  NaN
+           | (NaN,NaN)         | (0,0)             |                  NaN
+           | (NaN,NaN)         | (1e-300,-1e-300)  |                  NaN
+           | (NaN,NaN)         | (5.1,34.5)        |                  NaN
+           | (NaN,NaN)         | (10,10)           |                  NaN
+           | (NaN,NaN)         | (1e+300,Infinity) |                  NaN
+           | (NaN,NaN)         | (NaN,NaN)         |                  NaN
+(81 rows)
 
 SELECT '' AS thirty, p1.f1 AS point1, p2.f1 AS point2
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3;
- thirty |   point1   |   point2   
---------+------------+------------
-        | (0,0)      | (-10,0)
-        | (0,0)      | (-3,4)
-        | (0,0)      | (5.1,34.5)
-        | (0,0)      | (-5,-12)
-        | (0,0)      | (10,10)
-        | (-10,0)    | (0,0)
-        | (-10,0)    | (-3,4)
-        | (-10,0)    | (5.1,34.5)
-        | (-10,0)    | (-5,-12)
-        | (-10,0)    | (10,10)
-        | (-3,4)     | (0,0)
-        | (-3,4)     | (-10,0)
-        | (-3,4)     | (5.1,34.5)
-        | (-3,4)     | (-5,-12)
-        | (-3,4)     | (10,10)
-        | (5.1,34.5) | (0,0)
-        | (5.1,34.5) | (-10,0)
-        | (5.1,34.5) | (-3,4)
-        | (5.1,34.5) | (-5,-12)
-        | (5.1,34.5) | (10,10)
-        | (-5,-12)   | (0,0)
-        | (-5,-12)   | (-10,0)
-        | (-5,-12)   | (-3,4)
-        | (-5,-12)   | (5.1,34.5)
-        | (-5,-12)   | (10,10)
-        | (10,10)    | (0,0)
-        | (10,10)    | (-10,0)
-        | (10,10)    | (-3,4)
-        | (10,10)    | (5.1,34.5)
-        | (10,10)    | (-5,-12)
-(30 rows)
+ thirty |      point1       |      point2       
+--------+-------------------+-------------------
+        | (0,0)             | (-10,0)
+        | (0,0)             | (-3,4)
+        | (0,0)             | (5.1,34.5)
+        | (0,0)             | (-5,-12)
+        | (0,0)             | (1e+300,Infinity)
+        | (0,0)             | (NaN,NaN)
+        | (0,0)             | (10,10)
+        | (-10,0)           | (0,0)
+        | (-10,0)           | (-3,4)
+        | (-10,0)           | (5.1,34.5)
+        | (-10,0)           | (-5,-12)
+        | (-10,0)           | (1e-300,-1e-300)
+        | (-10,0)           | (1e+300,Infinity)
+        | (-10,0)           | (NaN,NaN)
+        | (-10,0)           | (10,10)
+        | (-3,4)            | (0,0)
+        | (-3,4)            | (-10,0)
+        | (-3,4)            | (5.1,34.5)
+        | (-3,4)            | (-5,-12)
+        | (-3,4)            | (1e-300,-1e-300)
+        | (-3,4)            | (1e+300,Infinity)
+        | (-3,4)            | (NaN,NaN)
+        | (-3,4)            | (10,10)
+        | (5.1,34.5)        | (0,0)
+        | (5.1,34.5)        | (-10,0)
+        | (5.1,34.5)        | (-3,4)
+        | (5.1,34.5)        | (-5,-12)
+        | (5.1,34.5)        | (1e-300,-1e-300)
+        | (5.1,34.5)        | (1e+300,Infinity)
+        | (5.1,34.5)        | (NaN,NaN)
+        | (5.1,34.5)        | (10,10)
+        | (-5,-12)          | (0,0)
+        | (-5,-12)          | (-10,0)
+        | (-5,-12)          | (-3,4)
+        | (-5,-12)          | (5.1,34.5)
+        | (-5,-12)          | (1e-300,-1e-300)
+        | (-5,-12)          | (1e+300,Infinity)
+        | (-5,-12)          | (NaN,NaN)
+        | (-5,-12)          | (10,10)
+        | (1e-300,-1e-300)  | (-10,0)
+        | (1e-300,-1e-300)  | (-3,4)
+        | (1e-300,-1e-300)  | (5.1,34.5)
+        | (1e-300,-1e-300)  | (-5,-12)
+        | (1e-300,-1e-300)  | (1e+300,Infinity)
+        | (1e-300,-1e-300)  | (NaN,NaN)
+        | (1e-300,-1e-300)  | (10,10)
+        | (1e+300,Infinity) | (0,0)
+        | (1e+300,Infinity) | (-10,0)
+        | (1e+300,Infinity) | (-3,4)
+        | (1e+300,Infinity) | (5.1,34.5)
+        | (1e+300,Infinity) | (-5,-12)
+        | (1e+300,Infinity) | (1e-300,-1e-300)
+        | (1e+300,Infinity) | (1e+300,Infinity)
+        | (1e+300,Infinity) | (NaN,NaN)
+        | (1e+300,Infinity) | (10,10)
+        | (NaN,NaN)         | (0,0)
+        | (NaN,NaN)         | (-10,0)
+        | (NaN,NaN)         | (-3,4)
+        | (NaN,NaN)         | (5.1,34.5)
+        | (NaN,NaN)         | (-5,-12)
+        | (NaN,NaN)         | (1e-300,-1e-300)
+        | (NaN,NaN)         | (1e+300,Infinity)
+        | (NaN,NaN)         | (NaN,NaN)
+        | (NaN,NaN)         | (10,10)
+        | (10,10)           | (0,0)
+        | (10,10)           | (-10,0)
+        | (10,10)           | (-3,4)
+        | (10,10)           | (5.1,34.5)
+        | (10,10)           | (-5,-12)
+        | (10,10)           | (1e-300,-1e-300)
+        | (10,10)           | (1e+300,Infinity)
+        | (10,10)           | (NaN,NaN)
+(72 rows)
 
 -- put distance result into output to allow sorting with GEQ optimizer - tgl 97/05/10
 SELECT '' AS fifteen, p1.f1 AS point1, p2.f1 AS point2, (p1.f1 <-> p2.f1) AS distance
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3 and p1.f1 << p2.f1
    ORDER BY distance, p1.f1[0], p2.f1[0];
- fifteen |   point1   |   point2   |     distance     
----------+------------+------------+------------------
-         | (-3,4)     | (0,0)      |                5
-         | (-10,0)    | (-3,4)     | 8.06225774829855
-         | (-10,0)    | (0,0)      |               10
-         | (-10,0)    | (-5,-12)   |               13
-         | (-5,-12)   | (0,0)      |               13
-         | (0,0)      | (10,10)    |  14.142135623731
-         | (-3,4)     | (10,10)    | 14.3178210632764
-         | (-5,-12)   | (-3,4)     | 16.1245154965971
-         | (-10,0)    | (10,10)    | 22.3606797749979
-         | (5.1,34.5) | (10,10)    | 24.9851956166046
-         | (-5,-12)   | (10,10)    | 26.6270539113887
-         | (-3,4)     | (5.1,34.5) | 31.5572495632937
-         | (0,0)      | (5.1,34.5) | 34.8749193547455
-         | (-10,0)    | (5.1,34.5) | 37.6597928831267
-         | (-5,-12)   | (5.1,34.5) | 47.5842410888311
-(15 rows)
+ fifteen |      point1      |      point2       |     distance     
+---------+------------------+-------------------+------------------
+         | (-3,4)           | (0,0)             |                5
+         | (-3,4)           | (1e-300,-1e-300)  |                5
+         | (-10,0)          | (-3,4)            | 8.06225774829855
+         | (-10,0)          | (0,0)             |               10
+         | (-10,0)          | (1e-300,-1e-300)  |               10
+         | (-10,0)          | (-5,-12)          |               13
+         | (-5,-12)         | (0,0)             |               13
+         | (-5,-12)         | (1e-300,-1e-300)  |               13
+         | (0,0)            | (10,10)           |  14.142135623731
+         | (1e-300,-1e-300) | (10,10)           |  14.142135623731
+         | (-3,4)           | (10,10)           | 14.3178210632764
+         | (-5,-12)         | (-3,4)            | 16.1245154965971
+         | (-10,0)          | (10,10)           | 22.3606797749979
+         | (5.1,34.5)       | (10,10)           | 24.9851956166046
+         | (-5,-12)         | (10,10)           | 26.6270539113887
+         | (-3,4)           | (5.1,34.5)        | 31.5572495632937
+         | (0,0)            | (5.1,34.5)        | 34.8749193547455
+         | (1e-300,-1e-300) | (5.1,34.5)        | 34.8749193547455
+         | (-10,0)          | (5.1,34.5)        | 37.6597928831267
+         | (-5,-12)         | (5.1,34.5)        | 47.5842410888311
+         | (-10,0)          | (1e+300,Infinity) |         Infinity
+         | (-5,-12)         | (1e+300,Infinity) |         Infinity
+         | (-3,4)           | (1e+300,Infinity) |         Infinity
+         | (0,0)            | (1e+300,Infinity) |         Infinity
+         | (1e-300,-1e-300) | (1e+300,Infinity) |         Infinity
+         | (5.1,34.5)       | (1e+300,Infinity) |         Infinity
+         | (10,10)          | (1e+300,Infinity) |         Infinity
+(27 rows)
 
 -- put distance result into output to allow sorting with GEQ optimizer - tgl 97/05/10
 SELECT '' AS three, p1.f1 AS point1, p2.f1 AS point2, (p1.f1 <-> p2.f1) AS distance
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3 and p1.f1 << p2.f1 and p1.f1 >^ p2.f1
    ORDER BY distance;
- three |   point1   |  point2  |     distance     
--------+------------+----------+------------------
-       | (-3,4)     | (0,0)    |                5
-       | (-10,0)    | (-5,-12) |               13
-       | (5.1,34.5) | (10,10)  | 24.9851956166046
-(3 rows)
+ three |   point1   |      point2      |     distance     
+-------+------------+------------------+------------------
+       | (-3,4)     | (0,0)            |                5
+       | (-3,4)     | (1e-300,-1e-300) |                5
+       | (-10,0)    | (-5,-12)         |               13
+       | (5.1,34.5) | (10,10)          | 24.9851956166046
+(4 rows)
 
 -- Test that GiST indexes provide same behavior as sequential scan
 CREATE TEMP TABLE point_gist_tbl(f1 point);
 INSERT INTO point_gist_tbl SELECT '(0,0)' FROM generate_series(0,1000);
 CREATE INDEX point_gist_tbl_index ON point_gist_tbl USING gist (f1);
 INSERT INTO point_gist_tbl VALUES ('(0.0000009,0.0000009)');
 SET enable_seqscan TO true;
 SET enable_indexscan TO false;
 SET enable_bitmapscan TO false;
 SELECT COUNT(*) FROM point_gist_tbl WHERE f1 ~= '(0.0000009,0.0000009)'::point;
diff --git a/src/test/regress/expected/polygon.out b/src/test/regress/expected/polygon.out
index 4a1f60427a..be5f76bf9d 100644
--- a/src/test/regress/expected/polygon.out
+++ b/src/test/regress/expected/polygon.out
@@ -1,18 +1,21 @@
 --
 -- POLYGON
 --
 -- polygon logic
 --
 CREATE TABLE POLYGON_TBL(f1 polygon);
 INSERT INTO POLYGON_TBL(f1) VALUES ('(2.0,0.0),(2.0,4.0),(0.0,0.0)');
 INSERT INTO POLYGON_TBL(f1) VALUES ('(3.0,1.0),(3.0,3.0),(1.0,0.0)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(3,4),(5,6),(7,8)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(7,8),(5,6),(3,4),(1,2)'); -- Reverse
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(7,8),(5,6),(3,-4)');
 -- degenerate polygons
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,0.0)');
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,1.0),(0.0,1.0)');
 -- bad polygon input strings
 INSERT INTO POLYGON_TBL(f1) VALUES ('0.0');
 ERROR:  invalid input syntax for type polygon: "0.0"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('0.0');
                                             ^
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0 0.0');
 ERROR:  invalid input syntax for type polygon: "(0.0 0.0"
@@ -24,215 +27,30 @@ LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2)');
                                             ^
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2,3');
 ERROR:  invalid input syntax for type polygon: "(0,1,2,3"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2,3');
                                             ^
 INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
 ERROR:  invalid input syntax for type polygon: "asdf"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
                                             ^
 SELECT '' AS four, * FROM POLYGON_TBL;
- four |         f1          
-------+---------------------
+ four |             f1             
+------+----------------------------
       | ((2,0),(2,4),(0,0))
       | ((3,1),(3,3),(1,0))
+      | ((1,2),(3,4),(5,6),(7,8))
+      | ((7,8),(5,6),(3,4),(1,2))
+      | ((1,2),(7,8),(5,6),(3,-4))
       | ((0,0))
       | ((0,1),(0,1))
-(4 rows)
-
--- overlap
-SELECT '' AS three, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 && '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- three |         f1          
--------+---------------------
-       | ((2,0),(2,4),(0,0))
-       | ((3,1),(3,3),(1,0))
-(2 rows)
-
--- left overlap
-SELECT '' AS four, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &< '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- four |         f1          
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
-
--- right overlap
-SELECT '' AS two, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- two |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- left of
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 << '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |      f1       
------+---------------
-     | ((0,0))
-     | ((0,1),(0,1))
-(2 rows)
-
--- right of
-SELECT '' AS zero, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 >> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- zero | f1 
-------+----
-(0 rows)
-
--- contained
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- same
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- contains
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
---
--- polygon logic
---
--- left of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- left overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
- true 
-------
- f
-(1 row)
-
--- right overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' &> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- right of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' >> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- contained in
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- contains
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((0,4),(6,4),(3,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
-SELECT '((1,1),(1,4),(5,4),(5,3),(2,3),(2,2),(5,2),(5,1))'::polygon @> '((3,2),(3,3),(4,3),(4,2))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((0,0),(0,3),(3,3),(3,0))'::polygon @> '((2,1),(2,2),(3,2),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
--- same
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' && polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
- true 
-------
- t
-(1 row)
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon && '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
-SELECT '((1,4),(1,1),(4,1),(4,2),(2,2),(2,4),(1,4))'::polygon && '((3,3),(4,3),(4,4),(3,4),(3,3))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((200,800),(800,800),(800,200),(200,200))' &&  '(1000,1000,0,0)'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
--- distance from a point
-SELECT	'(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
-	'(1,1)'::point <-> '((0,0),(2,2),(1,3))'::polygon as on_segment,
-	'(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;
- on_corner | on_segment | inside |   near_corner   | near_segment 
------------+------------+--------+-----------------+--------------
-         0 |          0 |      0 | 1.4142135623731 |          3.2
-(1 row)
+(7 rows)
 
 --
 -- 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
diff --git a/src/test/regress/sql/box.sql b/src/test/regress/sql/box.sql
index 135ac108eb..6710fc90f5 100644
--- a/src/test/regress/sql/box.sql
+++ b/src/test/regress/sql/box.sql
@@ -18,29 +18,38 @@
 
 -- boxes are specified by two points, given by four floats x1,y1,x2,y2
 
 
 CREATE TABLE BOX_TBL (f1 box);
 
 INSERT INTO BOX_TBL (f1) VALUES ('(2.0,2.0,0.0,0.0)');
 
 INSERT INTO BOX_TBL (f1) VALUES ('(1.0,1.0,3.0,3.0)');
 
+INSERT INTO BOX_TBL (f1) VALUES ('((-8, 2), (-2, -10))');
+
+
 -- degenerate cases where the box is a line or a point
 -- note that lines and points boxes all have zero area
 INSERT INTO BOX_TBL (f1) VALUES ('(2.5, 2.5, 2.5,3.5)');
 
 INSERT INTO BOX_TBL (f1) VALUES ('(3.0, 3.0,3.0,3.0)');
 
 -- badly formatted box inputs
 INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
 
+INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+
 INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
 
 
 SELECT '' AS four, * FROM BOX_TBL;
 
 SELECT '' AS four, b.*, area(b.f1) as barea
    FROM BOX_TBL b;
 
 -- overlap
 SELECT '' AS three, b.f1
diff --git a/src/test/regress/sql/circle.sql b/src/test/regress/sql/circle.sql
index c0284b2b59..46c96e1400 100644
--- a/src/test/regress/sql/circle.sql
+++ b/src/test/regress/sql/circle.sql
@@ -7,26 +7,34 @@ CREATE TABLE CIRCLE_TBL (f1 circle);
 INSERT INTO CIRCLE_TBL VALUES ('<(5,1),3>');
 
 INSERT INTO CIRCLE_TBL VALUES ('<(1,2),100>');
 
 INSERT INTO CIRCLE_TBL VALUES ('1,3,5');
 
 INSERT INTO CIRCLE_TBL VALUES ('((1,2),3)');
 
 INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10>');
 
-INSERT INTO CIRCLE_TBL VALUES ('<(100,1),115>');
+INSERT INTO CIRCLE_TBL VALUES (' < ( 100 , 1 ) , 115 > ');
+
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),0>');	-- Zero radius
+
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),NaN>');	-- NaN radius
 
 -- bad values
 
 INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
 
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+
 INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
 
 INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
 
 SELECT * FROM CIRCLE_TBL;
 
 SELECT '' AS six, center(f1) AS center
   FROM CIRCLE_TBL;
 
 SELECT '' AS six, radius(f1) AS radius
diff --git a/src/test/regress/sql/geometry.sql b/src/test/regress/sql/geometry.sql
index 1429ee772a..ce98b3e90c 100644
--- a/src/test/regress/sql/geometry.sql
+++ b/src/test/regress/sql/geometry.sql
@@ -39,74 +39,298 @@ SELECT '' AS two, p1.f1
 -- "is vertical" function
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE isvertical(p1.f1, point '(5.1,34.5)');
 
 -- "is vertical" operator
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?| point '(5.1,34.5)';
 
+-- Slope
+SELECT p1.f1, p2.f1, slope(p1.f1, p2.f1) FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Add point
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Subtract point
+SELECT p1.f1, p2.f1, p1.f1 - p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Multiply with point
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+
+-- Underflow error
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] < 1;
+
+-- Divide by point
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] BETWEEN 1 AND 1000;
+
+-- Overflow error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] > 1000;
+
+-- Division by 0 error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1 ~= '(0,0)'::point;
+
+-- Distance to line
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LINE_TBL l;
+
+-- Distance to line segment
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LSEG_TBL l;
+
+-- Distance to box
+SELECT p.f1, b.f1, p.f1 <-> b.f1 FROM POINT_TBL p, BOX_TBL b;
+
+-- Distance to path
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, PATH_TBL p1;
+
+-- Distance to polygon
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, POLYGON_TBL p1;
+
+-- Closest point to line
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LINE_TBL l;
+
+-- Closest point to line segment
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LSEG_TBL l;
+
+-- Closest point to box
+SELECT p.f1, b.f1, p.f1 ## b.f1 FROM POINT_TBL p, BOX_TBL b;
+
+-- On line
+SELECT p.f1, l.s FROM POINT_TBL p, LINE_TBL l WHERE p.f1 <@ l.s;
+
+-- On line segment
+SELECT p.f1, l.s FROM POINT_TBL p, LSEG_TBL l WHERE p.f1 <@ l.s;
+
+-- On path
+SELECT p.f1, p1.f1 FROM POINT_TBL p, PATH_TBL p1 WHERE p.f1 <@ p1.f1;
+
+--
+-- Lines
+--
+
+-- Vertical
+SELECT s FROM LINE_TBL WHERE ?| s;
+
+-- Horizontal
+SELECT s FROM LINE_TBL WHERE ?- s;
+
+-- Same as line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s = l2.s;
+
+-- Parallel to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?|| l2.s;
+
+-- Perpendicular to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?-| l2.s;
+
+-- Distance to line
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2;
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LINE_TBL l, BOX_TBL b;
+
+-- Intersect with line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?# l2.s;
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LINE_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+
+-- Intersection point with line
+SELECT l1.s, l2.s, l1.s # l2.s FROM LINE_TBL l1, LINE_TBL l2;
+
+-- Closest point to line segment
+SELECT l.s, l1.s, l.s ## l1.s FROM LINE_TBL l, LSEG_TBL l1;
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LINE_TBL l, BOX_TBL b;
+
 --
 -- Line segments
 --
 
 -- intersection
 SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
    FROM LSEG_TBL l, POINT_TBL p;
 
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
+-- Length
+SELECT s, @-@ s FROM LSEG_TBL;
+
+-- Vertical
+SELECT s FROM LSEG_TBL WHERE ?| s;
+
+-- Horizontal
+SELECT s FROM LSEG_TBL WHERE ?- s;
+
+-- Center
+SELECT s, @@ s FROM LSEG_TBL;
+
+-- To point
+SELECT s, s::point FROM LSEG_TBL;
+
+-- Has points less than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s < l2.s;
+
+-- Has points less than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s <= l2.s;
+
+-- Has points equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s = l2.s;
+
+-- Has points greater than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s >= l2.s;
+
+-- Has points greater than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s > l2.s;
+
+-- Has points not equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s != l2.s;
+
+-- Parallel with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?|| l2.s;
+
+-- Perpendicular with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?-| l2.s;
+
+-- Distance to line
+SELECT l.s, l1.s, l.s <-> l1.s FROM LSEG_TBL l, LINE_TBL l1;
+
+-- Distance to line segment
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LSEG_TBL l, BOX_TBL b;
+
+-- Intersect with line segment
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s ?# l1.s;
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+
+-- Intersection point with line segment
+SELECT l1.s, l2.s, l1.s # l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Closest point to line
+SELECT l.s, l1.s, l.s ## l1.s FROM LSEG_TBL l, LINE_TBL l1;
+
+-- Closest point to line segment
+SELECT l1.s, l2.s, l1.s ## l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LSEG_TBL l, BOX_TBL b;
+
+-- On line
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s <@ l1.s;
+
+-- On box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s <@ b.f1;
 
 --
 -- Boxes
 --
 
 SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
 
 -- translation
 SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
 
 SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
 
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
+-- Multiply with point
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
 
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
+-- Overflow error
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] > 1000;
 
+-- Divide by point
+SELECT b.f1, p.f1, b.f1 / p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+
+-- To box
 SELECT f1::box
 	FROM POINT_TBL;
 
 SELECT bound_box(a.f1, b.f1)
 	FROM BOX_TBL a, BOX_TBL b;
 
+-- Below box
+SELECT b1.f1, b2.f1, b1.f1 <^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Above box
+SELECT b1.f1, b2.f1, b1.f1 >^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Intersection point with box
+SELECT b1.f1, b2.f1, b1.f1 # b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Diagonal
+SELECT f1, diagonal(f1) FROM BOX_TBL;
+
+-- Distance to box
+SELECT b1.f1, b2.f1, b1.f1 <-> b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
 --
 -- Paths
 --
 
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
+-- Points
+SELECT f1, npoints(f1) FROM PATH_TBL;
 
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
+-- Area
+SELECT f1, area(f1) FROM PATH_TBL;
 
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
+-- Length
+SELECT f1, @-@ f1 FROM PATH_TBL;
 
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
+-- Center
+SELECT f1, @@ f1 FROM PATH_TBL;
+
+-- To polygon
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isclosed(f1);
+
+-- Open path cannot be converted to polygon error
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isopen(f1);
+
+-- Has points less than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 < p2.f1;
+
+-- Has points less than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 <= p2.f1;
+
+-- Has points equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 = p2.f1;
+
+-- Has points greater than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 >= p2.f1;
+
+-- Has points greater than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 > p2.f1;
+
+-- Add path
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+
+-- Add point
+SELECT p.f1, p1.f1, p.f1 + p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+
+-- Subtract point
+SELECT p.f1, p1.f1, p.f1 - p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+
+-- Multiply with point
+SELECT p.f1, p1.f1, p.f1 * p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+
+-- Divide by point
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+
+-- Division by 0 error
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1 ~= '(0,0)'::point;
+
+-- Distance to path
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
 
 --
 -- Polygons
 --
 
 -- containment
 SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
    FROM POLYGON_TBL poly, POINT_TBL p;
 
 SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
@@ -118,36 +342,166 @@ SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
 SELECT '' AS four, polygon(f1)
    FROM BOX_TBL;
 
 SELECT '' AS four, polygon(f1)
    FROM PATH_TBL WHERE isclosed(f1);
 
 SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
    FROM PATH_TBL
    WHERE isopen(f1);
 
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
+-- To box
+SELECT f1, f1::box FROM POLYGON_TBL;
 
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
+-- To path
+SELECT f1, f1::path FROM POLYGON_TBL;
+
+-- Same as polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 ~= p2.f1;
+
+-- Contained by polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <@ p2.f1;
+
+-- Contains polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 @> p2.f1;
+
+-- Overlap with polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 && p2.f1;
+
+-- Left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 << p2.f1;
+
+-- Overlap of left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &< p2.f1;
+
+-- Right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 >> p2.f1;
+
+-- Overlap of right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &> p2.f1;
+
+-- Below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <<| p2.f1;
+
+-- Overlap or below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &<| p2.f1;
+
+-- Above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |>> p2.f1;
+
+-- Overlap or above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |&> p2.f1;
+
+-- Distance to polygon
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2;
 
 --
 -- Circles
 --
 
 SELECT '' AS six, circle(f1, 50.0)
    FROM POINT_TBL;
 
 SELECT '' AS four, circle(f1)
    FROM BOX_TBL;
 
 SELECT '' AS two, circle(f1)
    FROM POLYGON_TBL
    WHERE (# f1) >= 3;
 
 SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
    FROM CIRCLE_TBL c1, POINT_TBL p1
    WHERE (p1.f1 <-> c1.f1) > 0
    ORDER BY distance, area(c1.f1), p1.f1[0];
+
+-- To polygon
+SELECT f1, f1::polygon FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+
+-- To polygon with less points
+SELECT f1, polygon(8, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+
+-- Too less points error
+SELECT f1, polygon(1, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+
+-- Zero radius error
+SELECT f1, polygon(10, f1) FROM CIRCLE_TBL WHERE f1 < '<(0,0),1>';
+
+-- Same as circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 ~= c2.f1;
+
+-- Overlap with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 && c2.f1;
+
+-- Overlap or left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &< c2.f1;
+
+-- Left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 << c2.f1;
+
+-- Right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >> c2.f1;
+
+-- Overlap or right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &> c2.f1;
+
+-- Contained by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <@ c2.f1;
+
+-- Contain by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 @> c2.f1;
+
+-- Below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <<| c2.f1;
+
+-- Above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |>> c2.f1;
+
+-- Overlap or below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &<| c2.f1;
+
+-- Overlap or above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |&> c2.f1;
+
+-- Area equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 = c2.f1;
+
+-- Area not equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 != c2.f1;
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 > c2.f1;
+
+-- Area less than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <= c2.f1;
+
+-- Area greater than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >= c2.f1;
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+
+-- Add point
+SELECT c.f1, p.f1, c.f1 + p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Subtract point
+SELECT c.f1, p.f1, c.f1 - p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Multiply with point
+SELECT c.f1, p.f1, c.f1 * p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Divide by point
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+
+-- Overflow error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] > 1000;
+
+-- Division by 0 error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1 ~= '(0,0)'::point;
+
+-- Distance to polygon
+SELECT c.f1, p.f1, c.f1 <-> p.f1 FROM CIRCLE_TBL c, POLYGON_TBL p;
diff --git a/src/test/regress/sql/line.sql b/src/test/regress/sql/line.sql
index 94067b0cee..f589ffecc8 100644
--- a/src/test/regress/sql/line.sql
+++ b/src/test/regress/sql/line.sql
@@ -1,87 +1,42 @@
 --
 -- LINE
 -- Infinite lines
 --
 
 --DROP TABLE LINE_TBL;
 CREATE TABLE LINE_TBL (s line);
 
-INSERT INTO LINE_TBL VALUES ('{1,-1,1}');
-INSERT INTO LINE_TBL VALUES ('(0,0),(6,6)');
+INSERT INTO LINE_TBL VALUES ('{0,-1,5}');	-- A == 0
+INSERT INTO LINE_TBL VALUES ('{1,0,5}');	-- B == 0
+INSERT INTO LINE_TBL VALUES ('{0,3,0}');	-- A == C == 0
+INSERT INTO LINE_TBL VALUES (' (0,0), (6,6)');
 INSERT INTO LINE_TBL VALUES ('10,-10 ,-5,-4');
 INSERT INTO LINE_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LINE_TBL VALUES ('(11,22,33,44)');
 
-INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
+INSERT INTO LINE_TBL VALUES ('{3,NaN,5}');
+INSERT INTO LINE_TBL VALUES ('{NaN,NaN,NaN}');
 
 -- horizontal
 INSERT INTO LINE_TBL VALUES ('[(1,3),(2,3)]');
 -- vertical
-INSERT INTO LINE_TBL VALUES ('[(3,1),(3,2)]');
+INSERT INTO LINE_TBL VALUES (line(point '(3,1)', point '(3,2)'));
 
 -- bad values for parser testing
+INSERT INTO LINE_TBL VALUES ('{}');
+INSERT INTO LINE_TBL VALUES ('{0');
+INSERT INTO LINE_TBL VALUES ('{0,0}');
+INSERT INTO LINE_TBL VALUES ('{0,0,1');
 INSERT INTO LINE_TBL VALUES ('{0,0,1}');
+INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
 INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
 INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
 INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
 INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
+INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
+
+INSERT INTO LINE_TBL VALUES (line(point '(1,0)', point '(1,0)'));
 
 select * from LINE_TBL;
 
-
--- functions and operators
-
-SELECT * FROM LINE_TBL WHERE (s <-> line '[(1,2),(3,4)]') < 10;
-
-SELECT * FROM LINE_TBL WHERE (point '(0.1,0.1)' <-> s) < 1;
-
-SELECT * FROM LINE_TBL WHERE (lseg '[(0.1,0.1),(0.2,0.2)]' <-> s) < 1;
-
-SELECT line '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
-SELECT lseg '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
-SELECT point '(-1,1)' <-> line '[(-3,0),(-4,0)]';
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(2,0),(0,2)]';  -- true
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(0,0),(1,0)]';  -- false
-
-SELECT line '[(0,0),(1,1)]' ?# box '(0,0,2,2)';  -- true
-SELECT line '[(3,0),(4,1)]' ?# box '(0,0,2,2)';  -- false
-
-SELECT point '(1,1)' <@ line '[(0,0),(2,2)]';  -- true
-SELECT point '(1,1)' <@ line '[(0,0),(1,0)]';  -- false
-
-SELECT point '(1,1)' @ line '[(0,0),(2,2)]';  -- true
-SELECT point '(1,1)' @ line '[(0,0),(1,0)]';  -- false
-
-SELECT lseg '[(1,1),(2,2)]' <@ line '[(0,0),(2,2)]';  -- true
-SELECT lseg '[(1,1),(2,1)]' <@ line '[(0,0),(1,0)]';  -- false
-
-SELECT lseg '[(1,1),(2,2)]' @ line '[(0,0),(2,2)]';  -- true
-SELECT lseg '[(1,1),(2,1)]' @ line '[(0,0),(1,0)]';  -- false
-
-SELECT point '(0,1)' ## line '[(0,0),(1,1)]';
-
-SELECT line '[(0,0),(1,1)]' ## lseg '[(1,0),(2,0)]';
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(2,1)]';  -- false
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(1,1)]';  -- true
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(2,1)]';
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(1,1)]';
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(2,1)]';  -- true
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(1,1)]';  -- false
-
-SELECT line '[(0,0),(1,0)]' ?-| line '[(0,0),(0,1)]';  -- true
-SELECT line '[(0,0),(1,1)]' ?-| line '[(1,0),(1,1)]';  -- false
-
-SELECT ?- line '[(0,0),(1,0)]';  -- true
-SELECT ?- line '[(0,0),(1,1)]';  -- false
-
-SELECT ?| line '[(0,0),(0,1)]';  -- true
-SELECT ?| line '[(0,0),(1,1)]';  -- false
-
-SELECT line(point '(1,2)', point '(3,4)');
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,5)]';  -- true
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,4)]';  -- false
+select '{nan, 1, nan}'::line = '{nan, 1, nan}'::line as true,
+	   '{nan, 1, nan}'::line = '{nan, 2, nan}'::line as false;
diff --git a/src/test/regress/sql/lseg.sql b/src/test/regress/sql/lseg.sql
index 07c5a29e0a..f266ca3e09 100644
--- a/src/test/regress/sql/lseg.sql
+++ b/src/test/regress/sql/lseg.sql
@@ -3,23 +3,22 @@
 -- Line segments
 --
 
 --DROP TABLE LSEG_TBL;
 CREATE TABLE LSEG_TBL (s lseg);
 
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('(0,0),(6,6)');
 INSERT INTO LSEG_TBL VALUES ('10,-10 ,-3,-4');
 INSERT INTO LSEG_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LSEG_TBL VALUES ('(11,22,33,44)');
+INSERT INTO LSEG_TBL VALUES (lseg(point(11, 22), point(33,44)));
+INSERT INTO LSEG_TBL VALUES ('[(-10,2),(-10,3)]');	-- vertical
+INSERT INTO LSEG_TBL VALUES ('[(0,-20),(30,-20)]');	-- horizontal
+INSERT INTO LSEG_TBL VALUES ('[(NaN,1),(NaN,90)]');	-- NaN
 
 -- bad values for parser testing
 INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
 INSERT INTO LSEG_TBL VALUES ('[1,2,3, 4');
 INSERT INTO LSEG_TBL VALUES ('[(,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)');
 
 select * from LSEG_TBL;
-
-SELECT * FROM LSEG_TBL WHERE s <= lseg '[(1,2),(3,4)]';
-
-SELECT * FROM LSEG_TBL WHERE (s <-> lseg '[(1,2),(3,4)]') < 10;
diff --git a/src/test/regress/sql/path.sql b/src/test/regress/sql/path.sql
index 7e69b539ad..318decf974 100644
--- a/src/test/regress/sql/path.sql
+++ b/src/test/regress/sql/path.sql
@@ -1,38 +1,44 @@
 --
 -- PATH
 --
 
 --DROP TABLE PATH_TBL;
 
 CREATE TABLE PATH_TBL (f1 path);
 
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)]');
 
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
+INSERT INTO PATH_TBL VALUES (' ( ( 1 , 2 ) , ( 3 , 4 ) ) ');
 
-INSERT INTO PATH_TBL VALUES ('[(0,0),(3,0),(4,5),(1,6)]');
+INSERT INTO PATH_TBL VALUES ('[ (0,0),(3,0),(4,5),(1,6) ]');
 
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
+INSERT INTO PATH_TBL VALUES ('((1,2) ,(3,4 ))');
 
-INSERT INTO PATH_TBL VALUES ('1,2 ,3,4');
+INSERT INTO PATH_TBL VALUES ('1,2 ,3,4 ');
 
-INSERT INTO PATH_TBL VALUES ('[1,2,3, 4]');
+INSERT INTO PATH_TBL VALUES (' [1,2,3, 4] ');
 
-INSERT INTO PATH_TBL VALUES ('[11,12,13,14]');
+INSERT INTO PATH_TBL VALUES ('((10,20))');	-- Only one point
 
-INSERT INTO PATH_TBL VALUES ('(11,12,13,14)');
+INSERT INTO PATH_TBL VALUES ('[ 11,12,13,14 ]');
+
+INSERT INTO PATH_TBL VALUES ('( 11,12,13,14) ');
 
 -- bad values for parser testing
+INSERT INTO PATH_TBL VALUES ('[]');
+
 INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
 
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
 
-SELECT f1 FROM PATH_TBL;
+INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+
+INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
 
 SELECT '' AS count, f1 AS open_path FROM PATH_TBL WHERE isopen(f1);
 
 SELECT '' AS count, f1 AS closed_path FROM PATH_TBL WHERE isclosed(f1);
 
 SELECT '' AS count, pclose(f1) AS closed_path FROM PATH_TBL;
 
 SELECT '' AS count, popen(f1) AS open_path FROM PATH_TBL;
diff --git a/src/test/regress/sql/point.sql b/src/test/regress/sql/point.sql
index 63a803a809..a209f3bfeb 100644
--- a/src/test/regress/sql/point.sql
+++ b/src/test/regress/sql/point.sql
@@ -7,29 +7,39 @@ CREATE TABLE POINT_TBL(f1 point);
 INSERT INTO POINT_TBL(f1) VALUES ('(0.0,0.0)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-10.0,0.0)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-3.0,4.0)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(5.1, 34.5)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-5.0,-12.0)');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(1e-300,-1e-300)');	-- To underflow
+
+INSERT INTO POINT_TBL(f1) VALUES ('(1e+300,Inf)');		-- To overflow
+
+INSERT INTO POINT_TBL(f1) VALUES (' ( Nan , NaN ) ');
+
 -- bad format points
 INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
 
 INSERT INTO POINT_TBL(f1) VALUES ('10.0,10.0');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');	-- Out of range
+
 
 SELECT '' AS six, * FROM POINT_TBL;
 
 -- left of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE p.f1 << '(0.0, 0.0)';
 
 -- right of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE '(0.0,0.0)' >> p.f1;
 
 -- above
diff --git a/src/test/regress/sql/polygon.sql b/src/test/regress/sql/polygon.sql
index 7e8cb08cd8..d3d2fe3457 100644
--- a/src/test/regress/sql/polygon.sql
+++ b/src/test/regress/sql/polygon.sql
@@ -4,126 +4,43 @@
 -- polygon logic
 --
 
 CREATE TABLE POLYGON_TBL(f1 polygon);
 
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(2.0,0.0),(2.0,4.0),(0.0,0.0)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(3.0,1.0),(3.0,3.0),(1.0,0.0)');
 
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(3,4),(5,6),(7,8)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(7,8),(5,6),(3,4),(1,2)'); -- Reverse
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(7,8),(5,6),(3,-4)');
+
 -- degenerate polygons
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,0.0)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,1.0),(0.0,1.0)');
 
 -- bad polygon input strings
 INSERT INTO POLYGON_TBL(f1) VALUES ('0.0');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0 0.0');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2,3');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
 
 
 SELECT '' AS four, * FROM POLYGON_TBL;
 
--- overlap
-SELECT '' AS three, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 && '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- left overlap
-SELECT '' AS four, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &< '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- right overlap
-SELECT '' AS two, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- left of
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 << '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- right of
-SELECT '' AS zero, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 >> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- contained
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- same
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- contains
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
---
--- polygon logic
---
--- left of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- left overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
-
--- right overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' &> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- right of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' >> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- contained in
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- contains
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "false";
-
-SELECT '((0,4),(6,4),(3,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
-
-SELECT '((1,1),(1,4),(5,4),(5,3),(2,3),(2,2),(5,2),(5,1))'::polygon @> '((3,2),(3,3),(4,3),(4,2))'::polygon AS "false";
-
-SELECT '((0,0),(0,3),(3,3),(3,0))'::polygon @> '((2,1),(2,2),(3,2),(3,1))'::polygon AS "true";
-
--- same
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' && polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon && '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
-
-SELECT '((1,4),(1,1),(4,1),(4,2),(2,2),(2,4),(1,4))'::polygon && '((3,3),(4,3),(4,4),(3,4),(3,3))'::polygon AS "false";
-SELECT '((200,800),(800,800),(800,200),(200,200))' &&  '(1000,1000,0,0)'::polygon AS "true";
-
--- distance from a point
-SELECT	'(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
-	'(1,1)'::point <-> '((0,0),(2,2),(1,3))'::polygon as on_segment,
-	'(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;
-- 
2.14.3 (Apple Git-98)

#56Emre Hasegeli
emre@hasegeli.com
In reply to: Andres Freund (#53)
Re: [HACKERS] [PATCH] Improve geometric types

I'm a bit confused how this patch has gone through several revisions
since, but has been marked as "ready for committer" since 2017-09-05. Am
I missing something?

This is floating between commitfests for longer than a year.
Aleksander Alekseev set it to "ready for committer", but Kyotaro
HORIGUCHI continues his review. I hope not many issues have remained.

#57Kyotaro HORIGUCHI
horiguchi.kyotaro@lab.ntt.co.jp
In reply to: Emre Hasegeli (#55)
Re: [PATCH] Improve geometric types

Hello, sorry to be late.

At Fri, 2 Mar 2018 15:26:25 +0100, Emre Hasegeli <emre@hasegeli.com> wrote in <CAE2gYzzj6wgGeBY1vdAHBzzQDSDs-8NhD+=eTcgBKEsCBWpUXg@mail.gmail.com>

Unfortunately according to http://commitfest.cputube.org/ this patch doesn't apply anymore.

New versions are attached.

Thank you for the revised version. This seems fine for me so
marked this as "Ready for Committer".

- This applies cleanly on the master head and regression passes.

- The new behavior looks sane (except for the EPSILON, which is
out of the scope of this patch).

- Test is complete as long as I can see. At least far more
completely filled than the previous state. Some test items
might seem a bit big, but it seems to be needed to raise
coverage on required combinaions of dimension values.

By the way I think that line_perp is back patched, could you
propose it for the older versions? (I already marked my entry as
Rejected)

Brief summary follows (almost same to the header of patch files):

- 0001 looks fine.

* Eliminate SQL level function calls
* Re-use more functions to implement others
* Unify internal function names and signatures
* Remove private functions from geo_decls.h
* Replace not-possible checks with Assert()
* Add comments to describe some functions
* Remove some unreachable code
* Define delimiter symbols of line datatype like the other ones
* Remove debugging print()s from the refactored functions

And one bug fix.

- 0002 looks fine.

Refactors adt/float.c and utils/float.h
making float checking *macros* into inline functions.
making float comparison operators more efficiently.

others are the consequence of the above change.
and fixes NaN problem of GiST.

- 0003 looks fine.

just changes the usage of double to float8 as more proper type.
uses operator functions instead of bare arithmetics to handle
arithmetic errors more properly.

- 0004 looks fine. (Sorry for overlooking that this treats bugs)

all overlooked failure cases seems to be fixed.

- 0005 looks fine.

this unifies +-0.0 to +0.0 for the convenient of later processing.

- 0006 It seems cover the all types of operations.

regards,

--
Kyotaro Horiguchi
NTT Open Source Software Center

#58Emre Hasegeli
emre@hasegeli.com
In reply to: Kyotaro HORIGUCHI (#57)
Re: [PATCH] Improve geometric types

Thank you for the revised version. This seems fine for me so
marked this as "Ready for Committer".

Thank you for bearing with me for longer than year.

By the way I think that line_perp is back patched, could you
propose it for the older versions? (I already marked my entry as
Rejected)

Do you mean back-patching?

Brief summary follows (almost same to the header of patch files):

- 0001 looks fine.

* Eliminate SQL level function calls
* Re-use more functions to implement others
* Unify internal function names and signatures
* Remove private functions from geo_decls.h
* Replace not-possible checks with Assert()
* Add comments to describe some functions
* Remove some unreachable code
* Define delimiter symbols of line datatype like the other ones
* Remove debugging print()s from the refactored functions

And one bug fix.

What is that one? Should I incorporate it into the commit message?

#59Emre Hasegeli
emre@hasegeli.com
In reply to: Emre Hasegeli (#55)
6 attachment(s)
Re: [PATCH] Improve geometric types

Rebased versions are attached.

Attachments:

0001-geo-funcs-v09.patchapplication/octet-stream; name=0001-geo-funcs-v09.patchDownload
From 1eb2418d52ecf46496ff026e315e35a2628ed91b Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 27 May 2017 11:27:18 -0400
Subject: [PATCH 1/6] geo-funcs-v09

Refactor geometric functions and operators code

Most of the geometric types were not using functions of each other's.
I believe the reason behind this is simpler types line point and line
being developed after more complicated ones.  This patch reduces
duplicate code and makes functions of different datatypes more
compatible.  The changes can be summarised as:

* Eliminate SQL level function calls
* Re-use more functions to implement others
* Unify internal function names and signatures
* Remove private functions from geo_decls.h
* Replace not-possible checks with Assert()
* Add comments to describe some functions
* Remove some unreachable code
* Define delimiter symbols of line datatype like the other ones
* Remove debugging print()s from the refactored functions
* Unify code style of a few oddly formatted lines

This commits aims to not cause any user visible changes, but it is
almost impossible to stay completely bug-compatible with the old code.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com
---
 src/backend/utils/adt/geo_ops.c    | 1908 +++++++++++++++++-------------------
 src/backend/utils/adt/geo_spgist.c |    3 +-
 src/include/utils/geo_decls.h      |    4 -
 src/test/regress/regress.c         |    7 +-
 4 files changed, 883 insertions(+), 1039 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index f57380a4df..3e7519015d 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -31,75 +31,104 @@
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
+/* Routines for points */
+static inline void point_construct(Point *result, float8 x, float8 y);
+static inline void point_add_point(Point *result, Point *pt1, Point *pt2);
+static inline void point_sub_point(Point *result, Point *pt1, Point *pt2);
+static inline void point_mul_point(Point *result, Point *pt1, Point *pt2);
+static inline void point_div_point(Point *result, Point *pt1, Point *pt2);
+static inline bool point_eq_point(Point *pt1, Point *pt2);
+static inline float8 point_dt(Point *pt1, Point *pt2);
+static inline float8 point_sl(Point *pt1, Point *pt2);
 static int	point_inside(Point *p, int npts, Point *plist);
+
+/* Routines for lines */
+static inline void line_construct(LINE *result, Point *pt, float8 m);
+static inline float8 line_invsl(LINE *line);
+static bool	line_interpt_line(Point *result, LINE *l1, LINE *l2);
+static bool line_contain_point(LINE *line, Point *point);
+static float8 line_closept_point(Point *result, LINE *line, Point *pt);
+
+/* Routines for line segments */
+static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
+static inline float8 lseg_sl(LSEG *lseg);
+static inline float8 lseg_invsl(LSEG *lseg);
+static bool	lseg_interpt_line(Point *result, LSEG *lseg, LINE *line);
+static bool	lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2);
 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_fill(BOX *result, double x1, double x2, double y1, double y2);
+static bool	lseg_contain_point(LSEG *lseg, Point *point);
+static float8 lseg_closept_point(Point *result, LSEG *lseg, Point *pt);
+static float8 lseg_closept_line(Point *result, LSEG *lseg, LINE *line);
+static float8 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2);
+
+/* Routines for boxes */
+static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
+static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
+static double box_ar(BOX *box);
 static double box_ht(BOX *box);
 static double box_wd(BOX *box);
+static bool box_contain_point(BOX *box, Point *point);
+static bool box_contain_box(BOX *box1, BOX *box2);
+static bool box_contain_lseg(BOX *box, LSEG *lseg);
+static bool box_interpt_lseg(Point *result, BOX *box, LSEG *lseg);
+static float8 box_closept_point(Point *result, BOX *box, Point *point);
+static float8 box_closept_lseg(Point *result, BOX *box, LSEG *lseg);
+
+/* Routines for circles */
 static double circle_ar(CIRCLE *circle);
-static CIRCLE *circle_copy(CIRCLE *circle);
-static LINE *line_construct_pm(Point *pt, double m);
-static void line_construct_pts(LINE *line, Point *pt1, Point *pt2);
-static bool lseg_intersect_internal(LSEG *l1, LSEG *l2);
-static double lseg_dt(LSEG *l1, LSEG *l2);
-static bool on_ps_internal(Point *pt, LSEG *lseg);
+
+/* Routines for polygons */
 static void make_bound_box(POLYGON *poly);
+static void poly_to_circle(CIRCLE *result, POLYGON *poly);
+static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
+static bool poly_contain_poly(POLYGON *polya, POLYGON *polyb);
 static bool plist_same(int npts, Point *p1, Point *p2);
-static Point *point_construct(double x, double y);
-static Point *point_copy(Point *pt);
+static float8 dist_ppoly_internal(Point *pt, POLYGON *poly);
+
+/* Routines for encoding and decoding */
 static double single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
 static void pair_decode(char *str, double *x, double *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
 static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
-static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
-static double box_ar(BOX *box);
-static void box_cn(Point *center, BOX *box);
-static Point *interpt_sl(LSEG *lseg, LINE *line);
-static bool has_interpt_sl(LSEG *lseg, LINE *line);
-static double dist_pl_internal(Point *pt, LINE *line);
-static double dist_ps_internal(Point *pt, LSEG *lseg);
-static Point *line_interpt_internal(LINE *l1, LINE *l2);
-static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
-static Point *lseg_interpt_internal(LSEG *l1, LSEG *l2);
-static double dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 
 /*
  * Delimiters for input and output strings.
  * LDELIM, RDELIM, and DELIM are left, right, and separator delimiters, respectively.
  * LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints.
  */
 
 #define LDELIM			'('
 #define RDELIM			')'
 #define DELIM			','
 #define LDELIM_EP		'['
 #define RDELIM_EP		']'
 #define LDELIM_C		'<'
 #define RDELIM_C		'>'
+#define LDELIM_L		'{'
+#define RDELIM_L		'}'
 
 
 /*
  * Geometric data types are composed of points.
  * This code tries to support a common format throughout the data types,
  *	to allow for more predictable usage and data type conversion.
  * The fundamental unit is the point. Other units are line segments,
  *	open paths, boxes, closed paths, and polygons (which should be considered
  *	non-intersecting closed paths).
  *
@@ -229,26 +258,23 @@ path_decode(char *str, bool opentype, int npts, Point *p,
 	}
 
 	for (i = 0; i < npts; i++)
 	{
 		pair_decode(str, &(p->x), &(p->y), &str, type_name, orig_string);
 		if (*str == DELIM)
 			str++;
 		p++;
 	}
 
-	while (isspace((unsigned char) *str))
-		str++;
 	while (depth > 0)
 	{
-		if ((*str == RDELIM)
-			|| ((*str == RDELIM_EP) && (*isopen) && (depth == 1)))
+		if (*str == RDELIM || (*str == RDELIM_EP && *isopen && depth == 1))
 		{
 			depth--;
 			str++;
 			while (isspace((unsigned char) *str))
 				str++;
 		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
@@ -433,89 +459,61 @@ box_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, box->high.x);
 	pq_sendfloat8(&buf, box->high.y);
 	pq_sendfloat8(&buf, box->low.x);
 	pq_sendfloat8(&buf, box->low.y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*		box_construct	-		fill in a new box.
  */
-static BOX *
-box_construct(double x1, double x2, double y1, double y2)
+static inline void
+box_construct(BOX *result, Point *pt1, Point *pt2)
 {
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	return box_fill(result, x1, x2, y1, y2);
-}
-
-
-/*		box_fill		-		fill in a given box struct
- */
-static BOX *
-box_fill(BOX *result, double x1, double x2, double y1, double y2)
-{
-	if (x1 > x2)
+	if (pt1->x > pt2->x)
 	{
-		result->high.x = x1;
-		result->low.x = x2;
+		result->high.x = pt1->x;
+		result->low.x = pt2->x;
 	}
 	else
 	{
-		result->high.x = x2;
-		result->low.x = x1;
+		result->high.x = pt2->x;
+		result->low.x = pt1->x;
 	}
-	if (y1 > y2)
+	if (pt1->y > pt2->y)
 	{
-		result->high.y = y1;
-		result->low.y = y2;
+		result->high.y = pt1->y;
+		result->low.y = pt2->y;
 	}
 	else
 	{
-		result->high.y = y2;
-		result->low.y = y1;
+		result->high.y = pt2->y;
+		result->low.y = pt1->y;
 	}
-
-	return result;
-}
-
-
-/*		box_copy		-		copy a box
- */
-BOX *
-box_copy(BOX *box)
-{
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	memcpy((char *) result, (char *) box, sizeof(BOX));
-
-	return result;
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for BOXes.
  *		<, >, <=, >=, and == are based on box area.
  *---------------------------------------------------------*/
 
 /*		box_same		-		are two boxes identical?
  */
 Datum
 box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPeq(box1->high.x, box2->high.x) &&
-				   FPeq(box1->low.x, box2->low.x) &&
-				   FPeq(box1->high.y, box2->high.y) &&
-				   FPeq(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(point_eq_point(&box1->high, &box2->high) &&
+				   point_eq_point(&box1->low, &box2->low));
 }
 
 /*		box_overlap		-		does box1 overlap box2?
  */
 Datum
 box_overlap(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
@@ -630,38 +628,44 @@ box_overabove(PG_FUNCTION_ARGS)
 }
 
 /*		box_contained	-		is box1 contained by box2?
  */
 Datum
 box_contained(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPle(box1->high.x, box2->high.x) &&
-				   FPge(box1->low.x, box2->low.x) &&
-				   FPle(box1->high.y, box2->high.y) &&
-				   FPge(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(box_contain_box(box2, box1));
 }
 
 /*		box_contain		-		does box1 contain box2?
  */
 Datum
 box_contain(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPge(box1->high.x, box2->high.x) &&
-				   FPle(box1->low.x, box2->low.x) &&
-				   FPge(box1->high.y, box2->high.y) &&
-				   FPle(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(box_contain_box(box1, box2));
+}
+
+/*
+ * Check whether the box is in the box or on its border
+ */
+static bool
+box_contain_box(BOX *box1, BOX *box2)
+{
+	return FPge(box1->high.x, box2->high.x) &&
+		   FPle(box1->low.x, box2->low.x) &&
+		   FPge(box1->high.y, box2->high.y) &&
+		   FPle(box1->low.y, box2->low.y);
 }
 
 
 /*		box_positionop	-
  *				is box1 entirely {above,below} box2?
  *
  * box_below_eq and box_above_eq are obsolete versions that (probably
  * erroneously) accept the equal-boundaries case.  Since these are not
  * in sync with the box_left and box_right code, they are deprecated and
  * not supported in the PG 8.1 rtree operator class extension.
@@ -750,51 +754,51 @@ box_area(PG_FUNCTION_ARGS)
 
 
 /*		box_width		-		returns the width of the box
  *								  (horizontal magnitude).
  */
 Datum
 box_width(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.x - box->low.x);
+	PG_RETURN_FLOAT8(box_wd(box));
 }
 
 
 /*		box_height		-		returns the height of the box
  *								  (vertical magnitude).
  */
 Datum
 box_height(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.y - box->low.y);
+	PG_RETURN_FLOAT8(box_ht(box));
 }
 
 
 /*		box_distance	-		returns the distance between the
  *								  center points of two boxes.
  */
 Datum
 box_distance(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 	Point		a,
 				b;
 
 	box_cn(&a, box1);
 	box_cn(&b, box2);
 
-	PG_RETURN_FLOAT8(HYPOT(a.x - b.x, a.y - b.y));
+	PG_RETURN_FLOAT8(point_dt(&a, &b));
 }
 
 
 /*		box_center		-		returns the center point of the box.
  */
 Datum
 box_center(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *result = (Point *) palloc(sizeof(Point));
@@ -898,76 +902,77 @@ static bool
 line_decode(char *s, const char *str, LINE *line)
 {
 	/* s was already advanced over leading '{' */
 	line->A = single_decode(s, &s, "line", str);
 	if (*s++ != DELIM)
 		return false;
 	line->B = single_decode(s, &s, "line", str);
 	if (*s++ != DELIM)
 		return false;
 	line->C = single_decode(s, &s, "line", str);
-	if (*s++ != '}')
+	if (*s++ != RDELIM_L)
 		return false;
 	while (isspace((unsigned char) *s))
 		s++;
 	if (*s != '\0')
 		return false;
 	return true;
 }
 
 Datum
 line_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	LINE	   *line = (LINE *) palloc(sizeof(LINE));
 	LSEG		lseg;
 	bool		isopen;
 	char	   *s;
 
 	s = str;
 	while (isspace((unsigned char) *s))
 		s++;
-	if (*s == '{')
+	if (*s == LDELIM_L)
 	{
 		if (!line_decode(s + 1, str, line))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
 							"line", str)));
 		if (FPzero(line->A) && FPzero(line->B))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: A and B cannot both be zero")));
 	}
 	else
 	{
-		path_decode(s, true, 2, &(lseg.p[0]), &isopen, NULL, "line", str);
-		if (FPeq(lseg.p[0].x, lseg.p[1].x) && FPeq(lseg.p[0].y, lseg.p[1].y))
+		path_decode(s, true, 2, &lseg.p[0], &isopen, NULL, "line", str);
+		if (point_eq_point(&lseg.p[0], &lseg.p[1]))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: must be two distinct points")));
-		line_construct_pts(line, &lseg.p[0], &lseg.p[1]);
+		line_construct(line, &lseg.p[0], lseg_sl(&lseg));
 	}
 
 	PG_RETURN_LINE_P(line);
 }
 
 
 Datum
 line_out(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	char	   *astr = float8out_internal(line->A);
 	char	   *bstr = float8out_internal(line->B);
 	char	   *cstr = float8out_internal(line->C);
 
-	PG_RETURN_CSTRING(psprintf("{%s,%s,%s}", astr, bstr, cstr));
+	PG_RETURN_CSTRING(psprintf("%c%s%c%s%c%s%c", LDELIM_L, astr, DELIM, bstr,
+							   DELIM, cstr, RDELIM_L));
 }
 
 /*
  *		line_recv			- converts external binary format to line
  */
 Datum
 line_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LINE	   *line;
@@ -996,128 +1001,78 @@ line_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, line->C);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*----------------------------------------------------------
  *	Conversion routines from one line formula to internal.
  *		Internal form:	Ax+By+C=0
  *---------------------------------------------------------*/
 
-/* line_construct_pm()
- * point-slope
+/*
+ * Fill already-allocated LINE struct from the point and the slope
  */
-static LINE *
-line_construct_pm(Point *pt, double m)
+static inline void
+line_construct(LINE *result, Point *pt, float8 m)
 {
-	LINE	   *result = (LINE *) palloc(sizeof(LINE));
-
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
 		result->A = -1;
 		result->B = 0;
 		result->C = pt->x;
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
 		result->C = pt->y - m * pt->x;
 	}
-
-	return result;
-}
-
-/*
- * Fill already-allocated LINE struct from two points on the line
- */
-static void
-line_construct_pts(LINE *line, Point *pt1, Point *pt2)
-{
-	if (FPeq(pt1->x, pt2->x))
-	{							/* vertical */
-		/* use "x = C" */
-		line->A = -1;
-		line->B = 0;
-		line->C = pt1->x;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is vertical\n");
-#endif
-	}
-	else if (FPeq(pt1->y, pt2->y))
-	{							/* horizontal */
-		/* use "y = C" */
-		line->A = 0;
-		line->B = -1;
-		line->C = pt1->y;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is horizontal\n");
-#endif
-	}
-	else
-	{
-		/* use "mx - y + yinter = 0" */
-		line->A = (pt2->y - pt1->y) / (pt2->x - pt1->x);
-		line->B = -1.0;
-		line->C = pt1->y - line->A * pt1->x;
-		/* on some platforms, the preceding expression tends to produce -0 */
-		if (line->C == 0.0)
-			line->C = 0.0;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is neither vertical nor horizontal (diffs x=%.*g, y=%.*g\n",
-			   DBL_DIG, (pt2->x - pt1->x), DBL_DIG, (pt2->y - pt1->y));
-#endif
-	}
 }
 
 /* line_construct_pp()
  * two points
  */
 Datum
 line_construct_pp(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 	LINE	   *result = (LINE *) palloc(sizeof(LINE));
 
-	line_construct_pts(result, pt1, pt2);
+	line_construct(result, pt1, point_sl(pt1, pt2));
+
 	PG_RETURN_LINE_P(result);
 }
 
 
 /*----------------------------------------------------------
  *	Relative position routines.
  *---------------------------------------------------------*/
 
 Datum
 line_intersect(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(!DatumGetBool(DirectFunctionCall2(line_parallel,
-													 LinePGetDatum(l1),
-													 LinePGetDatum(l2))));
+	PG_RETURN_BOOL(line_interpt_line(NULL, l1, l2));
 }
 
 Datum
 line_parallel(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
-	if (FPzero(l1->B))
-		PG_RETURN_BOOL(FPzero(l2->B));
-
-	PG_RETURN_BOOL(FPeq(l2->A, l1->A * (l2->B / l1->B)));
+	PG_RETURN_BOOL(!line_interpt_line(NULL, l1, l2));
 }
 
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
@@ -1162,105 +1117,114 @@ line_eq(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(FPeq(l1->A, k * l2->A) &&
 				   FPeq(l1->B, k * l2->B) &&
 				   FPeq(l1->C, k * l2->C));
 }
 
 
 /*----------------------------------------------------------
  *	Line arithmetic routines.
  *---------------------------------------------------------*/
 
+/*
+ * Return inverse slope of the line
+ */
+static inline float8
+line_invsl(LINE *line)
+{
+	if (FPzero(line->A))
+		return DBL_MAX;
+	if (FPzero(line->B))
+		return 0.0;
+	return line->B / line->A;
+}
+
+
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
-	Point	   *tmp;
+	Point		tmp;
 
-	if (!DatumGetBool(DirectFunctionCall2(line_parallel,
-										  LinePGetDatum(l1),
-										  LinePGetDatum(l2))))
+	if (line_interpt_line(NULL, l1, l2))	/* intersecting? */
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
 		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
-	tmp = point_construct(0.0, l1->C);
-	result = dist_pl_internal(tmp, l2);
+	point_construct(&tmp, 0.0, l1->C);
+	result = line_closept_point(NULL, l2, &tmp);
 	PG_RETURN_FLOAT8(result);
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
-	result = line_interpt_internal(l1, l2);
+	result = (Point *) palloc(sizeof(Point));
 
-	if (result == NULL)
+	if (!line_interpt_line(result, l1, l2))
 		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
 
 /*
  * Internal version of line_interpt
  *
- * returns a NULL pointer if no intersection point
+ * This returns true if two lines intersect (they do, if they are not
+ * parallel), false if they do not.  This also sets the intersection point
+ * to *result, if it is not NULL.
+ *
+ * NOTE: If the lines are identical then we will find they are parallel
+ * and report "no intersection".  This is a little weird, but since
+ * there's no *unique* intersection, maybe it's appropriate behavior.
  */
-static Point *
-line_interpt_internal(LINE *l1, LINE *l2)
+static bool
+line_interpt_line(Point *result, LINE *l1, LINE *l2)
 {
-	Point	   *result;
 	double		x,
 				y;
 
-	/*
-	 * NOTE: if the lines are identical then we will find they are parallel
-	 * and report "no intersection".  This is a little weird, but since
-	 * there's no *unique* intersection, maybe it's appropriate behavior.
-	 */
-	if (DatumGetBool(DirectFunctionCall2(line_parallel,
-										 LinePGetDatum(l1),
-										 LinePGetDatum(l2))))
-		return NULL;
-
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
+		if (FPzero(l2->B))		/* l2 vertical? */
+			return false;
+
 		x = l1->C;
 		y = (l2->A * x + l2->C);
 	}
 	else if (FPzero(l2->B))		/* l2 vertical? */
 	{
 		x = l2->C;
 		y = (l1->A * x + l1->C);
 	}
 	else
 	{
+		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+			return false;
+
 		x = (l1->C - l2->C) / (l2->A - l1->A);
 		y = (l1->A * x + l1->C);
 	}
-	result = point_construct(x, y);
 
-#ifdef GEODEBUG
-	printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
-		   DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
-	printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
-#endif
+	if (result != NULL)
+		point_construct(result, x, y);
 
-	return result;
+	return true;
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D paths (sequences of line segments, also
  **				called `polylines').
  **
  **				This is not a general package for geometric paths,
  **				which of course include polygons; the emphasis here
@@ -1555,22 +1519,21 @@ path_inter(PG_FUNCTION_ARGS)
 {
 	PATH	   *p1 = PG_GETARG_PATH_P(0);
 	PATH	   *p2 = PG_GETARG_PATH_P(1);
 	BOX			b1,
 				b2;
 	int			i,
 				j;
 	LSEG		seg1,
 				seg2;
 
-	if (p1->npts <= 0 || p2->npts <= 0)
-		PG_RETURN_BOOL(false);
+	Assert(p1->npts > 0 && p2->npts > 0);
 
 	b1.high.x = b1.low.x = p1->p[0].x;
 	b1.high.y = b1.low.y = p1->p[0].y;
 	for (i = 1; i < p1->npts; i++)
 	{
 		b1.high.x = Max(p1->p[i].x, b1.high.x);
 		b1.high.y = Max(p1->p[i].y, b1.high.y);
 		b1.low.x = Min(p1->p[i].x, b1.low.x);
 		b1.low.y = Min(p1->p[i].y, b1.low.y);
 	}
@@ -1608,21 +1571,21 @@ path_inter(PG_FUNCTION_ARGS)
 				jprev = j - 1;
 			else
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
-			if (lseg_intersect_internal(&seg1, &seg2))
+			if (lseg_interpt_lseg(NULL, &seg1, &seg2))
 				PG_RETURN_BOOL(true);
 		}
 	}
 
 	/* if we dropped through, no two segs intersected */
 	PG_RETURN_BOOL(false);
 }
 
 /* path_distance()
  * This essentially does a cartesian product of the lsegs in the
@@ -1663,23 +1626,21 @@ path_distance(PG_FUNCTION_ARGS)
 			else
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
-			tmp = DatumGetFloat8(DirectFunctionCall2(lseg_distance,
-													 LsegPGetDatum(&seg1),
-													 LsegPGetDatum(&seg2)));
+			tmp = lseg_closept_lseg(NULL, &seg1, &seg2);
 			if (!have_min || tmp < min)
 			{
 				min = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	if (!have_min)
 		PG_RETURN_NULL();
@@ -1773,44 +1734,28 @@ point_send(PG_FUNCTION_ARGS)
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	StringInfoData buf;
 
 	pq_begintypsend(&buf);
 	pq_sendfloat8(&buf, pt->x);
 	pq_sendfloat8(&buf, pt->y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
-static Point *
-point_construct(double x, double y)
+/*
+ * Initialize a point
+ */
+static inline void
+point_construct(Point *result, float8 x, float8 y)
 {
-	Point	   *result = (Point *) palloc(sizeof(Point));
-
 	result->x = x;
 	result->y = y;
-	return result;
-}
-
-
-static Point *
-point_copy(Point *pt)
-{
-	Point	   *result;
-
-	if (!PointerIsValid(pt))
-		return NULL;
-
-	result = (Point *) palloc(sizeof(Point));
-
-	result->x = pt->x;
-	result->y = pt->y;
-	return result;
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for Points.
  *		Since we do have a sense of coordinates being
  *		"equal" to a given accuracy (point_vert, point_horiz),
  *		the other ops must preserve that sense.  This means
  *		that results may, strictly speaking, be a lie (unless
  *		EPSILON = 0.0).
@@ -1869,71 +1814,97 @@ point_horiz(PG_FUNCTION_ARGS)
 
 	PG_RETURN_BOOL(FPeq(pt1->y, pt2->y));
 }
 
 Datum
 point_eq(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y));
+	PG_RETURN_BOOL(point_eq_point(pt1, pt2));
 }
 
 Datum
 point_ne(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPne(pt1->x, pt2->x) || FPne(pt1->y, pt2->y));
+	PG_RETURN_BOOL(!point_eq_point(pt1, pt2));
 }
 
+static inline bool
+point_eq_point(Point *pt1, Point *pt2)
+{
+	return FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y);
+}
+
+
 /*----------------------------------------------------------
  *	"Arithmetic" operators on points.
  *---------------------------------------------------------*/
 
 Datum
 point_distance(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_FLOAT8(HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
+	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
-double
+static inline float8
 point_dt(Point *pt1, Point *pt2)
 {
-#ifdef GEODEBUG
-	printf("point_dt- segment (%f,%f),(%f,%f) length is %f\n",
-		   pt1->x, pt1->y, pt2->x, pt2->y, HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
-#endif
 	return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
 }
 
 Datum
 point_slope(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_sl(pt1, pt2));
 }
 
 
-double
+/*
+ * Return slope of two points
+ *
+ * Note that this function returns DBL_MAX when the points are the same.
+ */
+static inline float8
 point_sl(Point *pt1, Point *pt2)
 {
-	return (FPeq(pt1->x, pt2->x)
-			? (double) DBL_MAX
-			: (pt1->y - pt2->y) / (pt1->x - pt2->x));
+	if (FPeq(pt1->x, pt2->x))
+		return DBL_MAX;
+	if (FPeq(pt1->y, pt2->y))
+		return 0.0;
+	return (pt1->y - pt2->y) / (pt1->x - pt2->x);
+}
+
+
+/*
+ * Return inverse slope of two points
+ *
+ * Note that this function returns 0.0 when the points are the same.
+ */
+static inline float8
+point_invsl(Point *pt1, Point *pt2)
+{
+	if (FPeq(pt1->x, pt2->x))
+		return 0.0;
+	if (FPeq(pt1->y, pt2->y))
+		return DBL_MAX;
+	return (pt1->x - pt2->x) / (pt2->y - pt1->y);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D line segments.
  **
  ***********************************************************************/
 
 /*----------------------------------------------------------
@@ -1945,31 +1916,31 @@ point_sl(Point *pt1, Point *pt2)
  *		(old form)		"(x1, y1, x2, y2)"
  *---------------------------------------------------------*/
 
 Datum
 lseg_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	LSEG	   *lseg = (LSEG *) palloc(sizeof(LSEG));
 	bool		isopen;
 
-	path_decode(str, true, 2, &(lseg->p[0]), &isopen, NULL, "lseg", str);
+	path_decode(str, true, 2, &lseg->p[0], &isopen, NULL, "lseg", str);
 	PG_RETURN_LSEG_P(lseg);
 }
 
 
 Datum
 lseg_out(PG_FUNCTION_ARGS)
 {
 	LSEG	   *ls = PG_GETARG_LSEG_P(0);
 
-	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, (Point *) &(ls->p[0])));
+	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, &ls->p[0]));
 }
 
 /*
  *		lseg_recv			- converts external binary format to lseg
  */
 Datum
 lseg_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LSEG	   *lseg;
@@ -2005,38 +1976,56 @@ lseg_send(PG_FUNCTION_ARGS)
 /* lseg_construct -
  *		form a LSEG from two Points.
  */
 Datum
 lseg_construct(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 	LSEG	   *result = (LSEG *) palloc(sizeof(LSEG));
 
-	result->p[0].x = pt1->x;
-	result->p[0].y = pt1->y;
-	result->p[1].x = pt2->x;
-	result->p[1].y = pt2->y;
+	statlseg_construct(result, pt1, pt2);
 
 	PG_RETURN_LSEG_P(result);
 }
 
 /* like lseg_construct, but assume space already allocated */
-static void
+static inline void
 statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2)
 {
 	lseg->p[0].x = pt1->x;
 	lseg->p[0].y = pt1->y;
 	lseg->p[1].x = pt2->x;
 	lseg->p[1].y = pt2->y;
 }
 
+
+/*
+ * Return slope of the line segment
+ */
+static inline float8
+lseg_sl(LSEG *lseg)
+{
+	return point_sl(&lseg->p[0], &lseg->p[1]);
+}
+
+
+/*
+ * Return inverse slope of the line segment
+ */
+static inline float8
+lseg_invsl(LSEG *lseg)
+{
+	return point_invsl(&lseg->p[0], &lseg->p[1]);
+}
+
+
 Datum
 lseg_length(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 
 	PG_RETURN_FLOAT8(point_dt(&lseg->p[0], &lseg->p[1]));
 }
 
 /*----------------------------------------------------------
  *	Relative position routines.
@@ -2045,79 +2034,43 @@ lseg_length(PG_FUNCTION_ARGS)
 /*
  **  find intersection of the two lines, and see if it falls on
  **  both segments.
  */
 Datum
 lseg_intersect(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(lseg_intersect_internal(l1, l2));
+	PG_RETURN_BOOL(lseg_interpt_lseg(NULL, l1, l2));
 }
 
-static bool
-lseg_intersect_internal(LSEG *l1, LSEG *l2)
-{
-	LINE		ln;
-	Point	   *interpt;
-	bool		retval;
-
-	line_construct_pts(&ln, &l2->p[0], &l2->p[1]);
-	interpt = interpt_sl(l1, &ln);
-
-	if (interpt != NULL && on_ps_internal(interpt, l2))
-		retval = true;			/* interpt on l1 and l2 */
-	else
-		retval = false;
-	return retval;
-}
 
 Datum
 lseg_parallel(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPeq(point_sl(&l1->p[0], &l1->p[1]),
-						point_sl(&l2->p[0], &l2->p[1])));
+	PG_RETURN_BOOL(FPeq(lseg_sl(l1), lseg_sl(l2)));
 }
 
-/* lseg_perp()
+/*
  * Determine if two line segments are perpendicular.
- *
- * This code did not get the correct answer for
- *	'((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg
- * So, modified it to check explicitly for slope of vertical line
- *	returned by point_sl() and the results seem better.
- * - thomas 1998-01-31
  */
 Datum
 lseg_perp(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	double		m1,
-				m2;
 
-	m1 = point_sl(&(l1->p[0]), &(l1->p[1]));
-	m2 = point_sl(&(l2->p[0]), &(l2->p[1]));
-
-#ifdef GEODEBUG
-	printf("lseg_perp- slopes are %g and %g\n", m1, m2);
-#endif
-	if (FPzero(m1))
-		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
-	else if (FPzero(m2))
-		PG_RETURN_BOOL(FPeq(m1, DBL_MAX));
-
-	PG_RETURN_BOOL(FPeq(m1 / m2, -1.0));
+	PG_RETURN_BOOL(FPeq(lseg_sl(l1), lseg_invsl(l2)));
 }
 
 Datum
 lseg_vertical(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 
 	PG_RETURN_BOOL(FPeq(lseg->p[0].x, lseg->p[1].x));
 }
 
@@ -2129,36 +2082,32 @@ lseg_horizontal(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(FPeq(lseg->p[0].y, lseg->p[1].y));
 }
 
 
 Datum
 lseg_eq(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPeq(l1->p[0].x, l2->p[0].x) &&
-				   FPeq(l1->p[0].y, l2->p[0].y) &&
-				   FPeq(l1->p[1].x, l2->p[1].x) &&
-				   FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(point_eq_point(&l1->p[0], &l2->p[0]) &&
+				   point_eq_point(&l1->p[1], &l2->p[1]));
 }
 
 Datum
 lseg_ne(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(!FPeq(l1->p[0].x, l2->p[0].x) ||
-				   !FPeq(l1->p[0].y, l2->p[0].y) ||
-				   !FPeq(l1->p[1].x, l2->p[1].x) ||
-				   !FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(!point_eq_point(&l1->p[0], &l2->p[0]) ||
+				   !point_eq_point(&l1->p[1], &l2->p[1]));
 }
 
 Datum
 lseg_lt(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_BOOL(FPlt(point_dt(&l1->p[0], &l1->p[1]),
 						point_dt(&l2->p[0], &l2->p[1])));
@@ -2203,126 +2152,81 @@ lseg_ge(PG_FUNCTION_ARGS)
  *		If two segments don't intersect, then the closest
  *		point will be from one of the endpoints to the other
  *		segment.
  */
 Datum
 lseg_distance(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_FLOAT8(lseg_dt(l1, l2));
-}
-
-/* lseg_dt()
- * Distance between two line segments.
- * Must check both sets of endpoints to ensure minimum distance is found.
- * - thomas 1998-02-01
- */
-static double
-lseg_dt(LSEG *l1, LSEG *l2)
-{
-	double		result,
-				d;
-
-	if (lseg_intersect_internal(l1, l2))
-		return 0.0;
-
-	d = dist_ps_internal(&l1->p[0], l2);
-	result = d;
-	d = dist_ps_internal(&l1->p[1], l2);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[0], l1);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[1], l1);
-	result = Min(result, d);
-
-	return result;
+	PG_RETURN_FLOAT8(lseg_closept_lseg(NULL, l1, l2));
 }
 
 
 Datum
 lseg_center(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
 	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
 
 	PG_RETURN_POINT_P(result);
 }
 
-static Point *
-lseg_interpt_internal(LSEG *l1, LSEG *l2)
+
+/*
+ *		Find the intersection point of two segments (if any).
+ *
+ * This returns true if two line segments intersect, false if they do not.
+ * This also sets the intersection point to *result, if it is not NULL.
+ * This function is almost perfectly symmetric, even though it doesn't look
+ * like it.  See lseg_interpt_line() for the other half of it.
+ */
+static bool
+lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2)
 {
-	Point	   *result;
-	LINE		tmp1,
-				tmp2;
+	Point		interpt;
+	LINE		tmp;
+
+	line_construct(&tmp, &l2->p[0], lseg_sl(l2));
+	if (!lseg_interpt_line(&interpt, l1, &tmp))
+		return false;
 
 	/*
-	 * Find the intersection of the appropriate lines, if any.
+	 * If the line intersection point isn't within l2, there is no valid
+	 * segment intersection point at all.
 	 */
-	line_construct_pts(&tmp1, &l1->p[0], &l1->p[1]);
-	line_construct_pts(&tmp2, &l2->p[0], &l2->p[1]);
-	result = line_interpt_internal(&tmp1, &tmp2);
-	if (!PointerIsValid(result))
-		return NULL;
+	if (!lseg_contain_point(l2, &interpt))
+		return false;
 
-	/*
-	 * If the line intersection point isn't within l1 (or equivalently l2),
-	 * there is no valid segment intersection point at all.
-	 */
-	if (!on_ps_internal(result, l1) ||
-		!on_ps_internal(result, l2))
-	{
-		pfree(result);
-		return NULL;
-	}
+	if (result != NULL)
+		*result = interpt;
 
-	/*
-	 * If there is an intersection, then check explicitly for matching
-	 * endpoints since there may be rounding effects with annoying lsb
-	 * residue. - tgl 1997-07-09
-	 */
-	if ((FPeq(l1->p[0].x, l2->p[0].x) && FPeq(l1->p[0].y, l2->p[0].y)) ||
-		(FPeq(l1->p[0].x, l2->p[1].x) && FPeq(l1->p[0].y, l2->p[1].y)))
-	{
-		result->x = l1->p[0].x;
-		result->y = l1->p[0].y;
-	}
-	else if ((FPeq(l1->p[1].x, l2->p[0].x) && FPeq(l1->p[1].y, l2->p[0].y)) ||
-			 (FPeq(l1->p[1].x, l2->p[1].x) && FPeq(l1->p[1].y, l2->p[1].y)))
-	{
-		result->x = l1->p[1].x;
-		result->y = l1->p[1].y;
-	}
-
-	return result;
+	return true;
 }
 
-/* lseg_interpt -
- *		Find the intersection point of two segments (if any).
- */
 Datum
 lseg_interpt(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
-	result = lseg_interpt_internal(l1, l2);
-	if (!PointerIsValid(result))
-		PG_RETURN_NULL();
+	result = (Point *) palloc(sizeof(Point));
 
+	if (!lseg_interpt_lseg(result, l1, l2))
+		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
 
 /***********************************************************************
  **
  **		Routines for position comparisons of differently-typed
  **				2D objects.
  **
  ***********************************************************************/
 
@@ -2333,215 +2237,128 @@ lseg_interpt(PG_FUNCTION_ARGS)
 
 /*
  * Distance from a point to a line
  */
 Datum
 dist_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_FLOAT8(dist_pl_internal(pt, line));
+	PG_RETURN_FLOAT8(line_closept_point(NULL, line, pt));
 }
 
-static double
-dist_pl_internal(Point *pt, LINE *line)
-{
-	return fabs((line->A * pt->x + line->B * pt->y + line->C) /
-				HYPOT(line->A, line->B));
-}
 
 /*
  * Distance from a point to a lseg
  */
 Datum
 dist_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_FLOAT8(dist_ps_internal(pt, lseg));
-}
-
-static double
-dist_ps_internal(Point *pt, LSEG *lseg)
-{
-	double		m;				/* slope of perp. */
-	LINE	   *ln;
-	double		result,
-				tmpdist;
-	Point	   *ip;
-
-	/*
-	 * Construct a line perpendicular to the input segment and through the
-	 * input point
-	 */
-	if (lseg->p[1].x == lseg->p[0].x)
-		m = 0;
-	else if (lseg->p[1].y == lseg->p[0].y)
-		m = (double) DBL_MAX;	/* slope is infinite */
-	else
-		m = (lseg->p[0].x - lseg->p[1].x) / (lseg->p[1].y - lseg->p[0].y);
-	ln = line_construct_pm(pt, m);
-
-#ifdef GEODEBUG
-	printf("dist_ps- line is A=%g B=%g C=%g from (point) slope (%f,%f) %g\n",
-		   ln->A, ln->B, ln->C, pt->x, pt->y, m);
-#endif
-
-	/*
-	 * Calculate distance to the line segment or to the nearest endpoint of
-	 * the segment.
-	 */
-
-	/* intersection is on the line segment? */
-	if ((ip = interpt_sl(lseg, ln)) != NULL)
-	{
-		/* yes, so use distance to the intersection point */
-		result = point_dt(pt, ip);
-#ifdef GEODEBUG
-		printf("dist_ps- distance is %f to intersection point is (%f,%f)\n",
-			   result, ip->x, ip->y);
-#endif
-	}
-	else
-	{
-		/* no, so use distance to the nearer endpoint */
-		result = point_dt(pt, &lseg->p[0]);
-		tmpdist = point_dt(pt, &lseg->p[1]);
-		if (tmpdist < result)
-			result = tmpdist;
-	}
-
-	return result;
+	PG_RETURN_FLOAT8(lseg_closept_point(NULL, lseg, pt));
 }
 
 /*
  * Distance from a point to a path
  */
 Datum
 dist_ppath(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	PATH	   *path = PG_GETARG_PATH_P(1);
 	float8		result = 0.0;	/* keep compiler quiet */
 	bool		have_min = false;
 	float8		tmp;
 	int			i;
 	LSEG		lseg;
 
-	switch (path->npts)
+	Assert(path->npts > 0);
+
+	/*
+	 * The distance from a point to a path is the smallest distance
+	 * from the point to any of its constituent segments.
+	 */
+	for (i = 0; i < path->npts; i++)
 	{
-		case 0:
-			/* no points in path? then result is undefined... */
-			PG_RETURN_NULL();
-		case 1:
-			/* one point in path? then get distance between two points... */
-			result = point_dt(pt, &path->p[0]);
-			break;
-		default:
-			/* make sure the path makes sense... */
-			Assert(path->npts > 1);
+		int			iprev;
 
-			/*
-			 * the distance from a point to a path is the smallest distance
-			 * from the point to any of its constituent segments.
-			 */
-			for (i = 0; i < path->npts; i++)
-			{
-				int			iprev;
+		if (i > 0)
+			iprev = i - 1;
+		else
+		{
+			if (!path->closed)
+				continue;
+			iprev = path->npts - 1; /* Include the closure segment */
+		}
 
-				if (i > 0)
-					iprev = i - 1;
-				else
-				{
-					if (!path->closed)
-						continue;
-					iprev = path->npts - 1; /* include the closure segment */
-				}
-
-				statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
-				tmp = dist_ps_internal(pt, &lseg);
-				if (!have_min || tmp < result)
-				{
-					result = tmp;
-					have_min = true;
-				}
-			}
-			break;
+		statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
+		tmp = lseg_closept_point(NULL, &lseg, pt);
+		if (!have_min || tmp < result)
+		{
+			result = tmp;
+			have_min = true;
+		}
 	}
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a point to a box
  */
 Datum
 dist_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
-	float8		result;
-	Point	   *near;
 
-	near = DatumGetPointP(DirectFunctionCall2(close_pb,
-											  PointPGetDatum(pt),
-											  BoxPGetDatum(box)));
-	result = point_dt(near, pt);
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(box_closept_point(NULL, box, pt));
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	float8		result,
 				d2;
 
-	if (has_interpt_sl(lseg, line))
+	if (lseg_interpt_line(NULL, lseg, line))
 		result = 0.0;
 	else
 	{
-		result = dist_pl_internal(&lseg->p[0], line);
-		d2 = dist_pl_internal(&lseg->p[1], line);
+		result = line_closept_point(NULL, line, &lseg->p[0]);
+		d2 = line_closept_point(NULL, line, &lseg->p[1]);
 		/* XXX shouldn't we take the min not max? */
 		if (d2 > result)
 			result = d2;
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
-	Point	   *tmp;
-	Datum		result;
 
-	tmp = DatumGetPointP(DirectFunctionCall2(close_sb,
-											 LsegPGetDatum(lseg),
-											 BoxPGetDatum(box)));
-	result = DirectFunctionCall2(dist_pb,
-								 PointPGetDatum(tmp),
-								 BoxPGetDatum(box));
-
-	PG_RETURN_DATUM(result);
+	PG_RETURN_FLOAT8(box_closept_lseg(NULL, box, lseg));
 }
 
 /*
  * Distance from a line to a box
  */
 Datum
 dist_lb(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -2577,37 +2394,31 @@ dist_cpoly(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a point to a polygon
  */
 Datum
 dist_ppoly(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	POLYGON    *poly = PG_GETARG_POLYGON_P(1);
-	float8		result;
 
-	result = dist_ppoly_internal(point, poly);
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(dist_ppoly_internal(point, poly));
 }
 
 Datum
 dist_polyp(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	float8		result;
 
-	result = dist_ppoly_internal(point, poly);
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(dist_ppoly_internal(point, poly));
 }
 
 static double
 dist_ppoly_internal(Point *pt, POLYGON *poly)
 {
 	float8		result;
 	float8		d;
 	int			i;
 	LSEG		seg;
 
@@ -2617,498 +2428,481 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
 		printf("dist_ppoly_internal- point inside of polygon\n");
 #endif
 		return 0.0;
 	}
 
 	/* initialize distance with segment between first and last points */
 	seg.p[0].x = poly->p[0].x;
 	seg.p[0].y = poly->p[0].y;
 	seg.p[1].x = poly->p[poly->npts - 1].x;
 	seg.p[1].y = poly->p[poly->npts - 1].y;
-	result = dist_ps_internal(pt, &seg);
+	result = lseg_closept_point(NULL, &seg, pt);
 #ifdef GEODEBUG
 	printf("dist_ppoly_internal- segment 0/n distance is %f\n", result);
 #endif
 
 	/* check distances for other segments */
-	for (i = 0; (i < poly->npts - 1); i++)
+	for (i = 0; i < poly->npts - 1; i++)
 	{
 		seg.p[0].x = poly->p[i].x;
 		seg.p[0].y = poly->p[i].y;
 		seg.p[1].x = poly->p[i + 1].x;
 		seg.p[1].y = poly->p[i + 1].y;
-		d = dist_ps_internal(pt, &seg);
+		d = lseg_closept_point(NULL, &seg, pt);
 #ifdef GEODEBUG
 		printf("dist_ppoly_internal- segment %d distance is %f\n", (i + 1), d);
 #endif
 		if (d < result)
 			result = d;
 	}
 
 	return result;
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
  *				Intersection point of objects.
  *				We choose to ignore the "point" of intersection between
  *				  lines and boxes, since there are typically two.
  *-------------------------------------------------------------------*/
 
-/* Get intersection point of lseg and line; returns NULL if no intersection */
-static Point *
-interpt_sl(LSEG *lseg, LINE *line)
-{
-	LINE		tmp;
-	Point	   *p;
-
-	line_construct_pts(&tmp, &lseg->p[0], &lseg->p[1]);
-	p = line_interpt_internal(&tmp, line);
-#ifdef GEODEBUG
-	printf("interpt_sl- segment is (%.*g %.*g) (%.*g %.*g)\n",
-		   DBL_DIG, lseg->p[0].x, DBL_DIG, lseg->p[0].y, DBL_DIG, lseg->p[1].x, DBL_DIG, lseg->p[1].y);
-	printf("interpt_sl- segment becomes line A=%.*g B=%.*g C=%.*g\n",
-		   DBL_DIG, tmp.A, DBL_DIG, tmp.B, DBL_DIG, tmp.C);
-#endif
-	if (PointerIsValid(p))
-	{
-#ifdef GEODEBUG
-		printf("interpt_sl- intersection point is (%.*g %.*g)\n", DBL_DIG, p->x, DBL_DIG, p->y);
-#endif
-		if (on_ps_internal(p, lseg))
-		{
-#ifdef GEODEBUG
-			printf("interpt_sl- intersection point is on segment\n");
-#endif
-		}
-		else
-			p = NULL;
-	}
-
-	return p;
-}
-
-/* variant: just indicate if intersection point exists */
+/*
+ * Check if the line segment intersects with the line
+ *
+ * This returns true if line segment intersects with line, false if they
+ * do not.  This also sets the intersection point to *result, if it is not
+ * NULL.
+ */
 static bool
-has_interpt_sl(LSEG *lseg, LINE *line)
+lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
 {
-	Point	   *tmp;
+	Point		interpt;
+	LINE		tmp;
 
-	tmp = interpt_sl(lseg, line);
-	if (tmp)
+	/*
+	 * First, we promote the line segment to a line, because we know how
+	 * to find the intersection point of two lines.  If they don't have
+	 * an intersection point, we are done.
+	 */
+	line_construct(&tmp, &lseg->p[0], lseg_sl(lseg));
+	if (!line_interpt_line(&interpt, &tmp, line))
+		return false;
+
+	/*
+	 * Then, we check whether the intersection point is actually on the line
+	 * segment.
+	 */
+	if (!lseg_contain_point(lseg, &interpt))
+		return false;
+
+	if (result == NULL)
 		return true;
-	return false;
+
+	/*
+	 * If there is an intersection, then check explicitly for matching
+	 * endpoints since there may be rounding effects with annoying LSB
+	 * residue.
+	 */
+	if (point_eq_point(&lseg->p[0], &interpt))
+		*result = lseg->p[0];
+	else if (point_eq_point(&lseg->p[1], &interpt))
+		*result = lseg->p[1];
+	else
+		*result = interpt;
+
+	return true;
 }
 
 /*---------------------------------------------------------------------
  *		close_
  *				Point of closest proximity between objects.
  *-------------------------------------------------------------------*/
 
-/* close_pl -
+/*
  *		The intersection point of a perpendicular of the line
  *		through the point.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
+static float8
+line_closept_point(Point *result, LINE *line, Point *point)
+{
+	bool		retval;
+	Point       closept;
+	LINE		tmp;
+
+	/* We drop a perpendicular to find the intersection point. */
+	line_construct(&tmp, point, line_invsl(line));
+	retval = line_interpt_line(&closept, line, &tmp);
+	Assert(retval);		/* XXX: We need something better. */
+
+	if (result != NULL)
+		*result = closept;
+
+	/* Then we calculate the distance between the points. */
+	return point_dt(&closept, point);
+}
+
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
-	LINE	   *tmp;
-	double		invm;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	if (FPzero(line->B))		/* vertical? */
-	{
-		result->x = line->C;
-		result->y = pt->y;
-		PG_RETURN_POINT_P(result);
-	}
-	if (FPzero(line->A))		/* horizontal? */
-	{
-		result->x = pt->x;
-		result->y = line->C;
-		PG_RETURN_POINT_P(result);
-	}
-	/* drop a perpendicular and find the intersection point */
+	line_closept_point(result, line, pt);
 
-	/* invert and flip the sign on the slope to get a perpendicular */
-	invm = line->B / line->A;
-	tmp = line_construct_pm(pt, invm);
-	result = line_interpt_internal(tmp, line);
-	Assert(result != NULL);
 	PG_RETURN_POINT_P(result);
 }
 
 
-/* close_ps()
+/*
  * Closest point on line segment to specified point.
- * Take the closest endpoint if the point is left, right,
- *	above, or below the segment, otherwise find the intersection
- *	point of the segment and its perpendicular through the point.
  *
- * Some tricky code here, relying on boolean expressions
- *	evaluating to only zero or one to use as an array index.
- *		bug fixes by gthaker@atl.lmco.com; May 1, 1998
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
+static float8
+lseg_closept_point(Point *result, LSEG *lseg, Point *pt)
+{
+	Point		closept;
+	LINE		tmp;
+
+	/*
+	 * To find the closest point, we draw a perpendicular line from the point
+	 * to the line segment.
+	 */
+	line_construct(&tmp, pt, point_invsl(&lseg->p[0], &lseg->p[1]));
+	lseg_closept_line(&closept, lseg, &tmp);
+
+	if (result != NULL)
+		*result = closept;
+
+	return point_dt(&closept, pt);
+}
+
 Datum
 close_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
-	LINE	   *tmp;
-	double		invm;
-	int			xh,
-				yh;
+	Point	   *result;
 
-#ifdef GEODEBUG
-	printf("close_sp:pt->x %f pt->y %f\nlseg(0).x %f lseg(0).y %f  lseg(1).x %f lseg(1).y %f\n",
-		   pt->x, pt->y, lseg->p[0].x, lseg->p[0].y,
-		   lseg->p[1].x, lseg->p[1].y);
-#endif
+	result = (Point *) palloc(sizeof(Point));
 
-	/* xh (or yh) is the index of upper x( or y) end point of lseg */
-	/* !xh (or !yh) is the index of lower x( or y) end point of lseg */
-	xh = lseg->p[0].x < lseg->p[1].x;
-	yh = lseg->p[0].y < lseg->p[1].y;
-
-	if (FPeq(lseg->p[0].x, lseg->p[1].x))	/* vertical? */
-	{
-#ifdef GEODEBUG
-		printf("close_ps- segment is vertical\n");
-#endif
-		/* first check if point is below or above the entire lseg. */
-		if (pt->y < lseg->p[!yh].y)
-			result = point_copy(&lseg->p[!yh]); /* below the lseg */
-		else if (pt->y > lseg->p[yh].y)
-			result = point_copy(&lseg->p[yh]);	/* above the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
-
-		/* point lines along (to left or right) of the vertical lseg. */
-
-		result = (Point *) palloc(sizeof(Point));
-		result->x = lseg->p[0].x;
-		result->y = pt->y;
-		PG_RETURN_POINT_P(result);
-	}
-	else if (FPeq(lseg->p[0].y, lseg->p[1].y))	/* horizontal? */
-	{
-#ifdef GEODEBUG
-		printf("close_ps- segment is horizontal\n");
-#endif
-		/* first check if point is left or right of the entire lseg. */
-		if (pt->x < lseg->p[!xh].x)
-			result = point_copy(&lseg->p[!xh]); /* left of the lseg */
-		else if (pt->x > lseg->p[xh].x)
-			result = point_copy(&lseg->p[xh]);	/* right of the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
-
-		/* point lines along (at top or below) the horiz. lseg. */
-		result = (Point *) palloc(sizeof(Point));
-		result->x = pt->x;
-		result->y = lseg->p[0].y;
-		PG_RETURN_POINT_P(result);
-	}
-
-	/*
-	 * vert. and horiz. cases are down, now check if the closest point is one
-	 * of the end points or someplace on the lseg.
-	 */
-
-	invm = -1.0 / point_sl(&(lseg->p[0]), &(lseg->p[1]));
-	tmp = line_construct_pm(&lseg->p[!yh], invm);	/* lower edge of the
-													 * "band" */
-	if (pt->y < (tmp->A * pt->x + tmp->C))
-	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[!yh]); /* below the lseg, take lower end
-											 * pt */
-#ifdef GEODEBUG
-		printf("close_ps below: tmp A %f  B %f   C %f\n",
-			   tmp->A, tmp->B, tmp->C);
-#endif
-		PG_RETURN_POINT_P(result);
-	}
-	tmp = line_construct_pm(&lseg->p[yh], invm);	/* upper edge of the
-													 * "band" */
-	if (pt->y > (tmp->A * pt->x + tmp->C))
-	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[yh]);	/* above the lseg, take higher end
-											 * pt */
-#ifdef GEODEBUG
-		printf("close_ps above: tmp A %f  B %f   C %f\n",
-			   tmp->A, tmp->B, tmp->C);
-#endif
-		PG_RETURN_POINT_P(result);
-	}
-
-	/*
-	 * at this point the "normal" from point will hit lseg. The closest point
-	 * will be somewhere on the lseg
-	 */
-	tmp = line_construct_pm(pt, invm);
-#ifdef GEODEBUG
-	printf("close_ps- tmp A %f  B %f   C %f\n",
-		   tmp->A, tmp->B, tmp->C);
-#endif
-	result = interpt_sl(lseg, tmp);
-
-	/*
-	 * ordinarily we should always find an intersection point, but that could
-	 * fail in the presence of NaN coordinates, and perhaps even from simple
-	 * roundoff issues.  Return a SQL NULL if so.
-	 */
-	if (result == NULL)
+	if (isnan(lseg_closept_point(result, lseg, pt)))
 		PG_RETURN_NULL();
 
-#ifdef GEODEBUG
-	printf("close_ps- result.x %f  result.y %f\n", result->x, result->y);
-#endif
 	PG_RETURN_POINT_P(result);
 }
 
 
-/* close_lseg()
- * Closest point to l1 on l2.
+/*
+ * Closest point on line segment to line segment
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
+static float8
+lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
+{
+	Point		point;
+	double		dist;
+	double		d;
+
+	d = lseg_closept_point(NULL, l1, &l2->p[0]);
+	dist = d;
+	if (result != NULL)
+		*result = l2->p[0];
+
+	d = lseg_closept_point(NULL, l1, &l2->p[1]);
+	if (d < dist)
+	{
+		dist = d;
+		if (result != NULL)
+			*result = l2->p[1];
+	}
+
+	if (lseg_closept_point(&point, l2, &l1->p[0]) < dist)
+		d = lseg_closept_point(result, l1, &point);
+
+	if (lseg_closept_point(&point, l2, &l1->p[1]) < dist)
+		d = lseg_closept_point(result, l1, &point);
+
+	if (d < dist)
+		dist = d;
+
+	return dist;
+}
+
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
-	Point		point;
-	double		dist;
-	double		d;
+	Point	   *result;
 
-	d = dist_ps_internal(&l1->p[0], l2);
-	dist = d;
-	memcpy(&point, &l1->p[0], sizeof(Point));
+	result = (Point *) palloc(sizeof(Point));
 
-	if ((d = dist_ps_internal(&l1->p[1], l2)) < dist)
-	{
-		dist = d;
-		memcpy(&point, &l1->p[1], sizeof(Point));
-	}
-
-	if (dist_ps_internal(&l2->p[0], l1) < dist)
-	{
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&l2->p[0]),
-													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
-													LsegPGetDatum(l2)));
-	}
-
-	if (dist_ps_internal(&l2->p[1], l1) < dist)
-	{
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&l2->p[1]),
-													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
-													LsegPGetDatum(l2)));
-	}
-
-	if (result == NULL)
-		result = point_copy(&point);
+	lseg_closept_lseg(result, l2, l1);
 
 	PG_RETURN_POINT_P(result);
 }
 
-/* close_pb()
+
+/*
  * Closest point on or in box to specified point.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
-Datum
-close_pb(PG_FUNCTION_ARGS)
+static float8
+box_closept_point(Point *result, BOX *box, Point *pt)
 {
-	Point	   *pt = PG_GETARG_POINT_P(0);
-	BOX		   *box = PG_GETARG_BOX_P(1);
-	LSEG		lseg,
-				seg;
-	Point		point;
+	LSEG		lseg;
+	Point		point,
+				closept;
 	double		dist,
 				d;
 
-	if (DatumGetBool(DirectFunctionCall2(on_pb,
-										 PointPGetDatum(pt),
-										 BoxPGetDatum(box))))
-		PG_RETURN_POINT_P(pt);
+	if (box_contain_point(box, pt))
+	{
+		if (result != NULL)
+			*result = *pt;
+
+		return 0.0;
+	}
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&lseg, &box->low, &point);
-	dist = dist_ps_internal(pt, &lseg);
+	dist = lseg_closept_point(result, &lseg, pt);
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	statlseg_construct(&lseg, &box->high, &point);
+	d = lseg_closept_point(&closept, &lseg, pt);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&lseg, &seg, sizeof(lseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
-	statlseg_construct(&seg, &box->low, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	statlseg_construct(&lseg, &box->low, &point);
+	d = lseg_closept_point(&closept, &lseg, pt);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&lseg, &seg, sizeof(lseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	statlseg_construct(&lseg, &box->high, &point);
+	d = lseg_closept_point(&closept, &lseg, pt);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&lseg, &seg, sizeof(lseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
-										PointPGetDatum(pt),
-										LsegPGetDatum(&lseg)));
+	return dist;
 }
 
+Datum
+close_pb(PG_FUNCTION_ARGS)
+{
+	Point	   *pt = PG_GETARG_POINT_P(0);
+	BOX		   *box = PG_GETARG_BOX_P(1);
+	Point	   *result;
+
+	result = (Point *) palloc(sizeof(Point));
+
+	box_closept_point(result, box, pt);
+
+	PG_RETURN_POINT_P(result);
+}
+
+
 /* close_sl()
  * Closest point on line to line segment.
  *
  * XXX THIS CODE IS WRONG
  * The code is actually calculating the point on the line segment
  *	which is backwards from the routine naming convention.
  * Copied code to new routine close_ls() but haven't fixed this one yet.
  * - thomas 1998-01-31
  */
 Datum
 close_sl(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 	float8		d1,
 				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
+	result = (Point *) palloc(sizeof(Point));
+
+	if (lseg_interpt_line(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
-	d1 = dist_pl_internal(&lseg->p[0], line);
-	d2 = dist_pl_internal(&lseg->p[1], line);
+	d1 = line_closept_point(NULL, line, &lseg->p[0]);
+	d2 = line_closept_point(NULL, line, &lseg->p[1]);
 	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
+		*result = lseg->p[0];
 	else
-		result = point_copy(&lseg->p[1]);
+		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
 
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_sl\" not implemented")));
 
 	PG_RETURN_NULL();
 }
 
-/* close_ls()
+/*
  * Closest point on line segment to line.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
+ *
+ * NOTE: When the lines are parallel, endpoints of one of the line segment
+ * are FPeq(), in presence of NaN or Infinitive coordinates, or perhaps =
+ * even because of simple roundoff issues, there may not be a single closest
+ * point.  We are likely to set the result to the second endpoint in these
+ * cases.
  */
+static float8
+lseg_closept_line(Point *result, LSEG *lseg, LINE *line)
+{
+	float8		dist1,
+				dist2;
+
+	if (lseg_interpt_line(result, lseg, line))
+		return 0.0;
+
+	dist1 = line_closept_point(NULL, line, &lseg->p[0]);
+	dist2 = line_closept_point(NULL, line, &lseg->p[1]);
+
+	if (dist1 < dist2)
+	{
+		if (result != NULL)
+			*result = lseg->p[0];
+
+		return dist1;
+	}
+	else
+	{
+		if (result != NULL)
+			*result = lseg->p[1];
+
+		return dist2;
+	}
+}
+
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
-	float8		d1,
-				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
-		PG_RETURN_POINT_P(result);
+	result = (Point *) palloc(sizeof(Point));
 
-	d1 = dist_pl_internal(&lseg->p[0], line);
-	d2 = dist_pl_internal(&lseg->p[1], line);
-	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
-	else
-		result = point_copy(&lseg->p[1]);
+	lseg_closept_line(result, lseg, line);
 
 	PG_RETURN_POINT_P(result);
 }
 
-/* close_sb()
+
+/*
  * Closest point on or in box to line segment.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
-Datum
-close_sb(PG_FUNCTION_ARGS)
+static float8
+box_closept_lseg(Point *result, BOX *box, LSEG *lseg)
 {
-	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
-	BOX		   *box = PG_GETARG_BOX_P(1);
-	Point		point;
-	LSEG		bseg,
-				seg;
+	Point		point,
+				closept;
+	LSEG		bseg;
 	double		dist,
 				d;
 
-	/* segment intersects box? then just return closest point to center */
-	if (DatumGetBool(DirectFunctionCall2(inter_sb,
-										 LsegPGetDatum(lseg),
-										 BoxPGetDatum(box))))
-	{
-		box_cn(&point, box);
-		PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
-											PointPGetDatum(&point),
-											LsegPGetDatum(lseg)));
-	}
+	if (box_interpt_lseg(result, box, lseg))
+		return 0.0;
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	dist = lseg_dt(lseg, &bseg);
+	dist = lseg_closept_lseg(result, &bseg, lseg);
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	statlseg_construct(&bseg, &box->high, &point);
+	d = lseg_closept_lseg(&closept, &bseg, lseg);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&bseg, &seg, sizeof(bseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
-	statlseg_construct(&seg, &box->low, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	statlseg_construct(&bseg, &box->low, &point);
+	d = lseg_closept_lseg(&closept, &bseg, lseg);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&bseg, &seg, sizeof(bseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	statlseg_construct(&bseg, &box->high, &point);
+	d = lseg_closept_lseg(&closept, &bseg, lseg);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&bseg, &seg, sizeof(bseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	/* OK, we now have the closest line segment on the box boundary */
-	PG_RETURN_DATUM(DirectFunctionCall2(close_lseg,
-										LsegPGetDatum(lseg),
-										LsegPGetDatum(&bseg)));
+	return dist;
 }
 
+Datum
+close_sb(PG_FUNCTION_ARGS)
+{
+	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
+	BOX		   *box = PG_GETARG_BOX_P(1);
+	Point	   *result;
+
+	result = (Point *) palloc(sizeof(Point));
+
+	box_closept_lseg(result, box, lseg);
+
+	PG_RETURN_POINT_P(result);
+}
+
+
 Datum
 close_lb(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 #endif
 
 	/* think about this one for a while */
 	ereport(ERROR,
@@ -3116,71 +2910,87 @@ close_lb(PG_FUNCTION_ARGS)
 			 errmsg("function \"close_lb\" not implemented")));
 
 	PG_RETURN_NULL();
 }
 
 /*---------------------------------------------------------------------
  *		on_
  *				Whether one object lies completely within another.
  *-------------------------------------------------------------------*/
 
-/* on_pl -
+/*
  *		Does the point satisfy the equation?
  */
+static bool
+line_contain_point(LINE *line, Point *point)
+{
+	return FPzero(line->A * point->x + line->B * point->y + line->C);
+}
+
 Datum
 on_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(FPzero(line->A * pt->x + line->B * pt->y + line->C));
+	PG_RETURN_BOOL(line_contain_point(line, pt));
 }
 
 
-/* on_ps -
+/*
  *		Determine colinearity by detecting a triangle inequality.
  * This algorithm seems to behave nicely even with lsb residues - tgl 1997-07-09
  */
+static bool
+lseg_contain_point(LSEG *lseg, Point *pt)
+{
+	return FPeq(point_dt(pt, &lseg->p[0]) +
+				point_dt(pt, &lseg->p[1]),
+				point_dt(&lseg->p[0], &lseg->p[1]));
+}
+
 Datum
 on_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(on_ps_internal(pt, lseg));
+	PG_RETURN_BOOL(lseg_contain_point(lseg, pt));
 }
 
+
+/*
+ * Check whether the point is in the box or on its border
+ */
 static bool
-on_ps_internal(Point *pt, LSEG *lseg)
+box_contain_point(BOX *box, Point *point)
 {
-	return FPeq(point_dt(pt, &lseg->p[0]) + point_dt(pt, &lseg->p[1]),
-				point_dt(&lseg->p[0], &lseg->p[1]));
+	return box->high.x >= point->x && box->low.x <= point->x &&
+		   box->high.y >= point->y && box->low.y <= point-> y;
 }
 
 Datum
 on_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_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);
+	PG_RETURN_BOOL(box_contain_point(box, pt));
 }
 
 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);
+	PG_RETURN_BOOL(box_contain_point(box, pt));
 }
 
 /* on_ppath -
  *		Whether a point lies within (on) a polyline.
  *		If open, we have to (groan) check each segment.
  * (uses same algorithm as for point intersecting segment - tgl 1997-07-09)
  *		If closed, we use the old O(n) ray method for point-in-polygon.
  *				The ray is horizontal, from pt out to the right.
  *				Each segment that crosses the ray counts as an
  *				intersection; note that an endpoint or edge may touch
@@ -3210,158 +3020,184 @@ on_ppath(PG_FUNCTION_ARGS)
 				PG_RETURN_BOOL(true);
 			a = b;
 		}
 		PG_RETURN_BOOL(false);
 	}
 
 	/*-- CLOSED --*/
 	PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
 }
 
+
+/*
+ * Check whether the line segment is on the line or close enough
+ *
+ * It is, if both of its points are on the line or close enough.
+ */
 Datum
 on_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(DatumGetBool(DirectFunctionCall2(on_pl,
-													PointPGetDatum(&lseg->p[0]),
-													LinePGetDatum(line))) &&
-				   DatumGetBool(DirectFunctionCall2(on_pl,
-													PointPGetDatum(&lseg->p[1]),
-													LinePGetDatum(line))));
+	PG_RETURN_BOOL(line_contain_point(line, &lseg->p[0]) &&
+				   line_contain_point(line, &lseg->p[1]));
+}
+
+
+/*
+ * Check whether the line segment is in the box or on its border
+ *
+ * It is, if both of its points are in the box or on its border.
+ */
+static bool
+box_contain_lseg(BOX *box, LSEG *lseg)
+{
+	return box_contain_point(box, &lseg->p[0]) &&
+		   box_contain_point(box, &lseg->p[1]);
 }
 
 Datum
 on_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(DatumGetBool(DirectFunctionCall2(on_pb,
-													PointPGetDatum(&lseg->p[0]),
-													BoxPGetDatum(box))) &&
-				   DatumGetBool(DirectFunctionCall2(on_pb,
-													PointPGetDatum(&lseg->p[1]),
-													BoxPGetDatum(box))));
+	PG_RETURN_BOOL(box_contain_lseg(box, lseg));
 }
 
 /*---------------------------------------------------------------------
  *		inter_
  *				Whether one object intersects another.
  *-------------------------------------------------------------------*/
 
 Datum
 inter_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(has_interpt_sl(lseg, line));
+	PG_RETURN_BOOL(lseg_interpt_line(NULL, lseg, line));
 }
 
-/* inter_sb()
+
+/*
  * Do line segment and box intersect?
  *
  * Segment completely inside box counts as intersection.
  * If you want only segments crossing box boundaries,
  *	try converting box to path first.
  *
+ * This function also sets the *result to the closest point on the line
+ * segment to the center of the box when they overlap and the result is
+ * not NULL.  It is somewhat arbitrary, but maybe the best we can do as
+ * there are typically two points they intersect.
+ *
  * Optimize for non-intersection by checking for box intersection first.
  * - thomas 1998-01-30
  */
-Datum
-inter_sb(PG_FUNCTION_ARGS)
+static bool
+box_interpt_lseg(Point *result, BOX *box, LSEG *lseg)
 {
-	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
-	BOX		   *box = PG_GETARG_BOX_P(1);
 	BOX			lbox;
 	LSEG		bseg;
 	Point		point;
 
 	lbox.low.x = Min(lseg->p[0].x, lseg->p[1].x);
 	lbox.low.y = Min(lseg->p[0].y, lseg->p[1].y);
 	lbox.high.x = Max(lseg->p[0].x, lseg->p[1].x);
 	lbox.high.y = Max(lseg->p[0].y, lseg->p[1].y);
 
 	/* nothing close to overlap? then not going to intersect */
 	if (!box_ov(&lbox, box))
-		PG_RETURN_BOOL(false);
+		return false;
+
+	if (result != NULL)
+	{
+		box_cn(&point, box);
+		lseg_closept_point(result, lseg, &point);
+	}
 
 	/* an endpoint of segment is inside box? then clearly intersects */
-	if (DatumGetBool(DirectFunctionCall2(on_pb,
-										 PointPGetDatum(&lseg->p[0]),
-										 BoxPGetDatum(box))) ||
-		DatumGetBool(DirectFunctionCall2(on_pb,
-										 PointPGetDatum(&lseg->p[1]),
-										 BoxPGetDatum(box))))
-		PG_RETURN_BOOL(true);
+	if (box_contain_point(box, &lseg->p[0]) ||
+		box_contain_point(box, &lseg->p[1]))
+		return true;
 
 	/* pairwise check lseg intersections */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	/* if we dropped through, no two segs intersected */
-	PG_RETURN_BOOL(false);
+	return false;
 }
 
+Datum
+inter_sb(PG_FUNCTION_ARGS)
+{
+	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
+	BOX		   *box = PG_GETARG_BOX_P(1);
+
+	PG_RETURN_BOOL(box_interpt_lseg(NULL, box, lseg));
+}
+
+
 /* inter_lb()
  * Do line and box intersect?
  */
 Datum
 inter_lb(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	LSEG		bseg;
 	Point		p1,
 				p2;
 
 	/* pairwise check lseg intersections */
 	p1.x = box->low.x;
 	p1.y = box->low.y;
 	p2.x = box->low.x;
 	p2.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->high.x;
 	p1.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p2.x = box->high.x;
 	p2.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->low.x;
 	p1.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 
 	/* if we dropped through, no intersection */
 	PG_RETURN_BOOL(false);
 }
 
 /*------------------------------------------------------------------
  * The following routines define a data type and operator class for
  * POLYGONS .... Part of which (the polygon's bounding box) is built on
  * top of the BOX data type.
@@ -3374,42 +3210,40 @@ inter_lb(PG_FUNCTION_ARGS)
  *---------------------------------------------------------------------*/
 static void
 make_bound_box(POLYGON *poly)
 {
 	int			i;
 	double		x1,
 				y1,
 				x2,
 				y2;
 
-	if (poly->npts > 0)
-	{
-		x2 = x1 = poly->p[0].x;
-		y2 = y1 = poly->p[0].y;
-		for (i = 1; i < poly->npts; i++)
-		{
-			if (poly->p[i].x < x1)
-				x1 = poly->p[i].x;
-			if (poly->p[i].x > x2)
-				x2 = poly->p[i].x;
-			if (poly->p[i].y < y1)
-				y1 = poly->p[i].y;
-			if (poly->p[i].y > y2)
-				y2 = poly->p[i].y;
-		}
+	Assert(poly->npts > 0);
 
-		box_fill(&(poly->boundbox), x1, x2, y1, y2);
+	x1 = x2 = poly->p[0].x;
+	y2 = y1 = poly->p[0].y;
+	for (i = 1; i < poly->npts; i++)
+	{
+		if (poly->p[i].x < x1)
+			x1 = poly->p[i].x;
+		if (poly->p[i].x > x2)
+			x2 = poly->p[i].x;
+		if (poly->p[i].y < y1)
+			y1 = poly->p[i].y;
+		if (poly->p[i].y > y2)
+			y2 = poly->p[i].y;
 	}
-	else
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot create bounding box for empty polygon")));
+
+	poly->boundbox.low.x = x1;
+	poly->boundbox.high.x = x2;
+	poly->boundbox.low.y = y1;
+	poly->boundbox.high.y = y2;
 }
 
 /*------------------------------------------------------------------
  * poly_in - read in the polygon from a string specification
  *
  *		External format:
  *				"((x0,y0),...,(xn,yn))"
  *				"x0,y0,...,xn,yn"
  *				also supports the older style "(x1,...,xn,y1,...yn)"
  *------------------------------------------------------------------*/
@@ -3739,65 +3573,65 @@ poly_same(PG_FUNCTION_ARGS)
 /*-----------------------------------------------------------------
  * Determine if polygon A overlaps polygon B
  *-----------------------------------------------------------------*/
 Datum
 poly_overlap(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
+	Assert(polya->npts > 0 && polyb->npts > 0);
+
 	/* Quick check by bounding box */
-	result = (polya->npts > 0 && polyb->npts > 0 &&
-			  box_ov(&polya->boundbox, &polyb->boundbox)) ? true : false;
+	result = box_ov(&polya->boundbox, &polyb->boundbox);
 
 	/*
 	 * Brute-force algorithm - try to find intersected edges, if so then
 	 * polygons are overlapped else check is one polygon inside other or not
 	 * by testing single point of them.
 	 */
 	if (result)
 	{
 		int			ia,
 					ib;
 		LSEG		sa,
 					sb;
 
 		/* Init first of polya's edge with last point */
 		sa.p[0] = polya->p[polya->npts - 1];
 		result = false;
 
-		for (ia = 0; ia < polya->npts && result == false; ia++)
+		for (ia = 0; ia < polya->npts && !result; ia++)
 		{
 			/* Second point of polya's edge is a current one */
 			sa.p[1] = polya->p[ia];
 
 			/* Init first of polyb's edge with last point */
 			sb.p[0] = polyb->p[polyb->npts - 1];
 
-			for (ib = 0; ib < polyb->npts && result == false; ib++)
+			for (ib = 0; ib < polyb->npts && !result; ib++)
 			{
 				sb.p[1] = polyb->p[ib];
-				result = lseg_intersect_internal(&sa, &sb);
+				result = lseg_interpt_lseg(NULL, &sa, &sb);
 				sb.p[0] = sb.p[1];
 			}
 
 			/*
 			 * move current endpoint to the first point of next edge
 			 */
 			sa.p[0] = sa.p[1];
 		}
 
-		if (result == false)
+		if (!result)
 		{
-			result = (point_inside(polya->p, polyb->npts, polyb->p)
-					  ||
+			result = (point_inside(polya->p, polyb->npts, polyb->p) ||
 					  point_inside(polyb->p, polya->npts, polya->p));
 		}
 	}
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
@@ -3817,36 +3651,35 @@ poly_overlap(PG_FUNCTION_ARGS)
 
 static bool
 touched_lseg_inside_poly(Point *a, Point *b, LSEG *s, POLYGON *poly, int start)
 {
 	/* point a is on s, b is not */
 	LSEG		t;
 
 	t.p[0] = *a;
 	t.p[1] = *b;
 
-#define POINTEQ(pt1, pt2)	(FPeq((pt1)->x, (pt2)->x) && FPeq((pt1)->y, (pt2)->y))
-	if (POINTEQ(a, s->p))
+	if (point_eq_point(a, s->p))
 	{
-		if (on_ps_internal(s->p + 1, &t))
+		if (lseg_contain_point(&t, s->p + 1))
 			return lseg_inside_poly(b, s->p + 1, poly, start);
 	}
-	else if (POINTEQ(a, s->p + 1))
+	else if (point_eq_point(a, s->p + 1))
 	{
-		if (on_ps_internal(s->p, &t))
+		if (lseg_contain_point(&t, s->p))
 			return lseg_inside_poly(b, s->p, poly, start);
 	}
-	else if (on_ps_internal(s->p, &t))
+	else if (lseg_contain_point(&t, s->p))
 	{
 		return lseg_inside_poly(b, s->p, poly, start);
 	}
-	else if (on_ps_internal(s->p + 1, &t))
+	else if (lseg_contain_point(&t, s->p + 1))
 	{
 		return lseg_inside_poly(b, s->p + 1, poly, start);
 	}
 
 	return true;				/* may be not true, but that will check later */
 }
 
 /*
  * Returns true if segment (a,b) is in polygon, option
  * start is used for optimization - function checks
@@ -3860,50 +3693,49 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 	int			i;
 	bool		res = true,
 				intersection = false;
 
 	t.p[0] = *a;
 	t.p[1] = *b;
 	s.p[0] = poly->p[(start == 0) ? (poly->npts - 1) : (start - 1)];
 
 	for (i = start; i < poly->npts && res; i++)
 	{
-		Point	   *interpt;
+		Point		interpt;
 
 		CHECK_FOR_INTERRUPTS();
 
 		s.p[1] = poly->p[i];
 
-		if (on_ps_internal(t.p, &s))
+		if (lseg_contain_point(&s, t.p))
 		{
-			if (on_ps_internal(t.p + 1, &s))
+			if (lseg_contain_point(&s, t.p + 1))
 				return true;	/* t is contained by s */
 
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p, t.p + 1, &s, poly, i + 1);
 		}
-		else if (on_ps_internal(t.p + 1, &s))
+		else if (lseg_contain_point(&s, t.p + 1))
 		{
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p + 1, t.p, &s, poly, i + 1);
 		}
-		else if ((interpt = lseg_interpt_internal(&t, &s)) != NULL)
+		else if (lseg_interpt_lseg(&interpt, &t, &s))
 		{
 			/*
 			 * segments are X-crossing, go to check each subsegment
 			 */
 
 			intersection = true;
-			res = lseg_inside_poly(t.p, interpt, poly, i + 1);
+			res = lseg_inside_poly(t.p, &interpt, poly, i + 1);
 			if (res)
-				res = lseg_inside_poly(t.p + 1, interpt, poly, i + 1);
-			pfree(interpt);
+				res = lseg_inside_poly(t.p + 1, &interpt, poly, i + 1);
 		}
 
 		s.p[0] = s.p[1];
 	}
 
 	if (res && !intersection)
 	{
 		Point		p;
 
 		/*
@@ -3915,74 +3747,86 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 
 		res = point_inside(&p, poly->npts, poly->p);
 	}
 
 	return res;
 }
 
 /*-----------------------------------------------------------------
  * Determine if polygon A contains polygon B.
  *-----------------------------------------------------------------*/
+static bool
+poly_contain_poly(POLYGON *polya, POLYGON *polyb)
+{
+	int			i;
+	LSEG		s;
+
+	Assert(polya->npts > 0 && polyb->npts > 0);
+
+	/*
+	 * Quick check to see if bounding box is contained.
+	 */
+	if (!box_contain_box(&polya->boundbox, &polyb->boundbox))
+		return false;
+
+	s.p[0] = polyb->p[polyb->npts - 1];
+
+	for (i = 0; i < polyb->npts; i++)
+	{
+		s.p[1] = polyb->p[i];
+		if (!lseg_inside_poly(s.p, s.p + 1, polya, 0))
+			return false;
+		s.p[0] = s.p[1];
+	}
+
+	return true;
+}
+
 Datum
 poly_contain(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	/*
-	 * Quick check to see if bounding box is contained.
-	 */
-	if (polya->npts > 0 && polyb->npts > 0 &&
-		DatumGetBool(DirectFunctionCall2(box_contain,
-										 BoxPGetDatum(&polya->boundbox),
-										 BoxPGetDatum(&polyb->boundbox))))
-	{
-		int			i;
-		LSEG		s;
-
-		s.p[0] = polyb->p[polyb->npts - 1];
-		result = true;
-
-		for (i = 0; i < polyb->npts && result; i++)
-		{
-			s.p[1] = polyb->p[i];
-			result = lseg_inside_poly(s.p, s.p + 1, polya, 0);
-			s.p[0] = s.p[1];
-		}
-	}
-	else
-	{
-		result = false;
-	}
+	result = poly_contain_poly(polya, polyb);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
 
 /*-----------------------------------------------------------------
  * Determine if polygon A is contained by polygon B
  *-----------------------------------------------------------------*/
 Datum
 poly_contained(PG_FUNCTION_ARGS)
 {
-	Datum		polya = PG_GETARG_DATUM(0);
-	Datum		polyb = PG_GETARG_DATUM(1);
+	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
+	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
+	bool		result;
 
 	/* Just switch the arguments and pass it off to poly_contain */
-	PG_RETURN_DATUM(DirectFunctionCall2(poly_contain, polyb, polya));
+	result = poly_contain_poly(polyb, polya);
+
+	/*
+	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
+	 */
+	PG_FREE_IF_COPY(polya, 0);
+	PG_FREE_IF_COPY(polyb, 1);
+
+	PG_RETURN_BOOL(result);
 }
 
 
 Datum
 poly_contain_pt(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_BOOL(point_inside(p, poly->npts, poly->p) != 0);
@@ -4018,170 +3862,215 @@ poly_distance(PG_FUNCTION_ARGS)
  **
  **		Routines for 2D points.
  **
  ***********************************************************************/
 
 Datum
 construct_point(PG_FUNCTION_ARGS)
 {
 	float8		x = PG_GETARG_FLOAT8(0);
 	float8		y = PG_GETARG_FLOAT8(1);
+	Point	   *result;
 
-	PG_RETURN_POINT_P(point_construct(x, y));
+	result = (Point *) palloc(sizeof(Point));
+
+	point_construct(result, x, y);
+
+	PG_RETURN_POINT_P(result);
+}
+
+
+static inline void
+point_add_point(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x + pt2->x,
+					pt1->y + pt2->y);
 }
 
 Datum
 point_add(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x + p2->x);
-	result->y = (p1->y + p2->y);
+	point_add_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+
+static inline void
+point_sub_point(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x - pt2->x,
+					pt1->y - pt2->y);
+}
+
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x - p2->x);
-	result->y = (p1->y - p2->y);
+	point_sub_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+
+static inline void
+point_mul_point(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					(pt1->x * pt2->x) - (pt1->y * pt2->y),
+					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+}
+
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x * p2->x) - (p1->y * p2->y);
-	result->y = (p1->x * p2->y) + (p1->y * p2->x);
+	point_mul_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+
+static inline void
+point_div_point(Point *result, Point *pt1, Point *pt2)
+{
+	double		div;
+
+	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
+
+	if (div == 0.0)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	point_construct(result,
+					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
+					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+}
+
 Datum
 point_div(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
-	double		div;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	div = (p2->x * p2->x) + (p2->y * p2->y);
-
-	if (div == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result->x = ((p1->x * p2->x) + (p1->y * p2->y)) / div;
-	result->y = ((p2->x * p1->y) - (p2->y * p1->x)) / div;
+	point_div_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D boxes.
  **
  ***********************************************************************/
 
 Datum
 points_box(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct(p1->x, p2->x, p1->y, p2->y));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	box_construct(result, p1, p2);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_add(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct((box->high.x + p->x),
-								  (box->low.x + p->x),
-								  (box->high.y + p->y),
-								  (box->low.y + p->y)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_add_point(&result->high, &box->high, p);
+	point_add_point(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_sub(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct((box->high.x - p->x),
-								  (box->low.x - p->x),
-								  (box->high.y - p->y),
-								  (box->low.y - p->y)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_sub_point(&result->high, &box->high, p);
+	point_sub_point(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_mul(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
 
-	high = DatumGetPointP(DirectFunctionCall2(point_mul,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_mul,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	result = (BOX *) palloc(sizeof(BOX));
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	point_mul_point(&high, &box->high, p);
+	point_mul_point(&low, &box->low, p);
+
+	box_construct(result, &high, &low);
 
 	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_div(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
 
-	high = DatumGetPointP(DirectFunctionCall2(point_div,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_div,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	result = (BOX *) palloc(sizeof(BOX));
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	point_div_point(&high, &box->high, p);
+	point_div_point(&low, &box->low, p);
+
+	box_construct(result, &high, &low);
 
 	PG_RETURN_BOX_P(result);
 }
 
 /*
  * Convert point to empty box
  */
 Datum
 point_box(PG_FUNCTION_ARGS)
 {
@@ -4277,83 +4166,63 @@ path_add(PG_FUNCTION_ARGS)
  * Translation operators.
  */
 Datum
 path_add_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x += point->x;
-		path->p[i].y += point->y;
-	}
+		point_add_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_sub_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x -= point->x;
-		path->p[i].y -= point->y;
-	}
+		point_sub_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 /* path_mul_pt()
  * Rotation and scaling operators.
  */
 Datum
 path_mul_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_mul,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_mul_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_div_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_div,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_div_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 
 Datum
 path_center(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	PATH	   *path = PG_GETARG_PATH_P(0);
@@ -4414,42 +4283,40 @@ poly_npoints(PG_FUNCTION_ARGS)
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 
 	PG_RETURN_INT32(poly->npts);
 }
 
 
 Datum
 poly_center(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
-	Datum		result;
-	CIRCLE	   *circle;
+	Point	   *result;
+	CIRCLE		circle;
 
-	circle = DatumGetCircleP(DirectFunctionCall1(poly_circle,
-												 PolygonPGetDatum(poly)));
-	result = DirectFunctionCall1(circle_center,
-								 CirclePGetDatum(circle));
+	result = (Point *) palloc(sizeof(Point));
 
-	PG_RETURN_DATUM(result);
+	poly_to_circle(&circle, poly);
+	*result = circle.center;
+
+	PG_RETURN_POINT_P(result);
 }
 
 
 Datum
 poly_box(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	BOX		   *box;
 
-	if (poly->npts < 1)
-		PG_RETURN_NULL();
-
-	box = box_copy(&poly->boundbox);
+	box = (BOX *) palloc(sizeof(BOX));
+	*box = poly->boundbox;
 
 	PG_RETURN_BOX_P(box);
 }
 
 
 /* box_poly()
  * Convert a box to a polygon.
  */
 Datum
 box_poly(PG_FUNCTION_ARGS)
@@ -4467,22 +4334,21 @@ box_poly(PG_FUNCTION_ARGS)
 
 	poly->p[0].x = box->low.x;
 	poly->p[0].y = box->low.y;
 	poly->p[1].x = box->low.x;
 	poly->p[1].y = box->high.y;
 	poly->p[2].x = box->high.x;
 	poly->p[2].y = box->high.y;
 	poly->p[3].x = box->high.x;
 	poly->p[3].y = box->low.y;
 
-	box_fill(&poly->boundbox, box->high.x, box->low.x,
-			 box->high.y, box->low.y);
+	box_construct(&poly->boundbox, &box->high, &box->low);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
 
 Datum
 poly_path(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	PATH	   *path;
@@ -4557,22 +4423,21 @@ circle_in(PG_FUNCTION_ARGS)
 
 	circle->radius = single_decode(s, &s, "circle", str);
 	if (circle->radius < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
 
 	while (depth > 0)
 	{
-		if ((*s == RDELIM)
-			|| ((*s == RDELIM_C) && (depth == 1)))
+		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
 			s++;
 			while (isspace((unsigned char) *s))
 				s++;
 		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
@@ -4656,22 +4521,21 @@ circle_send(PG_FUNCTION_ARGS)
 
 /*		circles identical?
  */
 Datum
 circle_same(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPeq(circle1->radius, circle2->radius) &&
-				   FPeq(circle1->center.x, circle2->center.x) &&
-				   FPeq(circle1->center.y, circle2->center.y));
+				   point_eq_point(&circle1->center, &circle2->center));
 }
 
 /*		circle_overlap	-		does circle1 overlap circle2?
  */
 Datum
 circle_overlap(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
@@ -4730,32 +4594,34 @@ circle_overright(PG_FUNCTION_ARGS)
 }
 
 /*		circle_contained		-		is circle1 contained by circle2?
  */
 Datum
 circle_contained(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle1->radius), circle2->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						circle2->radius - circle1->radius));
 }
 
 /*		circle_contain	-		does circle1 contain circle2?
  */
 Datum
 circle_contain(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle2->radius), circle1->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						circle1->radius - circle2->radius));
 }
 
 
 /*		circle_below		-		is circle1 strictly below circle2?
  */
 Datum
 circle_below(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
@@ -4858,107 +4724,83 @@ circle_ge(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPge(circle_ar(circle1), circle_ar(circle2)));
 }
 
 
 /*----------------------------------------------------------
  *	"Arithmetic" operators on circles.
  *---------------------------------------------------------*/
 
-static CIRCLE *
-circle_copy(CIRCLE *circle)
-{
-	CIRCLE	   *result;
-
-	if (!PointerIsValid(circle))
-		return NULL;
-
-	result = (CIRCLE *) palloc(sizeof(CIRCLE));
-	memcpy((char *) result, (char *) circle, sizeof(CIRCLE));
-	return result;
-}
-
-
 /* circle_add_pt()
  * Translation operator.
  */
 Datum
 circle_add_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x += point->x;
-	result->center.y += point->y;
+	point_add_point(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_sub_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x -= point->x;
-	result->center.y -= point->y;
+	point_sub_point(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /* circle_mul_pt()
  * Rotation and scaling operators.
  */
 Datum
 circle_mul_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_mul,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
-	result->radius *= HYPOT(point->x, point->y);
+	point_mul_point(&result->center, &circle->center, point);
+	result->radius = circle->radius * HYPOT(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_div_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_div,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
-	result->radius /= HYPOT(point->x, point->y);
+	point_div_point(&result->center, &circle->center, point);
+	result->radius = circle->radius / HYPOT(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /*		circle_area		-		returns the area of the circle.
  */
 Datum
 circle_area(PG_FUNCTION_ARGS)
 {
@@ -4993,22 +4835,22 @@ circle_radius(PG_FUNCTION_ARGS)
 /*		circle_distance -		returns the distance between
  *								  two circles.
  */
 Datum
 circle_distance(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(&circle1->center, &circle2->center)
-		- (circle1->radius + circle2->radius);
+	result = point_dt(&circle1->center, &circle2->center) -
+		(circle1->radius + circle2->radius);
 	if (result < 0)
 		result = 0;
 	PG_RETURN_FLOAT8(result);
 }
 
 
 Datum
 circle_contain_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
@@ -5190,56 +5032,60 @@ circle_poly(PG_FUNCTION_ARGS)
 		angle = i * anglestep;
 		poly->p[i].x = circle->center.x - (circle->radius * cos(angle));
 		poly->p[i].y = circle->center.y + (circle->radius * sin(angle));
 	}
 
 	make_bound_box(poly);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
-/*		poly_circle		- convert polygon to circle
+/*
+ * Convert polygon to circle
+ *
+ * The result must be preallocated.
  *
  * XXX This algorithm should use weighted means of line segments
  *	rather than straight average values of points - tgl 97/01/21.
  */
+static void
+poly_to_circle(CIRCLE *result, POLYGON *poly)
+{
+	int			i;
+
+	Assert(poly->npts > 0);
+
+	result->center.x = 0;
+	result->center.y = 0;
+	result->radius = 0;
+
+	for (i = 0; i < poly->npts; i++)
+		point_add_point(&result->center, &result->center, &poly->p[i]);
+	result->center.x /= poly->npts;
+	result->center.y /= poly->npts;
+
+	for (i = 0; i < poly->npts; i++)
+		result->radius += point_dt(&poly->p[i], &result->center);
+	result->radius /= poly->npts;
+}
+
 Datum
 poly_circle(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
-	CIRCLE	   *circle;
-	int			i;
+	CIRCLE	   *result;
 
-	if (poly->npts < 1)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot convert empty polygon to circle")));
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
+	poly_to_circle(result, poly);
 
-	circle->center.x = 0;
-	circle->center.y = 0;
-	circle->radius = 0;
-
-	for (i = 0; i < poly->npts; i++)
-	{
-		circle->center.x += poly->p[i].x;
-		circle->center.y += poly->p[i].y;
-	}
-	circle->center.x /= poly->npts;
-	circle->center.y /= poly->npts;
-
-	for (i = 0; i < poly->npts; i++)
-		circle->radius += point_dt(&poly->p[i], &circle->center);
-	circle->radius /= poly->npts;
-
-	PG_RETURN_CIRCLE_P(circle);
+	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /***********************************************************************
  **
  **		Private routines for multiple types.
  **
  ***********************************************************************/
 
 /*
@@ -5261,22 +5107,21 @@ point_inside(Point *p, int npts, Point *plist)
 	double		x0,
 				y0;
 	double		prev_x,
 				prev_y;
 	int			i = 0;
 	double		x,
 				y;
 	int			cross,
 				total_cross = 0;
 
-	if (npts <= 0)
-		return 0;
+	Assert(npts > 0);
 
 	/* compute first polygon point relative to single point */
 	x0 = plist[0].x - p->x;
 	y0 = plist[0].y - p->y;
 
 	prev_x = x0;
 	prev_y = y0;
 	/* loop over polygon points and aggregate total_cross */
 	for (i = 1; i < npts; i++)
 	{
@@ -5371,51 +5216,48 @@ lseg_crossing(double x, double y, double prev_x, double prev_y)
 static bool
 plist_same(int npts, Point *p1, Point *p2)
 {
 	int			i,
 				ii,
 				j;
 
 	/* find match for first point */
 	for (i = 0; i < npts; i++)
 	{
-		if ((FPeq(p2[i].x, p1[0].x))
-			&& (FPeq(p2[i].y, p1[0].y)))
+		if (point_eq_point(&p2[i], &p1[0]))
 		{
 
 			/* match found? then look forward through remaining points */
 			for (ii = 1, j = i + 1; ii < npts; ii++, j++)
 			{
 				if (j >= npts)
 					j = 0;
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_point(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed forward match with %d\n", j, ii);
 #endif
 					break;
 				}
 			}
 #ifdef GEODEBUG
 			printf("plist_same- ii = %d/%d after forward match\n", ii, npts);
 #endif
 			if (ii == npts)
 				return true;
 
 			/* match not found forwards? then look backwards */
 			for (ii = 1, j = i - 1; ii < npts; ii++, j--)
 			{
 				if (j < 0)
 					j = (npts - 1);
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_point(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed reverse match with %d\n", j, ii);
 #endif
 					break;
 				}
 			}
 #ifdef GEODEBUG
 			printf("plist_same- ii = %d/%d after reverse match\n", ii, npts);
 #endif
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index 06411aea9e..d7c807f8d9 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -786,14 +786,15 @@ spg_bbox_quad_config(PG_FUNCTION_ARGS)
 
 /*
  * 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);
+	box = (BOX *) palloc(sizeof(BOX));
+	*box = polygon->boundbox;
 
 	PG_RETURN_BOX_P(box);
 }
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index a589e4239f..0e066894cd 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -171,17 +171,13 @@ typedef struct
 #define DatumGetCircleP(X)	  ((CIRCLE *) DatumGetPointer(X))
 #define CirclePGetDatum(X)	  PointerGetDatum(X)
 #define PG_GETARG_CIRCLE_P(n) DatumGetCircleP(PG_GETARG_DATUM(n))
 #define PG_RETURN_CIRCLE_P(x) return CirclePGetDatum(x)
 
 
 /*
  * 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/regress.c b/src/test/regress/regress.c
index 7060b6fbf3..c3a833cc56 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -170,22 +170,27 @@ widget_out(PG_FUNCTION_ARGS)
 	PG_RETURN_CSTRING(str);
 }
 
 PG_FUNCTION_INFO_V1(pt_in_widget);
 
 Datum
 pt_in_widget(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	WIDGET	   *widget = (WIDGET *) PG_GETARG_POINTER(1);
+	float8		distance;
 
-	PG_RETURN_BOOL(point_dt(point, &widget->center) < widget->radius);
+	distance = DatumGetFloat8(DirectFunctionCall2(point_distance,
+												  PointPGetDatum(point),
+											PointPGetDatum(&widget->center)));
+
+	PG_RETURN_BOOL(distance < widget->radius);
 }
 
 PG_FUNCTION_INFO_V1(reverse_name);
 
 Datum
 reverse_name(PG_FUNCTION_ARGS)
 {
 	char	   *string = PG_GETARG_CSTRING(0);
 	int			i;
 	int			len;
-- 
2.14.3 (Apple Git-98)

0002-float-header-v13.patchapplication/octet-stream; name=0002-float-header-v13.patchDownload
From 704fad48cc6767424c6a76dadfcd0f00e13770fd Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 28 May 2016 18:16:05 +0200
Subject: [PATCH 2/6] float-header-v13

Provide header file for built-in float datatypes

Even though, some datatypes under adt/ have separate header files,
most of the simple ones do not.  Their public functions were on
the builtins.h.  We would need to make more functions of floats public
to let the geometric types built on top of them.  This is a good
opportunity to make a separate header file for floats.

1acf7572554515b99ef6e783750aaea8777524ec made _cmp functions public
to solve NaN problem locally for GiST indexes.  This patch reworks it
in favour of a more extensive API.  The API uses inline functions
instead of macros, as they are easier to use compared to macros,
and avoid double-evaluation hazards.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com
---
 contrib/btree_gin/btree_gin.c                 |   1 +
 contrib/btree_gist/btree_ts.c                 |   1 +
 contrib/cube/cube.c                           |   2 +-
 contrib/cube/cubeparse.y                      |   2 +-
 contrib/postgres_fdw/postgres_fdw.c           |   1 +
 src/backend/access/gist/gistget.c             |   2 +-
 src/backend/access/gist/gistproc.c            |  55 +--
 src/backend/access/gist/gistutil.c            |   2 +-
 src/backend/utils/adt/float.c                 | 589 ++++++--------------------
 src/backend/utils/adt/formatting.c            |   1 +
 src/backend/utils/adt/geo_ops.c               |   6 +-
 src/backend/utils/adt/geo_spgist.c            |   2 +-
 src/backend/utils/adt/numeric.c               |   1 +
 src/backend/utils/adt/rangetypes_gist.c       |   3 +-
 src/backend/utils/adt/rangetypes_selfuncs.c   |   3 +-
 src/backend/utils/adt/rangetypes_typanalyze.c |   3 +-
 src/backend/utils/adt/timestamp.c             |   1 +
 src/backend/utils/misc/guc.c                  |   1 +
 src/include/utils/builtins.h                  |  14 -
 src/include/utils/float.h                     | 376 ++++++++++++++++
 src/include/utils/geo_decls.h                 |   1 +
 21 files changed, 554 insertions(+), 513 deletions(-)
 create mode 100644 src/include/utils/float.h

diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index b6d22d2b00..2ecf7a2d87 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -3,20 +3,21 @@
  */
 #include "postgres.h"
 
 #include <limits.h>
 
 #include "access/stratnum.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/cash.h"
 #include "utils/date.h"
+#include "utils/float.h"
 #include "utils/inet.h"
 #include "utils/numeric.h"
 #include "utils/timestamp.h"
 #include "utils/varbit.h"
 #include "utils/uuid.h"
 
 PG_MODULE_MAGIC;
 
 typedef struct QueryInfo
 {
diff --git a/contrib/btree_gist/btree_ts.c b/contrib/btree_gist/btree_ts.c
index 18740cad38..49d1849d88 100644
--- a/contrib/btree_gist/btree_ts.c
+++ b/contrib/btree_gist/btree_ts.c
@@ -2,20 +2,21 @@
  * contrib/btree_gist/btree_ts.c
  */
 #include "postgres.h"
 
 #include <limits.h>
 
 #include "btree_gist.h"
 #include "btree_utils_num.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 typedef struct
 {
 	Timestamp	lower;
 	Timestamp	upper;
 } tsKEY;
 
 /*
 ** timestamp ops
 */
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c
index 092ef149cf..c3f7410eab 100644
--- a/contrib/cube/cube.c
+++ b/contrib/cube/cube.c
@@ -7,21 +7,21 @@
 ******************************************************************************/
 
 #include "postgres.h"
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 
 #include "cubedata.h"
 
 PG_MODULE_MAGIC;
 
 /*
  * Taken from the intarray contrib header
  */
 #define ARRPTR(x)  ( (double *) ARR_DATA_PTR(x) )
 #define ARRNELEMS(x)  ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x))
diff --git a/contrib/cube/cubeparse.y b/contrib/cube/cubeparse.y
index 1b65fa967c..deb2efdc0d 100644
--- a/contrib/cube/cubeparse.y
+++ b/contrib/cube/cubeparse.y
@@ -1,20 +1,20 @@
 %{
 /* contrib/cube/cubeparse.y */
 
 /* NdBox = [(lowerleft),(upperright)] */
 /* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */
 
 #include "postgres.h"
 
 #include "cubedata.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 
 /* All grammar constructs return strings */
 #define YYSTYPE char *
 
 /*
  * Bison doesn't allocate anything that needs to live across parser calls,
  * so we can easily have it use palloc instead of malloc.  This prevents
  * memory leaks if we error out during parsing.  Note this only works with
  * bison >= 2.0.  However, in bison 1.875 the default is to use alloca()
  * if possible, so there's not really much problem anyhow, at least if
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 78b0f43ca8..af33c1e3ab 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -28,20 +28,21 @@
 #include "optimizer/cost.h"
 #include "optimizer/clauses.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
 #include "optimizer/planmain.h"
 #include "optimizer/restrictinfo.h"
 #include "optimizer/var.h"
 #include "optimizer/tlist.h"
 #include "parser/parsetree.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 #include "utils/sampling.h"
 #include "utils/selfuncs.h"
 
 PG_MODULE_MAGIC;
 
 /* Default CPU cost to start up a foreign query. */
diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c
index c4e8a3b913..ad07b9e63c 100644
--- a/src/backend/access/gist/gistget.c
+++ b/src/backend/access/gist/gistget.c
@@ -15,21 +15,21 @@
 #include "postgres.h"
 
 #include "access/gist_private.h"
 #include "access/relscan.h"
 #include "catalog/pg_type.h"
 #include "miscadmin.h"
 #include "storage/lmgr.h"
 #include "storage/predicate.h"
 #include "pgstat.h"
 #include "lib/pairingheap.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 
 /*
  * gistkillitems() -- set LP_DEAD state for items an indexscan caller has
  * told us were killed.
  *
  * We re-read page here, so it's important to check page LSN. If the page
  * has been modified since the last read (as determined by LSN), we cannot
  * flag any entries because it is possible that the old entry was vacuumed
diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index 97e6dc9910..4bbfdadf9f 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -27,62 +27,53 @@
 
 
 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
 						 StrategyNumber strategy);
 static bool rtree_internal_consistent(BOX *key, BOX *query,
 						  StrategyNumber strategy);
 
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
 
-/* Convenience macros for NaN-aware comparisons */
-#define FLOAT8_EQ(a,b)	(float8_cmp_internal(a, b) == 0)
-#define FLOAT8_LT(a,b)	(float8_cmp_internal(a, b) < 0)
-#define FLOAT8_LE(a,b)	(float8_cmp_internal(a, b) <= 0)
-#define FLOAT8_GT(a,b)	(float8_cmp_internal(a, b) > 0)
-#define FLOAT8_GE(a,b)	(float8_cmp_internal(a, b) >= 0)
-#define FLOAT8_MAX(a,b)  (FLOAT8_GT(a, b) ? (a) : (b))
-#define FLOAT8_MIN(a,b)  (FLOAT8_LT(a, b) ? (a) : (b))
-
 
 /**************************************************
  * Box ops
  **************************************************/
 
 /*
  * Calculates union of two boxes, a and b. The result is stored in *n.
  */
 static void
 rt_box_union(BOX *n, const BOX *a, const BOX *b)
 {
-	n->high.x = FLOAT8_MAX(a->high.x, b->high.x);
-	n->high.y = FLOAT8_MAX(a->high.y, b->high.y);
-	n->low.x = FLOAT8_MIN(a->low.x, b->low.x);
-	n->low.y = FLOAT8_MIN(a->low.y, b->low.y);
+	n->high.x = float8_max(a->high.x, b->high.x);
+	n->high.y = float8_max(a->high.y, b->high.y);
+	n->low.x = float8_min(a->low.x, b->low.x);
+	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
 static double
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
-	if (FLOAT8_LE(box->high.x, box->low.x) ||
-		FLOAT8_LE(box->high.y, box->low.y))
+	if (float8_le(box->high.x, box->low.x) ||
+		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
 	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
@@ -137,27 +128,27 @@ gist_box_consistent(PG_FUNCTION_ARGS)
 												 query,
 												 strategy));
 }
 
 /*
  * Increase BOX b to include addon.
  */
 static void
 adjustBox(BOX *b, const BOX *addon)
 {
-	if (FLOAT8_LT(b->high.x, addon->high.x))
+	if (float8_lt(b->high.x, addon->high.x))
 		b->high.x = addon->high.x;
-	if (FLOAT8_GT(b->low.x, addon->low.x))
+	if (float8_gt(b->low.x, addon->low.x))
 		b->low.x = addon->low.x;
-	if (FLOAT8_LT(b->high.y, addon->high.y))
+	if (float8_lt(b->high.y, addon->high.y))
 		b->high.y = addon->high.y;
-	if (FLOAT8_GT(b->low.y, addon->low.y))
+	if (float8_gt(b->low.y, addon->low.y))
 		b->low.y = addon->low.y;
 }
 
 /*
  * The GiST Union method for boxes
  *
  * returns the minimal bounding box that encloses all the entries in entryvec
  */
 Datum
 gist_box_union(PG_FUNCTION_ARGS)
@@ -609,36 +600,36 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		i1 = 0;
 		i2 = 0;
 		rightLower = intervalsLower[i1].lower;
 		leftUpper = intervalsUpper[i2].lower;
 		while (true)
 		{
 			/*
 			 * Find next lower bound of right group.
 			 */
 			while (i1 < nentries &&
-				   FLOAT8_EQ(rightLower, intervalsLower[i1].lower))
+				   float8_eq(rightLower, intervalsLower[i1].lower))
 			{
-				if (FLOAT8_LT(leftUpper, intervalsLower[i1].upper))
+				if (float8_lt(leftUpper, intervalsLower[i1].upper))
 					leftUpper = intervalsLower[i1].upper;
 				i1++;
 			}
 			if (i1 >= nentries)
 				break;
 			rightLower = intervalsLower[i1].lower;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * left group.
 			 */
 			while (i2 < nentries &&
-				   FLOAT8_LE(intervalsUpper[i2].upper, leftUpper))
+				   float8_le(intervalsUpper[i2].upper, leftUpper))
 				i2++;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim, rightLower, i1, leftUpper, i2);
 		}
 
 		/*
 		 * Iterate over upper bound of left group finding greatest possible
@@ -646,35 +637,35 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		 */
 		i1 = nentries - 1;
 		i2 = nentries - 1;
 		rightLower = intervalsLower[i1].upper;
 		leftUpper = intervalsUpper[i2].upper;
 		while (true)
 		{
 			/*
 			 * Find next upper bound of left group.
 			 */
-			while (i2 >= 0 && FLOAT8_EQ(leftUpper, intervalsUpper[i2].upper))
+			while (i2 >= 0 && float8_eq(leftUpper, intervalsUpper[i2].upper))
 			{
-				if (FLOAT8_GT(rightLower, intervalsUpper[i2].lower))
+				if (float8_gt(rightLower, intervalsUpper[i2].lower))
 					rightLower = intervalsUpper[i2].lower;
 				i2--;
 			}
 			if (i2 < 0)
 				break;
 			leftUpper = intervalsUpper[i2].upper;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * right group.
 			 */
-			while (i1 >= 0 && FLOAT8_GE(intervalsLower[i1].lower, rightLower))
+			while (i1 >= 0 && float8_ge(intervalsLower[i1].lower, rightLower))
 				i1--;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim,
 								 rightLower, i1 + 1, leftUpper, i2 + 1);
 		}
 	}
 
@@ -748,42 +739,42 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
 		}
 		else
 		{
 			lower = box->low.y;
 			upper = box->high.y;
 		}
 
-		if (FLOAT8_LE(upper, context.leftUpper))
+		if (float8_le(upper, context.leftUpper))
 		{
 			/* Fits to the left group */
-			if (FLOAT8_GE(lower, context.rightLower))
+			if (float8_ge(lower, context.rightLower))
 			{
 				/* Fits also to the right group, so "common entry" */
 				commonEntries[commonEntriesCount++].index = i;
 			}
 			else
 			{
 				/* Doesn't fit to the right group, so join to the left group */
 				PLACE_LEFT(box, i);
 			}
 		}
 		else
 		{
 			/*
 			 * Each entry should fit on either left or right group. Since this
 			 * entry didn't fit on the left group, it better fit in the right
 			 * group.
 			 */
-			Assert(FLOAT8_GE(lower, context.rightLower));
+			Assert(float8_ge(lower, context.rightLower));
 
 			/* Doesn't fit to the left group, so join to the right group */
 			PLACE_RIGHT(box, i);
 		}
 	}
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
@@ -853,24 +844,24 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
  * equivalent to box_same().
  */
 Datum
 gist_box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *b1 = PG_GETARG_BOX_P(0);
 	BOX		   *b2 = PG_GETARG_BOX_P(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
 	if (b1 && b2)
-		*result = (FLOAT8_EQ(b1->low.x, b2->low.x) &&
-				   FLOAT8_EQ(b1->low.y, b2->low.y) &&
-				   FLOAT8_EQ(b1->high.x, b2->high.x) &&
-				   FLOAT8_EQ(b1->high.y, b2->high.y));
+		*result = (float8_eq(b1->low.x, b2->low.x) &&
+				   float8_eq(b1->low.y, b2->low.y) &&
+				   float8_eq(b1->high.x, b2->high.x) &&
+				   float8_eq(b1->high.y, b2->high.y));
 	else
 		*result = (b1 == NULL && b2 == NULL);
 	PG_RETURN_POINTER(result);
 }
 
 /*
  * Leaf-level consistency for boxes: just apply the query operator
  */
 static bool
 gist_box_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy)
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 55cccd247a..7e43b8fc87 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -15,21 +15,21 @@
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist_private.h"
 #include "access/htup_details.h"
 #include "access/reloptions.h"
 #include "catalog/pg_opclass.h"
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/syscache.h"
 
 
 /*
  * Write itup vector to page, has no control of free space.
  */
 void
 gistfillbuffer(Page page, IndexTuple *itup, int len, OffsetNumber off)
 {
 	OffsetNumber l = InvalidOffsetNumber;
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index d32c1c141f..db60f516d7 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -16,58 +16,25 @@
 
 #include <ctype.h>
 #include <float.h>
 #include <math.h>
 #include <limits.h>
 
 #include "catalog/pg_type.h"
 #include "common/int.h"
 #include "libpq/pqformat.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/sortsupport.h"
 
 
-#ifndef M_PI
-/* from my RH5.2 gcc math.h file - thomas 2000-04-03 */
-#define M_PI 3.14159265358979323846
-#endif
-
-/* Radians per degree, a.k.a. PI / 180 */
-#define RADIANS_PER_DEGREE 0.0174532925199432957692
-
-/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0.  NAN definition from
- * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfNotNumberNANItems.asp
- */
-#if defined(WIN32) && !defined(NAN)
-static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
-
-#define NAN (*(const double *) nan)
-#endif
-
-/*
- * check to see if a float4/8 val has underflowed or overflowed
- */
-#define CHECKFLOATVAL(val, inf_is_valid, zero_is_valid)			\
-do {															\
-	if (isinf(val) && !(inf_is_valid))							\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		  errmsg("value out of range: overflow")));				\
-																\
-	if ((val) == 0.0 && !(zero_is_valid))						\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		 errmsg("value out of range: underflow")));				\
-} while(0)
-
-
 /* Configurable GUC parameter */
 int			extra_float_digits = 0; /* Added to DBL_DIG or FLT_DIG */
 
 /* Cached constants for degree-based trig functions */
 static bool degree_consts_set = false;
 static float8 sin_30 = 0;
 static float8 one_minus_cos_60 = 0;
 static float8 asin_0_5 = 0;
 static float8 acos_0_5 = 0;
 static float8 atan_1_0 = 0;
@@ -98,100 +65,20 @@ static void init_degree_constants(void);
  * function, which causes configure to not set HAVE_CBRT.  Furthermore,
  * their compilers spit up at the mismatch between extern declaration
  * and static definition.  We work around that here by the expedient
  * of a #define to make the actual name of the static function different.
  */
 #define cbrt my_cbrt
 static double cbrt(double x);
 #endif							/* HAVE_CBRT */
 
 
-/*
- * Routines to provide reasonably platform-independent handling of
- * infinity and NaN.  We assume that isinf() and isnan() are available
- * and work per spec.  (On some platforms, we have to supply our own;
- * see src/port.)  However, generating an Infinity or NaN in the first
- * place is less well standardized; pre-C99 systems tend not to have C99's
- * INFINITY and NAN macros.  We centralize our workarounds for this here.
- */
-
-double
-get_float8_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (double) INFINITY;
-#else
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (double) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-/*
-* The funny placements of the two #pragmas is necessary because of a
-* long lived bug in the Microsoft compilers.
-* See http://support.microsoft.com/kb/120968/en-us for details
-*/
-#if (_MSC_VER >= 1800)
-#pragma warning(disable:4756)
-#endif
-float
-get_float4_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (float) INFINITY;
-#else
-#if (_MSC_VER >= 1800)
-#pragma warning(default:4756)
-#endif
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (float) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-double
-get_float8_nan(void)
-{
-	/* (double) NAN doesn't work on some NetBSD/MIPS releases */
-#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
-	/* C99 standard way */
-	return (double) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (double) (0.0 / 0.0);
-#endif
-}
-
-float
-get_float4_nan(void)
-{
-#ifdef NAN
-	/* C99 standard way */
-	return (float) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (float) (0.0 / 0.0);
-#endif
-}
-
-
 /*
  * Returns -1 if 'val' represents negative infinity, 1 if 'val'
  * represents (positive) infinity, and 0 otherwise. On some platforms,
  * this is equivalent to the isinf() macro, but not everywhere: C99
  * does not specify that isinf() needs to distinguish between positive
  * and negative infinity.
  */
 int
 is_infinite(double val)
 {
@@ -336,21 +223,21 @@ float4in(PG_FUNCTION_ARGS)
 	if (*endptr != '\0')
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"real", orig_num)));
 
 	/*
 	 * if we get here, we have a legal double, still need to check to see if
 	 * it's a legal float4
 	 */
-	CHECKFLOATVAL((float4) val, isinf(val), val == 0);
+	check_float4_val((float4) val, isinf(val), val == 0);
 
 	PG_RETURN_FLOAT4((float4) val);
 }
 
 /*
  *		float4out		- converts a float4 number to a string
  *						  using a standard output format
  */
 Datum
 float4out(PG_FUNCTION_ARGS)
@@ -686,35 +573,35 @@ float4up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT4(arg);
 }
 
 Datum
 float4larger(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) > 0)
+	if (float4_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 Datum
 float4smaller(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) < 0)
+	if (float4_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 /*
  *		======================
  *		FLOAT8 BASE OPERATIONS
  *		======================
@@ -753,35 +640,35 @@ float8up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT8(arg);
 }
 
 Datum
 float8larger(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) > 0)
+	if (float8_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 Datum
 float8smaller(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) < 0)
+	if (float8_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		====================
  *		ARITHMETIC OPERATORS
@@ -792,234 +679,165 @@ float8smaller(PG_FUNCTION_ARGS)
  *		float4pl		- returns arg1 + arg2
  *		float4mi		- returns arg1 - arg2
  *		float4mul		- returns arg1 * arg2
  *		float4div		- returns arg1 / arg2
  */
 Datum
 float4pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 + arg2;
-
-	/*
-	 * There isn't any way to check for underflow of addition/subtraction
-	 * because numbers near the underflow value have already been rounded to
-	 * the point where we can't detect that the two values were originally
-	 * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
-	 * 1.4013e-45.
-	 */
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_pl(arg1, arg2));
 }
 
 Datum
 float4mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mi(arg1, arg2));
 }
 
 Datum
 float4mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mul(arg1, arg2));
 }
 
 Datum
 float4div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_div(arg1, arg2));
 }
 
 /*
  *		float8pl		- returns arg1 + arg2
  *		float8mi		- returns arg1 - arg2
  *		float8mul		- returns arg1 * arg2
  *		float8div		- returns arg1 / arg2
  */
 Datum
 float8pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 + arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, arg2));
 }
 
 Datum
 float8mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 - arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, arg2));
 }
 
 Datum
 float8mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 * arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, arg2));
 }
 
 Datum
 float8div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, arg2));
 }
 
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float4{eq,ne,lt,le,gt,ge}		- float4/float4 comparison operations
  */
 int
 float4_cmp_internal(float4 a, float4 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float4_gt(a, b))
+		return 1;
+	if (float4_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
 float4eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float4_eq(arg1, arg2));
 }
 
 Datum
 float4ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float4_ne(arg1, arg2));
 }
 
 Datum
 float4lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float4_lt(arg1, arg2));
 }
 
 Datum
 float4le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float4_le(arg1, arg2));
 }
 
 Datum
 float4gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float4_gt(arg1, arg2));
 }
 
 Datum
 float4ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float4_ge(arg1, arg2));
 }
 
 Datum
 btfloat4cmp(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
 	PG_RETURN_INT32(float4_cmp_internal(arg1, arg2));
 }
@@ -1041,99 +859,79 @@ btfloat4sortsupport(PG_FUNCTION_ARGS)
 	ssup->comparator = btfloat4fastcmp;
 	PG_RETURN_VOID();
 }
 
 /*
  *		float8{eq,ne,lt,le,gt,ge}		- float8/float8 comparison operations
  */
 int
 float8_cmp_internal(float8 a, float8 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float8_gt(a, b))
+		return 1;
+	if (float8_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
 float8eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, arg2));
 }
 
 Datum
 float8ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, arg2));
 }
 
 Datum
 float8lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, arg2));
 }
 
 Datum
 float8le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, arg2));
 }
 
 Datum
 float8gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, arg2));
 }
 
 Datum
 float8ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, arg2));
 }
 
 Datum
 btfloat8cmp(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
 	PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
 }
@@ -1334,21 +1132,21 @@ ftod(PG_FUNCTION_ARGS)
 
 
 /*
  *		dtof			- converts a float8 number to a float4 number
  */
 Datum
 dtof(PG_FUNCTION_ARGS)
 {
 	float8		num = PG_GETARG_FLOAT8(0);
 
-	CHECKFLOATVAL((float4) num, isinf(num), num == 0);
+	check_float4_val((float4) num, isinf(num), num == 0);
 
 	PG_RETURN_FLOAT4((float4) num);
 }
 
 
 /*
  *		dtoi4			- converts a float8 number to an int4 number
  */
 Datum
 dtoi4(PG_FUNCTION_ARGS)
@@ -1559,36 +1357,36 @@ dsqrt(PG_FUNCTION_ARGS)
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
 				 errmsg("cannot take square root of a negative number")));
 
 	result = sqrt(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcbrt			- returns cube root of arg1
  */
 Datum
 dcbrt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	result = cbrt(arg1);
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dpow			- returns pow(arg1,arg2)
  */
 Datum
 dpow(PG_FUNCTION_ARGS)
 {
@@ -1646,40 +1444,40 @@ dpow(PG_FUNCTION_ARGS)
 			/* The sign of Inf is not significant in this case. */
 			result = get_float8_infinity();
 		else if (fabs(arg1) != 1)
 			result = 0;
 		else
 			result = 1;
 	}
 	else if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
+	check_float8_val(result, isinf(arg1) || isinf(arg2), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dexp			- returns the exponential function of arg1
  */
 Datum
 dexp(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	errno = 0;
 	result = exp(arg1);
 	if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1), false);
+	check_float8_val(result, isinf(arg1), false);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dlog1			- returns the natural logarithm of arg1
  */
 Datum
 dlog1(PG_FUNCTION_ARGS)
 {
@@ -1694,21 +1492,21 @@ dlog1(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of zero")));
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of a negative number")));
 
 	result = log(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dlog10			- returns the base 10 logarithm of arg1
  */
 Datum
 dlog10(PG_FUNCTION_ARGS)
 {
@@ -1724,21 +1522,21 @@ dlog10(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of zero")));
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of a negative number")));
 
 	result = log10(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dacos			- returns the arccos of arg1 (radians)
  */
 Datum
 dacos(PG_FUNCTION_ARGS)
 {
@@ -1754,21 +1552,21 @@ dacos(PG_FUNCTION_ARGS)
 	 * range [-1, 1] to values in the range [0, Pi], so we should reject any
 	 * inputs outside that range and the result will always be finite.
 	 */
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = acos(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dasin			- returns the arcsin of arg1 (radians)
  */
 Datum
 dasin(PG_FUNCTION_ARGS)
 {
@@ -1784,21 +1582,21 @@ dasin(PG_FUNCTION_ARGS)
 	 * range [-1, 1] to values in the range [-Pi/2, Pi/2], so we should reject
 	 * any inputs outside that range and the result will always be finite.
 	 */
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = asin(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		datan			- returns the arctan of arg1 (radians)
  */
 Datum
 datan(PG_FUNCTION_ARGS)
 {
@@ -1809,21 +1607,21 @@ datan(PG_FUNCTION_ARGS)
 	if (isnan(arg1))
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/*
 	 * The principal branch of the inverse tangent function maps all inputs to
 	 * values in the range [-Pi/2, Pi/2], so the result should always be
 	 * finite, even if the input is infinite.
 	 */
 	result = atan(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		atan2			- returns the arctan of arg1/arg2 (radians)
  */
 Datum
 datan2(PG_FUNCTION_ARGS)
 {
@@ -1834,21 +1632,21 @@ datan2(PG_FUNCTION_ARGS)
 	/* Per the POSIX spec, return NaN if either input is NaN */
 	if (isnan(arg1) || isnan(arg2))
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/*
 	 * atan2 maps all inputs to values in the range [-Pi, Pi], so the result
 	 * should always be finite, even if the inputs are infinite.
 	 */
 	result = atan2(arg1, arg2);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcos			- returns the cosine of arg1 (radians)
  */
 Datum
 dcos(PG_FUNCTION_ARGS)
 {
@@ -1874,21 +1672,21 @@ dcos(PG_FUNCTION_ARGS)
 	 * platform reports via errno, so also explicitly test for infinite
 	 * inputs.
 	 */
 	errno = 0;
 	result = cos(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcot			- returns the cotangent of arg1 (radians)
  */
 Datum
 dcot(PG_FUNCTION_ARGS)
 {
@@ -1901,21 +1699,21 @@ dcot(PG_FUNCTION_ARGS)
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = tan(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = 1.0 / result;
-	CHECKFLOATVAL(result, true /* cot(0) == Inf */ , true);
+	check_float8_val(result, true /* cot(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dsin			- returns the sine of arg1 (radians)
  */
 Datum
 dsin(PG_FUNCTION_ARGS)
 {
@@ -1927,21 +1725,21 @@ dsin(PG_FUNCTION_ARGS)
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = sin(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dtan			- returns the tangent of arg1 (radians)
  */
 Datum
 dtan(PG_FUNCTION_ARGS)
 {
@@ -1953,21 +1751,21 @@ dtan(PG_FUNCTION_ARGS)
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = tan(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, true /* tan(pi/2) == Inf */ , true);
+	check_float8_val(result, true /* tan(pi/2) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /* ========== DEGREE-BASED TRIGONOMETRIC FUNCTIONS ========== */
 
 
 /*
  * Initialize the cached constants declared at the head of this file
  * (sin_30 etc).  The fact that we need those at all, let alone need this
@@ -2105,21 +1903,21 @@ dacosd(PG_FUNCTION_ARGS)
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	if (arg1 >= 0.0)
 		result = acosd_q1(arg1);
 	else
 		result = 90.0 + asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dasind			- returns the arcsin of arg1 (degrees)
  */
 Datum
 dasind(PG_FUNCTION_ARGS)
 {
@@ -2140,21 +1938,21 @@ dasind(PG_FUNCTION_ARGS)
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	if (arg1 >= 0.0)
 		result = asind_q1(arg1);
 	else
 		result = -asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		datand			- returns the arctan of arg1 (degrees)
  */
 Datum
 datand(PG_FUNCTION_ARGS)
 {
@@ -2170,21 +1968,21 @@ datand(PG_FUNCTION_ARGS)
 
 	/*
 	 * The principal branch of the inverse tangent function maps all inputs to
 	 * values in the range [-90, 90], so the result should always be finite,
 	 * even if the input is infinite.  Additionally, we take care to ensure
 	 * than when arg1 is 1, the result is exactly 45.
 	 */
 	atan_arg1 = atan(arg1);
 	result = (atan_arg1 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		atan2d			- returns the arctan of arg1/arg2 (degrees)
  */
 Datum
 datan2d(PG_FUNCTION_ARGS)
 {
@@ -2204,21 +2002,21 @@ datan2d(PG_FUNCTION_ARGS)
 	 * result should always be finite, even if the inputs are infinite.
 	 *
 	 * Note: this coding assumes that atan(1.0) is a suitable scaling constant
 	 * to get an exact result from atan2().  This might well fail on us at
 	 * some point, requiring us to decide exactly what inputs we think we're
 	 * going to guarantee an exact result for.
 	 */
 	atan2_arg1_arg2 = atan2(arg1, arg2);
 	result = (atan2_arg1_arg2 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		sind_0_to_30	- returns the sine of an angle that lies between 0 and
  *						  30 degrees.  This will return exactly 0 when x is 0,
  *						  and exactly 0.5 when x is 30 degrees.
  */
 static double
@@ -2325,21 +2123,21 @@ dcosd(PG_FUNCTION_ARGS)
 
 	if (arg1 > 90.0)
 	{
 		/* cosd(180-x) = -cosd(x) */
 		arg1 = 180.0 - arg1;
 		sign = -sign;
 	}
 
 	result = sign * cosd_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcotd			- returns the cotangent of arg1 (degrees)
  */
 Datum
 dcotd(PG_FUNCTION_ARGS)
 {
@@ -2390,21 +2188,21 @@ dcotd(PG_FUNCTION_ARGS)
 	result = sign * (cot_arg1 / cot_45);
 
 	/*
 	 * On some machines we get cotd(270) = minus zero, but this isn't always
 	 * true.  For portability, and because the user constituency for this
 	 * function probably doesn't want minus zero, force it to plain zero.
 	 */
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* cotd(0) == Inf */ , true);
+	check_float8_val(result, true /* cotd(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dsind			- returns the sine of arg1 (degrees)
  */
 Datum
 dsind(PG_FUNCTION_ARGS)
 {
@@ -2444,21 +2242,21 @@ dsind(PG_FUNCTION_ARGS)
 	}
 
 	if (arg1 > 90.0)
 	{
 		/* sind(180-x) = sind(x) */
 		arg1 = 180.0 - arg1;
 	}
 
 	result = sign * sind_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dtand			- returns the tangent of arg1 (degrees)
  */
 Datum
 dtand(PG_FUNCTION_ARGS)
 {
@@ -2509,64 +2307,56 @@ dtand(PG_FUNCTION_ARGS)
 	result = sign * (tan_arg1 / tan_45);
 
 	/*
 	 * On some machines we get tand(180) = minus zero, but this isn't always
 	 * true.  For portability, and because the user constituency for this
 	 * function probably doesn't want minus zero, force it to plain zero.
 	 */
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* tand(90) == Inf */ , true);
+	check_float8_val(result, true /* tand(90) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		degrees		- returns degrees converted from radians
  */
 Datum
 degrees(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
 
-	result = arg1 / RADIANS_PER_DEGREE;
-
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, RADIANS_PER_DEGREE));
 }
 
 
 /*
  *		dpi				- returns the constant PI
  */
 Datum
 dpi(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_FLOAT8(M_PI);
 }
 
 
 /*
  *		radians		- returns radians converted from degrees
  */
 Datum
 radians(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
 
-	result = arg1 * RADIANS_PER_DEGREE;
-
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, RADIANS_PER_DEGREE));
 }
 
 
 /*
  *		drandom		- returns a random number
  */
 Datum
 drandom(PG_FUNCTION_ARGS)
 {
 	float8		result;
@@ -2644,144 +2434,105 @@ check_float8_array(ArrayType *transarray, const char *caller, int n)
  * This function is used only in two stage aggregation and
  * shouldn't be called outside aggregate context.
  */
 Datum
 float8_combine(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_combine", 3);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-
 	transvalues2 = check_float8_array(transarray2, "float8_combine", 3);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
 
 Datum
 float8_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8		newval = PG_GETARG_FLOAT8(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float8_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
 	else
 	{
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
 								 sizeof(float8), FLOAT8PASSBYVAL, 'd');
 
 		PG_RETURN_ARRAYTYPE_P(result);
 	}
 }
 
 Datum
 float4_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 
 	/* do computations as float8 */
 	float8		newval = PG_GETARG_FLOAT4(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float4_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
 	else
 	{
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
 								 sizeof(float8), FLOAT8PASSBYVAL, 'd');
 
 		PG_RETURN_ARRAYTYPE_P(result);
 	}
 }
 
 Datum
@@ -2817,21 +2568,21 @@ float8_var_pop(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_var_pop", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Population variance is undefined when N is 0, so return NULL */
 	if (N == 0.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / (N * N));
 }
 
 Datum
 float8_var_samp(PG_FUNCTION_ARGS)
@@ -2846,21 +2597,21 @@ float8_var_samp(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_var_samp", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Sample variance is undefined when N is 0 or 1, so return NULL */
 	if (N <= 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
 }
 
 Datum
 float8_stddev_pop(PG_FUNCTION_ARGS)
@@ -2875,21 +2626,21 @@ float8_stddev_pop(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_stddev_pop", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Population stddev is undefined when N is 0, so return NULL */
 	if (N == 0.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(sqrt(numerator / (N * N)));
 }
 
 Datum
 float8_stddev_samp(PG_FUNCTION_ARGS)
@@ -2904,21 +2655,21 @@ float8_stddev_samp(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_stddev_samp", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Sample stddev is undefined when N is 0 or 1, so return NULL */
 	if (N <= 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(sqrt(numerator / (N * (N - 1.0))));
 }
 
 /*
  *		=========================
@@ -2953,30 +2704,30 @@ float8_regr_accum(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_accum", 6);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	N += 1.0;
 	sumX += newvalX;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
+	check_float8_val(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
 	sumX2 += newvalX * newvalX;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
+	check_float8_val(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
 	sumY += newvalY;
-	CHECKFLOATVAL(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
+	check_float8_val(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
 	sumY2 += newvalY * newvalY;
-	CHECKFLOATVAL(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
+	check_float8_val(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
 	sumXY += newvalX * newvalY;
-	CHECKFLOATVAL(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
-				  isinf(newvalY), true);
+	check_float8_val(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
+					 isinf(newvalY), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
 		transvalues[0] = N;
 		transvalues[1] = sumX;
@@ -3015,63 +2766,33 @@ float8_regr_accum(PG_FUNCTION_ARGS)
  * This function is used only in two stage aggregation and
  * shouldn't be called outside aggregate context.
  */
 Datum
 float8_regr_combine(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2,
-				sumY,
-				sumY2,
-				sumXY;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_regr_combine", 6);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-	sumY = transvalues1[3];
-	sumY2 = transvalues1[4];
-	sumXY = transvalues1[5];
-
 	transvalues2 = check_float8_array(transarray2, "float8_regr_combine", 6);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-	sumY += transvalues2[3];
-	CHECKFLOATVAL(sumY, isinf(transvalues1[3]) || isinf(transvalues2[3]),
-				  true);
-	sumY2 += transvalues2[4];
-	CHECKFLOATVAL(sumY2, isinf(transvalues1[4]) || isinf(transvalues2[4]),
-				  true);
-	sumXY += transvalues2[5];
-	CHECKFLOATVAL(sumXY, isinf(transvalues1[5]) || isinf(transvalues2[5]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
-	transvalues1[3] = sumY;
-	transvalues1[4] = sumY2;
-	transvalues1[5] = sumXY;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
+	transvalues1[3] = float8_pl(transvalues1[3], transvalues2[3]);
+	transvalues1[4] = float8_pl(transvalues1[4], transvalues2[4]);
+	transvalues1[5] = float8_pl(transvalues1[5], transvalues2[5]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
 
 
 Datum
 float8_regr_sxx(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
@@ -3083,21 +2804,21 @@ float8_regr_sxx(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_sxx", 6);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_syy(PG_FUNCTION_ARGS)
@@ -3112,21 +2833,21 @@ float8_regr_syy(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_syy", 6);
 	N = transvalues[0];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumY2) || isinf(sumY), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_sxy(PG_FUNCTION_ARGS)
@@ -3143,22 +2864,22 @@ float8_regr_sxy(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	/* A negative result is valid here */
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_avgx(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3211,22 +2932,22 @@ float8_covar_pop(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * N));
 }
 
 Datum
 float8_covar_samp(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
 	float8		N,
@@ -3239,22 +2960,22 @@ float8_covar_samp(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is <= 1 we should return NULL */
 	if (N < 2.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
 }
 
 Datum
 float8_corr(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
 	float8		N,
@@ -3273,26 +2994,26 @@ float8_corr(PG_FUNCTION_ARGS)
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0 || numeratorY <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXY / sqrt(numeratorX * numeratorY));
 }
 
 Datum
 float8_regr_r2(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3313,26 +3034,26 @@ float8_regr_r2(PG_FUNCTION_ARGS)
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 	/* per spec, horizontal line produces 1.0 */
 	if (numeratorY <= 0)
 		PG_RETURN_FLOAT8(1.0);
 
 	PG_RETURN_FLOAT8((numeratorXY * numeratorXY) /
 					 (numeratorX * numeratorY));
 }
 
@@ -3354,24 +3075,24 @@ float8_regr_slope(PG_FUNCTION_ARGS)
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXY / numeratorX);
 }
 
 Datum
 float8_regr_intercept(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3389,24 +3110,24 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXXY = sumY * sumX2 - sumX * sumXY;
-	CHECKFLOATVAL(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
-				  isinf(sumX) || isinf(sumXY), true);
+	check_float8_val(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
+					 isinf(sumX) || isinf(sumXY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXXY / numeratorX);
 }
 
 
 /*
  *		====================================
  *		MIXED-PRECISION ARITHMETIC OPERATORS
@@ -3417,251 +3138,211 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
  *		float48pl		- returns arg1 + arg2
  *		float48mi		- returns arg1 - arg2
  *		float48mul		- returns arg1 * arg2
  *		float48div		- returns arg1 / arg2
  */
 Datum
 float48pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 + arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl((float8) arg1, arg2));
 }
 
 Datum
 float48mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi((float8) arg1, arg2));
 }
 
 Datum
 float48mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul((float8) arg1, arg2));
 }
 
 Datum
 float48div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div((float8) arg1, arg2));
 }
 
 /*
  *		float84pl		- returns arg1 + arg2
  *		float84mi		- returns arg1 - arg2
  *		float84mul		- returns arg1 * arg2
  *		float84div		- returns arg1 / arg2
  */
 Datum
 float84pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 + arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, (float8) arg2));
 }
 
 Datum
 float84mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 - arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, (float8) arg2));
 }
 
 Datum
 float84mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 * arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, (float8) arg2));
 }
 
 Datum
 float84div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, (float8) arg2));
 }
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float48{eq,ne,lt,le,gt,ge}		- float4/float8 comparison operations
  */
 Datum
 float48eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq((float8) arg1, arg2));
 }
 
 Datum
 float48ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne((float8) arg1, arg2));
 }
 
 Datum
 float48lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt((float8) arg1, arg2));
 }
 
 Datum
 float48le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le((float8) arg1, arg2));
 }
 
 Datum
 float48gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt((float8) arg1, arg2));
 }
 
 Datum
 float48ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge((float8) arg1, arg2));
 }
 
 /*
  *		float84{eq,ne,lt,le,gt,ge}		- float8/float4 comparison operations
  */
 Datum
 float84eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, (float8) arg2));
 }
 
 Datum
 float84ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, (float8) arg2));
 }
 
 Datum
 float84lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, (float8) arg2));
 }
 
 Datum
 float84le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, (float8) arg2));
 }
 
 Datum
 float84gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, (float8) arg2));
 }
 
 Datum
 float84ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, (float8) arg2));
 }
 
 /*
  * Implements the float8 version of the width_bucket() function
  * defined by SQL2003. See also width_bucket_numeric().
  *
  * 'bound1' and 'bound2' are the lower and upper bounds of the
  * histogram's range, respectively. 'count' is the number of buckets
  * in the histogram. width_bucket() returns an integer indicating the
  * bucket number that 'operand' belongs to in an equiwidth histogram
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c
index a345c65605..30696e3575 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -84,20 +84,21 @@
 
 #ifdef USE_ICU
 #include <unicode/ustring.h>
 #endif
 
 #include "catalog/pg_collation.h"
 #include "mb/pg_wchar.h"
 #include "utils/builtins.h"
 #include "utils/date.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 #include "utils/formatting.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/pg_locale.h"
 
 /* ----------
  * Routines type
  * ----------
  */
 #define DCH_TYPE		1		/* DATE-TIME version	*/
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 3e7519015d..0f12684478 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -14,27 +14,23 @@
  */
 #include "postgres.h"
 
 #include <math.h>
 #include <limits.h>
 #include <float.h>
 #include <ctype.h>
 
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
-#include "utils/builtins.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index d7c807f8d9..5489ed9585 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -69,21 +69,21 @@
  *			src/backend/utils/adt/geo_spgist.c
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
 
 #include "access/spgist.h"
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
  * is going only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 8dfdffcfbd..04a7849707 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -29,20 +29,21 @@
 #include "access/hash.h"
 #include "catalog/pg_type.h"
 #include "common/int.h"
 #include "funcapi.h"
 #include "lib/hyperloglog.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/sortsupport.h"
 
 /* ----------
  * Uncomment the following to enable compilation of dump_numeric()
  * and dump_var() and to get a dump of any result produced by make_result().
  * ----------
 #define NUMERIC_DEBUG
diff --git a/src/backend/utils/adt/rangetypes_gist.c b/src/backend/utils/adt/rangetypes_gist.c
index 2fe61043d9..450479e31c 100644
--- a/src/backend/utils/adt/rangetypes_gist.c
+++ b/src/backend/utils/adt/rangetypes_gist.c
@@ -9,21 +9,22 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_gist.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/gist.h"
 #include "access/stratnum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/datum.h"
 #include "utils/rangetypes.h"
 
 
 /*
  * Range class properties used to segregate different classes of ranges in
  * GiST.  Each unique combination of properties is a class.  CLS_EMPTY cannot
  * be combined with anything else.
  */
 #define CLS_NORMAL			0	/* Ordinary finite range (no bits set) */
diff --git a/src/backend/utils/adt/rangetypes_selfuncs.c b/src/backend/utils/adt/rangetypes_selfuncs.c
index 59761ecf34..f9a5117492 100644
--- a/src/backend/utils/adt/rangetypes_selfuncs.c
+++ b/src/backend/utils/adt/rangetypes_selfuncs.c
@@ -14,21 +14,22 @@
  *	  src/backend/utils/adt/rangetypes_selfuncs.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/htup_details.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 #include "utils/selfuncs.h"
 #include "utils/typcache.h"
 
 static double calc_rangesel(TypeCacheEntry *typcache, VariableStatData *vardata,
 			  RangeType *constval, Oid operator);
 static double default_range_selectivity(Oid operator);
 static double calc_hist_selectivity(TypeCacheEntry *typcache,
 					  VariableStatData *vardata, RangeType *constval,
diff --git a/src/backend/utils/adt/rangetypes_typanalyze.c b/src/backend/utils/adt/rangetypes_typanalyze.c
index f2c11f54bc..9c50e4c1be 100644
--- a/src/backend/utils/adt/rangetypes_typanalyze.c
+++ b/src/backend/utils/adt/rangetypes_typanalyze.c
@@ -19,21 +19,22 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_typanalyze.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "catalog/pg_operator.h"
 #include "commands/vacuum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 
 static int	float8_qsort_cmp(const void *a1, const void *a2);
 static int	range_bound_qsort_cmp(const void *a1, const void *a2, void *arg);
 static void compute_range_stats(VacAttrStats *stats,
 					AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows);
 
 /*
  * range_typanalyze -- typanalyze function for range columns
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 265b1db7f6..72fa939e3c 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -27,20 +27,21 @@
 #include "common/int128.h"
 #include "funcapi.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
 #include "parser/scansup.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 /*
  * gcc's -ffast-math switch breaks routines that expect exact results from
  * expressions like timeval / SECS_PER_HOUR, where timeval is double.
  */
 #ifdef __FAST_MATH__
 #error -ffast-math is known to break this code
 #endif
 
 #define SAMESIGN(a,b)	(((a) < 0) == ((b) < 0))
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index ee1444c427..73e6550786 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -73,20 +73,21 @@
 #include "storage/fd.h"
 #include "storage/large_object.h"
 #include "storage/pg_shmem.h"
 #include "storage/proc.h"
 #include "storage/predicate.h"
 #include "tcop/tcopprot.h"
 #include "tsearch/ts_cache.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/guc_tables.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/pg_locale.h"
 #include "utils/plancache.h"
 #include "utils/portal.h"
 #include "utils/ps_status.h"
 #include "utils/rls.h"
 #include "utils/snapmgr.h"
 #include "utils/tzparser.h"
 #include "utils/varlena.h"
 #include "utils/xml.h"
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index d0416e90fc..b83a22767a 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -43,34 +43,20 @@ extern int	namestrcmp(Name name, const char *str);
 
 /* numutils.c */
 extern int32 pg_atoi(const char *s, int size, int c);
 extern void pg_itoa(int16 i, char *a);
 extern void pg_ltoa(int32 l, char *a);
 extern void pg_lltoa(int64 ll, char *a);
 extern char *pg_ltostr_zeropad(char *str, int32 value, int32 minwidth);
 extern char *pg_ltostr(char *str, int32 value);
 extern uint64 pg_strtouint64(const char *str, char **endptr, int base);
 
-/* float.c */
-extern PGDLLIMPORT int extra_float_digits;
-
-extern double get_float8_infinity(void);
-extern float get_float4_infinity(void);
-extern double get_float8_nan(void);
-extern float get_float4_nan(void);
-extern int	is_infinite(double val);
-extern double float8in_internal(char *num, char **endptr_p,
-				  const char *type_name, const char *orig_string);
-extern char *float8out_internal(double num);
-extern int	float4_cmp_internal(float4 a, float4 b);
-extern int	float8_cmp_internal(float8 a, float8 b);
-
 /* oid.c */
 extern oidvector *buildoidvector(const Oid *oids, int n);
 extern Oid	oidparse(Node *node);
 extern int	oid_cmp(const void *p1, const void *p2);
 
 /* regexp.c */
 extern char *regexp_fixed_prefix(text *text_re, bool case_insensitive,
 					Oid collation, bool *exact);
 
 /* ruleutils.c */
diff --git a/src/include/utils/float.h b/src/include/utils/float.h
new file mode 100644
index 0000000000..0e8483c930
--- /dev/null
+++ b/src/include/utils/float.h
@@ -0,0 +1,376 @@
+/*-------------------------------------------------------------------------
+ *
+ * float.h
+ *	  Definitions for the built-in floating-point types
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/include/utils/float.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef FLOAT_H
+#define FLOAT_H
+
+#include <math.h>
+
+#ifndef M_PI
+/* From my RH5.2 gcc math.h file - thomas 2000-04-03 */
+#define M_PI 3.14159265358979323846
+#endif
+
+/* Radians per degree, a.k.a. PI / 180 */
+#define RADIANS_PER_DEGREE 0.0174532925199432957692
+
+/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0. */
+#if defined(WIN32) && !defined(NAN)
+static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
+
+#define NAN (*(const float8 *) nan)
+#endif
+
+extern PGDLLIMPORT int extra_float_digits;
+
+/*
+ * Utility functions in float.c
+ */
+extern int	is_infinite(float8 val);
+extern float8 float8in_internal(char *num, char **endptr_p,
+				  const char *type_name, const char *orig_string);
+extern char *float8out_internal(float8 num);
+extern int	float4_cmp_internal(float4 a, float4 b);
+extern int	float8_cmp_internal(float8 a, float8 b);
+
+/*
+ * Routines to provide reasonably platform-independent handling of
+ * infinity and NaN
+ *
+ * We assume that isinf() and isnan() are available and work per spec.
+ * (On some platforms, we have to supply our own; see src/port.)  However,
+ * generating an Infinity or NaN in the first place is less well standardized;
+ * pre-C99 systems tend not to have C99's INFINITY and NaN macros.  We
+ * centralize our workarounds for this here.
+ */
+
+/*
+ * The funny placements of the two #pragmas is necessary because of a
+ * long lived bug in the Microsoft compilers.
+ * See http://support.microsoft.com/kb/120968/en-us for details
+ */
+#if (_MSC_VER >= 1800)
+#pragma warning(disable:4756)
+#endif
+static inline float4
+get_float4_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float4) INFINITY;
+#else
+#if (_MSC_VER >= 1800)
+#pragma warning(default:4756)
+#endif
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float4) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float8
+get_float8_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float8) INFINITY;
+#else
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float8) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float4
+get_float4_nan(void)
+{
+#ifdef NAN
+	/* C99 standard way */
+	return (float4) NAN;
+#else
+	/* Assume we can get a NAN via zero divide */
+	return (float4) (0.0 / 0.0);
+#endif
+}
+
+static inline float8
+get_float8_nan(void)
+{
+	/* (float8) NAN doesn't work on some NetBSD/MIPS releases */
+#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
+	/* C99 standard way */
+	return (float8) NAN;
+#else
+	/* Assume we can get a NaN via zero divide */
+	return (float8) (0.0 / 0.0);
+#endif
+}
+
+/*
+ * Checks to see if a float4/8 val has underflowed or overflowed
+ */
+
+static inline void
+check_float4_val(const float4 val, const bool inf_is_valid,
+				 const bool zero_is_valid)
+{
+	if (!inf_is_valid && unlikely(isinf(val)))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if (!zero_is_valid && unlikely(val == 0.0))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+static inline void
+check_float8_val(const float8 val, const bool inf_is_valid,
+				 const bool zero_is_valid)
+{
+	if (!inf_is_valid && unlikely(isinf(val)))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if (!zero_is_valid && unlikely(val == 0.0))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+/*
+ * Routines for operations with the checks above
+ *
+ * There isn't any way to check for underflow of addition/subtraction
+ * because numbers near the underflow value have already been rounded to
+ * the point where we can't detect that the two values were originally
+ * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
+ * 1.4013e-45.
+ */
+
+static inline float4
+float4_pl(const float4 val1, const float4 val2)
+{
+	float4		result;
+
+	result = val1 + val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_pl(const float8 val1, const float8 val2)
+{
+	float8		result;
+
+	result = val1 + val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mi(const float4 val1, const float4 val2)
+{
+	float4		result;
+
+	result = val1 - val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_mi(const float8 val1, const float8 val2)
+{
+	float8		result;
+
+	result = val1 - val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mul(const float4 val1, const float4 val2)
+{
+	float4		result;
+
+	result = val1 * val2;
+	check_float4_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0f || val2 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_mul(const float8 val1, const float8 val2)
+{
+	float8		result;
+
+	result = val1 * val2;
+	check_float8_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0 || val2 == 0.0);
+
+	return result;
+}
+
+static inline float4
+float4_div(const float4 val1, const float4 val2)
+{
+	float4		result;
+
+	if (val2 == 0.0f)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), val1 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_div(const float8 val1, const float8 val2)
+{
+	float8		result;
+
+	if (val2 == 0.0)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
+
+	return result;
+}
+
+/*
+ * Routines for NaN-aware comparisons
+ *
+ * We consider all NaNs to be equal and larger than any non-NaN. This is
+ * somewhat arbitrary; the important thing is to have a consistent sort
+ * order.
+ */
+
+static inline bool
+float4_eq(const float4 val1, const float4 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float8_eq(const float8 val1, const float8 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float4_ne(const float4 val1, const float4 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float8_ne(const float8 val1, const float8 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float4_lt(const float4 val1, const float4 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float8_lt(const float8 val1, const float8 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float4_le(const float4 val1, const float4 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float8_le(const float8 val1, const float8 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float4_gt(const float4 val1, const float4 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float8_gt(const float8 val1, const float8 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float4_ge(const float4 val1, const float4 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline bool
+float8_ge(const float8 val1, const float8 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline float4
+float4_min(const float4 val1, const float4 val2)
+{
+	return float4_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_min(const float8 val1, const float8 val2)
+{
+	return float8_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float4
+float4_max(const float4 val1, const float4 val2)
+{
+	return float4_gt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_max(const float8 val1, const float8 val2)
+{
+	return float8_gt(val1, val2) ? val1 : val2;
+}
+
+#endif							/* FLOAT_H */
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 0e066894cd..aeb31515e4 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -17,20 +17,21 @@
  *		and data types. There are still some more to do. - tgl 97/04/19
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEO_DECLS_H
 #define GEO_DECLS_H
 
 #include <math.h>
 
 #include "fmgr.h"
+#include "utils/float.h"
 
 /*--------------------------------------------------------------------
  * Useful floating point utilities and constants.
  *-------------------------------------------------------------------*/
 
 
 #define EPSILON					1.0E-06
 
 #ifdef EPSILON
 #define FPzero(A)				(fabs(A) <= EPSILON)
-- 
2.14.3 (Apple Git-98)

0003-geo-float-v10.patchapplication/octet-stream; name=0003-geo-float-v10.patchDownload
From 88a7918a26fd13cf9bdc7ac1ca01fa20da574f30 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 27 May 2017 16:17:42 -0400
Subject: [PATCH 3/6] geo-float-v10

Use the built-in float datatype to implement geometric types

This patch makes the geometric operators and functions use the exported
function of the float datatype.  The main reason of doing so is to check
for underflow and overflow, and to handle NaNs consciously.

The float datatypes consider NaNs to be equal and greater than any
non-NaN.  This change considers NaNs equal only for the equality
operators.  The placement operators, contains, overlaps, left/right of
etc. continues to return false when NaNs are involved.  We don't need
to worry about them being considered greater than any-NaN because there
aren't any basic comparison operators like less/greater than for the
geometric datatypes.

All changes can be summarised as:

* Check for underflow and overflow
* Check for division by zero
* Let the objects with NaN values to be the same
* Return NULL when the distance is NaN for all closest point operators
* Favour not-NaN over NaN where it makes sense

The patch also replaces all occurrences of "double" as "float8".  They
are the same, but were randomly spread on the same file.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com

Parallel discussions:

* https://www.postgresql.org/message-id/28685.1468246504%40sss.pgh.pa.us
---
 src/backend/access/gist/gistproc.c |  91 +++----
 src/backend/utils/adt/geo_ops.c    | 499 ++++++++++++++++++++-----------------
 src/backend/utils/adt/geo_spgist.c |  28 +--
 src/include/utils/geo_decls.h      |  17 +-
 4 files changed, 341 insertions(+), 294 deletions(-)

diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index 4bbfdadf9f..4b6233f212 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -16,20 +16,21 @@
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/geo_decls.h"
 
 
 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
 						 StrategyNumber strategy);
 static bool rtree_internal_consistent(BOX *key, BOX *query,
 						  StrategyNumber strategy);
 
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
@@ -48,55 +49,56 @@ rt_box_union(BOX *n, const BOX *a, const BOX *b)
 	n->high.x = float8_max(a->high.x, b->high.x);
 	n->high.y = float8_max(a->high.y, b->high.y);
 	n->low.x = float8_min(a->low.x, b->low.x);
 	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
 	if (float8_le(box->high.x, box->low.x) ||
 		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
-	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
+	return float8_mul(float8_mi(box->high.x, box->low.x),
+					  float8_mi(box->high.y, box->low.y));
 }
 
 /*
  * Return amount by which the union of the two boxes is larger than
  * the original BOX's area.  The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 box_penalty(const BOX *original, const BOX *new)
 {
 	BOX			unionbox;
 
 	rt_box_union(&unionbox, original, new);
-	return size_box(&unionbox) - size_box(original);
+	return float8_mi(size_box(&unionbox), size_box(original));
 }
 
 /*
  * The GiST Consistent method for boxes
  *
  * Should return false if for all data items x below entry,
  * the predicate x op query must be false, where op is the oper
  * corresponding to strategy in the pg_amop table.
  */
 Datum
@@ -256,74 +258,74 @@ fallbackSplit(GistEntryVector *entryvec, GIST_SPLITVEC *v)
 
 /*
  * Represents information about an entry that can be placed to either group
  * without affecting overlap over selected axis ("common entry").
  */
 typedef struct
 {
 	/* Index of entry in the initial array */
 	int			index;
 	/* Delta between penalties of entry insertion into different groups */
-	double		delta;
+	float8		delta;
 } CommonEntry;
 
 /*
  * Context for g_box_consider_split. Contains information about currently
  * selected split and some general information.
  */
 typedef struct
 {
 	int			entriesCount;	/* total number of entries being split */
 	BOX			boundingBox;	/* minimum bounding box across all entries */
 
 	/* Information about currently selected split follows */
 
 	bool		first;			/* true if no split was selected yet */
 
-	double		leftUpper;		/* upper bound of left interval */
-	double		rightLower;		/* lower bound of right interval */
+	float8		leftUpper;		/* upper bound of left interval */
+	float8		rightLower;		/* lower bound of right interval */
 
 	float4		ratio;
 	float4		overlap;
 	int			dim;			/* axis of this split */
-	double		range;			/* width of general MBR projection to the
+	float8		range;			/* width of general MBR projection to the
 								 * selected axis */
 } ConsiderSplitContext;
 
 /*
  * Interval represents projection of box to axis.
  */
 typedef struct
 {
-	double		lower,
+	float8		lower,
 				upper;
 } SplitInterval;
 
 /*
  * Interval comparison function by lower bound of the interval;
  */
 static int
 interval_cmp_lower(const void *i1, const void *i2)
 {
-	double		lower1 = ((const SplitInterval *) i1)->lower,
+	float8		lower1 = ((const SplitInterval *) i1)->lower,
 				lower2 = ((const SplitInterval *) i2)->lower;
 
 	return float8_cmp_internal(lower1, lower2);
 }
 
 /*
  * Interval comparison function by upper bound of the interval;
  */
 static int
 interval_cmp_upper(const void *i1, const void *i2)
 {
-	double		upper1 = ((const SplitInterval *) i1)->upper,
+	float8		upper1 = ((const SplitInterval *) i1)->upper,
 				upper2 = ((const SplitInterval *) i2)->upper;
 
 	return float8_cmp_internal(upper1, upper2);
 }
 
 /*
  * Replace negative (or NaN) value with zero.
  */
 static inline float
 non_negative(float val)
@@ -332,28 +334,28 @@ non_negative(float val)
 		return val;
 	else
 		return 0.0f;
 }
 
 /*
  * Consider replacement of currently selected split with the better one.
  */
 static inline void
 g_box_consider_split(ConsiderSplitContext *context, int dimNum,
-					 double rightLower, int minLeftCount,
-					 double leftUpper, int maxLeftCount)
+					 float8 rightLower, int minLeftCount,
+					 float8 leftUpper, int maxLeftCount)
 {
 	int			leftCount,
 				rightCount;
 	float4		ratio,
 				overlap;
-	double		range;
+	float8		range;
 
 	/*
 	 * Calculate entries distribution ratio assuming most uniform distribution
 	 * of common entries.
 	 */
 	if (minLeftCount >= (context->entriesCount + 1) / 2)
 	{
 		leftCount = minLeftCount;
 	}
 	else
@@ -362,40 +364,41 @@ g_box_consider_split(ConsiderSplitContext *context, int dimNum,
 			leftCount = maxLeftCount;
 		else
 			leftCount = context->entriesCount / 2;
 	}
 	rightCount = context->entriesCount - leftCount;
 
 	/*
 	 * Ratio of split - quotient between size of lesser group and total
 	 * entries count.
 	 */
-	ratio = ((float4) Min(leftCount, rightCount)) /
-		((float4) context->entriesCount);
+	ratio = float4_div(Min(leftCount, rightCount), context->entriesCount);
 
 	if (ratio > LIMIT_RATIO)
 	{
 		bool		selectthis = false;
 
 		/*
 		 * The ratio is acceptable, so compare current split with previously
 		 * selected one. Between splits of one dimension we search for minimal
 		 * overlap (allowing negative values) and minimal ration (between same
 		 * overlaps. We switch dimension if find less overlap (non-negative)
 		 * or less range with same overlap.
 		 */
 		if (dimNum == 0)
-			range = context->boundingBox.high.x - context->boundingBox.low.x;
+			range = float8_mi(context->boundingBox.high.x,
+							  context->boundingBox.low.x);
 		else
-			range = context->boundingBox.high.y - context->boundingBox.low.y;
+			range = float8_mi(context->boundingBox.high.y,
+							  context->boundingBox.low.y);
 
-		overlap = (leftUpper - rightLower) / range;
+		overlap = float8_div(float8_mi(leftUpper, rightLower), range);
 
 		/* If there is no previous selection, select this */
 		if (context->first)
 			selectthis = true;
 		else if (context->dim == dimNum)
 		{
 			/*
 			 * Within the same dimension, choose the new split if it has a
 			 * smaller overlap, or same overlap but better ratio.
 			 */
@@ -524,21 +527,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		else
 			adjustBox(&context.boundingBox, box);
 	}
 
 	/*
 	 * Iterate over axes for optimal split searching.
 	 */
 	context.first = true;		/* nothing selected yet */
 	for (dim = 0; dim < 2; dim++)
 	{
-		double		leftUpper,
+		float8		leftUpper,
 					rightLower;
 		int			i1,
 					i2;
 
 		/* Project each entry as an interval on the selected axis. */
 		for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 		{
 			box = DatumGetBoxP(entryvec->vector[i].key);
 			if (dim == 0)
 			{
@@ -721,21 +724,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 			*rightBox = *(box);					\
 		v->spl_right[v->spl_nright++] = off;	\
 	} while(0)
 
 	/*
 	 * Distribute entries which can be distributed unambiguously, and collect
 	 * common entries.
 	 */
 	for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 	{
-		double		lower,
+		float8		lower,
 					upper;
 
 		/*
 		 * Get upper and lower bounds along selected axis.
 		 */
 		box = DatumGetBoxP(entryvec->vector[i].key);
 		if (context.dim == 0)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
@@ -776,31 +779,31 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
 	{
 		/*
 		 * Calculate minimum number of entries that must be placed in both
 		 * groups, to reach LIMIT_RATIO.
 		 */
-		int			m = ceil(LIMIT_RATIO * (double) nentries);
+		int			m = ceil(LIMIT_RATIO * (float8) nentries);
 
 		/*
 		 * Calculate delta between penalties of join "common entries" to
 		 * different groups.
 		 */
 		for (i = 0; i < commonEntriesCount; i++)
 		{
 			box = DatumGetBoxP(entryvec->vector[commonEntries[i].index].key);
-			commonEntries[i].delta = Abs(box_penalty(leftBox, box) -
-										 box_penalty(rightBox, box));
+			commonEntries[i].delta = Abs(float8_mi(box_penalty(leftBox, box),
+												   box_penalty(rightBox, box)));
 		}
 
 		/*
 		 * Sort "common entries" by calculated deltas in order to distribute
 		 * the most ambiguous entries first.
 		 */
 		qsort(commonEntries, commonEntriesCount, sizeof(CommonEntry), common_entry_cmp);
 
 		/*
 		 * Distribute "common entries" between groups.
@@ -1100,24 +1103,24 @@ gist_circle_compress(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	GISTENTRY  *retval;
 
 	if (entry->leafkey)
 	{
 		CIRCLE	   *in = DatumGetCircleP(entry->key);
 		BOX		   *r;
 
 		r = (BOX *) palloc(sizeof(BOX));
-		r->high.x = in->center.x + in->radius;
-		r->low.x = in->center.x - in->radius;
-		r->high.y = in->center.y + in->radius;
-		r->low.y = in->center.y - in->radius;
+		r->high.x = float8_pl(in->center.x, in->radius);
+		r->low.x = float8_mi(in->center.x, in->radius);
+		r->high.y = float8_pl(in->center.y, in->radius);
+		r->low.y = float8_mi(in->center.y, in->radius);
 
 		retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
 		gistentryinit(*retval, PointerGetDatum(r),
 					  entry->rel, entry->page,
 					  entry->offset, false);
 	}
 	else
 		retval = entry;
 	PG_RETURN_POINTER(retval);
 }
@@ -1141,24 +1144,24 @@ gist_circle_consistent(PG_FUNCTION_ARGS)
 	*recheck = true;
 
 	if (DatumGetBoxP(entry->key) == NULL || query == NULL)
 		PG_RETURN_BOOL(false);
 
 	/*
 	 * Since the operators require recheck anyway, we can just use
 	 * rtree_internal_consistent even at leaf nodes.  (This works in part
 	 * because the index entries are bounding boxes not circles.)
 	 */
-	bbox.high.x = query->center.x + query->radius;
-	bbox.low.x = query->center.x - query->radius;
-	bbox.high.y = query->center.y + query->radius;
-	bbox.low.y = query->center.y - query->radius;
+	bbox.high.x = float8_pl(query->center.x, query->radius);
+	bbox.low.x = float8_mi(query->center.x, query->radius);
+	bbox.high.y = float8_pl(query->center.y, query->radius);
+	bbox.low.y = float8_mi(query->center.y, query->radius);
 
 	result = rtree_internal_consistent(DatumGetBoxP(entry->key),
 									   &bbox, strategy);
 
 	PG_RETURN_BOOL(result);
 }
 
 /**************************************************
  * Point ops
  **************************************************/
@@ -1209,63 +1212,63 @@ gist_point_fetch(PG_FUNCTION_ARGS)
 				  entry->offset, false);
 
 	PG_RETURN_POINTER(retval);
 }
 
 
 #define point_point_distance(p1,p2) \
 	DatumGetFloat8(DirectFunctionCall2(point_distance, \
 									   PointPGetDatum(p1), PointPGetDatum(p2)))
 
-static double
+static float8
 computeDistance(bool isLeaf, BOX *box, Point *point)
 {
-	double		result = 0.0;
+	float8		result = 0.0;
 
 	if (isLeaf)
 	{
 		/* simple point to point distance */
 		result = point_point_distance(point, &box->low);
 	}
 	else if (point->x <= box->high.x && point->x >= box->low.x &&
 			 point->y <= box->high.y && point->y >= box->low.y)
 	{
 		/* point inside the box */
 		result = 0.0;
 	}
 	else if (point->x <= box->high.x && point->x >= box->low.x)
 	{
 		/* point is over or below box */
 		Assert(box->low.y <= box->high.y);
 		if (point->y > box->high.y)
-			result = point->y - box->high.y;
+			result = float8_mi(point->y, box->high.y);
 		else if (point->y < box->low.y)
-			result = box->low.y - point->y;
+			result = float8_mi(box->low.y, point->y);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
 	else if (point->y <= box->high.y && point->y >= box->low.y)
 	{
 		/* point is to left or right of box */
 		Assert(box->low.x <= box->high.x);
 		if (point->x > box->high.x)
-			result = point->x - box->high.x;
+			result = float8_mi(point->x, box->high.x);
 		else if (point->x < box->low.x)
-			result = box->low.x - point->x;
+			result = float8_mi(box->low.x, point->x);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
 	else
 	{
 		/* closest point will be a vertex */
 		Point		p;
-		double		subresult;
+		float8		subresult;
 
 		result = point_point_distance(point, &box->low);
 
 		subresult = point_point_distance(point, &box->high);
 		if (result > subresult)
 			result = subresult;
 
 		p.x = box->low.x;
 		p.y = box->high.y;
 		subresult = point_point_distance(point, &p);
@@ -1442,21 +1445,21 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 	}
 
 	PG_RETURN_BOOL(result);
 }
 
 Datum
 gist_point_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(GIST_LEAF(entry),
 									   DatumGetBoxP(entry->key),
 									   PG_GETARG_POINT_P(1));
 			break;
 		default:
@@ -1471,25 +1474,25 @@ gist_point_distance(PG_FUNCTION_ARGS)
 /*
  * The inexact GiST distance method for geometric types that store bounding
  * boxes.
  *
  * Compute lossy distance from point to index entries.  The result is inexact
  * because index entries are bounding boxes, not the exact shapes of the
  * indexed geometric types.  We use distance from point to MBR of index entry.
  * This is a lower bound estimate of distance from point to indexed geometric
  * type.
  */
-static double
+static float8
 gist_bbox_distance(GISTENTRY *entry, Datum query,
 				   StrategyNumber strategy, bool *recheck)
 {
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	/* Bounding box distance is always inexact. */
 	*recheck = true;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(false,
 									   DatumGetBoxP(entry->key),
@@ -1505,32 +1508,32 @@ gist_bbox_distance(GISTENTRY *entry, Datum query,
 
 Datum
 gist_circle_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
 
 Datum
 gist_poly_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 0f12684478..df185affcb 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -51,56 +51,56 @@ static inline float8 line_invsl(LINE *line);
 static bool	line_interpt_line(Point *result, LINE *l1, LINE *l2);
 static bool line_contain_point(LINE *line, Point *point);
 static float8 line_closept_point(Point *result, LINE *line, Point *pt);
 
 /* Routines for line segments */
 static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
 static inline float8 lseg_sl(LSEG *lseg);
 static inline float8 lseg_invsl(LSEG *lseg);
 static bool	lseg_interpt_line(Point *result, LSEG *lseg, LINE *line);
 static bool	lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2);
-static int	lseg_crossing(double x, double y, double px, double py);
+static int	lseg_crossing(float8 x, float8 y, float8 px, float8 py);
 static bool	lseg_contain_point(LSEG *lseg, Point *point);
 static float8 lseg_closept_point(Point *result, LSEG *lseg, Point *pt);
 static float8 lseg_closept_line(Point *result, LSEG *lseg, LINE *line);
 static float8 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2);
 
 /* Routines for boxes */
 static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
 static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
-static double box_ar(BOX *box);
-static double box_ht(BOX *box);
-static double box_wd(BOX *box);
+static float8 box_ar(BOX *box);
+static float8 box_ht(BOX *box);
+static float8 box_wd(BOX *box);
 static bool box_contain_point(BOX *box, Point *point);
 static bool box_contain_box(BOX *box1, BOX *box2);
 static bool box_contain_lseg(BOX *box, LSEG *lseg);
 static bool box_interpt_lseg(Point *result, BOX *box, LSEG *lseg);
 static float8 box_closept_point(Point *result, BOX *box, Point *point);
 static float8 box_closept_lseg(Point *result, BOX *box, LSEG *lseg);
 
 /* Routines for circles */
-static double circle_ar(CIRCLE *circle);
+static float8 circle_ar(CIRCLE *circle);
 
 /* Routines for polygons */
 static void make_bound_box(POLYGON *poly);
 static void poly_to_circle(CIRCLE *result, POLYGON *poly);
 static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
 static bool poly_contain_poly(POLYGON *polya, POLYGON *polyb);
 static bool plist_same(int npts, Point *p1, Point *p2);
 static float8 dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 /* Routines for encoding and decoding */
-static double single_decode(char *num, char **endptr_p,
+static float8 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
-static void pair_decode(char *str, double *x, double *y, char **endptr_p,
+static void pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
 static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
 
 
 /*
@@ -138,38 +138,38 @@ static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
  *
  * For boxes, the points are opposite corners with the first point at the top right.
  * For closed paths and polygons, the points should be reordered to allow
  *	fast and correct equality comparisons.
  *
  * XXX perhaps points in complex shapes should be reordered internally
  *	to allow faster internal operations, but should keep track of input order
  *	and restore that order for text output - tgl 97/01/16
  */
 
-static double
+static float8
 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string)
 {
 	return float8in_internal(num, endptr_p, type_name, orig_string);
 }								/* single_decode() */
 
 static void
 single_encode(float8 x, StringInfo str)
 {
 	char	   *xstr = float8out_internal(x);
 
 	appendStringInfoString(str, xstr);
 	pfree(xstr);
 }								/* single_encode() */
 
 static void
-pair_decode(char *str, double *x, double *y, char **endptr_p,
+pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string)
 {
 	bool		has_delim;
 
 	while (isspace((unsigned char) *str))
 		str++;
 	if ((has_delim = (*str == LDELIM)))
 		str++;
 
 	*x = float8in_internal(str, &str, type_name, orig_string);
@@ -368,33 +368,33 @@ pair_count(char *s, char delim)
  *		External format: (two corners of box)
  *				"(f8, f8), (f8, f8)"
  *				also supports the older style "(f8, f8, f8, f8)"
  */
 Datum
 box_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	BOX		   *box = (BOX *) palloc(sizeof(BOX));
 	bool		isopen;
-	double		x,
+	float8		x,
 				y;
 
 	path_decode(str, false, 2, &(box->high), &isopen, NULL, "box", str);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*		box_out -		convert a box to external form.
@@ -408,38 +408,38 @@ box_out(PG_FUNCTION_ARGS)
 }
 
 /*
  *		box_recv			- converts external binary format to box
  */
 Datum
 box_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	BOX		   *box;
-	double		x,
+	float8		x,
 				y;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
 	box->high.x = pq_getmsgfloat8(buf);
 	box->high.y = pq_getmsgfloat8(buf);
 	box->low.x = pq_getmsgfloat8(buf);
 	box->low.y = pq_getmsgfloat8(buf);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*
@@ -458,31 +458,31 @@ box_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, box->low.y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*		box_construct	-		fill in a new box.
  */
 static inline void
 box_construct(BOX *result, Point *pt1, Point *pt2)
 {
-	if (pt1->x > pt2->x)
+	if (float8_gt(pt1->x, pt2->x))
 	{
 		result->high.x = pt1->x;
 		result->low.x = pt2->x;
 	}
 	else
 	{
 		result->high.x = pt2->x;
 		result->low.x = pt1->x;
 	}
-	if (pt1->y > pt2->y)
+	if (float8_gt(pt1->y, pt2->y))
 	{
 		result->high.y = pt1->y;
 		result->low.y = pt2->y;
 	}
 	else
 	{
 		result->high.y = pt2->y;
 		result->low.y = pt1->y;
 	}
 }
@@ -800,54 +800,54 @@ box_center(PG_FUNCTION_ARGS)
 	Point	   *result = (Point *) palloc(sizeof(Point));
 
 	box_cn(result, box);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		box_ar	-		returns the area of the box.
  */
-static double
+static float8
 box_ar(BOX *box)
 {
-	return box_wd(box) * box_ht(box);
+	return float8_mul(box_wd(box), box_ht(box));
 }
 
 
 /*		box_cn	-		stores the centerpoint of the box into *center.
  */
 static void
 box_cn(Point *center, BOX *box)
 {
-	center->x = (box->high.x + box->low.x) / 2.0;
-	center->y = (box->high.y + box->low.y) / 2.0;
+	center->x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	center->y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 }
 
 
 /*		box_wd	-		returns the width (length) of the box
  *								  (horizontal magnitude).
  */
-static double
+static float8
 box_wd(BOX *box)
 {
-	return box->high.x - box->low.x;
+	return float8_mi(box->high.x, box->low.x);
 }
 
 
 /*		box_ht	-		returns the height of the box
  *								  (vertical magnitude).
  */
-static double
+static float8
 box_ht(BOX *box)
 {
-	return box->high.y - box->low.y;
+	return float8_mi(box->high.y, box->low.y);
 }
 
 
 /*----------------------------------------------------------
  *	Funky operations.
  *---------------------------------------------------------*/
 
 /*		box_intersect	-
  *				returns the overlapping portion of two boxes,
  *				  or NULL if they do not intersect.
@@ -857,24 +857,24 @@ box_intersect(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 	BOX		   *result;
 
 	if (!box_ov(box1, box2))
 		PG_RETURN_NULL();
 
 	result = (BOX *) palloc(sizeof(BOX));
 
-	result->high.x = Min(box1->high.x, box2->high.x);
-	result->low.x = Max(box1->low.x, box2->low.x);
-	result->high.y = Min(box1->high.y, box2->high.y);
-	result->low.y = Max(box1->low.y, box2->low.y);
+	result->high.x = float8_min(box1->high.x, box2->high.x);
+	result->low.x = float8_max(box1->low.x, box2->low.x);
+	result->high.y = float8_min(box1->high.y, box2->high.y);
+	result->low.y = float8_max(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(result);
 }
 
 
 /*		box_diagonal	-
  *				returns a line segment which happens to be the
  *				  positive-slope diagonal of "box".
  */
 Datum
@@ -1006,30 +1006,30 @@ line_send(PG_FUNCTION_ARGS)
 
 /*
  * Fill already-allocated LINE struct from the point and the slope
  */
 static inline void
 line_construct(LINE *result, Point *pt, float8 m)
 {
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
-		result->A = -1;
-		result->B = 0;
+		result->A = -1.0;
+		result->B = 0.0;
 		result->C = pt->x;
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
-		result->C = pt->y - m * pt->x;
+		result->C = float8_mi(pt->y, float8_mul(m, pt->x));
 	}
 }
 
 /* line_construct_pp()
  * two points
  */
 Datum
 line_construct_pp(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
@@ -1068,94 +1068,105 @@ Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
 	else if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
 
-	PG_RETURN_BOOL(FPeq(((l1->A * l2->B) / (l1->B * l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
+								   float8_mul(l1->B, l2->A)), -1.0));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
 Datum
 line_horizontal(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->A));
 }
 
+
+/*
+ * Check whether the two lines are the same
+ *
+ * We consider NaNs values to be equal to each other to let those lines
+ * to be found.
+ */
 Datum
 line_eq(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	double		k;
+	float8		ratio;
 
-	if (!FPzero(l2->A))
-		k = l1->A / l2->A;
-	else if (!FPzero(l2->B))
-		k = l1->B / l2->B;
-	else if (!FPzero(l2->C))
-		k = l1->C / l2->C;
+	if (!FPzero(l2->A) && !isnan(l2->A))
+		ratio = float8_div(l1->A, l2->A);
+	else if (!FPzero(l2->B) && !isnan(l2->B))
+		ratio = float8_div(l1->B, l2->B);
+	else if (!FPzero(l2->C) && !isnan(l2->C))
+		ratio = float8_div(l1->C, l2->C);
 	else
-		k = 1.0;
+		ratio = 1.0;
 
-	PG_RETURN_BOOL(FPeq(l1->A, k * l2->A) &&
-				   FPeq(l1->B, k * l2->B) &&
-				   FPeq(l1->C, k * l2->C));
+	PG_RETURN_BOOL((FPeq(l1->A, float8_mul(ratio, l2->A)) &&
+					FPeq(l1->B, float8_mul(ratio, l2->B)) &&
+					FPeq(l1->C, float8_mul(ratio, l2->C))) ||
+				   (float8_eq(l1->A, l2->A) &&
+					float8_eq(l1->B, l2->B) &&
+					float8_eq(l1->C, l2->C)));
 }
 
 
 /*----------------------------------------------------------
  *	Line arithmetic routines.
  *---------------------------------------------------------*/
 
 /*
  * Return inverse slope of the line
  */
 static inline float8
 line_invsl(LINE *line)
 {
 	if (FPzero(line->A))
 		return DBL_MAX;
 	if (FPzero(line->B))
 		return 0.0;
-	return line->B / line->A;
+	return float8_div(line->B, line->A);
 }
 
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
 	Point		tmp;
 
 	if (line_interpt_line(NULL, l1, l2))	/* intersecting? */
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
+		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
 	point_construct(&tmp, 0.0, l1->C);
 	result = line_closept_point(NULL, l2, &tmp);
 	PG_RETURN_FLOAT8(result);
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
@@ -1174,47 +1185,51 @@ line_interpt(PG_FUNCTION_ARGS)
 /*
  * Internal version of line_interpt
  *
  * This returns true if two lines intersect (they do, if they are not
  * parallel), false if they do not.  This also sets the intersection point
  * to *result, if it is not NULL.
  *
  * NOTE: If the lines are identical then we will find they are parallel
  * and report "no intersection".  This is a little weird, but since
  * there's no *unique* intersection, maybe it's appropriate behavior.
+ *
+ * If the lines have NaN constants, we will return true, and the intersection
+ * point would have NaN coordinates.  We shouldn't return false in this case
+ * because that would mean the lines are parallel.
  */
 static bool
 line_interpt_line(Point *result, LINE *l1, LINE *l2)
 {
-	double		x,
+	float8		x,
 				y;
 
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
 		if (FPzero(l2->B))		/* l2 vertical? */
 			return false;
 
 		x = l1->C;
-		y = (l2->A * x + l2->C);
+		y = float8_pl(float8_mul(l2->A, x), l2->C);
 	}
 	else if (FPzero(l2->B))		/* l2 vertical? */
 	{
 		x = l2->C;
-		y = (l1->A * x + l1->C);
+		y = float8_pl(float8_mul(l1->A, x), l1->C);
 	}
 	else
 	{
-		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
 			return false;
 
-		x = (l1->C - l2->C) / (l2->A - l1->A);
-		y = (l1->A * x + l1->C);
+		x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
+		y = float8_pl(float8_mul(l1->A, x), l1->C);
 	}
 
 	if (result != NULL)
 		point_construct(result, x, y);
 
 	return true;
 }
 
 
 /***********************************************************************
@@ -1236,36 +1251,35 @@ line_interpt_line(Point *result, LINE *l1, LINE *l2)
  *				"(xcoord, ycoord),... "
  *				"[xcoord, ycoord,... ]"
  *		Also support older format:
  *				"(closed, npts, xcoord, ycoord,... )"
  *---------------------------------------------------------*/
 
 Datum
 path_area(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P(0);
-	double		area = 0.0;
+	float8		area = 0.0;
 	int			i,
 				j;
 
 	if (!path->closed)
 		PG_RETURN_NULL();
 
 	for (i = 0; i < path->npts; i++)
 	{
 		j = (i + 1) % path->npts;
-		area += path->p[i].x * path->p[j].y;
-		area -= path->p[i].y * path->p[j].x;
+		area = float8_pl(area, float8_mul(path->p[i].x, path->p[j].y));
+		area = float8_mi(area, float8_mul(path->p[i].y, path->p[j].x));
 	}
 
-	area *= 0.5;
-	PG_RETURN_FLOAT8(area < 0.0 ? -area : area);
+	PG_RETURN_FLOAT8(float8_div(fabs(area), 2.0));
 }
 
 
 Datum
 path_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	PATH	   *path;
 	bool		isopen;
 	char	   *s;
@@ -1521,33 +1535,33 @@ path_inter(PG_FUNCTION_ARGS)
 				j;
 	LSEG		seg1,
 				seg2;
 
 	Assert(p1->npts > 0 && p2->npts > 0);
 
 	b1.high.x = b1.low.x = p1->p[0].x;
 	b1.high.y = b1.low.y = p1->p[0].y;
 	for (i = 1; i < p1->npts; i++)
 	{
-		b1.high.x = Max(p1->p[i].x, b1.high.x);
-		b1.high.y = Max(p1->p[i].y, b1.high.y);
-		b1.low.x = Min(p1->p[i].x, b1.low.x);
-		b1.low.y = Min(p1->p[i].y, b1.low.y);
+		b1.high.x = float8_max(p1->p[i].x, b1.high.x);
+		b1.high.y = float8_max(p1->p[i].y, b1.high.y);
+		b1.low.x = float8_min(p1->p[i].x, b1.low.x);
+		b1.low.y = float8_min(p1->p[i].y, b1.low.y);
 	}
 	b2.high.x = b2.low.x = p2->p[0].x;
 	b2.high.y = b2.low.y = p2->p[0].y;
 	for (i = 1; i < p2->npts; i++)
 	{
-		b2.high.x = Max(p2->p[i].x, b2.high.x);
-		b2.high.y = Max(p2->p[i].y, b2.high.y);
-		b2.low.x = Min(p2->p[i].x, b2.low.x);
-		b2.low.y = Min(p2->p[i].y, b2.low.y);
+		b2.high.x = float8_max(p2->p[i].x, b2.high.x);
+		b2.high.y = float8_max(p2->p[i].y, b2.high.y);
+		b2.low.x = float8_min(p2->p[i].x, b2.low.x);
+		b2.low.y = float8_min(p2->p[i].y, b2.low.y);
 	}
 	if (!box_ov(&b1, &b2))
 		PG_RETURN_BOOL(false);
 
 	/* pairwise check lseg intersections */
 	for (i = 0; i < p1->npts; i++)
 	{
 		int			iprev;
 
 		if (i > 0)
@@ -1623,21 +1637,21 @@ path_distance(PG_FUNCTION_ARGS)
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
 			tmp = lseg_closept_lseg(NULL, &seg1, &seg2);
-			if (!have_min || tmp < min)
+			if (!have_min || float8_lt(tmp, min))
 			{
 				min = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	if (!have_min)
 		PG_RETURN_NULL();
 
@@ -1662,21 +1676,21 @@ path_length(PG_FUNCTION_ARGS)
 
 		if (i > 0)
 			iprev = i - 1;
 		else
 		{
 			if (!path->closed)
 				continue;
 			iprev = path->npts - 1; /* include the closure segment */
 		}
 
-		result += point_dt(&path->p[iprev], &path->p[i]);
+		result = float8_pl(result, point_dt(&path->p[iprev], &path->p[i]));
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /***********************************************************************
  **
  **		Routines for 2D points.
  **
  ***********************************************************************/
@@ -1822,44 +1836,52 @@ point_eq(PG_FUNCTION_ARGS)
 
 Datum
 point_ne(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_BOOL(!point_eq_point(pt1, pt2));
 }
 
+
+/*
+ * Check whether the two points are the same
+ *
+ * We consider NaNs coordinates to be equal to each other to let those points
+ * to be found.
+ */
 static inline bool
 point_eq_point(Point *pt1, Point *pt2)
 {
-	return FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y);
+	return ((FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y)) ||
+			(float8_eq(pt1->x, pt2->x) && float8_eq(pt1->y, pt2->y)));
 }
 
 
 /*----------------------------------------------------------
  *	"Arithmetic" operators on points.
  *---------------------------------------------------------*/
 
 Datum
 point_distance(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
 static inline float8
 point_dt(Point *pt1, Point *pt2)
 {
-	return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
+	return HYPOT(float8_mi(pt1->x, pt2->x), float8_mi(pt1->y, pt2->y));
 }
 
 Datum
 point_slope(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_sl(pt1, pt2));
 }
@@ -1870,37 +1892,37 @@ point_slope(PG_FUNCTION_ARGS)
  *
  * Note that this function returns DBL_MAX when the points are the same.
  */
 static inline float8
 point_sl(Point *pt1, Point *pt2)
 {
 	if (FPeq(pt1->x, pt2->x))
 		return DBL_MAX;
 	if (FPeq(pt1->y, pt2->y))
 		return 0.0;
-	return (pt1->y - pt2->y) / (pt1->x - pt2->x);
+	return float8_div(float8_mi(pt1->y, pt2->y), float8_mi(pt1->x, pt2->x));
 }
 
 
 /*
  * Return inverse slope of two points
  *
  * Note that this function returns 0.0 when the points are the same.
  */
 static inline float8
 point_invsl(Point *pt1, Point *pt2)
 {
 	if (FPeq(pt1->x, pt2->x))
 		return 0.0;
 	if (FPeq(pt1->y, pt2->y))
 		return DBL_MAX;
-	return (pt1->x - pt2->x) / (pt2->y - pt1->y);
+	return float8_div(float8_mi(pt1->x, pt2->x), float8_mi(pt2->y, pt1->y));
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D line segments.
  **
  ***********************************************************************/
 
 /*----------------------------------------------------------
@@ -2160,22 +2182,22 @@ lseg_distance(PG_FUNCTION_ARGS)
 
 
 Datum
 lseg_center(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
-	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
+	result->x = float8_div(float8_pl(lseg->p[0].x, lseg->p[1].x), 2.0);
+	result->y = float8_div(float8_pl(lseg->p[0].y, lseg->p[1].y), 2.0);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  *		Find the intersection point of two segments (if any).
  *
  * This returns true if two line segments intersect, false if they do not.
  * This also sets the intersection point to *result, if it is not NULL.
@@ -2284,21 +2306,21 @@ dist_ppath(PG_FUNCTION_ARGS)
 			iprev = i - 1;
 		else
 		{
 			if (!path->closed)
 				continue;
 			iprev = path->npts - 1; /* Include the closure segment */
 		}
 
 		statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
 		tmp = lseg_closept_point(NULL, &lseg, pt);
-		if (!have_min || tmp < result)
+		if (!have_min || float8_lt(tmp, result))
 		{
 			result = tmp;
 			have_min = true;
 		}
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
@@ -2314,33 +2336,28 @@ dist_pb(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
-	float8		result,
-				d2;
+	float8		result;
 
 	if (lseg_interpt_line(NULL, lseg, line))
 		result = 0.0;
 	else
-	{
-		result = line_closept_point(NULL, line, &lseg->p[0]);
-		d2 = line_closept_point(NULL, line, &lseg->p[1]);
 		/* XXX shouldn't we take the min not max? */
-		if (d2 > result)
-			result = d2;
-	}
+		result = float8_max(line_closept_point(NULL, line, &lseg->p[0]),
+							line_closept_point(NULL, line, &lseg->p[1]));
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
@@ -2373,25 +2390,24 @@ dist_lb(PG_FUNCTION_ARGS)
  * Distance from a circle to a polygon
  */
 Datum
 dist_cpoly(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	POLYGON    *poly = PG_GETARG_POLYGON_P(1);
 	float8		result;
 
 	/* calculate distance to center, and subtract radius */
-	result = dist_ppoly_internal(&circle->center, poly);
-
-	result -= circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(dist_ppoly_internal(&circle->center, poly),
+					   circle->radius);
+	if (result < 0.0)
+		result = 0.0;
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a point to a polygon
  */
 Datum
 dist_ppoly(PG_FUNCTION_ARGS)
 {
@@ -2403,21 +2419,21 @@ dist_ppoly(PG_FUNCTION_ARGS)
 
 Datum
 dist_polyp(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(dist_ppoly_internal(point, poly));
 }
 
-static double
+static float8
 dist_ppoly_internal(Point *pt, POLYGON *poly)
 {
 	float8		result;
 	float8		d;
 	int			i;
 	LSEG		seg;
 
 	if (point_inside(pt, poly->npts, poly->p) != 0)
 	{
 #ifdef GEODEBUG
@@ -2440,21 +2456,21 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
 	for (i = 0; i < poly->npts - 1; i++)
 	{
 		seg.p[0].x = poly->p[i].x;
 		seg.p[0].y = poly->p[i].y;
 		seg.p[1].x = poly->p[i + 1].x;
 		seg.p[1].y = poly->p[i + 1].y;
 		d = lseg_closept_point(NULL, &seg, pt);
 #ifdef GEODEBUG
 		printf("dist_ppoly_internal- segment %d distance is %f\n", (i + 1), d);
 #endif
-		if (d < result)
+		if (float8_lt(d, result))
 			result = d;
 	}
 
 	return result;
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
  *				Intersection point of objects.
@@ -2542,21 +2558,22 @@ line_closept_point(Point *result, LINE *line, Point *point)
 
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	line_closept_point(result, line, pt);
+	if (isnan(line_closept_point(result, line, pt)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point on line segment to specified point.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
@@ -2599,134 +2616,136 @@ close_ps(PG_FUNCTION_ARGS)
 /*
  * Closest point on line segment to line segment
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
 {
 	Point		point;
-	double		dist;
-	double		d;
+	float8		dist,
+				d;
 
 	d = lseg_closept_point(NULL, l1, &l2->p[0]);
 	dist = d;
 	if (result != NULL)
 		*result = l2->p[0];
 
 	d = lseg_closept_point(NULL, l1, &l2->p[1]);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = l2->p[1];
 	}
 
-	if (lseg_closept_point(&point, l2, &l1->p[0]) < dist)
+	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[0]), dist))
 		d = lseg_closept_point(result, l1, &point);
 
-	if (lseg_closept_point(&point, l2, &l1->p[1]) < dist)
+	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[1]), dist))
 		d = lseg_closept_point(result, l1, &point);
 
-	if (d < dist)
+	if (float8_lt(d, dist))
 		dist = d;
 
 	return dist;
 }
 
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	lseg_closept_lseg(result, l2, l1);
+	if (isnan(lseg_closept_lseg(result, l2, l1)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point on or in box to specified point.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 box_closept_point(Point *result, BOX *box, Point *pt)
 {
-	LSEG		lseg;
+	float8		dist,
+				d;
 	Point		point,
 				closept;
-	double		dist,
-				d;
+	LSEG		lseg;
 
 	if (box_contain_point(box, pt))
 	{
 		if (result != NULL)
 			*result = *pt;
 
 		return 0.0;
 	}
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&lseg, &box->low, &point);
 	dist = lseg_closept_point(result, &lseg, pt);
 
 	statlseg_construct(&lseg, &box->high, &point);
 	d = lseg_closept_point(&closept, &lseg, pt);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&lseg, &box->low, &point);
 	d = lseg_closept_point(&closept, &lseg, pt);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	statlseg_construct(&lseg, &box->high, &point);
 	d = lseg_closept_point(&closept, &lseg, pt);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	return dist;
 }
 
 Datum
 close_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	box_closept_point(result, box, pt);
+	if (isnan(box_closept_point(result, box, pt)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_sl()
  * Closest point on line to line segment.
  *
  * XXX THIS CODE IS WRONG
  * The code is actually calculating the point on the line segment
@@ -2744,21 +2763,21 @@ close_sl(PG_FUNCTION_ARGS)
 	float8		d1,
 				d2;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (lseg_interpt_line(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = line_closept_point(NULL, line, &lseg->p[0]);
 	d2 = line_closept_point(NULL, line, &lseg->p[1]);
-	if (d1 < d2)
+	if (float8_lt(d1, d2))
 		*result = lseg->p[0];
 	else
 		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
 
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_sl\" not implemented")));
@@ -2808,92 +2827,94 @@ lseg_closept_line(Point *result, LSEG *lseg, LINE *line)
 
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	lseg_closept_line(result, lseg, line);
+	if (isnan(lseg_closept_line(result, lseg, line)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point on or in box to line segment.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 box_closept_lseg(Point *result, BOX *box, LSEG *lseg)
 {
+	float8		dist,
+				d;
 	Point		point,
 				closept;
 	LSEG		bseg;
-	double		dist,
-				d;
 
 	if (box_interpt_lseg(result, box, lseg))
 		return 0.0;
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
 	dist = lseg_closept_lseg(result, &bseg, lseg);
 
 	statlseg_construct(&bseg, &box->high, &point);
 	d = lseg_closept_lseg(&closept, &bseg, lseg);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&bseg, &box->low, &point);
 	d = lseg_closept_lseg(&closept, &bseg, lseg);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	statlseg_construct(&bseg, &box->high, &point);
 	d = lseg_closept_lseg(&closept, &bseg, lseg);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	return dist;
 }
 
 Datum
 close_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	box_closept_lseg(result, box, lseg);
+	if (isnan(box_closept_lseg(result, box, lseg)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 Datum
 close_lb(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -2912,21 +2933,23 @@ close_lb(PG_FUNCTION_ARGS)
  *		on_
  *				Whether one object lies completely within another.
  *-------------------------------------------------------------------*/
 
 /*
  *		Does the point satisfy the equation?
  */
 static bool
 line_contain_point(LINE *line, Point *point)
 {
-	return FPzero(line->A * point->x + line->B * point->y + line->C);
+	return FPzero(float8_pl(float8_pl(float8_mul(line->A, point->x),
+									  float8_mul(line->B, point->y)),
+							line->C));
 }
 
 Datum
 on_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
 	PG_RETURN_BOOL(line_contain_point(line, pt));
 }
@@ -2993,33 +3016,32 @@ box_contain_pt(PG_FUNCTION_ARGS)
  *				but not cross.
  *				(we can do p-in-p in lg(n), but it takes preprocessing)
  */
 Datum
 on_ppath(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	PATH	   *path = PG_GETARG_PATH_P(1);
 	int			i,
 				n;
-	double		a,
+	float8		a,
 				b;
 
 	/*-- OPEN --*/
 	if (!path->closed)
 	{
 		n = path->npts - 1;
 		a = point_dt(pt, &path->p[0]);
 		for (i = 0; i < n; i++)
 		{
 			b = point_dt(pt, &path->p[i + 1]);
-			if (FPeq(a + b,
-					 point_dt(&path->p[i], &path->p[i + 1])))
+			if (FPeq(float8_pl(a, b), point_dt(&path->p[i], &path->p[i + 1])))
 				PG_RETURN_BOOL(true);
 			a = b;
 		}
 		PG_RETURN_BOOL(false);
 	}
 
 	/*-- CLOSED --*/
 	PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
 }
 
@@ -3091,24 +3113,24 @@ inter_sl(PG_FUNCTION_ARGS)
  * Optimize for non-intersection by checking for box intersection first.
  * - thomas 1998-01-30
  */
 static bool
 box_interpt_lseg(Point *result, BOX *box, LSEG *lseg)
 {
 	BOX			lbox;
 	LSEG		bseg;
 	Point		point;
 
-	lbox.low.x = Min(lseg->p[0].x, lseg->p[1].x);
-	lbox.low.y = Min(lseg->p[0].y, lseg->p[1].y);
-	lbox.high.x = Max(lseg->p[0].x, lseg->p[1].x);
-	lbox.high.y = Max(lseg->p[0].y, lseg->p[1].y);
+	lbox.low.x = float8_min(lseg->p[0].x, lseg->p[1].x);
+	lbox.low.y = float8_min(lseg->p[0].y, lseg->p[1].y);
+	lbox.high.x = float8_max(lseg->p[0].x, lseg->p[1].x);
+	lbox.high.y = float8_max(lseg->p[0].y, lseg->p[1].y);
 
 	/* nothing close to overlap? then not going to intersect */
 	if (!box_ov(&lbox, box))
 		return false;
 
 	if (result != NULL)
 	{
 		box_cn(&point, box);
 		lseg_closept_point(result, lseg, &point);
 	}
@@ -3201,38 +3223,38 @@ inter_lb(PG_FUNCTION_ARGS)
  * make_bound_box - create the bounding box for the input polygon
  *------------------------------------------------------------------*/
 
 /*---------------------------------------------------------------------
  * Make the smallest bounding box for the given polygon.
  *---------------------------------------------------------------------*/
 static void
 make_bound_box(POLYGON *poly)
 {
 	int			i;
-	double		x1,
+	float8		x1,
 				y1,
 				x2,
 				y2;
 
 	Assert(poly->npts > 0);
 
 	x1 = x2 = poly->p[0].x;
 	y2 = y1 = poly->p[0].y;
 	for (i = 1; i < poly->npts; i++)
 	{
-		if (poly->p[i].x < x1)
+		if (float8_lt(poly->p[i].x, x1))
 			x1 = poly->p[i].x;
-		if (poly->p[i].x > x2)
+		if (float8_gt(poly->p[i].x, x2))
 			x2 = poly->p[i].x;
-		if (poly->p[i].y < y1)
+		if (float8_lt(poly->p[i].y, y1))
 			y1 = poly->p[i].y;
-		if (poly->p[i].y > y2)
+		if (float8_gt(poly->p[i].y, y2))
 			y2 = poly->p[i].y;
 	}
 
 	poly->boundbox.low.x = x1;
 	poly->boundbox.high.x = x2;
 	poly->boundbox.low.y = y1;
 	poly->boundbox.high.y = y2;
 }
 
 /*------------------------------------------------------------------
@@ -3731,22 +3753,22 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 	}
 
 	if (res && !intersection)
 	{
 		Point		p;
 
 		/*
 		 * if X-intersection wasn't found  then check central point of tested
 		 * segment. In opposite case we already check all subsegments
 		 */
-		p.x = (t.p[0].x + t.p[1].x) / 2.0;
-		p.y = (t.p[0].y + t.p[1].y) / 2.0;
+		p.x = float8_div(float8_pl(t.p[0].x, t.p[1].x), 2.0);
+		p.y = float8_div(float8_pl(t.p[0].y, t.p[1].y), 2.0);
 
 		res = point_inside(&p, poly->npts, poly->p);
 	}
 
 	return res;
 }
 
 /*-----------------------------------------------------------------
  * Determine if polygon A contains polygon B.
  *-----------------------------------------------------------------*/
@@ -3872,22 +3894,22 @@ construct_point(PG_FUNCTION_ARGS)
 	point_construct(result, x, y);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_add_point(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x + pt2->x,
-					pt1->y + pt2->y);
+					float8_pl(pt1->x, pt2->x),
+					float8_pl(pt1->y, pt2->y));
 }
 
 Datum
 point_add(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -3895,22 +3917,22 @@ point_add(PG_FUNCTION_ARGS)
 	point_add_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_sub_point(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x - pt2->x,
-					pt1->y - pt2->y);
+					float8_mi(pt1->x, pt2->x),
+					float8_mi(pt1->y, pt2->y));
 }
 
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -3918,54 +3940,53 @@ point_sub(PG_FUNCTION_ARGS)
 	point_sub_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_mul_point(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					(pt1->x * pt2->x) - (pt1->y * pt2->y),
-					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+					float8_mi(float8_mul(pt1->x, pt2->x),
+							  float8_mul(pt1->y, pt2->y)),
+					float8_pl(float8_mul(pt1->x, pt2->y),
+							  float8_mul(pt1->y, pt2->x)));
 }
 
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	point_mul_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_div_point(Point *result, Point *pt1, Point *pt2)
 {
-	double		div;
+	float8		div;
 
-	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
-
-	if (div == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
+	div = float8_pl(float8_mul(pt2->x, pt2->x), float8_mul(pt2->y, pt2->y));
 
 	point_construct(result,
-					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
-					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+					float8_div(float8_pl(float8_mul(pt1->x, pt2->x),
+										 float8_mul(pt1->y, pt2->y)), div),
+					float8_div(float8_mi(float8_mul(pt1->y, pt2->x),
+										 float8_mul(pt1->x, pt2->y)), div));
 }
 
 Datum
 point_div(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -4088,24 +4109,24 @@ point_box(PG_FUNCTION_ARGS)
  */
 Datum
 boxes_bound_box(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0),
 			   *box2 = PG_GETARG_BOX_P(1),
 			   *container;
 
 	container = (BOX *) palloc(sizeof(BOX));
 
-	container->high.x = Max(box1->high.x, box2->high.x);
-	container->low.x = Min(box1->low.x, box2->low.x);
-	container->high.y = Max(box1->high.y, box2->high.y);
-	container->low.y = Min(box1->low.y, box2->low.y);
+	container->high.x = float8_max(box1->high.x, box2->high.x);
+	container->low.x = float8_min(box1->low.x, box2->low.x);
+	container->high.y = float8_max(box1->high.y, box2->high.y);
+	container->low.y = float8_min(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(container);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D paths.
  **
  ***********************************************************************/
@@ -4411,21 +4432,22 @@ circle_in(PG_FUNCTION_ARGS)
 		if (*cp == LDELIM)
 			s = cp;
 	}
 
 	pair_decode(s, &circle->center.x, &circle->center.y, &s, "circle", str);
 
 	if (*s == DELIM)
 		s++;
 
 	circle->radius = single_decode(s, &s, "circle", str);
-	if (circle->radius < 0)
+	/* We have to accept NaN. */
+	if (circle->radius < 0.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
 
 	while (depth > 0)
 	{
 		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
@@ -4478,21 +4500,22 @@ circle_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	circle->center.x = pq_getmsgfloat8(buf);
 	circle->center.y = pq_getmsgfloat8(buf);
 	circle->radius = pq_getmsgfloat8(buf);
 
-	if (circle->radius < 0)
+	/* We have to accept NaN. */
+	if (circle->radius < 0.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
 				 errmsg("invalid radius in external \"circle\" value")));
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 /*
  *		circle_send			- converts circle to binary format
  */
@@ -4509,166 +4532,170 @@ circle_send(PG_FUNCTION_ARGS)
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for CIRCLEs.
  *		<, >, <=, >=, and == are based on circle area.
  *---------------------------------------------------------*/
 
 /*		circles identical?
+ *
+ * We consider NaNs values to be equal to each other to let those circles
+ * to be found.
  */
 Datum
 circle_same(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPeq(circle1->radius, circle2->radius) &&
+	PG_RETURN_BOOL(((isnan(circle1->radius) && isnan(circle1->radius)) ||
+					FPeq(circle1->radius, circle2->radius)) &&
 				   point_eq_point(&circle1->center, &circle2->center));
 }
 
 /*		circle_overlap	-		does circle1 overlap circle2?
  */
 Datum
 circle_overlap(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle1->radius + circle2->radius));
+						float8_pl(circle1->radius, circle2->radius)));
 }
 
 /*		circle_overleft -		is the right edge of circle1 at or left of
  *								the right edge of circle2?
  */
 Datum
 circle_overleft(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.x + circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_left		-		is circle1 strictly left of circle2?
  */
 Datum
 circle_left(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.x + circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_right	-		is circle1 strictly right of circle2?
  */
 Datum
 circle_right(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.x - circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_overright	-	is the left edge of circle1 at or right of
  *								the left edge of circle2?
  */
 Datum
 circle_overright(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.x - circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_contained		-		is circle1 contained by circle2?
  */
 Datum
 circle_contained(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle2->radius - circle1->radius));
+						float8_mi(circle2->radius, circle1->radius)));
 }
 
 /*		circle_contain	-		does circle1 contain circle2?
  */
 Datum
 circle_contain(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle1->radius - circle2->radius));
+						float8_mi(circle1->radius, circle2->radius)));
 }
 
 
 /*		circle_below		-		is circle1 strictly below circle2?
  */
 Datum
 circle_below(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.y + circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_above	-		is circle1 strictly above circle2?
  */
 Datum
 circle_above(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.y - circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overbelow -		is the upper edge of circle1 at or below
  *								the upper edge of circle2?
  */
 Datum
 circle_overbelow(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.y + circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overabove	-	is the lower edge of circle1 at or above
  *								the lower edge of circle2?
  */
 Datum
 circle_overabove(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.y - circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 
 /*		circle_relop	-		is area(circle1) relop area(circle2), within
  *								our accuracy constraint?
  */
 Datum
 circle_eq(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
@@ -4767,36 +4794,36 @@ circle_sub_pt(PG_FUNCTION_ARGS)
 Datum
 circle_mul_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_mul_point(&result->center, &circle->center, point);
-	result->radius = circle->radius * HYPOT(point->x, point->y);
+	result->radius = float8_mul(circle->radius, HYPOT(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_div_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_div_point(&result->center, &circle->center, point);
-	result->radius = circle->radius / HYPOT(point->x, point->y);
+	result->radius = float8_div(circle->radius, HYPOT(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /*		circle_area		-		returns the area of the circle.
  */
 Datum
 circle_area(PG_FUNCTION_ARGS)
 {
@@ -4806,21 +4833,21 @@ circle_area(PG_FUNCTION_ARGS)
 }
 
 
 /*		circle_diameter -		returns the diameter of the circle.
  */
 Datum
 circle_diameter(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
-	PG_RETURN_FLOAT8(2 * circle->radius);
+	PG_RETURN_FLOAT8(float8_mul(circle->radius, 2.0));
 }
 
 
 /*		circle_radius	-		returns the radius of the circle.
  */
 Datum
 circle_radius(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
@@ -4831,81 +4858,85 @@ circle_radius(PG_FUNCTION_ARGS)
 /*		circle_distance -		returns the distance between
  *								  two circles.
  */
 Datum
 circle_distance(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(&circle1->center, &circle2->center) -
-		(circle1->radius + circle2->radius);
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(&circle1->center, &circle2->center),
+					   float8_pl(circle1->radius, circle2->radius));
+	if (result < 0.0)
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 
 Datum
 circle_contain_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
 	PG_RETURN_BOOL(d <= circle->radius);
 }
 
 
 Datum
 pt_contained_circle(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
 	PG_RETURN_BOOL(d <= circle->radius);
 }
 
 
 /*		dist_pc -		returns the distance between
  *						  a point and a circle.
  */
 Datum
 dist_pc(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center),
+					   circle->radius);
+	if (result < 0.0)
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a circle to a point
  */
 Datum
 dist_cpoint(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center), circle->radius);
+	if (result < 0.0)
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*		circle_center	-		returns the center point of the circle.
  */
 Datum
 circle_center(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *result;
@@ -4913,24 +4944,24 @@ circle_center(PG_FUNCTION_ARGS)
 	result = (Point *) palloc(sizeof(Point));
 	result->x = circle->center.x;
 	result->y = circle->center.y;
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		circle_ar		-		returns the area of the circle.
  */
-static double
+static float8
 circle_ar(CIRCLE *circle)
 {
-	return M_PI * (circle->radius * circle->radius);
+	return float8_mul(float8_mul(circle->radius, circle->radius), M_PI);
 }
 
 
 /*----------------------------------------------------------
  *	Conversion operators.
  *---------------------------------------------------------*/
 
 Datum
 cr_circle(PG_FUNCTION_ARGS)
 {
@@ -4945,65 +4976,65 @@ cr_circle(PG_FUNCTION_ARGS)
 	result->radius = radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_box(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	BOX		   *box;
-	double		delta;
+	float8		delta;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
-	delta = circle->radius / sqrt(2.0);
+	delta = float8_div(circle->radius, sqrt(2.0));
 
-	box->high.x = circle->center.x + delta;
-	box->low.x = circle->center.x - delta;
-	box->high.y = circle->center.y + delta;
-	box->low.y = circle->center.y - delta;
+	box->high.x = float8_pl(circle->center.x, delta);
+	box->low.x = float8_mi(circle->center.x, delta);
+	box->high.y = float8_pl(circle->center.y, delta);
+	box->low.y = float8_mi(circle->center.y, delta);
 
 	PG_RETURN_BOX_P(box);
 }
 
 /* box_circle()
  * Convert a box to a circle.
  */
 Datum
 box_circle(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	circle->center.x = (box->high.x + box->low.x) / 2;
-	circle->center.y = (box->high.y + box->low.y) / 2;
+	circle->center.x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	circle->center.y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 
 	circle->radius = point_dt(&circle->center, &box->high);
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 
 Datum
 circle_poly(PG_FUNCTION_ARGS)
 {
 	int32		npts = PG_GETARG_INT32(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	POLYGON    *poly;
 	int			base_size,
 				size;
 	int			i;
-	double		angle;
-	double		anglestep;
+	float8		angle;
+	float8		anglestep;
 
 	if (FPzero(circle->radius))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("cannot convert circle with radius zero to polygon")));
 
 	if (npts < 2)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("must request at least 2 points")));
@@ -5014,27 +5045,30 @@ circle_poly(PG_FUNCTION_ARGS)
 	/* Check for integer overflow */
 	if (base_size / npts != sizeof(poly->p[0]) || size <= base_size)
 		ereport(ERROR,
 				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 				 errmsg("too many points requested")));
 
 	poly = (POLYGON *) palloc0(size);	/* zero any holes */
 	SET_VARSIZE(poly, size);
 	poly->npts = npts;
 
-	anglestep = (2.0 * M_PI) / npts;
+	anglestep = float8_div(2.0 * M_PI, npts);
 
 	for (i = 0; i < npts; i++)
 	{
-		angle = i * anglestep;
-		poly->p[i].x = circle->center.x - (circle->radius * cos(angle));
-		poly->p[i].y = circle->center.y + (circle->radius * sin(angle));
+		angle = float8_mul(anglestep, i);
+
+		poly->p[i].x = float8_mi(circle->center.x,
+								 float8_mul(circle->radius, cos(angle)));
+		poly->p[i].y = float8_pl(circle->center.y,
+								 float8_mul(circle->radius, sin(angle)));
 	}
 
 	make_bound_box(poly);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
 /*
  * Convert polygon to circle
  *
@@ -5049,26 +5083,27 @@ poly_to_circle(CIRCLE *result, POLYGON *poly)
 	int			i;
 
 	Assert(poly->npts > 0);
 
 	result->center.x = 0;
 	result->center.y = 0;
 	result->radius = 0;
 
 	for (i = 0; i < poly->npts; i++)
 		point_add_point(&result->center, &result->center, &poly->p[i]);
-	result->center.x /= poly->npts;
-	result->center.y /= poly->npts;
+	result->center.x = float8_div(result->center.x, poly->npts);
+	result->center.y = float8_div(result->center.y, poly->npts);
 
 	for (i = 0; i < poly->npts; i++)
-		result->radius += point_dt(&poly->p[i], &result->center);
-	result->radius /= poly->npts;
+		result->radius = float8_pl(result->radius,
+								   point_dt(&poly->p[i], &result->center));
+	result->radius = float8_div(result->radius, poly->npts);
 }
 
 Datum
 poly_circle(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
@@ -5093,44 +5128,44 @@ poly_circle(PG_FUNCTION_ARGS)
  *	http://hopf.math.northwestern.edu/index.html
  *	Description of algorithm:  http://www.linuxjournal.com/article/2197
  *							   http://www.linuxjournal.com/article/2029
  */
 
 #define POINT_ON_POLYGON INT_MAX
 
 static int
 point_inside(Point *p, int npts, Point *plist)
 {
-	double		x0,
+	float8		x0,
 				y0;
-	double		prev_x,
+	float8		prev_x,
 				prev_y;
 	int			i = 0;
-	double		x,
+	float8		x,
 				y;
 	int			cross,
 				total_cross = 0;
 
 	Assert(npts > 0);
 
 	/* compute first polygon point relative to single point */
-	x0 = plist[0].x - p->x;
-	y0 = plist[0].y - p->y;
+	x0 = float8_mi(plist[0].x, p->x);
+	y0 = float8_mi(plist[0].y, p->y);
 
 	prev_x = x0;
 	prev_y = y0;
 	/* loop over polygon points and aggregate total_cross */
 	for (i = 1; i < npts; i++)
 	{
 		/* compute next polygon point relative to single point */
-		x = plist[i].x - p->x;
-		y = plist[i].y - p->y;
+		x = float8_mi(plist[i].x, p->x);
+		y = float8_mi(plist[i].y, p->y);
 
 		/* compute previous to current point crossing */
 		if ((cross = lseg_crossing(x, y, prev_x, prev_y)) == POINT_ON_POLYGON)
 			return 2;
 		total_cross += cross;
 
 		prev_x = x;
 		prev_y = y;
 	}
 
@@ -5148,69 +5183,74 @@ point_inside(Point *p, int npts, Point *plist)
 /* lseg_crossing()
  * Returns +/-2 if line segment crosses the positive X-axis in a +/- direction.
  * Returns +/-1 if one point is on the positive X-axis.
  * Returns 0 if both points are on the positive X-axis, or there is no crossing.
  * Returns POINT_ON_POLYGON if the segment contains (0,0).
  * Wow, that is one confusing API, but it is used above, and when summed,
  * can tell is if a point is in a polygon.
  */
 
 static int
-lseg_crossing(double x, double y, double prev_x, double prev_y)
+lseg_crossing(float8 x, float8 y, float8 prev_x, float8 prev_y)
 {
-	double		z;
+	float8		z;
 	int			y_sign;
 
 	if (FPzero(y))
 	{							/* y == 0, on X axis */
 		if (FPzero(x))			/* (x,y) is (0,0)? */
 			return POINT_ON_POLYGON;
 		else if (FPgt(x, 0))
 		{						/* x > 0 */
 			if (FPzero(prev_y)) /* y and prev_y are zero */
 				/* prev_x > 0? */
-				return FPgt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
-			return FPlt(prev_y, 0) ? 1 : -1;
+				return FPgt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
+			return FPlt(prev_y, 0.0) ? 1 : -1;
 		}
 		else
 		{						/* x < 0, x not on positive X axis */
 			if (FPzero(prev_y))
 				/* prev_x < 0? */
-				return FPlt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
+				return FPlt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
 			return 0;
 		}
 	}
 	else
 	{							/* y != 0 */
 		/* compute y crossing direction from previous point */
-		y_sign = FPgt(y, 0) ? 1 : -1;
+		y_sign = FPgt(y, 0.0) ? 1 : -1;
 
 		if (FPzero(prev_y))
 			/* previous point was on X axis, so new point is either off or on */
-			return FPlt(prev_x, 0) ? 0 : y_sign;
-		else if (FPgt(y_sign * prev_y, 0))
+			return FPlt(prev_x, 0.0) ? 0 : y_sign;
+		else if ((y_sign < 0 && FPlt(prev_y, 0.0)) ||
+				 (y_sign > 0 && FPgt(prev_y, 0.0)))
 			/* both above or below X axis */
 			return 0;			/* same sign */
 		else
 		{						/* y and prev_y cross X-axis */
-			if (FPge(x, 0) && FPgt(prev_x, 0))
+			if (FPge(x, 0.0) && FPgt(prev_x, 0.0))
 				/* both non-negative so cross positive X-axis */
 				return 2 * y_sign;
-			if (FPlt(x, 0) && FPle(prev_x, 0))
+			if (FPlt(x, 0.0) && FPle(prev_x, 0.0))
 				/* both non-positive so do not cross positive X-axis */
 				return 0;
 
 			/* x and y cross axises, see URL above point_inside() */
-			z = (x - prev_x) * y - (y - prev_y) * x;
+			z = float8_mi(float8_mul(float8_mi(x, prev_x), y),
+						  float8_mul(float8_mi(y, prev_y), x));
 			if (FPzero(z))
 				return POINT_ON_POLYGON;
-			return FPgt((y_sign * z), 0) ? 0 : 2 * y_sign;
+			if ((y_sign < 0 && FPlt(z, 0.0)) ||
+				(y_sign > 0 && FPgt(z, 0.0)))
+				return 0;
+			return 2 * y_sign;
 		}
 	}
 }
 
 
 static bool
 plist_same(int npts, Point *p1, Point *p2)
 {
 	int			i,
 				ii,
@@ -5280,47 +5320,52 @@ plist_same(int npts, Point *p1, Point *p2)
  *					 = x * sqrt( 1 + y^2/x^2 )
  *					 = x * sqrt( 1 + y/x * y/x )
  *
  * It is expected that this routine will eventually be replaced with the
  * C99 hypot() function.
  *
  * This implementation conforms to IEEE Std 1003.1 and GLIBC, in that the
  * case of hypot(inf,nan) results in INF, and not NAN.
  *-----------------------------------------------------------------------
  */
-double
-pg_hypot(double x, double y)
+float8
+pg_hypot(float8 x, float8 y)
 {
-	double		yx;
+	float8		yx,
+				result;
 
 	/* Handle INF and NaN properly */
 	if (isinf(x) || isinf(y))
 		return get_float8_infinity();
 
 	if (isnan(x) || isnan(y))
 		return get_float8_nan();
 
 	/* Else, drop any minus signs */
 	x = fabs(x);
 	y = fabs(y);
 
 	/* Swap x and y if needed to make x the larger one */
 	if (x < y)
 	{
-		double		temp = x;
+		float8		temp = x;
 
 		x = y;
 		y = temp;
 	}
 
 	/*
 	 * If y is zero, the hypotenuse is x.  This test saves a few cycles in
 	 * such cases, but more importantly it also protects against
 	 * divide-by-zero errors, since now x >= y.
 	 */
 	if (y == 0.0)
 		return x;
 
 	/* Determine the hypotenuse */
 	yx = y / x;
-	return x * sqrt(1.0 + (yx * yx));
+	result = x * sqrt(1.0 + (yx * yx));
+
+	check_float8_val(result, false, false);
+
+	return result;
 }
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index 5489ed9585..17e24b9628 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -76,38 +76,38 @@
 #include "access/spgist.h"
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
 #include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
- * is going only going to be used in a place to effect the performance
+ * is only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
 compareDoubles(const void *a, const void *b)
 {
-	double		x = *(double *) a;
-	double		y = *(double *) b;
+	float8		x = *(float8 *) a;
+	float8		y = *(float8 *) b;
 
 	if (x == y)
 		return 0;
 	return (x > y) ? 1 : -1;
 }
 
 typedef struct
 {
-	double		low;
-	double		high;
+	float8		low;
+	float8		high;
 } Range;
 
 typedef struct
 {
 	Range		left;
 	Range		right;
 } RangeBox;
 
 typedef struct
 {
@@ -167,21 +167,21 @@ getRangeBox(BOX *box)
 /*
  * Initialize the traversal value
  *
  * In the beginning, we don't have any restrictions.  We have to
  * initialize the struct to cover the whole 4D space.
  */
 static RectBox *
 initRectBox(void)
 {
 	RectBox    *rect_box = (RectBox *) palloc(sizeof(RectBox));
-	double		infinity = get_float8_infinity();
+	float8		infinity = get_float8_infinity();
 
 	rect_box->range_box_x.left.low = -infinity;
 	rect_box->range_box_x.left.high = infinity;
 
 	rect_box->range_box_x.right.low = -infinity;
 	rect_box->range_box_x.right.high = infinity;
 
 	rect_box->range_box_y.left.low = -infinity;
 	rect_box->range_box_y.left.high = infinity;
 
@@ -410,40 +410,40 @@ spg_box_quad_choose(PG_FUNCTION_ARGS)
  * point as the median of the coordinates of the boxes.
  */
 Datum
 spg_box_quad_picksplit(PG_FUNCTION_ARGS)
 {
 	spgPickSplitIn *in = (spgPickSplitIn *) PG_GETARG_POINTER(0);
 	spgPickSplitOut *out = (spgPickSplitOut *) PG_GETARG_POINTER(1);
 	BOX		   *centroid;
 	int			median,
 				i;
-	double	   *lowXs = palloc(sizeof(double) * in->nTuples);
-	double	   *highXs = palloc(sizeof(double) * in->nTuples);
-	double	   *lowYs = palloc(sizeof(double) * in->nTuples);
-	double	   *highYs = palloc(sizeof(double) * in->nTuples);
+	float8	   *lowXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *lowYs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highYs = palloc(sizeof(float8) * in->nTuples);
 
 	/* Calculate median of all 4D coordinates */
 	for (i = 0; i < in->nTuples; i++)
 	{
 		BOX		   *box = DatumGetBoxP(in->datums[i]);
 
 		lowXs[i] = box->low.x;
 		highXs[i] = box->high.x;
 		lowYs[i] = box->low.y;
 		highYs[i] = box->high.y;
 	}
 
-	qsort(lowXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(lowYs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highYs, in->nTuples, sizeof(double), compareDoubles);
+	qsort(lowXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(lowYs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highYs, in->nTuples, sizeof(float8), compareDoubles);
 
 	median = in->nTuples / 2;
 
 	centroid = palloc(sizeof(BOX));
 
 	centroid->low.x = lowXs[median];
 	centroid->high.x = highXs[median];
 	centroid->low.y = lowYs[median];
 	centroid->high.y = highYs[median];
 
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index aeb31515e4..d14e8c8f72 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -1,42 +1,41 @@
 /*-------------------------------------------------------------------------
  *
  * geo_decls.h - Declarations for various 2D constructs.
  *
  *
  * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * src/include/utils/geo_decls.h
  *
- * NOTE
- *	  These routines do *not* use the float types from adt/.
- *
  *	  XXX These routines were not written by a numerical analyst.
  *
  *	  XXX I have made some attempt to flesh out the operators
  *		and data types. There are still some more to do. - tgl 97/04/19
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEO_DECLS_H
 #define GEO_DECLS_H
 
 #include <math.h>
 
 #include "fmgr.h"
 #include "utils/float.h"
 
 /*--------------------------------------------------------------------
  * Useful floating point utilities and constants.
- *-------------------------------------------------------------------*/
-
+ *-------------------------------------------------------------------
+ *
+ * XXX They are not NaN-aware.
+ */
 
 #define EPSILON					1.0E-06
 
 #ifdef EPSILON
 #define FPzero(A)				(fabs(A) <= EPSILON)
 #define FPeq(A,B)				(fabs((A) - (B)) <= EPSILON)
 #define FPne(A,B)				(fabs((A) - (B)) > EPSILON)
 #define FPlt(A,B)				((B) - (A) > EPSILON)
 #define FPle(A,B)				((A) - (B) <= EPSILON)
 #define FPgt(A,B)				((A) - (B) > EPSILON)
@@ -51,21 +50,21 @@
 #define FPge(A,B)				((A) >= (B))
 #endif
 
 #define HYPOT(A, B)				pg_hypot(A, B)
 
 /*---------------------------------------------------------------------
  * Point - (x,y)
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		x,
+	float8		x,
 				y;
 } Point;
 
 
 /*---------------------------------------------------------------------
  * LSEG - A straight line, specified by endpoints.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		p[2];
@@ -83,21 +82,21 @@ typedef struct
 	int32		dummy;			/* padding to make it double align */
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } PATH;
 
 
 /*---------------------------------------------------------------------
  * LINE - Specified by its general equation (Ax+By+C=0).
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		A,
+	float8		A,
 				B,
 				C;
 } LINE;
 
 
 /*---------------------------------------------------------------------
  * BOX	- Specified by two corner points, which are
  *		 sorted to save calculation time later.
  *-------------------------------------------------------------------*/
 typedef struct
@@ -118,21 +117,21 @@ typedef struct
 	BOX			boundbox;
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } POLYGON;
 
 /*---------------------------------------------------------------------
  * CIRCLE - Specified by a center point and radius.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		center;
-	double		radius;
+	float8		radius;
 } CIRCLE;
 
 /*
  * fmgr interface macros
  *
  * Path and Polygon are toastable varlena types, the others are just
  * fixed-size pass-by-reference types.
  */
 
 #define DatumGetPointP(X)	 ((Point *) DatumGetPointer(X))
@@ -172,13 +171,13 @@ typedef struct
 #define DatumGetCircleP(X)	  ((CIRCLE *) DatumGetPointer(X))
 #define CirclePGetDatum(X)	  PointerGetDatum(X)
 #define PG_GETARG_CIRCLE_P(n) DatumGetCircleP(PG_GETARG_DATUM(n))
 #define PG_RETURN_CIRCLE_P(x) return CirclePGetDatum(x)
 
 
 /*
  * in geo_ops.c
  */
 
-extern double pg_hypot(double x, double y);
+extern float8 pg_hypot(float8 x, float8 y);
 
 #endif							/* GEO_DECLS_H */
-- 
2.14.3 (Apple Git-98)

0004-line-fixes-v09.patchapplication/octet-stream; name=0004-line-fixes-v09.patchDownload
From a807dab4ec595865c817dcbc1a3d9702971b2d7e Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sun, 28 May 2017 11:35:17 +0200
Subject: [PATCH 4/6] line-fixes-v09

Fix obvious problems around the line datatype

I have noticed some line operators retuning wrong results, and Tom Lane
spotted similar problems on more places.  Source history reveals that
during 1990s, the internal format of the line datatype is changed, but
most functions haven't got the hint.  The fixes include:

* Reject invalid specification A=B=0 on receive
* Reject same points on line_construct_pp()
* Fix perpendicular operator when negative values are involved
* Avoid division by zero on perpendicular operator
* Fix intersection and distance operators when neither A nor B are 1
* Return NULL for closest point when objects are parallel
* Check whether closest point of line segments is the intersection point
* Fix closest point of line segments being on the wrong segment

The changes are also aiming make line operators more symmetric and less
sensitive to floating point precision loss.  The EPSILON interferes with
every minor change in different ways.  It is hard to guess which
behaviour is more expected, but we can assume threating both sides of
the operators more equally is more expected.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com

Parallel discussions:

* https://www.postgresql.org/message-id/CAE2gYzw_-z%3DV2kh8QqFjenu%3D8MJXzOP44wRW%3DAzzeamrmTT1%3DQ%40mail.gmail.com
* https://www.postgresql.org/message-id/20180201.205138.34583581.horiguchi.kyotaro@lab.ntt.co.jp
---
 src/backend/utils/adt/geo_ops.c | 159 ++++++++++++++++++++++++++--------------
 1 file changed, 106 insertions(+), 53 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index df185affcb..d5d4797b3f 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -40,20 +40,21 @@ static inline void point_add_point(Point *result, Point *pt1, Point *pt2);
 static inline void point_sub_point(Point *result, Point *pt1, Point *pt2);
 static inline void point_mul_point(Point *result, Point *pt1, Point *pt2);
 static inline void point_div_point(Point *result, Point *pt1, Point *pt2);
 static inline bool point_eq_point(Point *pt1, Point *pt2);
 static inline float8 point_dt(Point *pt1, Point *pt2);
 static inline float8 point_sl(Point *pt1, Point *pt2);
 static int	point_inside(Point *p, int npts, Point *plist);
 
 /* Routines for lines */
 static inline void line_construct(LINE *result, Point *pt, float8 m);
+static inline float8 line_sl(LINE *line);
 static inline float8 line_invsl(LINE *line);
 static bool	line_interpt_line(Point *result, LINE *l1, LINE *l2);
 static bool line_contain_point(LINE *line, Point *point);
 static float8 line_closept_point(Point *result, LINE *line, Point *pt);
 
 /* Routines for line segments */
 static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
 static inline float8 lseg_sl(LSEG *lseg);
 static inline float8 lseg_invsl(LSEG *lseg);
 static bool	lseg_interpt_line(Point *result, LSEG *lseg, LINE *line);
@@ -972,20 +973,25 @@ line_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LINE	   *line;
 
 	line = (LINE *) palloc(sizeof(LINE));
 
 	line->A = pq_getmsgfloat8(buf);
 	line->B = pq_getmsgfloat8(buf);
 	line->C = pq_getmsgfloat8(buf);
 
+	if (FPzero(line->A) && FPzero(line->B))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("invalid line specification: A and B cannot both be zero")));
+
 	PG_RETURN_LINE_P(line);
 }
 
 /*
  *		line_send			- converts line to binary format
  */
 Datum
 line_send(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -1029,20 +1035,25 @@ line_construct(LINE *result, Point *pt, float8 m)
 /* line_construct_pp()
  * two points
  */
 Datum
 line_construct_pp(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 	LINE	   *result = (LINE *) palloc(sizeof(LINE));
 
+	if (point_eq_point(pt1, pt2))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("invalid line specification: must be two distinct points")));
+
 	line_construct(result, pt1, point_sl(pt1, pt2));
 
 	PG_RETURN_LINE_P(result);
 }
 
 
 /*----------------------------------------------------------
  *	Relative position routines.
  *---------------------------------------------------------*/
 
@@ -1065,25 +1076,29 @@ line_parallel(PG_FUNCTION_ARGS)
 }
 
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
-	else if (FPzero(l1->B))
+	if (FPzero(l2->A))
+		PG_RETURN_BOOL(FPzero(l1->B));
+	if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
+	if (FPzero(l2->B))
+		PG_RETURN_BOOL(FPzero(l1->A));
 
-	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
-								   float8_mul(l1->B, l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->A),
+								   float8_mul(l1->B, l2->B)), -1.0));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
@@ -1124,20 +1139,34 @@ line_eq(PG_FUNCTION_ARGS)
 				   (float8_eq(l1->A, l2->A) &&
 					float8_eq(l1->B, l2->B) &&
 					float8_eq(l1->C, l2->C)));
 }
 
 
 /*----------------------------------------------------------
  *	Line arithmetic routines.
  *---------------------------------------------------------*/
 
+/*
+ * Return slope of the line
+ */
+static inline float8
+line_sl(LINE *line)
+{
+	if (FPzero(line->A))
+		return 0.0;
+	if (FPzero(line->B))
+		return DBL_MAX;
+	return float8_div(line->A, -line->B);
+}
+
+
 /*
  * Return inverse slope of the line
  */
 static inline float8
 line_invsl(LINE *line)
 {
 	if (FPzero(line->A))
 		return DBL_MAX;
 	if (FPzero(line->B))
 		return 0.0;
@@ -1146,30 +1175,35 @@ line_invsl(LINE *line)
 
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	float8		result;
-	Point		tmp;
+	float8		ratio;
 
 	if (line_interpt_line(NULL, l1, l2))	/* intersecting? */
 		PG_RETURN_FLOAT8(0.0);
-	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
-	point_construct(&tmp, 0.0, l1->C);
-	result = line_closept_point(NULL, l2, &tmp);
-	PG_RETURN_FLOAT8(result);
+
+	if (!FPzero(l1->A) && !isnan(l1->A) && !FPzero(l2->A) && !isnan(l2->A))
+		ratio = float8_div(l1->A, l2->A);
+	else if (!FPzero(l1->B) && !isnan(l1->B) && !FPzero(l2->B) && !isnan(l2->B))
+		ratio = float8_div(l1->B, l2->B);
+	else
+		ratio = 1.0;
+
+	PG_RETURN_FLOAT8(float8_div(fabs(float8_mi(l1->C,
+											   float8_mul(ratio, l2->C))),
+								HYPOT(l1->A, l1->B)));
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
@@ -1196,41 +1230,44 @@ line_interpt(PG_FUNCTION_ARGS)
  * If the lines have NaN constants, we will return true, and the intersection
  * point would have NaN coordinates.  We shouldn't return false in this case
  * because that would mean the lines are parallel.
  */
 static bool
 line_interpt_line(Point *result, LINE *l1, LINE *l2)
 {
 	float8		x,
 				y;
 
-	if (FPzero(l1->B))			/* l1 vertical? */
-	{
-		if (FPzero(l2->B))		/* l2 vertical? */
-			return false;
-
-		x = l1->C;
-		y = float8_pl(float8_mul(l2->A, x), l2->C);
-	}
-	else if (FPzero(l2->B))		/* l2 vertical? */
-	{
-		x = l2->C;
-		y = float8_pl(float8_mul(l1->A, x), l1->C);
-	}
-	else
+	if (!FPzero(l1->B))
 	{
 		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
 			return false;
 
-		x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
-		y = float8_pl(float8_mul(l1->A, x), l1->C);
+		x = float8_div(float8_mi(float8_mul(l1->B, l2->C),
+								 float8_mul(l2->B, l1->C)),
+					   float8_mi(float8_mul(l1->A, l2->B),
+								 float8_mul(l2->A, l1->B)));
+		y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
 	}
+	else if (!FPzero(l2->B))
+	{
+		if (FPeq(l1->A, float8_mul(l2->A, float8_div(l1->B, l2->B))))
+			return false;
+
+		x = float8_div(float8_mi(float8_mul(l2->B, l1->C),
+								 float8_mul(l1->B, l2->C)),
+					   float8_mi(float8_mul(l2->A, l1->B),
+								 float8_mul(l1->A, l2->B)));
+		y = float8_div(-float8_pl(float8_mul(l2->A, x), l2->C), l2->B);
+	}
+	else
+		return false;
 
 	if (result != NULL)
 		point_construct(result, x, y);
 
 	return true;
 }
 
 
 /***********************************************************************
  **
@@ -2336,30 +2373,22 @@ dist_pb(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
-	float8		result;
 
-	if (lseg_interpt_line(NULL, lseg, line))
-		result = 0.0;
-	else
-		/* XXX shouldn't we take the min not max? */
-		result = float8_max(line_closept_point(NULL, line, &lseg->p[0]),
-							line_closept_point(NULL, line, &lseg->p[1]));
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(lseg_closept_line(NULL, lseg, line));
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
@@ -2533,33 +2562,40 @@ lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
 /*
  *		The intersection point of a perpendicular of the line
  *		through the point.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 line_closept_point(Point *result, LINE *line, Point *point)
 {
-	bool		retval;
-	Point       closept;
+	Point		closept;
 	LINE		tmp;
 
-	/* We drop a perpendicular to find the intersection point. */
+	/*
+	 * We drop a perpendicular to find the intersection point.  Ordinarily
+	 * we should always find it, but that can fail in the presence of NaN
+	 * coordinates, and perhaps even from simple roundoff issues.
+	 */
 	line_construct(&tmp, point, line_invsl(line));
-	retval = line_interpt_line(&closept, line, &tmp);
-	Assert(retval);		/* XXX: We need something better. */
+	if (!line_interpt_line(&closept, &tmp, line))
+	{
+		if (result != NULL)
+			*result = *point;
+
+		return get_float8_nan();
+	}
 
 	if (result != NULL)
 		*result = closept;
 
-	/* Then we calculate the distance between the points. */
 	return point_dt(&closept, point);
 }
 
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
@@ -2619,52 +2655,66 @@ close_ps(PG_FUNCTION_ARGS)
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
 {
 	Point		point;
 	float8		dist,
 				d;
 
-	d = lseg_closept_point(NULL, l1, &l2->p[0]);
-	dist = d;
-	if (result != NULL)
-		*result = l2->p[0];
+	/* First, we handle the case when the line segments are intersecting. */
+	if (lseg_interpt_lseg(result, l1, l2))
+		return 0.0;
 
-	d = lseg_closept_point(NULL, l1, &l2->p[1]);
+	/*
+	 * Then, we find the closest points from the endpoints of the second
+	 * line segment, and keep the closest one.
+	 */
+	dist = lseg_closept_point(result, l1, &l2->p[0]);
+	d = lseg_closept_point(&point, l1, &l2->p[1]);
 	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
-			*result = l2->p[1];
+			*result = point;
 	}
 
-	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[0]), dist))
-		d = lseg_closept_point(result, l1, &point);
-
-	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[1]), dist))
-		d = lseg_closept_point(result, l1, &point);
-
+	/* The closest point can still be one of the endpoints, so we test them. */
+	d = lseg_closept_point(NULL, l2, &l1->p[0]);
 	if (float8_lt(d, dist))
+	{
 		dist = d;
+		if (result != NULL)
+			*result = l1->p[0];
+	}
+	d = lseg_closept_point(NULL, l2, &l1->p[1]);
+	if (float8_lt(d, dist))
+	{
+		dist = d;
+		if (result != NULL)
+			*result = l1->p[1];
+	}
 
 	return dist;
 }
 
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
+	if (lseg_sl(l1) == lseg_sl(l2))
+		PG_RETURN_NULL();
+
 	result = (Point *) palloc(sizeof(Point));
 
 	if (isnan(lseg_closept_lseg(result, l2, l1)))
 		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
@@ -2825,20 +2875,23 @@ lseg_closept_line(Point *result, LSEG *lseg, LINE *line)
 	}
 }
 
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
+	if (lseg_sl(lseg) == line_sl(line))
+		PG_RETURN_NULL();
+
 	result = (Point *) palloc(sizeof(Point));
 
 	if (isnan(lseg_closept_line(result, lseg, line)))
 		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
-- 
2.14.3 (Apple Git-98)

0005-float-zero-v05.patchapplication/octet-stream; name=0005-float-zero-v05.patchDownload
From 5b859f00b0580c4a3259403a13ecf18b4f183474 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Thu, 2 Nov 2017 12:21:19 +0100
Subject: [PATCH 5/6] float-zero-v05

Check for float -0 after multiplications and divisions

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com
---
 src/include/utils/float.h | 26 ++++++++++++++++++++------
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/src/include/utils/float.h b/src/include/utils/float.h
index 0e8483c930..e359d8a3d4 100644
--- a/src/include/utils/float.h
+++ b/src/include/utils/float.h
@@ -209,69 +209,83 @@ float8_mi(const float8 val1, const float8 val2)
 
 	result = val1 - val2;
 	check_float8_val(result, isinf(val1) || isinf(val2), true);
 
 	return result;
 }
 
 static inline float4
 float4_mul(const float4 val1, const float4 val2)
 {
+	const bool	zero_is_valid = val1 == 0.0f || val2 == 0.0f;
 	float4		result;
 
 	result = val1 * val2;
-	check_float4_val(result, isinf(val1) || isinf(val2),
-					 val1 == 0.0f || val2 == 0.0f);
+	check_float4_val(result, isinf(val1) || isinf(val2), zero_is_valid);
+
+	if (zero_is_valid && unlikely(result == -0.0f))
+		result = 0.0f;
 
 	return result;
 }
 
 static inline float8
 float8_mul(const float8 val1, const float8 val2)
 {
+	const bool	zero_is_valid = val1 == 0.0 || val2 == 0.0;
 	float8		result;
 
 	result = val1 * val2;
-	check_float8_val(result, isinf(val1) || isinf(val2),
-					 val1 == 0.0 || val2 == 0.0);
+	check_float8_val(result, isinf(val1) || isinf(val2), zero_is_valid);
+
+	if (zero_is_valid && unlikely(result == -0.0))
+		result = 0.0;
 
 	return result;
 }
 
 static inline float4
 float4_div(const float4 val1, const float4 val2)
 {
+	const bool	zero_is_valid = val1 == 0.0f;
 	float4		result;
 
 	if (val2 == 0.0f)
 		ereport(ERROR,
 				(errcode(ERRCODE_DIVISION_BY_ZERO),
 				 errmsg("division by zero")));
 
 	result = val1 / val2;
-	check_float4_val(result, isinf(val1) || isinf(val2), val1 == 0.0f);
+	check_float4_val(result, isinf(val1) || isinf(val2), zero_is_valid);
+
+	if (zero_is_valid && unlikely(result == -0.0f))
+		result = 0.0f;
 
 	return result;
 }
 
 static inline float8
 float8_div(const float8 val1, const float8 val2)
 {
+	const bool	zero_is_valid = val1 == 0.0;
 	float8		result;
 
 	if (val2 == 0.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_DIVISION_BY_ZERO),
 				 errmsg("division by zero")));
 
 	result = val1 / val2;
-	check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
+	check_float8_val(result, isinf(val1) || isinf(val2), zero_is_valid);
+
+	if (zero_is_valid && unlikely(result == -0.0))
+		result = 0.0;
 
 	return result;
 }
 
 /*
  * Routines for NaN-aware comparisons
  *
  * We consider all NaNs to be equal and larger than any non-NaN. This is
  * somewhat arbitrary; the important thing is to have a consistent sort
  * order.
-- 
2.14.3 (Apple Git-98)

0006-geo-tests-v05.patchapplication/octet-stream; name=0006-geo-tests-v05.patchDownload
From d30ef367368d46eb4fa020733bf78f53e3dd6173 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Tue, 24 Oct 2017 11:28:21 +0200
Subject: [PATCH 6/6] geo-tests-v05

Improve test coverage of geometric types

The tests for the geometric functions and operators were in sad state.
This commit increases test coverage of geo_ops.c significantly.  It
removes the alternative results to expect -0 on some platforms.  We
better try to return the same results on different platforms, but if we
can't we can add them back using the results from build farm.

The tests are added to geometric.sql file.  It is not clear where to
put them as there are many cross datatype operators.  Organising them
on a single file sorted by the left hand side of the operators appear
to be a simple solution.  We may take this further and remove the other
tests later.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com
---
 src/test/regress/expected/box.out          |   44 +-
 src/test/regress/expected/circle.out       |   39 +-
 src/test/regress/expected/create_index.out |   73 +-
 src/test/regress/expected/geometry.out     | 4879 ++++++++++++++++++++++++++--
 src/test/regress/expected/geometry_1.out   |  563 ----
 src/test/regress/expected/geometry_2.out   |  563 ----
 src/test/regress/expected/line.out         |  272 +-
 src/test/regress/expected/lseg.out         |   24 +-
 src/test/regress/expected/path.out         |   49 +-
 src/test/regress/expected/point.out        |  358 +-
 src/test/regress/expected/polygon.out      |  200 +-
 src/test/regress/sql/box.sql               |    9 +
 src/test/regress/sql/circle.sql            |   10 +-
 src/test/regress/sql/geometry.sql          |  400 ++-
 src/test/regress/sql/line.sql              |   79 +-
 src/test/regress/sql/lseg.sql              |    9 +-
 src/test/regress/sql/path.sql              |   22 +-
 src/test/regress/sql/point.sql             |   10 +
 src/test/regress/sql/polygon.sql           |   91 +-
 19 files changed, 5483 insertions(+), 2211 deletions(-)
 delete mode 100644 src/test/regress/expected/geometry_1.out
 delete mode 100644 src/test/regress/expected/geometry_2.out

diff --git a/src/test/regress/expected/box.out b/src/test/regress/expected/box.out
index 49af242c8c..998b52223c 100644
--- a/src/test/regress/expected/box.out
+++ b/src/test/regress/expected/box.out
@@ -11,92 +11,109 @@
 -- 1	| o-+-o
 --	|   |
 -- 0	+---+
 --
 --	0 1 2 3
 --
 -- boxes are specified by two points, given by four floats x1,y1,x2,y2
 CREATE TABLE BOX_TBL (f1 box);
 INSERT INTO BOX_TBL (f1) VALUES ('(2.0,2.0,0.0,0.0)');
 INSERT INTO BOX_TBL (f1) VALUES ('(1.0,1.0,3.0,3.0)');
+INSERT INTO BOX_TBL (f1) VALUES ('((-8, 2), (-2, -10))');
 -- degenerate cases where the box is a line or a point
 -- note that lines and points boxes all have zero area
 INSERT INTO BOX_TBL (f1) VALUES ('(2.5, 2.5, 2.5,3.5)');
 INSERT INTO BOX_TBL (f1) VALUES ('(3.0, 3.0,3.0,3.0)');
 -- badly formatted box inputs
 INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
 ERROR:  invalid input syntax for type box: "(2.3, 4.5)"
 LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
                                          ^
+INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+ERROR:  invalid input syntax for type box: "[1, 2, 3, 4)"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+                                         ^
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+ERROR:  invalid input syntax for type box: "(1, 2, 3, 4]"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+                                         ^
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+ERROR:  invalid input syntax for type box: "(1, 2, 3, 4) x"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+                                         ^
 INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
 ERROR:  invalid input syntax for type box: "asdfasdf(ad"
 LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
                                          ^
 SELECT '' AS four, * FROM BOX_TBL;
  four |         f1          
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
+      | (-2,2),(-8,-10)
       | (2.5,3.5),(2.5,2.5)
       | (3,3),(3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, b.*, area(b.f1) as barea
    FROM BOX_TBL b;
  four |         f1          | barea 
 ------+---------------------+-------
       | (2,2),(0,0)         |     4
       | (3,3),(1,1)         |     4
+      | (-2,2),(-8,-10)     |    72
       | (2.5,3.5),(2.5,2.5) |     0
       | (3,3),(3,3)         |     0
-(4 rows)
+(5 rows)
 
 -- overlap
 SELECT '' AS three, b.f1
    FROM BOX_TBL b
    WHERE b.f1 && box '(2.5,2.5,1.0,1.0)';
  three |         f1          
 -------+---------------------
        | (2,2),(0,0)
        | (3,3),(1,1)
        | (2.5,3.5),(2.5,2.5)
 (3 rows)
 
 -- left-or-overlap (x only)
 SELECT '' AS two, b1.*
    FROM BOX_TBL b1
    WHERE b1.f1 &< box '(2.0,2.0,2.5,2.5)';
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- right-or-overlap (x only)
 SELECT '' AS two, b1.*
    FROM BOX_TBL b1
    WHERE b1.f1 &> box '(2.0,2.0,2.5,2.5)';
  two |         f1          
 -----+---------------------
      | (2.5,3.5),(2.5,2.5)
      | (3,3),(3,3)
 (2 rows)
 
 -- left of
 SELECT '' AS two, b.f1
    FROM BOX_TBL b
    WHERE b.f1 << box '(3.0,3.0,5.0,5.0)';
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- area <=
 SELECT '' AS four, b.f1
    FROM BOX_TBL b
    WHERE b.f1 <= box '(3.0,3.0,5.0,5.0)';
  four |         f1          
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
       | (2.5,3.5),(2.5,2.5)
@@ -120,47 +137,50 @@ SELECT '' AS two, b.f1
  two |     f1      
 -----+-------------
      | (2,2),(0,0)
      | (3,3),(1,1)
 (2 rows)
 
 -- area >
 SELECT '' AS two, b.f1
    FROM BOX_TBL b				-- zero area
    WHERE b.f1 > box '(3.5,3.0,4.5,3.0)';
- two |     f1      
------+-------------
+ two |       f1        
+-----+-----------------
      | (2,2),(0,0)
      | (3,3),(1,1)
-(2 rows)
+     | (-2,2),(-8,-10)
+(3 rows)
 
 -- area >=
 SELECT '' AS four, b.f1
    FROM BOX_TBL b				-- zero area
    WHERE b.f1 >= box '(3.5,3.0,4.5,3.0)';
  four |         f1          
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
+      | (-2,2),(-8,-10)
       | (2.5,3.5),(2.5,2.5)
       | (3,3),(3,3)
-(4 rows)
+(5 rows)
 
 -- right of
 SELECT '' AS two, b.f1
    FROM BOX_TBL b
    WHERE box '(3.0,3.0,5.0,5.0)' >> b.f1;
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- contained in
 SELECT '' AS three, b.f1
    FROM BOX_TBL b
    WHERE b.f1 <@ box '(0,0,3,3)';
  three |     f1      
 -------+-------------
        | (2,2),(0,0)
        | (3,3),(1,1)
        | (3,3),(3,3)
@@ -186,41 +206,43 @@ SELECT '' AS one, b.f1
      | (3,3),(1,1)
 (1 row)
 
 -- center of box, left unary operator
 SELECT '' AS four, @@(b1.f1) AS p
    FROM BOX_TBL b1;
  four |    p    
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 -- wholly-contained
 SELECT '' AS one, b1.*, b2.*
    FROM BOX_TBL b1, BOX_TBL b2
    WHERE b1.f1 @> b2.f1 and not b1.f1 ~= b2.f1;
  one |     f1      |     f1      
 -----+-------------+-------------
      | (3,3),(1,1) | (3,3),(3,3)
 (1 row)
 
 SELECT '' AS four, height(f1), width(f1) FROM BOX_TBL;
  four | height | width 
 ------+--------+-------
       |      2 |     2
       |      2 |     2
+      |     12 |     6
       |      1 |     0
       |      0 |     0
-(4 rows)
+(5 rows)
 
 --
 -- Test the SP-GiST index
 --
 CREATE TEMPORARY TABLE box_temp (f1 box);
 INSERT INTO box_temp
 	SELECT box(point(i, i), point(i * 2, i * 2))
 	FROM generate_series(1, 50) AS i;
 CREATE INDEX box_spgist ON box_temp USING spgist (f1);
 INSERT INTO box_temp
diff --git a/src/test/regress/expected/circle.out b/src/test/regress/expected/circle.out
index 9ba4a0495d..2ed74cc6aa 100644
--- a/src/test/regress/expected/circle.out
+++ b/src/test/regress/expected/circle.out
@@ -1,99 +1,122 @@
 --
 -- CIRCLE
 --
 CREATE TABLE CIRCLE_TBL (f1 circle);
 INSERT INTO CIRCLE_TBL VALUES ('<(5,1),3>');
 INSERT INTO CIRCLE_TBL VALUES ('<(1,2),100>');
 INSERT INTO CIRCLE_TBL VALUES ('1,3,5');
 INSERT INTO CIRCLE_TBL VALUES ('((1,2),3)');
 INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10>');
-INSERT INTO CIRCLE_TBL VALUES ('<(100,1),115>');
+INSERT INTO CIRCLE_TBL VALUES (' < ( 100 , 1 ) , 115 > ');
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),0>');	-- Zero radius
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),NaN>');	-- NaN radius
 -- bad values
 INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
 ERROR:  invalid input syntax for type circle: "<(-100,0),-100>"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
                                        ^
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+ERROR:  invalid input syntax for type circle: "<(100,200),10"
+LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+                                       ^
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+ERROR:  invalid input syntax for type circle: "<(100,200),10> x"
+LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+                                       ^
 INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
 ERROR:  invalid input syntax for type circle: "1abc,3,5"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
                                        ^
 INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
 ERROR:  invalid input syntax for type circle: "(3,(1,2),3)"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
                                        ^
 SELECT * FROM CIRCLE_TBL;
        f1       
 ----------------
  <(5,1),3>
  <(1,2),100>
  <(1,3),5>
  <(1,2),3>
  <(100,200),10>
  <(100,1),115>
-(6 rows)
+ <(3,5),0>
+ <(3,5),NaN>
+(8 rows)
 
 SELECT '' AS six, center(f1) AS center
   FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS six, radius(f1) AS radius
   FROM CIRCLE_TBL;
  six | radius 
 -----+--------
      |      3
      |    100
      |      5
      |      3
      |     10
      |    115
-(6 rows)
+     |      0
+     |    NaN
+(8 rows)
 
 SELECT '' AS six, diameter(f1) AS diameter
   FROM CIRCLE_TBL;
  six | diameter 
 -----+----------
      |        6
      |      200
      |       10
      |        6
      |       20
      |      230
-(6 rows)
+     |        0
+     |      NaN
+(8 rows)
 
 SELECT '' AS two, f1 FROM CIRCLE_TBL WHERE radius(f1) < 5;
  two |    f1     
 -----+-----------
      | <(5,1),3>
      | <(1,2),3>
-(2 rows)
+     | <(3,5),0>
+(3 rows)
 
 SELECT '' AS four, f1 FROM CIRCLE_TBL WHERE diameter(f1) >= 10;
  four |       f1       
 ------+----------------
       | <(1,2),100>
       | <(1,3),5>
       | <(100,200),10>
       | <(100,1),115>
-(4 rows)
+      | <(3,5),NaN>
+(5 rows)
 
 SELECT '' as five, c1.f1 AS one, c2.f1 AS two, (c1.f1 <-> c2.f1) AS distance
   FROM CIRCLE_TBL c1, CIRCLE_TBL c2
   WHERE (c1.f1 < c2.f1) AND ((c1.f1 <-> c2.f1) > 0)
   ORDER BY distance, area(c1.f1), area(c2.f1);
  five |      one       |      two       |     distance     
 ------+----------------+----------------+------------------
+      | <(3,5),0>      | <(1,2),3>      | 0.60555127546399
+      | <(3,5),0>      | <(5,1),3>      | 1.47213595499958
       | <(100,200),10> | <(100,1),115>  |               74
       | <(100,200),10> | <(1,2),100>    | 111.370729772479
       | <(1,3),5>      | <(100,200),10> | 205.476756144497
       | <(5,1),3>      | <(100,200),10> |  207.51303816328
+      | <(3,5),0>      | <(100,200),10> | 207.793480159531
       | <(1,2),3>      | <(100,200),10> | 208.370729772479
-(5 rows)
+(8 rows)
 
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc81088d4b..4e5f573349 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -150,96 +150,103 @@ SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)';
 
 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
+     5
 (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
+     3
 (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
+     4
 (1 row)
 
 SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
  count 
 -------
      1
 (1 row)
 
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
  (-5,-12)
  (5.1,34.5)
+ (1e+300,Infinity)
+ (NaN,NaN)
  
-(7 rows)
+(10 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NULL;
  f1 
 ----
  
 (1 row)
 
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (1e-300,-1e-300)
  (0,0)
  (-3,4)
  (-10,0)
  (10,10)
  (-5,-12)
  (5.1,34.5)
-(6 rows)
+ (1e+300,Infinity)
+ (NaN,NaN)
+(9 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
  count 
 -------
      3
 (1 row)
 
 SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
  count 
 -------
@@ -567,21 +574,21 @@ SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,
                                        QUERY PLAN                                       
 ----------------------------------------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     4
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>';
                      QUERY PLAN                     
 ----------------------------------------------------
  Aggregate
    ->  Index Only Scan using gpointind on point_tbl
          Index Cond: (f1 <@ '<(50,50),50>'::circle)
 (3 rows)
@@ -612,21 +619,21 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     3
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl p WHERE p.f1 <^ '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only Scan using gpointind on point_tbl p
          Index Cond: (f1 <^ '(0,0)'::point)
 (3 rows)
@@ -642,21 +649,21 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 >^ '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     4
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only Scan using gpointind on point_tbl p
          Index Cond: (f1 ~= '(-5,-12)'::point)
 (3 rows)
@@ -669,30 +676,33 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
                   QUERY PLAN                  
 ----------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Order By: (f1 <-> '(0,1)'::point)
 (2 rows)
 
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (10,10)
+ (NaN,NaN)
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
- (10,10)
  (-5,-12)
  (5.1,34.5)
  
-(7 rows)
+ (1e+300,Infinity)
+(10 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 IS NULL;
                   QUERY PLAN                  
 ----------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Index Cond: (f1 IS NULL)
 (2 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NULL;
@@ -704,47 +714,51 @@ SELECT * FROM point_tbl WHERE f1 IS NULL;
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
                   QUERY PLAN                  
 ----------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Index Cond: (f1 IS NOT NULL)
    Order By: (f1 <-> '(0,1)'::point)
 (3 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (10,10)
+ (NaN,NaN)
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
- (10,10)
  (-5,-12)
  (5.1,34.5)
-(6 rows)
+ (1e+300,Infinity)
+(9 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
                    QUERY PLAN                   
 ------------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Index Cond: (f1 <@ '(10,10),(-10,-10)'::box)
    Order By: (f1 <-> '(0,1)'::point)
 (3 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
                         QUERY PLAN                         
 -----------------------------------------------------------
  Aggregate
    ->  Index Only Scan using sp_quad_ind on quad_point_tbl
          Index Cond: (p IS NULL)
 (3 rows)
 
@@ -1261,27 +1275,28 @@ SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0
 ------------------------------------------------------------
  Sort
    Sort Key: ((f1 <-> '(0,1)'::point))
    ->  Bitmap Heap Scan on point_tbl
          Recheck Cond: (f1 <@ '(10,10),(-10,-10)'::box)
          ->  Bitmap Index Scan on gpointind
                Index Cond: (f1 <@ '(10,10),(-10,-10)'::box)
 (6 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
                   QUERY PLAN                  
 ----------------------------------------------
  Aggregate
    ->  Bitmap Heap Scan on quad_point_tbl
          Recheck Cond: (p IS NULL)
          ->  Bitmap Index Scan on sp_quad_ind
                Index Cond: (p IS NULL)
diff --git a/src/test/regress/expected/geometry.out b/src/test/regress/expected/geometry.out
index e4c0039040..b4da3baa37 100644
--- a/src/test/regress/expected/geometry.out
+++ b/src/test/regress/expected/geometry.out
@@ -6,558 +6,4885 @@
 SET extra_float_digits TO -3;
 --
 -- Points
 --
 SELECT '' AS four, center(f1) AS center
    FROM BOX_TBL;
  four | center  
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, (@@ f1) AS center
    FROM BOX_TBL;
  four | center  
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS six, point(f1) AS center
    FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS six, (@@ f1) AS center
    FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS two, (@@ f1) AS center
    FROM POLYGON_TBL
    WHERE (# f1) > 2;
  two |            center             
 -----+-------------------------------
      | (1.33333333333,1.33333333333)
      | (2.33333333333,1.33333333333)
-(2 rows)
+     | (4,5)
+     | (4,5)
+     | (4,3)
+(5 rows)
 
 -- "is horizontal" function
 SELECT '' AS two, p1.f1
    FROM POINT_TBL p1
    WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 -- "is horizontal" operator
 SELECT '' AS two, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 -- "is vertical" function
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE isvertical(p1.f1, point '(5.1,34.5)');
  one |     f1     
 -----+------------
      | (5.1,34.5)
 (1 row)
 
 -- "is vertical" operator
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?| point '(5.1,34.5)';
  one |     f1     
 -----+------------
      | (5.1,34.5)
 (1 row)
 
+-- Slope
+SELECT p1.f1, p2.f1, slope(p1.f1, p2.f1) FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |       slope        
+-------------------+-------------------+--------------------
+ (0,0)             | (0,0)             | 1.79769313486e+308
+ (0,0)             | (-10,0)           |                  0
+ (0,0)             | (-3,4)            |     -1.33333333333
+ (0,0)             | (5.1,34.5)        |      6.76470588235
+ (0,0)             | (-5,-12)          |                2.4
+ (0,0)             | (1e-300,-1e-300)  | 1.79769313486e+308
+ (0,0)             | (1e+300,Infinity) |           Infinity
+ (0,0)             | (NaN,NaN)         |                NaN
+ (0,0)             | (10,10)           |                  1
+ (-10,0)           | (0,0)             |                  0
+ (-10,0)           | (-10,0)           | 1.79769313486e+308
+ (-10,0)           | (-3,4)            |     0.571428571429
+ (-10,0)           | (5.1,34.5)        |      2.28476821192
+ (-10,0)           | (-5,-12)          |               -2.4
+ (-10,0)           | (1e-300,-1e-300)  |                  0
+ (-10,0)           | (1e+300,Infinity) |           Infinity
+ (-10,0)           | (NaN,NaN)         |                NaN
+ (-10,0)           | (10,10)           |                0.5
+ (-3,4)            | (0,0)             |     -1.33333333333
+ (-3,4)            | (-10,0)           |     0.571428571429
+ (-3,4)            | (-3,4)            | 1.79769313486e+308
+ (-3,4)            | (5.1,34.5)        |      3.76543209877
+ (-3,4)            | (-5,-12)          |                  8
+ (-3,4)            | (1e-300,-1e-300)  |     -1.33333333333
+ (-3,4)            | (1e+300,Infinity) |           Infinity
+ (-3,4)            | (NaN,NaN)         |                NaN
+ (-3,4)            | (10,10)           |     0.461538461538
+ (5.1,34.5)        | (0,0)             |      6.76470588235
+ (5.1,34.5)        | (-10,0)           |      2.28476821192
+ (5.1,34.5)        | (-3,4)            |      3.76543209877
+ (5.1,34.5)        | (5.1,34.5)        | 1.79769313486e+308
+ (5.1,34.5)        | (-5,-12)          |      4.60396039604
+ (5.1,34.5)        | (1e-300,-1e-300)  |      6.76470588235
+ (5.1,34.5)        | (1e+300,Infinity) |           Infinity
+ (5.1,34.5)        | (NaN,NaN)         |                NaN
+ (5.1,34.5)        | (10,10)           |                 -5
+ (-5,-12)          | (0,0)             |                2.4
+ (-5,-12)          | (-10,0)           |               -2.4
+ (-5,-12)          | (-3,4)            |                  8
+ (-5,-12)          | (5.1,34.5)        |      4.60396039604
+ (-5,-12)          | (-5,-12)          | 1.79769313486e+308
+ (-5,-12)          | (1e-300,-1e-300)  |                2.4
+ (-5,-12)          | (1e+300,Infinity) |           Infinity
+ (-5,-12)          | (NaN,NaN)         |                NaN
+ (-5,-12)          | (10,10)           |      1.46666666667
+ (1e-300,-1e-300)  | (0,0)             | 1.79769313486e+308
+ (1e-300,-1e-300)  | (-10,0)           |                  0
+ (1e-300,-1e-300)  | (-3,4)            |     -1.33333333333
+ (1e-300,-1e-300)  | (5.1,34.5)        |      6.76470588235
+ (1e-300,-1e-300)  | (-5,-12)          |                2.4
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | 1.79769313486e+308
+ (1e-300,-1e-300)  | (1e+300,Infinity) |           Infinity
+ (1e-300,-1e-300)  | (NaN,NaN)         |                NaN
+ (1e-300,-1e-300)  | (10,10)           |                  1
+ (1e+300,Infinity) | (0,0)             |           Infinity
+ (1e+300,Infinity) | (-10,0)           |           Infinity
+ (1e+300,Infinity) | (-3,4)            |           Infinity
+ (1e+300,Infinity) | (5.1,34.5)        |           Infinity
+ (1e+300,Infinity) | (-5,-12)          |           Infinity
+ (1e+300,Infinity) | (1e-300,-1e-300)  |           Infinity
+ (1e+300,Infinity) | (1e+300,Infinity) | 1.79769313486e+308
+ (1e+300,Infinity) | (NaN,NaN)         |                NaN
+ (1e+300,Infinity) | (10,10)           |           Infinity
+ (NaN,NaN)         | (0,0)             |                NaN
+ (NaN,NaN)         | (-10,0)           |                NaN
+ (NaN,NaN)         | (-3,4)            |                NaN
+ (NaN,NaN)         | (5.1,34.5)        |                NaN
+ (NaN,NaN)         | (-5,-12)          |                NaN
+ (NaN,NaN)         | (1e-300,-1e-300)  |                NaN
+ (NaN,NaN)         | (1e+300,Infinity) |                NaN
+ (NaN,NaN)         | (NaN,NaN)         |                NaN
+ (NaN,NaN)         | (10,10)           |                NaN
+ (10,10)           | (0,0)             |                  1
+ (10,10)           | (-10,0)           |                0.5
+ (10,10)           | (-3,4)            |     0.461538461538
+ (10,10)           | (5.1,34.5)        |                 -5
+ (10,10)           | (-5,-12)          |      1.46666666667
+ (10,10)           | (1e-300,-1e-300)  |                  1
+ (10,10)           | (1e+300,Infinity) |           Infinity
+ (10,10)           | (NaN,NaN)         |                NaN
+ (10,10)           | (10,10)           | 1.79769313486e+308
+(81 rows)
+
+-- Add point
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |     ?column?      
+-------------------+-------------------+-------------------
+ (0,0)             | (0,0)             | (0,0)
+ (0,0)             | (-10,0)           | (-10,0)
+ (0,0)             | (-3,4)            | (-3,4)
+ (0,0)             | (5.1,34.5)        | (5.1,34.5)
+ (0,0)             | (-5,-12)          | (-5,-12)
+ (0,0)             | (1e-300,-1e-300)  | (1e-300,-1e-300)
+ (0,0)             | (1e+300,Infinity) | (1e+300,Infinity)
+ (0,0)             | (NaN,NaN)         | (NaN,NaN)
+ (0,0)             | (10,10)           | (10,10)
+ (-10,0)           | (0,0)             | (-10,0)
+ (-10,0)           | (-10,0)           | (-20,0)
+ (-10,0)           | (-3,4)            | (-13,4)
+ (-10,0)           | (5.1,34.5)        | (-4.9,34.5)
+ (-10,0)           | (-5,-12)          | (-15,-12)
+ (-10,0)           | (1e-300,-1e-300)  | (-10,-1e-300)
+ (-10,0)           | (1e+300,Infinity) | (1e+300,Infinity)
+ (-10,0)           | (NaN,NaN)         | (NaN,NaN)
+ (-10,0)           | (10,10)           | (0,10)
+ (-3,4)            | (0,0)             | (-3,4)
+ (-3,4)            | (-10,0)           | (-13,4)
+ (-3,4)            | (-3,4)            | (-6,8)
+ (-3,4)            | (5.1,34.5)        | (2.1,38.5)
+ (-3,4)            | (-5,-12)          | (-8,-8)
+ (-3,4)            | (1e-300,-1e-300)  | (-3,4)
+ (-3,4)            | (1e+300,Infinity) | (1e+300,Infinity)
+ (-3,4)            | (NaN,NaN)         | (NaN,NaN)
+ (-3,4)            | (10,10)           | (7,14)
+ (5.1,34.5)        | (0,0)             | (5.1,34.5)
+ (5.1,34.5)        | (-10,0)           | (-4.9,34.5)
+ (5.1,34.5)        | (-3,4)            | (2.1,38.5)
+ (5.1,34.5)        | (5.1,34.5)        | (10.2,69)
+ (5.1,34.5)        | (-5,-12)          | (0.1,22.5)
+ (5.1,34.5)        | (1e-300,-1e-300)  | (5.1,34.5)
+ (5.1,34.5)        | (1e+300,Infinity) | (1e+300,Infinity)
+ (5.1,34.5)        | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5)        | (10,10)           | (15.1,44.5)
+ (-5,-12)          | (0,0)             | (-5,-12)
+ (-5,-12)          | (-10,0)           | (-15,-12)
+ (-5,-12)          | (-3,4)            | (-8,-8)
+ (-5,-12)          | (5.1,34.5)        | (0.1,22.5)
+ (-5,-12)          | (-5,-12)          | (-10,-24)
+ (-5,-12)          | (1e-300,-1e-300)  | (-5,-12)
+ (-5,-12)          | (1e+300,Infinity) | (1e+300,Infinity)
+ (-5,-12)          | (NaN,NaN)         | (NaN,NaN)
+ (-5,-12)          | (10,10)           | (5,-2)
+ (1e-300,-1e-300)  | (0,0)             | (1e-300,-1e-300)
+ (1e-300,-1e-300)  | (-10,0)           | (-10,-1e-300)
+ (1e-300,-1e-300)  | (-3,4)            | (-3,4)
+ (1e-300,-1e-300)  | (5.1,34.5)        | (5.1,34.5)
+ (1e-300,-1e-300)  | (-5,-12)          | (-5,-12)
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | (2e-300,-2e-300)
+ (1e-300,-1e-300)  | (1e+300,Infinity) | (1e+300,Infinity)
+ (1e-300,-1e-300)  | (NaN,NaN)         | (NaN,NaN)
+ (1e-300,-1e-300)  | (10,10)           | (10,10)
+ (1e+300,Infinity) | (0,0)             | (1e+300,Infinity)
+ (1e+300,Infinity) | (-10,0)           | (1e+300,Infinity)
+ (1e+300,Infinity) | (-3,4)            | (1e+300,Infinity)
+ (1e+300,Infinity) | (5.1,34.5)        | (1e+300,Infinity)
+ (1e+300,Infinity) | (-5,-12)          | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e-300,-1e-300)  | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e+300,Infinity) | (2e+300,Infinity)
+ (1e+300,Infinity) | (NaN,NaN)         | (NaN,NaN)
+ (1e+300,Infinity) | (10,10)           | (1e+300,Infinity)
+ (NaN,NaN)         | (0,0)             | (NaN,NaN)
+ (NaN,NaN)         | (-10,0)           | (NaN,NaN)
+ (NaN,NaN)         | (-3,4)            | (NaN,NaN)
+ (NaN,NaN)         | (5.1,34.5)        | (NaN,NaN)
+ (NaN,NaN)         | (-5,-12)          | (NaN,NaN)
+ (NaN,NaN)         | (1e-300,-1e-300)  | (NaN,NaN)
+ (NaN,NaN)         | (1e+300,Infinity) | (NaN,NaN)
+ (NaN,NaN)         | (NaN,NaN)         | (NaN,NaN)
+ (NaN,NaN)         | (10,10)           | (NaN,NaN)
+ (10,10)           | (0,0)             | (10,10)
+ (10,10)           | (-10,0)           | (0,10)
+ (10,10)           | (-3,4)            | (7,14)
+ (10,10)           | (5.1,34.5)        | (15.1,44.5)
+ (10,10)           | (-5,-12)          | (5,-2)
+ (10,10)           | (1e-300,-1e-300)  | (10,10)
+ (10,10)           | (1e+300,Infinity) | (1e+300,Infinity)
+ (10,10)           | (NaN,NaN)         | (NaN,NaN)
+ (10,10)           | (10,10)           | (20,20)
+(81 rows)
+
+-- Subtract point
+SELECT p1.f1, p2.f1, p1.f1 - p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |      ?column?       
+-------------------+-------------------+---------------------
+ (0,0)             | (0,0)             | (0,0)
+ (0,0)             | (-10,0)           | (10,0)
+ (0,0)             | (-3,4)            | (3,-4)
+ (0,0)             | (5.1,34.5)        | (-5.1,-34.5)
+ (0,0)             | (-5,-12)          | (5,12)
+ (0,0)             | (1e-300,-1e-300)  | (-1e-300,1e-300)
+ (0,0)             | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (0,0)             | (NaN,NaN)         | (NaN,NaN)
+ (0,0)             | (10,10)           | (-10,-10)
+ (-10,0)           | (0,0)             | (-10,0)
+ (-10,0)           | (-10,0)           | (0,0)
+ (-10,0)           | (-3,4)            | (-7,-4)
+ (-10,0)           | (5.1,34.5)        | (-15.1,-34.5)
+ (-10,0)           | (-5,-12)          | (-5,12)
+ (-10,0)           | (1e-300,-1e-300)  | (-10,1e-300)
+ (-10,0)           | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-10,0)           | (NaN,NaN)         | (NaN,NaN)
+ (-10,0)           | (10,10)           | (-20,-10)
+ (-3,4)            | (0,0)             | (-3,4)
+ (-3,4)            | (-10,0)           | (7,4)
+ (-3,4)            | (-3,4)            | (0,0)
+ (-3,4)            | (5.1,34.5)        | (-8.1,-30.5)
+ (-3,4)            | (-5,-12)          | (2,16)
+ (-3,4)            | (1e-300,-1e-300)  | (-3,4)
+ (-3,4)            | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-3,4)            | (NaN,NaN)         | (NaN,NaN)
+ (-3,4)            | (10,10)           | (-13,-6)
+ (5.1,34.5)        | (0,0)             | (5.1,34.5)
+ (5.1,34.5)        | (-10,0)           | (15.1,34.5)
+ (5.1,34.5)        | (-3,4)            | (8.1,30.5)
+ (5.1,34.5)        | (5.1,34.5)        | (0,0)
+ (5.1,34.5)        | (-5,-12)          | (10.1,46.5)
+ (5.1,34.5)        | (1e-300,-1e-300)  | (5.1,34.5)
+ (5.1,34.5)        | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (5.1,34.5)        | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5)        | (10,10)           | (-4.9,24.5)
+ (-5,-12)          | (0,0)             | (-5,-12)
+ (-5,-12)          | (-10,0)           | (5,-12)
+ (-5,-12)          | (-3,4)            | (-2,-16)
+ (-5,-12)          | (5.1,34.5)        | (-10.1,-46.5)
+ (-5,-12)          | (-5,-12)          | (0,0)
+ (-5,-12)          | (1e-300,-1e-300)  | (-5,-12)
+ (-5,-12)          | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-5,-12)          | (NaN,NaN)         | (NaN,NaN)
+ (-5,-12)          | (10,10)           | (-15,-22)
+ (1e-300,-1e-300)  | (0,0)             | (1e-300,-1e-300)
+ (1e-300,-1e-300)  | (-10,0)           | (10,-1e-300)
+ (1e-300,-1e-300)  | (-3,4)            | (3,-4)
+ (1e-300,-1e-300)  | (5.1,34.5)        | (-5.1,-34.5)
+ (1e-300,-1e-300)  | (-5,-12)          | (5,12)
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | (0,0)
+ (1e-300,-1e-300)  | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (1e-300,-1e-300)  | (NaN,NaN)         | (NaN,NaN)
+ (1e-300,-1e-300)  | (10,10)           | (-10,-10)
+ (1e+300,Infinity) | (0,0)             | (1e+300,Infinity)
+ (1e+300,Infinity) | (-10,0)           | (1e+300,Infinity)
+ (1e+300,Infinity) | (-3,4)            | (1e+300,Infinity)
+ (1e+300,Infinity) | (5.1,34.5)        | (1e+300,Infinity)
+ (1e+300,Infinity) | (-5,-12)          | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e-300,-1e-300)  | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e+300,Infinity) | (0,NaN)
+ (1e+300,Infinity) | (NaN,NaN)         | (NaN,NaN)
+ (1e+300,Infinity) | (10,10)           | (1e+300,Infinity)
+ (NaN,NaN)         | (0,0)             | (NaN,NaN)
+ (NaN,NaN)         | (-10,0)           | (NaN,NaN)
+ (NaN,NaN)         | (-3,4)            | (NaN,NaN)
+ (NaN,NaN)         | (5.1,34.5)        | (NaN,NaN)
+ (NaN,NaN)         | (-5,-12)          | (NaN,NaN)
+ (NaN,NaN)         | (1e-300,-1e-300)  | (NaN,NaN)
+ (NaN,NaN)         | (1e+300,Infinity) | (NaN,NaN)
+ (NaN,NaN)         | (NaN,NaN)         | (NaN,NaN)
+ (NaN,NaN)         | (10,10)           | (NaN,NaN)
+ (10,10)           | (0,0)             | (10,10)
+ (10,10)           | (-10,0)           | (20,10)
+ (10,10)           | (-3,4)            | (13,6)
+ (10,10)           | (5.1,34.5)        | (4.9,-24.5)
+ (10,10)           | (-5,-12)          | (15,22)
+ (10,10)           | (1e-300,-1e-300)  | (10,10)
+ (10,10)           | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (10,10)           | (NaN,NaN)         | (NaN,NaN)
+ (10,10)           | (10,10)           | (0,0)
+(81 rows)
+
+-- Multiply with point
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+     f1     |        f1         |       ?column?        
+------------+-------------------+-----------------------
+ (5.1,34.5) | (0,0)             | (0,0)
+ (10,10)    | (0,0)             | (0,0)
+ (5.1,34.5) | (-10,0)           | (-51,-345)
+ (10,10)    | (-10,0)           | (-100,-100)
+ (5.1,34.5) | (-3,4)            | (-153.3,-83.1)
+ (10,10)    | (-3,4)            | (-70,10)
+ (5.1,34.5) | (5.1,34.5)        | (-1164.24,351.9)
+ (10,10)    | (5.1,34.5)        | (-294,396)
+ (5.1,34.5) | (-5,-12)          | (388.5,-233.7)
+ (10,10)    | (-5,-12)          | (70,-170)
+ (5.1,34.5) | (1e-300,-1e-300)  | (3.96e-299,2.94e-299)
+ (10,10)    | (1e-300,-1e-300)  | (2e-299,0)
+ (5.1,34.5) | (1e+300,Infinity) | (-Infinity,Infinity)
+ (10,10)    | (1e+300,Infinity) | (-Infinity,Infinity)
+ (5.1,34.5) | (NaN,NaN)         | (NaN,NaN)
+ (10,10)    | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5) | (10,10)           | (-294,396)
+ (10,10)    | (10,10)           | (0,200)
+(18 rows)
+
+-- Underflow error
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] < 1;
+ERROR:  value out of range: underflow
+-- Divide by point
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] BETWEEN 1 AND 1000;
+        f1         |     f1     |                 ?column?                  
+-------------------+------------+-------------------------------------------
+ (0,0)             | (5.1,34.5) | (0,0)
+ (0,0)             | (10,10)    | (0,0)
+ (-10,0)           | (5.1,34.5) | (-0.0419318237877,0.283656455034)
+ (-10,0)           | (10,10)    | (-0.5,0.5)
+ (-3,4)            | (5.1,34.5) | (0.100883034877,0.101869666025)
+ (-3,4)            | (10,10)    | (0.05,0.35)
+ (5.1,34.5)        | (5.1,34.5) | (1,0)
+ (5.1,34.5)        | (10,10)    | (1.98,1.47)
+ (-5,-12)          | (5.1,34.5) | (-0.361353657935,0.0915100389719)
+ (-5,-12)          | (10,10)    | (-0.85,-0.35)
+ (1e-300,-1e-300)  | (5.1,34.5) | (-2.41724631247e-302,-3.25588278822e-302)
+ (1e-300,-1e-300)  | (10,10)    | (0,-1e-301)
+ (1e+300,Infinity) | (5.1,34.5) | (Infinity,Infinity)
+ (1e+300,Infinity) | (10,10)    | (Infinity,Infinity)
+ (NaN,NaN)         | (5.1,34.5) | (NaN,NaN)
+ (NaN,NaN)         | (10,10)    | (NaN,NaN)
+ (10,10)           | (5.1,34.5) | (0.325588278822,-0.241724631247)
+ (10,10)           | (10,10)    | (1,0)
+(18 rows)
+
+-- Overflow error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] > 1000;
+ERROR:  value out of range: overflow
+-- Division by 0 error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to line
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LINE_TBL l;
+        f1         |                   s                   |      ?column?      
+-------------------+---------------------------------------+--------------------
+ (0,0)             | {0,-1,5}                              |                  5
+ (0,0)             | {1,0,5}                               |                  5
+ (0,0)             | {0,3,0}                               |                  0
+ (0,0)             | {1,-1,0}                              |                  0
+ (0,0)             | {-0.4,-1,-6}                          |      5.57086014531
+ (0,0)             | {-0.000184615384615,-1,15.3846153846} |      15.3846151224
+ (0,0)             | {3,NaN,5}                             |                NaN
+ (0,0)             | {NaN,NaN,NaN}                         |                NaN
+ (0,0)             | {0,-1,3}                              |                  3
+ (0,0)             | {-1,0,3}                              |                  3
+ (-10,0)           | {0,-1,5}                              |                  5
+ (-10,0)           | {1,0,5}                               |                  5
+ (-10,0)           | {0,3,0}                               |                  0
+ (-10,0)           | {1,-1,0}                              |      7.07106781187
+ (-10,0)           | {-0.4,-1,-6}                          |      1.85695338177
+ (-10,0)           | {-0.000184615384615,-1,15.3846153846} |      15.3864612763
+ (-10,0)           | {3,NaN,5}                             |                NaN
+ (-10,0)           | {NaN,NaN,NaN}                         |                NaN
+ (-10,0)           | {0,-1,3}                              |                  3
+ (-10,0)           | {-1,0,3}                              |                 13
+ (-3,4)            | {0,-1,5}                              |                  1
+ (-3,4)            | {1,0,5}                               |                  2
+ (-3,4)            | {0,3,0}                               |                  4
+ (-3,4)            | {1,-1,0}                              |      4.94974746831
+ (-3,4)            | {-0.4,-1,-6}                          |      8.17059487979
+ (-3,4)            | {-0.000184615384615,-1,15.3846153846} |      11.3851690368
+ (-3,4)            | {3,NaN,5}                             |                NaN
+ (-3,4)            | {NaN,NaN,NaN}                         |                NaN
+ (-3,4)            | {0,-1,3}                              |                  1
+ (-3,4)            | {-1,0,3}                              |                  6
+ (5.1,34.5)        | {0,-1,5}                              |               29.5
+ (5.1,34.5)        | {1,0,5}                               |               10.1
+ (5.1,34.5)        | {0,3,0}                               |               34.5
+ (5.1,34.5)        | {1,-1,0}                              |      20.7889393669
+ (5.1,34.5)        | {-0.4,-1,-6}                          |      39.4973984303
+ (5.1,34.5)        | {-0.000184615384615,-1,15.3846153846} |      19.1163258281
+ (5.1,34.5)        | {3,NaN,5}                             |                NaN
+ (5.1,34.5)        | {NaN,NaN,NaN}                         |                NaN
+ (5.1,34.5)        | {0,-1,3}                              |               31.5
+ (5.1,34.5)        | {-1,0,3}                              |                2.1
+ (-5,-12)          | {0,-1,5}                              |                 17
+ (-5,-12)          | {1,0,5}                               |                  0
+ (-5,-12)          | {0,3,0}                               |                 12
+ (-5,-12)          | {1,-1,0}                              |      4.94974746831
+ (-5,-12)          | {-0.4,-1,-6}                          |      7.42781352708
+ (-5,-12)          | {-0.000184615384615,-1,15.3846153846} |      27.3855379948
+ (-5,-12)          | {3,NaN,5}                             |                NaN
+ (-5,-12)          | {NaN,NaN,NaN}                         |                NaN
+ (-5,-12)          | {0,-1,3}                              |                 15
+ (-5,-12)          | {-1,0,3}                              |                  8
+ (1e-300,-1e-300)  | {0,-1,5}                              |                  5
+ (1e-300,-1e-300)  | {1,0,5}                               |                  5
+ (1e-300,-1e-300)  | {0,3,0}                               |             1e-300
+ (1e-300,-1e-300)  | {1,-1,0}                              | 1.41421356237e-300
+ (1e-300,-1e-300)  | {-0.4,-1,-6}                          |      5.57086014531
+ (1e-300,-1e-300)  | {-0.000184615384615,-1,15.3846153846} |      15.3846151224
+ (1e-300,-1e-300)  | {3,NaN,5}                             |                NaN
+ (1e-300,-1e-300)  | {NaN,NaN,NaN}                         |                NaN
+ (1e-300,-1e-300)  | {0,-1,3}                              |                  3
+ (1e-300,-1e-300)  | {-1,0,3}                              |                  3
+ (1e+300,Infinity) | {0,-1,5}                              |           Infinity
+ (1e+300,Infinity) | {1,0,5}                               |                NaN
+ (1e+300,Infinity) | {0,3,0}                               |           Infinity
+ (1e+300,Infinity) | {1,-1,0}                              |           Infinity
+ (1e+300,Infinity) | {-0.4,-1,-6}                          |           Infinity
+ (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} |           Infinity
+ (1e+300,Infinity) | {3,NaN,5}                             |                NaN
+ (1e+300,Infinity) | {NaN,NaN,NaN}                         |                NaN
+ (1e+300,Infinity) | {0,-1,3}                              |           Infinity
+ (1e+300,Infinity) | {-1,0,3}                              |                NaN
+ (NaN,NaN)         | {0,-1,5}                              |                NaN
+ (NaN,NaN)         | {1,0,5}                               |                NaN
+ (NaN,NaN)         | {0,3,0}                               |                NaN
+ (NaN,NaN)         | {1,-1,0}                              |                NaN
+ (NaN,NaN)         | {-0.4,-1,-6}                          |                NaN
+ (NaN,NaN)         | {-0.000184615384615,-1,15.3846153846} |                NaN
+ (NaN,NaN)         | {3,NaN,5}                             |                NaN
+ (NaN,NaN)         | {NaN,NaN,NaN}                         |                NaN
+ (NaN,NaN)         | {0,-1,3}                              |                NaN
+ (NaN,NaN)         | {-1,0,3}                              |                NaN
+ (10,10)           | {0,-1,5}                              |                  5
+ (10,10)           | {1,0,5}                               |                 15
+ (10,10)           | {0,3,0}                               |                 10
+ (10,10)           | {1,-1,0}                              |                  0
+ (10,10)           | {-0.4,-1,-6}                          |      18.5695338177
+ (10,10)           | {-0.000184615384615,-1,15.3846153846} |      5.38276913903
+ (10,10)           | {3,NaN,5}                             |                NaN
+ (10,10)           | {NaN,NaN,NaN}                         |                NaN
+ (10,10)           | {0,-1,3}                              |                  7
+ (10,10)           | {-1,0,3}                              |                  7
+(90 rows)
+
+-- Distance to line segment
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LSEG_TBL l;
+        f1         |               s               |      ?column?      
+-------------------+-------------------------------+--------------------
+ (0,0)             | [(1,2),(3,4)]                 |       2.2360679775
+ (0,0)             | [(0,0),(6,6)]                 |                  0
+ (0,0)             | [(10,-10),(-3,-4)]            |      4.88901207039
+ (0,0)             | [(-1000000,200),(300000,-40)] |      15.3846151224
+ (0,0)             | [(11,22),(33,44)]             |      24.5967477525
+ (0,0)             | [(-10,2),(-10,3)]             |      10.1980390272
+ (0,0)             | [(0,-20),(30,-20)]            |                 20
+ (0,0)             | [(NaN,1),(NaN,90)]            |                NaN
+ (-10,0)           | [(1,2),(3,4)]                 |      11.1803398875
+ (-10,0)           | [(0,0),(6,6)]                 |                 10
+ (-10,0)           | [(10,-10),(-3,-4)]            |       8.0622577483
+ (-10,0)           | [(-1000000,200),(300000,-40)] |      15.3864612763
+ (-10,0)           | [(11,22),(33,44)]             |      30.4138126515
+ (-10,0)           | [(-10,2),(-10,3)]             |                  2
+ (-10,0)           | [(0,-20),(30,-20)]            |       22.360679775
+ (-10,0)           | [(NaN,1),(NaN,90)]            |                NaN
+ (-3,4)            | [(1,2),(3,4)]                 |        4.472135955
+ (-3,4)            | [(0,0),(6,6)]                 |      4.94974746831
+ (-3,4)            | [(10,-10),(-3,-4)]            |                  8
+ (-3,4)            | [(-1000000,200),(300000,-40)] |      11.3851690367
+ (-3,4)            | [(11,22),(33,44)]             |       22.803508502
+ (-3,4)            | [(-10,2),(-10,3)]             |      7.07106781187
+ (-3,4)            | [(0,-20),(30,-20)]            |      24.1867732449
+ (-3,4)            | [(NaN,1),(NaN,90)]            |                NaN
+ (5.1,34.5)        | [(1,2),(3,4)]                 |      30.5722096028
+ (5.1,34.5)        | [(0,0),(6,6)]                 |      28.5142069853
+ (5.1,34.5)        | [(10,-10),(-3,-4)]            |      39.3428519556
+ (5.1,34.5)        | [(-1000000,200),(300000,-40)] |      19.1163258281
+ (5.1,34.5)        | [(11,22),(33,44)]             |      13.0107647738
+ (5.1,34.5)        | [(-10,2),(-10,3)]             |       34.932220084
+ (5.1,34.5)        | [(0,-20),(30,-20)]            |               54.5
+ (5.1,34.5)        | [(NaN,1),(NaN,90)]            |                NaN
+ (-5,-12)          | [(1,2),(3,4)]                 |      15.2315462117
+ (-5,-12)          | [(0,0),(6,6)]                 |                 13
+ (-5,-12)          | [(10,-10),(-3,-4)]            |      8.10179143093
+ (-5,-12)          | [(-1000000,200),(300000,-40)] |      27.3855379949
+ (-5,-12)          | [(11,22),(33,44)]             |      37.5765884561
+ (-5,-12)          | [(-10,2),(-10,3)]             |      14.8660687473
+ (-5,-12)          | [(0,-20),(30,-20)]            |      9.43398113206
+ (-5,-12)          | [(NaN,1),(NaN,90)]            |                NaN
+ (1e-300,-1e-300)  | [(1,2),(3,4)]                 |       2.2360679775
+ (1e-300,-1e-300)  | [(0,0),(6,6)]                 | 1.41421356237e-300
+ (1e-300,-1e-300)  | [(10,-10),(-3,-4)]            |      4.88901207039
+ (1e-300,-1e-300)  | [(-1000000,200),(300000,-40)] |      15.3846151224
+ (1e-300,-1e-300)  | [(11,22),(33,44)]             |      24.5967477525
+ (1e-300,-1e-300)  | [(-10,2),(-10,3)]             |      10.1980390272
+ (1e-300,-1e-300)  | [(0,-20),(30,-20)]            |                 20
+ (1e-300,-1e-300)  | [(NaN,1),(NaN,90)]            |                NaN
+ (1e+300,Infinity) | [(1,2),(3,4)]                 |           Infinity
+ (1e+300,Infinity) | [(0,0),(6,6)]                 |           Infinity
+ (1e+300,Infinity) | [(10,-10),(-3,-4)]            |           Infinity
+ (1e+300,Infinity) | [(-1000000,200),(300000,-40)] |           Infinity
+ (1e+300,Infinity) | [(11,22),(33,44)]             |           Infinity
+ (1e+300,Infinity) | [(-10,2),(-10,3)]             |           Infinity
+ (1e+300,Infinity) | [(0,-20),(30,-20)]            |           Infinity
+ (1e+300,Infinity) | [(NaN,1),(NaN,90)]            |           Infinity
+ (NaN,NaN)         | [(1,2),(3,4)]                 |                NaN
+ (NaN,NaN)         | [(0,0),(6,6)]                 |                NaN
+ (NaN,NaN)         | [(10,-10),(-3,-4)]            |                NaN
+ (NaN,NaN)         | [(-1000000,200),(300000,-40)] |                NaN
+ (NaN,NaN)         | [(11,22),(33,44)]             |                NaN
+ (NaN,NaN)         | [(-10,2),(-10,3)]             |                NaN
+ (NaN,NaN)         | [(0,-20),(30,-20)]            |                NaN
+ (NaN,NaN)         | [(NaN,1),(NaN,90)]            |                NaN
+ (10,10)           | [(1,2),(3,4)]                 |      9.21954445729
+ (10,10)           | [(0,0),(6,6)]                 |      5.65685424949
+ (10,10)           | [(10,-10),(-3,-4)]            |        18.15918769
+ (10,10)           | [(-1000000,200),(300000,-40)] |      5.38276913904
+ (10,10)           | [(11,22),(33,44)]             |      12.0415945788
+ (10,10)           | [(-10,2),(-10,3)]             |      21.1896201004
+ (10,10)           | [(0,-20),(30,-20)]            |                 30
+ (10,10)           | [(NaN,1),(NaN,90)]            |                NaN
+(72 rows)
+
+-- Distance to box
+SELECT p.f1, b.f1, p.f1 <-> b.f1 FROM POINT_TBL p, BOX_TBL b;
+        f1         |         f1          |      ?column?      
+-------------------+---------------------+--------------------
+ (0,0)             | (2,2),(0,0)         |                  0
+ (0,0)             | (3,3),(1,1)         |      1.41421356237
+ (0,0)             | (-2,2),(-8,-10)     |                  2
+ (0,0)             | (2.5,3.5),(2.5,2.5) |      3.53553390593
+ (0,0)             | (3,3),(3,3)         |      4.24264068712
+ (-10,0)           | (2,2),(0,0)         |                 10
+ (-10,0)           | (3,3),(1,1)         |      11.0453610172
+ (-10,0)           | (-2,2),(-8,-10)     |                  2
+ (-10,0)           | (2.5,3.5),(2.5,2.5) |       12.747548784
+ (-10,0)           | (3,3),(3,3)         |      13.3416640641
+ (-3,4)            | (2,2),(0,0)         |      3.60555127546
+ (-3,4)            | (3,3),(1,1)         |      4.12310562562
+ (-3,4)            | (-2,2),(-8,-10)     |                  2
+ (-3,4)            | (2.5,3.5),(2.5,2.5) |      5.52268050859
+ (-3,4)            | (3,3),(3,3)         |       6.0827625303
+ (5.1,34.5)        | (2,2),(0,0)         |      32.6475113906
+ (5.1,34.5)        | (3,3),(1,1)         |      31.5699223946
+ (5.1,34.5)        | (-2,2),(-8,-10)     |      33.2664996656
+ (5.1,34.5)        | (2.5,3.5),(2.5,2.5) |       31.108841187
+ (5.1,34.5)        | (3,3),(3,3)         |      31.5699223946
+ (-5,-12)          | (2,2),(0,0)         |                 13
+ (-5,-12)          | (3,3),(1,1)         |      14.3178210633
+ (-5,-12)          | (-2,2),(-8,-10)     |                  2
+ (-5,-12)          | (2.5,3.5),(2.5,2.5) |      16.3248277173
+ (-5,-12)          | (3,3),(3,3)         |                 17
+ (1e-300,-1e-300)  | (2,2),(0,0)         | 1.41421356237e-300
+ (1e-300,-1e-300)  | (3,3),(1,1)         |      1.41421356237
+ (1e-300,-1e-300)  | (-2,2),(-8,-10)     |                  2
+ (1e-300,-1e-300)  | (2.5,3.5),(2.5,2.5) |      3.53553390593
+ (1e-300,-1e-300)  | (3,3),(3,3)         |      4.24264068712
+ (1e+300,Infinity) | (2,2),(0,0)         |           Infinity
+ (1e+300,Infinity) | (3,3),(1,1)         |           Infinity
+ (1e+300,Infinity) | (-2,2),(-8,-10)     |           Infinity
+ (1e+300,Infinity) | (2.5,3.5),(2.5,2.5) |           Infinity
+ (1e+300,Infinity) | (3,3),(3,3)         |           Infinity
+ (NaN,NaN)         | (2,2),(0,0)         |                NaN
+ (NaN,NaN)         | (3,3),(1,1)         |                NaN
+ (NaN,NaN)         | (-2,2),(-8,-10)     |                NaN
+ (NaN,NaN)         | (2.5,3.5),(2.5,2.5) |                NaN
+ (NaN,NaN)         | (3,3),(3,3)         |                NaN
+ (10,10)           | (2,2),(0,0)         |       11.313708499
+ (10,10)           | (3,3),(1,1)         |      9.89949493661
+ (10,10)           | (-2,2),(-8,-10)     |      14.4222051019
+ (10,10)           | (2.5,3.5),(2.5,2.5) |      9.92471662064
+ (10,10)           | (3,3),(3,3)         |      9.89949493661
+(45 rows)
+
+-- Distance to path
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, PATH_TBL p1;
+        f1         |            f1             |      ?column?      
+-------------------+---------------------------+--------------------
+ (0,0)             | [(1,2),(3,4)]             |       2.2360679775
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | [(0,0),(3,0),(4,5),(1,6)] |                  0
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | [(1,2),(3,4)]             |       2.2360679775
+ (0,0)             | ((10,20))                 |       22.360679775
+ (0,0)             | [(11,12),(13,14)]         |      16.2788205961
+ (0,0)             | ((11,12),(13,14))         |      16.2788205961
+ (-10,0)           | [(1,2),(3,4)]             |      11.1803398875
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | [(0,0),(3,0),(4,5),(1,6)] |                 10
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | [(1,2),(3,4)]             |      11.1803398875
+ (-10,0)           | ((10,20))                 |      28.2842712475
+ (-10,0)           | [(11,12),(13,14)]         |      24.1867732449
+ (-10,0)           | ((11,12),(13,14))         |      24.1867732449
+ (-3,4)            | [(1,2),(3,4)]             |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | [(0,0),(3,0),(4,5),(1,6)] |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | [(1,2),(3,4)]             |        4.472135955
+ (-3,4)            | ((10,20))                 |      20.6155281281
+ (-3,4)            | [(11,12),(13,14)]         |      16.1245154966
+ (-3,4)            | ((11,12),(13,14))         |      16.1245154966
+ (5.1,34.5)        | [(1,2),(3,4)]             |      30.5722096028
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | [(0,0),(3,0),(4,5),(1,6)] |       28.793402022
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | [(1,2),(3,4)]             |      30.5722096028
+ (5.1,34.5)        | ((10,20))                 |      15.3055545473
+ (5.1,34.5)        | [(11,12),(13,14)]         |      21.9695243462
+ (5.1,34.5)        | ((11,12),(13,14))         |      21.9695243462
+ (-5,-12)          | [(1,2),(3,4)]             |      15.2315462117
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | [(0,0),(3,0),(4,5),(1,6)] |                 13
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | [(1,2),(3,4)]             |      15.2315462117
+ (-5,-12)          | ((10,20))                 |      35.3411940941
+ (-5,-12)          | [(11,12),(13,14)]         |      28.8444102037
+ (-5,-12)          | ((11,12),(13,14))         |      28.8444102037
+ (1e-300,-1e-300)  | [(1,2),(3,4)]             |       2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | [(0,0),(3,0),(4,5),(1,6)] | 1.41421356237e-300
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | [(1,2),(3,4)]             |       2.2360679775
+ (1e-300,-1e-300)  | ((10,20))                 |       22.360679775
+ (1e-300,-1e-300)  | [(11,12),(13,14)]         |      16.2788205961
+ (1e-300,-1e-300)  | ((11,12),(13,14))         |      16.2788205961
+ (1e+300,Infinity) | [(1,2),(3,4)]             |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | [(0,0),(3,0),(4,5),(1,6)] |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | [(1,2),(3,4)]             |           Infinity
+ (1e+300,Infinity) | ((10,20))                 |           Infinity
+ (1e+300,Infinity) | [(11,12),(13,14)]         |           Infinity
+ (1e+300,Infinity) | ((11,12),(13,14))         |           Infinity
+ (NaN,NaN)         | [(1,2),(3,4)]             |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | [(0,0),(3,0),(4,5),(1,6)] |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | [(1,2),(3,4)]             |                NaN
+ (NaN,NaN)         | ((10,20))                 |                NaN
+ (NaN,NaN)         | [(11,12),(13,14)]         |                NaN
+ (NaN,NaN)         | ((11,12),(13,14))         |                NaN
+ (10,10)           | [(1,2),(3,4)]             |      9.21954445729
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | [(0,0),(3,0),(4,5),(1,6)] |      7.81024967591
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | [(1,2),(3,4)]             |      9.21954445729
+ (10,10)           | ((10,20))                 |                 10
+ (10,10)           | [(11,12),(13,14)]         |       2.2360679775
+ (10,10)           | ((11,12),(13,14))         |       2.2360679775
+(81 rows)
+
+-- Distance to polygon
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, POLYGON_TBL p1;
+        f1         |             f1             |   ?column?    
+-------------------+----------------------------+---------------
+ (0,0)             | ((2,0),(2,4),(0,0))        |             0
+ (0,0)             | ((3,1),(3,3),(1,0))        |             1
+ (0,0)             | ((1,2),(3,4),(5,6),(7,8))  |  2.2360679775
+ (0,0)             | ((7,8),(5,6),(3,4),(1,2))  |  2.2360679775
+ (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | 1.58113883008
+ (0,0)             | ((0,0))                    |             0
+ (0,0)             | ((0,1),(0,1))              |             1
+ (-10,0)           | ((2,0),(2,4),(0,0))        |            10
+ (-10,0)           | ((3,1),(3,3),(1,0))        |            11
+ (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | 11.1803398875
+ (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | 11.1803398875
+ (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | 11.1803398875
+ (-10,0)           | ((0,0))                    |            10
+ (-10,0)           | ((0,1),(0,1))              | 10.0498756211
+ (-3,4)            | ((2,0),(2,4),(0,0))        |   4.472135955
+ (-3,4)            | ((3,1),(3,3),(1,0))        | 5.54700196225
+ (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  |   4.472135955
+ (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  |   4.472135955
+ (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) |   4.472135955
+ (-3,4)            | ((0,0))                    |             5
+ (-3,4)            | ((0,1),(0,1))              | 4.24264068712
+ (5.1,34.5)        | ((2,0),(2,4),(0,0))        | 30.6571362002
+ (5.1,34.5)        | ((3,1),(3,3),(1,0))        | 31.5699223946
+ (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | 26.5680258958
+ (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | 26.5680258958
+ (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | 26.5680258958
+ (5.1,34.5)        | ((0,0))                    | 34.8749193547
+ (5.1,34.5)        | ((0,1),(0,1))              | 33.8859853037
+ (-5,-12)          | ((2,0),(2,4),(0,0))        |            13
+ (-5,-12)          | ((3,1),(3,3),(1,0))        |  13.416407865
+ (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | 15.2315462117
+ (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | 15.2315462117
+ (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) |  11.313708499
+ (-5,-12)          | ((0,0))                    |            13
+ (-5,-12)          | ((0,1),(0,1))              | 13.9283882772
+ (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        |             0
+ (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        |             1
+ (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  |  2.2360679775
+ (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  |  2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | 1.58113883008
+ (1e-300,-1e-300)  | ((0,0))                    |             0
+ (1e-300,-1e-300)  | ((0,1),(0,1))              |             1
+ (1e+300,Infinity) | ((2,0),(2,4),(0,0))        |      Infinity
+ (1e+300,Infinity) | ((3,1),(3,3),(1,0))        |      Infinity
+ (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  |      Infinity
+ (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  |      Infinity
+ (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) |      Infinity
+ (1e+300,Infinity) | ((0,0))                    |      Infinity
+ (1e+300,Infinity) | ((0,1),(0,1))              |      Infinity
+ (NaN,NaN)         | ((2,0),(2,4),(0,0))        |             0
+ (NaN,NaN)         | ((3,1),(3,3),(1,0))        |             0
+ (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  |             0
+ (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  |             0
+ (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) |             0
+ (NaN,NaN)         | ((0,0))                    |             0
+ (NaN,NaN)         | ((0,1),(0,1))              |             0
+ (10,10)           | ((2,0),(2,4),(0,0))        |            10
+ (10,10)           | ((3,1),(3,3),(1,0))        | 9.89949493661
+ (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | 3.60555127546
+ (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | 3.60555127546
+ (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | 3.60555127546
+ (10,10)           | ((0,0))                    | 14.1421356237
+ (10,10)           | ((0,1),(0,1))              | 13.4536240471
+(63 rows)
+
+-- Closest point to line
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LINE_TBL l;
+        f1         |                   s                   |             ?column?             
+-------------------+---------------------------------------+----------------------------------
+ (0,0)             | {0,-1,5}                              | (0,5)
+ (0,0)             | {1,0,5}                               | (-5,0)
+ (0,0)             | {0,3,0}                               | (0,0)
+ (0,0)             | {1,-1,0}                              | (0,0)
+ (0,0)             | {-0.4,-1,-6}                          | (-2.06896551724,-5.1724137931)
+ (0,0)             | {-0.000184615384615,-1,15.3846153846} | (0.00284023658959,15.3846148603)
+ (0,0)             | {3,NaN,5}                             | 
+ (0,0)             | {NaN,NaN,NaN}                         | 
+ (0,0)             | {0,-1,3}                              | (0,3)
+ (0,0)             | {-1,0,3}                              | (3,0)
+ (-10,0)           | {0,-1,5}                              | (-10,5)
+ (-10,0)           | {1,0,5}                               | (-5,0)
+ (-10,0)           | {0,3,0}                               | (-10,0)
+ (-10,0)           | {1,-1,0}                              | (-5,-5)
+ (-10,0)           | {-0.4,-1,-6}                          | (-10.6896551724,-1.72413793103)
+ (-10,0)           | {-0.000184615384615,-1,15.3846153846} | (-9.99715942258,15.386461014)
+ (-10,0)           | {3,NaN,5}                             | 
+ (-10,0)           | {NaN,NaN,NaN}                         | 
+ (-10,0)           | {0,-1,3}                              | (-10,3)
+ (-10,0)           | {-1,0,3}                              | (3,0)
+ (-3,4)            | {0,-1,5}                              | (-3,5)
+ (-3,4)            | {1,0,5}                               | (-5,4)
+ (-3,4)            | {0,3,0}                               | (-3,0)
+ (-3,4)            | {1,-1,0}                              | (0.5,0.5)
+ (-3,4)            | {-0.4,-1,-6}                          | (-6.03448275862,-3.58620689655)
+ (-3,4)            | {-0.000184615384615,-1,15.3846153846} | (-2.99789812268,15.3851688427)
+ (-3,4)            | {3,NaN,5}                             | 
+ (-3,4)            | {NaN,NaN,NaN}                         | 
+ (-3,4)            | {0,-1,3}                              | (-3,3)
+ (-3,4)            | {-1,0,3}                              | (3,4)
+ (5.1,34.5)        | {0,-1,5}                              | (5.1,5)
+ (5.1,34.5)        | {1,0,5}                               | (-5,34.5)
+ (5.1,34.5)        | {0,3,0}                               | (5.1,0)
+ (5.1,34.5)        | {1,-1,0}                              | (19.8,19.8)
+ (5.1,34.5)        | {-0.4,-1,-6}                          | (-9.56896551724,-2.1724137931)
+ (5.1,34.5)        | {-0.000184615384615,-1,15.3846153846} | (5.09647083221,15.3836744977)
+ (5.1,34.5)        | {3,NaN,5}                             | 
+ (5.1,34.5)        | {NaN,NaN,NaN}                         | 
+ (5.1,34.5)        | {0,-1,3}                              | (5.1,3)
+ (5.1,34.5)        | {-1,0,3}                              | (3,34.5)
+ (-5,-12)          | {0,-1,5}                              | (-5,5)
+ (-5,-12)          | {1,0,5}                               | (-5,-12)
+ (-5,-12)          | {0,3,0}                               | (-5,0)
+ (-5,-12)          | {1,-1,0}                              | (-8.5,-8.5)
+ (-5,-12)          | {-0.4,-1,-6}                          | (-2.24137931034,-5.10344827586)
+ (-5,-12)          | {-0.000184615384615,-1,15.3846153846} | (-4.99494420846,15.3855375282)
+ (-5,-12)          | {3,NaN,5}                             | 
+ (-5,-12)          | {NaN,NaN,NaN}                         | 
+ (-5,-12)          | {0,-1,3}                              | (-5,3)
+ (-5,-12)          | {-1,0,3}                              | (3,-12)
+ (1e-300,-1e-300)  | {0,-1,5}                              | (1e-300,5)
+ (1e-300,-1e-300)  | {1,0,5}                               | (-5,-1e-300)
+ (1e-300,-1e-300)  | {0,3,0}                               | (1e-300,0)
+ (1e-300,-1e-300)  | {1,-1,0}                              | (0,0)
+ (1e-300,-1e-300)  | {-0.4,-1,-6}                          | (-2.06896551724,-5.1724137931)
+ (1e-300,-1e-300)  | {-0.000184615384615,-1,15.3846153846} | (0.00284023658959,15.3846148603)
+ (1e-300,-1e-300)  | {3,NaN,5}                             | 
+ (1e-300,-1e-300)  | {NaN,NaN,NaN}                         | 
+ (1e-300,-1e-300)  | {0,-1,3}                              | (1e-300,3)
+ (1e-300,-1e-300)  | {-1,0,3}                              | (3,-1e-300)
+ (1e+300,Infinity) | {0,-1,5}                              | (1e+300,5)
+ (1e+300,Infinity) | {1,0,5}                               | 
+ (1e+300,Infinity) | {0,3,0}                               | (1e+300,0)
+ (1e+300,Infinity) | {1,-1,0}                              | (Infinity,NaN)
+ (1e+300,Infinity) | {-0.4,-1,-6}                          | (-Infinity,NaN)
+ (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} | (-Infinity,NaN)
+ (1e+300,Infinity) | {3,NaN,5}                             | 
+ (1e+300,Infinity) | {NaN,NaN,NaN}                         | 
+ (1e+300,Infinity) | {0,-1,3}                              | (1e+300,3)
+ (1e+300,Infinity) | {-1,0,3}                              | 
+ (NaN,NaN)         | {0,-1,5}                              | 
+ (NaN,NaN)         | {1,0,5}                               | 
+ (NaN,NaN)         | {0,3,0}                               | 
+ (NaN,NaN)         | {1,-1,0}                              | 
+ (NaN,NaN)         | {-0.4,-1,-6}                          | 
+ (NaN,NaN)         | {-0.000184615384615,-1,15.3846153846} | 
+ (NaN,NaN)         | {3,NaN,5}                             | 
+ (NaN,NaN)         | {NaN,NaN,NaN}                         | 
+ (NaN,NaN)         | {0,-1,3}                              | 
+ (NaN,NaN)         | {-1,0,3}                              | 
+ (10,10)           | {0,-1,5}                              | (10,5)
+ (10,10)           | {1,0,5}                               | (-5,10)
+ (10,10)           | {0,3,0}                               | (10,0)
+ (10,10)           | {1,-1,0}                              | (10,10)
+ (10,10)           | {-0.4,-1,-6}                          | (3.10344827586,-7.24137931034)
+ (10,10)           | {-0.000184615384615,-1,15.3846153846} | (10.000993742,15.3827690473)
+ (10,10)           | {3,NaN,5}                             | 
+ (10,10)           | {NaN,NaN,NaN}                         | 
+ (10,10)           | {0,-1,3}                              | (10,3)
+ (10,10)           | {-1,0,3}                              | (3,10)
+(90 rows)
+
+-- Closest point to line segment
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LSEG_TBL l;
+        f1         |               s               |             ?column?             
+-------------------+-------------------------------+----------------------------------
+ (0,0)             | [(1,2),(3,4)]                 | (1,2)
+ (0,0)             | [(0,0),(6,6)]                 | (0,0)
+ (0,0)             | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ (0,0)             | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
+ (0,0)             | [(11,22),(33,44)]             | (11,22)
+ (0,0)             | [(-10,2),(-10,3)]             | (-10,2)
+ (0,0)             | [(0,-20),(30,-20)]            | (0,-20)
+ (0,0)             | [(NaN,1),(NaN,90)]            | 
+ (-10,0)           | [(1,2),(3,4)]                 | (1,2)
+ (-10,0)           | [(0,0),(6,6)]                 | (0,0)
+ (-10,0)           | [(10,-10),(-3,-4)]            | (-3,-4)
+ (-10,0)           | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
+ (-10,0)           | [(11,22),(33,44)]             | (11,22)
+ (-10,0)           | [(-10,2),(-10,3)]             | (-10,2)
+ (-10,0)           | [(0,-20),(30,-20)]            | (0,-20)
+ (-10,0)           | [(NaN,1),(NaN,90)]            | 
+ (-3,4)            | [(1,2),(3,4)]                 | (1,2)
+ (-3,4)            | [(0,0),(6,6)]                 | (0.5,0.5)
+ (-3,4)            | [(10,-10),(-3,-4)]            | (-3,-4)
+ (-3,4)            | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
+ (-3,4)            | [(11,22),(33,44)]             | (11,22)
+ (-3,4)            | [(-10,2),(-10,3)]             | (-10,3)
+ (-3,4)            | [(0,-20),(30,-20)]            | (0,-20)
+ (-3,4)            | [(NaN,1),(NaN,90)]            | 
+ (5.1,34.5)        | [(1,2),(3,4)]                 | (3,4)
+ (5.1,34.5)        | [(0,0),(6,6)]                 | (6,6)
+ (5.1,34.5)        | [(10,-10),(-3,-4)]            | (-3,-4)
+ (5.1,34.5)        | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
+ (5.1,34.5)        | [(11,22),(33,44)]             | (14.3,25.3)
+ (5.1,34.5)        | [(-10,2),(-10,3)]             | (-10,3)
+ (5.1,34.5)        | [(0,-20),(30,-20)]            | (5.1,-20)
+ (5.1,34.5)        | [(NaN,1),(NaN,90)]            | 
+ (-5,-12)          | [(1,2),(3,4)]                 | (1,2)
+ (-5,-12)          | [(0,0),(6,6)]                 | (0,0)
+ (-5,-12)          | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
+ (-5,-12)          | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
+ (-5,-12)          | [(11,22),(33,44)]             | (11,22)
+ (-5,-12)          | [(-10,2),(-10,3)]             | (-10,2)
+ (-5,-12)          | [(0,-20),(30,-20)]            | (0,-20)
+ (-5,-12)          | [(NaN,1),(NaN,90)]            | 
+ (1e-300,-1e-300)  | [(1,2),(3,4)]                 | (1,2)
+ (1e-300,-1e-300)  | [(0,0),(6,6)]                 | (0,0)
+ (1e-300,-1e-300)  | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ (1e-300,-1e-300)  | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
+ (1e-300,-1e-300)  | [(11,22),(33,44)]             | (11,22)
+ (1e-300,-1e-300)  | [(-10,2),(-10,3)]             | (-10,2)
+ (1e-300,-1e-300)  | [(0,-20),(30,-20)]            | (0,-20)
+ (1e-300,-1e-300)  | [(NaN,1),(NaN,90)]            | 
+ (1e+300,Infinity) | [(1,2),(3,4)]                 | (3,4)
+ (1e+300,Infinity) | [(0,0),(6,6)]                 | (6,6)
+ (1e+300,Infinity) | [(10,-10),(-3,-4)]            | (-3,-4)
+ (1e+300,Infinity) | [(-1000000,200),(300000,-40)] | (300000,-40)
+ (1e+300,Infinity) | [(11,22),(33,44)]             | (33,44)
+ (1e+300,Infinity) | [(-10,2),(-10,3)]             | (-10,3)
+ (1e+300,Infinity) | [(0,-20),(30,-20)]            | (30,-20)
+ (1e+300,Infinity) | [(NaN,1),(NaN,90)]            | (NaN,90)
+ (NaN,NaN)         | [(1,2),(3,4)]                 | 
+ (NaN,NaN)         | [(0,0),(6,6)]                 | 
+ (NaN,NaN)         | [(10,-10),(-3,-4)]            | 
+ (NaN,NaN)         | [(-1000000,200),(300000,-40)] | 
+ (NaN,NaN)         | [(11,22),(33,44)]             | 
+ (NaN,NaN)         | [(-10,2),(-10,3)]             | 
+ (NaN,NaN)         | [(0,-20),(30,-20)]            | 
+ (NaN,NaN)         | [(NaN,1),(NaN,90)]            | 
+ (10,10)           | [(1,2),(3,4)]                 | (3,4)
+ (10,10)           | [(0,0),(6,6)]                 | (6,6)
+ (10,10)           | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
+ (10,10)           | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
+ (10,10)           | [(11,22),(33,44)]             | (11,22)
+ (10,10)           | [(-10,2),(-10,3)]             | (-10,3)
+ (10,10)           | [(0,-20),(30,-20)]            | (10,-20)
+ (10,10)           | [(NaN,1),(NaN,90)]            | 
+(72 rows)
+
+-- Closest point to box
+SELECT p.f1, b.f1, p.f1 ## b.f1 FROM POINT_TBL p, BOX_TBL b;
+        f1         |         f1          |   ?column?   
+-------------------+---------------------+--------------
+ (0,0)             | (2,2),(0,0)         | (0,0)
+ (0,0)             | (3,3),(1,1)         | (1,1)
+ (0,0)             | (-2,2),(-8,-10)     | (-2,0)
+ (0,0)             | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (0,0)             | (3,3),(3,3)         | (3,3)
+ (-10,0)           | (2,2),(0,0)         | (0,0)
+ (-10,0)           | (3,3),(1,1)         | (1,1)
+ (-10,0)           | (-2,2),(-8,-10)     | (-8,0)
+ (-10,0)           | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (-10,0)           | (3,3),(3,3)         | (3,3)
+ (-3,4)            | (2,2),(0,0)         | (0,2)
+ (-3,4)            | (3,3),(1,1)         | (1,3)
+ (-3,4)            | (-2,2),(-8,-10)     | (-3,2)
+ (-3,4)            | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (-3,4)            | (3,3),(3,3)         | (3,3)
+ (5.1,34.5)        | (2,2),(0,0)         | (2,2)
+ (5.1,34.5)        | (3,3),(1,1)         | (3,3)
+ (5.1,34.5)        | (-2,2),(-8,-10)     | (-2,2)
+ (5.1,34.5)        | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (5.1,34.5)        | (3,3),(3,3)         | (3,3)
+ (-5,-12)          | (2,2),(0,0)         | (0,0)
+ (-5,-12)          | (3,3),(1,1)         | (1,1)
+ (-5,-12)          | (-2,2),(-8,-10)     | (-5,-10)
+ (-5,-12)          | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (-5,-12)          | (3,3),(3,3)         | (3,3)
+ (1e-300,-1e-300)  | (2,2),(0,0)         | (0,0)
+ (1e-300,-1e-300)  | (3,3),(1,1)         | (1,1)
+ (1e-300,-1e-300)  | (-2,2),(-8,-10)     | (-2,-1e-300)
+ (1e-300,-1e-300)  | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (1e-300,-1e-300)  | (3,3),(3,3)         | (3,3)
+ (1e+300,Infinity) | (2,2),(0,0)         | (0,2)
+ (1e+300,Infinity) | (3,3),(1,1)         | (1,3)
+ (1e+300,Infinity) | (-2,2),(-8,-10)     | (-8,2)
+ (1e+300,Infinity) | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (1e+300,Infinity) | (3,3),(3,3)         | (3,3)
+ (NaN,NaN)         | (2,2),(0,0)         | 
+ (NaN,NaN)         | (3,3),(1,1)         | 
+ (NaN,NaN)         | (-2,2),(-8,-10)     | 
+ (NaN,NaN)         | (2.5,3.5),(2.5,2.5) | 
+ (NaN,NaN)         | (3,3),(3,3)         | 
+ (10,10)           | (2,2),(0,0)         | (2,2)
+ (10,10)           | (3,3),(1,1)         | (3,3)
+ (10,10)           | (-2,2),(-8,-10)     | (-2,2)
+ (10,10)           | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (10,10)           | (3,3),(3,3)         | (3,3)
+(45 rows)
+
+-- On line
+SELECT p.f1, l.s FROM POINT_TBL p, LINE_TBL l WHERE p.f1 <@ l.s;
+        f1        |    s     
+------------------+----------
+ (0,0)            | {0,3,0}
+ (0,0)            | {1,-1,0}
+ (-10,0)          | {0,3,0}
+ (-5,-12)         | {1,0,5}
+ (1e-300,-1e-300) | {0,3,0}
+ (1e-300,-1e-300) | {1,-1,0}
+ (10,10)          | {1,-1,0}
+(7 rows)
+
+-- On line segment
+SELECT p.f1, l.s FROM POINT_TBL p, LSEG_TBL l WHERE p.f1 <@ l.s;
+        f1        |       s       
+------------------+---------------
+ (0,0)            | [(0,0),(6,6)]
+ (1e-300,-1e-300) | [(0,0),(6,6)]
+(2 rows)
+
+-- On path
+SELECT p.f1, p1.f1 FROM POINT_TBL p, PATH_TBL p1 WHERE p.f1 <@ p1.f1;
+        f1        |            f1             
+------------------+---------------------------
+ (0,0)            | [(0,0),(3,0),(4,5),(1,6)]
+ (1e-300,-1e-300) | [(0,0),(3,0),(4,5),(1,6)]
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((10,20))
+ (NaN,NaN)        | ((11,12),(13,14))
+(7 rows)
+
+--
+-- Lines
+--
+-- Vertical
+SELECT s FROM LINE_TBL WHERE ?| s;
+    s     
+----------
+ {1,0,5}
+ {-1,0,3}
+(2 rows)
+
+-- Horizontal
+SELECT s FROM LINE_TBL WHERE ?- s;
+    s     
+----------
+ {0,-1,5}
+ {0,3,0}
+ {0,-1,3}
+(3 rows)
+
+-- Same as line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s = l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {0,-1,5}
+ {1,0,5}                               | {1,0,5}
+ {0,3,0}                               | {0,3,0}
+ {1,-1,0}                              | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846}
+ {3,NaN,5}                             | {3,NaN,5}
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}
+ {0,-1,3}                              | {0,-1,3}
+ {-1,0,3}                              | {-1,0,3}
+(10 rows)
+
+-- Parallel to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?|| l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {0,-1,5}
+ {0,-1,5}                              | {0,3,0}
+ {0,-1,5}                              | {0,-1,3}
+ {1,0,5}                               | {1,0,5}
+ {1,0,5}                               | {-1,0,3}
+ {0,3,0}                               | {0,-1,5}
+ {0,3,0}                               | {0,3,0}
+ {0,3,0}                               | {0,-1,3}
+ {1,-1,0}                              | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,3}                              | {0,-1,5}
+ {0,-1,3}                              | {0,3,0}
+ {0,-1,3}                              | {0,-1,3}
+ {-1,0,3}                              | {1,0,5}
+ {-1,0,3}                              | {-1,0,3}
+(16 rows)
+
+-- Perpendicular to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?-| l2.s;
+    s     |    s     
+----------+----------
+ {0,-1,5} | {1,0,5}
+ {0,-1,5} | {-1,0,3}
+ {1,0,5}  | {0,-1,5}
+ {1,0,5}  | {0,3,0}
+ {1,0,5}  | {0,-1,3}
+ {0,3,0}  | {1,0,5}
+ {0,3,0}  | {-1,0,3}
+ {0,-1,3} | {1,0,5}
+ {0,-1,3} | {-1,0,3}
+ {-1,0,3} | {0,-1,5}
+ {-1,0,3} | {0,3,0}
+ {-1,0,3} | {0,-1,3}
+(12 rows)
+
+-- Distance to line
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2;
+                   s                   |                   s                   | ?column? 
+---------------------------------------+---------------------------------------+----------
+ {0,-1,5}                              | {0,-1,5}                              |        0
+ {0,-1,5}                              | {1,0,5}                               |        0
+ {0,-1,5}                              | {0,3,0}                               |        5
+ {0,-1,5}                              | {1,-1,0}                              |        0
+ {0,-1,5}                              | {-0.4,-1,-6}                          |        0
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,-1,5}                              | {3,NaN,5}                             |        0
+ {0,-1,5}                              | {NaN,NaN,NaN}                         |        0
+ {0,-1,5}                              | {0,-1,3}                              |        2
+ {0,-1,5}                              | {-1,0,3}                              |        0
+ {1,0,5}                               | {0,-1,5}                              |        0
+ {1,0,5}                               | {1,0,5}                               |        0
+ {1,0,5}                               | {0,3,0}                               |        0
+ {1,0,5}                               | {1,-1,0}                              |        0
+ {1,0,5}                               | {-0.4,-1,-6}                          |        0
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846} |        0
+ {1,0,5}                               | {3,NaN,5}                             |        0
+ {1,0,5}                               | {NaN,NaN,NaN}                         |        0
+ {1,0,5}                               | {0,-1,3}                              |        0
+ {1,0,5}                               | {-1,0,3}                              |        8
+ {0,3,0}                               | {0,-1,5}                              |        5
+ {0,3,0}                               | {1,0,5}                               |        0
+ {0,3,0}                               | {0,3,0}                               |        0
+ {0,3,0}                               | {1,-1,0}                              |        0
+ {0,3,0}                               | {-0.4,-1,-6}                          |        0
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,3,0}                               | {3,NaN,5}                             |        0
+ {0,3,0}                               | {NaN,NaN,NaN}                         |        0
+ {0,3,0}                               | {0,-1,3}                              |        3
+ {0,3,0}                               | {-1,0,3}                              |        0
+ {1,-1,0}                              | {0,-1,5}                              |        0
+ {1,-1,0}                              | {1,0,5}                               |        0
+ {1,-1,0}                              | {0,3,0}                               |        0
+ {1,-1,0}                              | {1,-1,0}                              |        0
+ {1,-1,0}                              | {-0.4,-1,-6}                          |        0
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {1,-1,0}                              | {3,NaN,5}                             |        0
+ {1,-1,0}                              | {NaN,NaN,NaN}                         |        0
+ {1,-1,0}                              | {0,-1,3}                              |        0
+ {1,-1,0}                              | {-1,0,3}                              |        0
+ {-0.4,-1,-6}                          | {0,-1,5}                              |        0
+ {-0.4,-1,-6}                          | {1,0,5}                               |        0
+ {-0.4,-1,-6}                          | {0,3,0}                               |        0
+ {-0.4,-1,-6}                          | {1,-1,0}                              |        0
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}                          |        0
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846} |        0
+ {-0.4,-1,-6}                          | {3,NaN,5}                             |        0
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}                         |        0
+ {-0.4,-1,-6}                          | {0,-1,3}                              |        0
+ {-0.4,-1,-6}                          | {-1,0,3}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}                               |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}                               |        0
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}                          |        0
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} |        0
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}                             |        0
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}                         |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}                              |        0
+ {3,NaN,5}                             | {0,-1,5}                              |        0
+ {3,NaN,5}                             | {1,0,5}                               |        0
+ {3,NaN,5}                             | {0,3,0}                               |        0
+ {3,NaN,5}                             | {1,-1,0}                              |        0
+ {3,NaN,5}                             | {-0.4,-1,-6}                          |        0
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846} |        0
+ {3,NaN,5}                             | {3,NaN,5}                             |        0
+ {3,NaN,5}                             | {NaN,NaN,NaN}                         |        0
+ {3,NaN,5}                             | {0,-1,3}                              |        0
+ {3,NaN,5}                             | {-1,0,3}                              |        0
+ {NaN,NaN,NaN}                         | {0,-1,5}                              |        0
+ {NaN,NaN,NaN}                         | {1,0,5}                               |        0
+ {NaN,NaN,NaN}                         | {0,3,0}                               |        0
+ {NaN,NaN,NaN}                         | {1,-1,0}                              |        0
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}                          |        0
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846} |        0
+ {NaN,NaN,NaN}                         | {3,NaN,5}                             |        0
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}                         |        0
+ {NaN,NaN,NaN}                         | {0,-1,3}                              |        0
+ {NaN,NaN,NaN}                         | {-1,0,3}                              |        0
+ {0,-1,3}                              | {0,-1,5}                              |        2
+ {0,-1,3}                              | {1,0,5}                               |        0
+ {0,-1,3}                              | {0,3,0}                               |        3
+ {0,-1,3}                              | {1,-1,0}                              |        0
+ {0,-1,3}                              | {-0.4,-1,-6}                          |        0
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,-1,3}                              | {3,NaN,5}                             |        0
+ {0,-1,3}                              | {NaN,NaN,NaN}                         |        0
+ {0,-1,3}                              | {0,-1,3}                              |        0
+ {0,-1,3}                              | {-1,0,3}                              |        0
+ {-1,0,3}                              | {0,-1,5}                              |        0
+ {-1,0,3}                              | {1,0,5}                               |        8
+ {-1,0,3}                              | {0,3,0}                               |        0
+ {-1,0,3}                              | {1,-1,0}                              |        0
+ {-1,0,3}                              | {-0.4,-1,-6}                          |        0
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {-1,0,3}                              | {3,NaN,5}                             |        0
+ {-1,0,3}                              | {NaN,NaN,NaN}                         |        0
+ {-1,0,3}                              | {0,-1,3}                              |        0
+ {-1,0,3}                              | {-1,0,3}                              |        0
+(100 rows)
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LINE_TBL l, BOX_TBL b;
+ERROR:  function "dist_lb" not implemented
+-- Intersect with line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?# l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {1,0,5}
+ {0,-1,5}                              | {1,-1,0}
+ {0,-1,5}                              | {-0.4,-1,-6}
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,5}                              | {3,NaN,5}
+ {0,-1,5}                              | {NaN,NaN,NaN}
+ {0,-1,5}                              | {-1,0,3}
+ {1,0,5}                               | {0,-1,5}
+ {1,0,5}                               | {0,3,0}
+ {1,0,5}                               | {1,-1,0}
+ {1,0,5}                               | {-0.4,-1,-6}
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846}
+ {1,0,5}                               | {3,NaN,5}
+ {1,0,5}                               | {NaN,NaN,NaN}
+ {1,0,5}                               | {0,-1,3}
+ {0,3,0}                               | {1,0,5}
+ {0,3,0}                               | {1,-1,0}
+ {0,3,0}                               | {-0.4,-1,-6}
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846}
+ {0,3,0}                               | {3,NaN,5}
+ {0,3,0}                               | {NaN,NaN,NaN}
+ {0,3,0}                               | {-1,0,3}
+ {1,-1,0}                              | {0,-1,5}
+ {1,-1,0}                              | {1,0,5}
+ {1,-1,0}                              | {0,3,0}
+ {1,-1,0}                              | {-0.4,-1,-6}
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846}
+ {1,-1,0}                              | {3,NaN,5}
+ {1,-1,0}                              | {NaN,NaN,NaN}
+ {1,-1,0}                              | {0,-1,3}
+ {1,-1,0}                              | {-1,0,3}
+ {-0.4,-1,-6}                          | {0,-1,5}
+ {-0.4,-1,-6}                          | {1,0,5}
+ {-0.4,-1,-6}                          | {0,3,0}
+ {-0.4,-1,-6}                          | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846}
+ {-0.4,-1,-6}                          | {3,NaN,5}
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}
+ {-0.4,-1,-6}                          | {0,-1,3}
+ {-0.4,-1,-6}                          | {-1,0,3}
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}
+ {3,NaN,5}                             | {0,-1,5}
+ {3,NaN,5}                             | {1,0,5}
+ {3,NaN,5}                             | {0,3,0}
+ {3,NaN,5}                             | {1,-1,0}
+ {3,NaN,5}                             | {-0.4,-1,-6}
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846}
+ {3,NaN,5}                             | {3,NaN,5}
+ {3,NaN,5}                             | {NaN,NaN,NaN}
+ {3,NaN,5}                             | {0,-1,3}
+ {3,NaN,5}                             | {-1,0,3}
+ {NaN,NaN,NaN}                         | {0,-1,5}
+ {NaN,NaN,NaN}                         | {1,0,5}
+ {NaN,NaN,NaN}                         | {0,3,0}
+ {NaN,NaN,NaN}                         | {1,-1,0}
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846}
+ {NaN,NaN,NaN}                         | {3,NaN,5}
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}
+ {NaN,NaN,NaN}                         | {0,-1,3}
+ {NaN,NaN,NaN}                         | {-1,0,3}
+ {0,-1,3}                              | {1,0,5}
+ {0,-1,3}                              | {1,-1,0}
+ {0,-1,3}                              | {-0.4,-1,-6}
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,3}                              | {3,NaN,5}
+ {0,-1,3}                              | {NaN,NaN,NaN}
+ {0,-1,3}                              | {-1,0,3}
+ {-1,0,3}                              | {0,-1,5}
+ {-1,0,3}                              | {0,3,0}
+ {-1,0,3}                              | {1,-1,0}
+ {-1,0,3}                              | {-0.4,-1,-6}
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846}
+ {-1,0,3}                              | {3,NaN,5}
+ {-1,0,3}                              | {NaN,NaN,NaN}
+ {-1,0,3}                              | {0,-1,3}
+(84 rows)
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LINE_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+      s       |         f1          
+--------------+---------------------
+ {1,0,5}      | (-2,2),(-8,-10)
+ {0,3,0}      | (2,2),(0,0)
+ {0,3,0}      | (-2,2),(-8,-10)
+ {1,-1,0}     | (2,2),(0,0)
+ {1,-1,0}     | (3,3),(1,1)
+ {1,-1,0}     | (-2,2),(-8,-10)
+ {1,-1,0}     | (2.5,3.5),(2.5,2.5)
+ {1,-1,0}     | (3,3),(3,3)
+ {-0.4,-1,-6} | (-2,2),(-8,-10)
+ {0,-1,3}     | (3,3),(1,1)
+ {0,-1,3}     | (2.5,3.5),(2.5,2.5)
+ {0,-1,3}     | (3,3),(3,3)
+ {-1,0,3}     | (3,3),(1,1)
+(13 rows)
+
+-- Intersection point with line
+SELECT l1.s, l2.s, l1.s # l2.s FROM LINE_TBL l1, LINE_TBL l2;
+                   s                   |                   s                   |             ?column?              
+---------------------------------------+---------------------------------------+-----------------------------------
+ {0,-1,5}                              | {0,-1,5}                              | 
+ {0,-1,5}                              | {1,0,5}                               | (-5,5)
+ {0,-1,5}                              | {0,3,0}                               | 
+ {0,-1,5}                              | {1,-1,0}                              | (5,5)
+ {0,-1,5}                              | {-0.4,-1,-6}                          | (-27.5,5)
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846} | (56250,5)
+ {0,-1,5}                              | {3,NaN,5}                             | (NaN,NaN)
+ {0,-1,5}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,-1,5}                              | {0,-1,3}                              | 
+ {0,-1,5}                              | {-1,0,3}                              | (3,5)
+ {1,0,5}                               | {0,-1,5}                              | (-5,5)
+ {1,0,5}                               | {1,0,5}                               | 
+ {1,0,5}                               | {0,3,0}                               | (-5,0)
+ {1,0,5}                               | {1,-1,0}                              | (-5,-5)
+ {1,0,5}                               | {-0.4,-1,-6}                          | (-5,-4)
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846} | (-5,15.3855384615)
+ {1,0,5}                               | {3,NaN,5}                             | (NaN,NaN)
+ {1,0,5}                               | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {1,0,5}                               | {0,-1,3}                              | (-5,3)
+ {1,0,5}                               | {-1,0,3}                              | 
+ {0,3,0}                               | {0,-1,5}                              | 
+ {0,3,0}                               | {1,0,5}                               | (-5,0)
+ {0,3,0}                               | {0,3,0}                               | 
+ {0,3,0}                               | {1,-1,0}                              | (0,0)
+ {0,3,0}                               | {-0.4,-1,-6}                          | (-15,0)
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846} | (83333.3333333,0)
+ {0,3,0}                               | {3,NaN,5}                             | (NaN,NaN)
+ {0,3,0}                               | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,3,0}                               | {0,-1,3}                              | 
+ {0,3,0}                               | {-1,0,3}                              | (3,0)
+ {1,-1,0}                              | {0,-1,5}                              | (5,5)
+ {1,-1,0}                              | {1,0,5}                               | (-5,-5)
+ {1,-1,0}                              | {0,3,0}                               | (0,0)
+ {1,-1,0}                              | {1,-1,0}                              | 
+ {1,-1,0}                              | {-0.4,-1,-6}                          | (-4.28571428571,-4.28571428571)
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846} | (15.3817756722,15.3817756722)
+ {1,-1,0}                              | {3,NaN,5}                             | (NaN,NaN)
+ {1,-1,0}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {1,-1,0}                              | {0,-1,3}                              | (3,3)
+ {1,-1,0}                              | {-1,0,3}                              | (3,3)
+ {-0.4,-1,-6}                          | {0,-1,5}                              | (-27.5,5)
+ {-0.4,-1,-6}                          | {1,0,5}                               | (-5,-4)
+ {-0.4,-1,-6}                          | {0,3,0}                               | (-15,0)
+ {-0.4,-1,-6}                          | {1,-1,0}                              | (-4.28571428571,-4.28571428571)
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}                          | 
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846} | (-53.4862244113,15.3944897645)
+ {-0.4,-1,-6}                          | {3,NaN,5}                             | (NaN,NaN)
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-0.4,-1,-6}                          | {0,-1,3}                              | (-22.5,3)
+ {-0.4,-1,-6}                          | {-1,0,3}                              | (3,-7.2)
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}                              | (56250,5)
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}                               | (-5,15.3855384615)
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}                               | (83333.3333333,-1.7763568394e-15)
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}                              | (15.3817756722,15.3817756722)
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}                          | (-53.4862244113,15.3944897645)
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} | 
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}                             | (NaN,NaN)
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}                              | (67083.3333333,3)
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}                              | (3,15.3840615385)
+ {3,NaN,5}                             | {0,-1,5}                              | (NaN,NaN)
+ {3,NaN,5}                             | {1,0,5}                               | (NaN,NaN)
+ {3,NaN,5}                             | {0,3,0}                               | (NaN,NaN)
+ {3,NaN,5}                             | {1,-1,0}                              | (NaN,NaN)
+ {3,NaN,5}                             | {-0.4,-1,-6}                          | (NaN,NaN)
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ {3,NaN,5}                             | {3,NaN,5}                             | (NaN,NaN)
+ {3,NaN,5}                             | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {3,NaN,5}                             | {0,-1,3}                              | (NaN,NaN)
+ {3,NaN,5}                             | {-1,0,3}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,-1,5}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {1,0,5}                               | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,3,0}                               | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {1,-1,0}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}                          | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {3,NaN,5}                             | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,-1,3}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-1,0,3}                              | (NaN,NaN)
+ {0,-1,3}                              | {0,-1,5}                              | 
+ {0,-1,3}                              | {1,0,5}                               | (-5,3)
+ {0,-1,3}                              | {0,3,0}                               | 
+ {0,-1,3}                              | {1,-1,0}                              | (3,3)
+ {0,-1,3}                              | {-0.4,-1,-6}                          | (-22.5,3)
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846} | (67083.3333333,3)
+ {0,-1,3}                              | {3,NaN,5}                             | (NaN,NaN)
+ {0,-1,3}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,-1,3}                              | {0,-1,3}                              | 
+ {0,-1,3}                              | {-1,0,3}                              | (3,3)
+ {-1,0,3}                              | {0,-1,5}                              | (3,5)
+ {-1,0,3}                              | {1,0,5}                               | 
+ {-1,0,3}                              | {0,3,0}                               | (3,0)
+ {-1,0,3}                              | {1,-1,0}                              | (3,3)
+ {-1,0,3}                              | {-0.4,-1,-6}                          | (3,-7.2)
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846} | (3,15.3840615385)
+ {-1,0,3}                              | {3,NaN,5}                             | (NaN,NaN)
+ {-1,0,3}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-1,0,3}                              | {0,-1,3}                              | (3,3)
+ {-1,0,3}                              | {-1,0,3}                              | 
+(100 rows)
+
+-- Closest point to line segment
+SELECT l.s, l1.s, l.s ## l1.s FROM LINE_TBL l, LSEG_TBL l1;
+                   s                   |               s               |             ?column?              
+---------------------------------------+-------------------------------+-----------------------------------
+ {0,-1,5}                              | [(1,2),(3,4)]                 | (3,4)
+ {0,-1,5}                              | [(0,0),(6,6)]                 | (5,5)
+ {0,-1,5}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,-1,5}                              | [(-1000000,200),(300000,-40)] | (56250,5)
+ {0,-1,5}                              | [(11,22),(33,44)]             | (11,22)
+ {0,-1,5}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {0,-1,5}                              | [(0,-20),(30,-20)]            | 
+ {0,-1,5}                              | [(NaN,1),(NaN,90)]            | 
+ {1,0,5}                               | [(1,2),(3,4)]                 | (1,2)
+ {1,0,5}                               | [(0,0),(6,6)]                 | (0,0)
+ {1,0,5}                               | [(10,-10),(-3,-4)]            | (-3,-4)
+ {1,0,5}                               | [(-1000000,200),(300000,-40)] | (-5,15.3855384615)
+ {1,0,5}                               | [(11,22),(33,44)]             | (11,22)
+ {1,0,5}                               | [(-10,2),(-10,3)]             | 
+ {1,0,5}                               | [(0,-20),(30,-20)]            | (0,-20)
+ {1,0,5}                               | [(NaN,1),(NaN,90)]            | 
+ {0,3,0}                               | [(1,2),(3,4)]                 | (1,2)
+ {0,3,0}                               | [(0,0),(6,6)]                 | (0,0)
+ {0,3,0}                               | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,3,0}                               | [(-1000000,200),(300000,-40)] | (83333.3333333,-1.7763568394e-15)
+ {0,3,0}                               | [(11,22),(33,44)]             | (11,22)
+ {0,3,0}                               | [(-10,2),(-10,3)]             | (-10,2)
+ {0,3,0}                               | [(0,-20),(30,-20)]            | 
+ {0,3,0}                               | [(NaN,1),(NaN,90)]            | 
+ {1,-1,0}                              | [(1,2),(3,4)]                 | 
+ {1,-1,0}                              | [(0,0),(6,6)]                 | 
+ {1,-1,0}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {1,-1,0}                              | [(-1000000,200),(300000,-40)] | (15.3817756722,15.3817756722)
+ {1,-1,0}                              | [(11,22),(33,44)]             | 
+ {1,-1,0}                              | [(-10,2),(-10,3)]             | (-10,2)
+ {1,-1,0}                              | [(0,-20),(30,-20)]            | (0,-20)
+ {1,-1,0}                              | [(NaN,1),(NaN,90)]            | 
+ {-0.4,-1,-6}                          | [(1,2),(3,4)]                 | (1,2)
+ {-0.4,-1,-6}                          | [(0,0),(6,6)]                 | (0,0)
+ {-0.4,-1,-6}                          | [(10,-10),(-3,-4)]            | (10,-10)
+ {-0.4,-1,-6}                          | [(-1000000,200),(300000,-40)] | (-53.4862244113,15.3944897645)
+ {-0.4,-1,-6}                          | [(11,22),(33,44)]             | (11,22)
+ {-0.4,-1,-6}                          | [(-10,2),(-10,3)]             | (-10,2)
+ {-0.4,-1,-6}                          | [(0,-20),(30,-20)]            | (30,-20)
+ {-0.4,-1,-6}                          | [(NaN,1),(NaN,90)]            | 
+ {-0.000184615384615,-1,15.3846153846} | [(1,2),(3,4)]                 | (3,4)
+ {-0.000184615384615,-1,15.3846153846} | [(0,0),(6,6)]                 | (6,6)
+ {-0.000184615384615,-1,15.3846153846} | [(10,-10),(-3,-4)]            | (-3,-4)
+ {-0.000184615384615,-1,15.3846153846} | [(-1000000,200),(300000,-40)] | 
+ {-0.000184615384615,-1,15.3846153846} | [(11,22),(33,44)]             | (11,22)
+ {-0.000184615384615,-1,15.3846153846} | [(-10,2),(-10,3)]             | (-10,3)
+ {-0.000184615384615,-1,15.3846153846} | [(0,-20),(30,-20)]            | (30,-20)
+ {-0.000184615384615,-1,15.3846153846} | [(NaN,1),(NaN,90)]            | 
+ {3,NaN,5}                             | [(1,2),(3,4)]                 | 
+ {3,NaN,5}                             | [(0,0),(6,6)]                 | 
+ {3,NaN,5}                             | [(10,-10),(-3,-4)]            | 
+ {3,NaN,5}                             | [(-1000000,200),(300000,-40)] | 
+ {3,NaN,5}                             | [(11,22),(33,44)]             | 
+ {3,NaN,5}                             | [(-10,2),(-10,3)]             | 
+ {3,NaN,5}                             | [(0,-20),(30,-20)]            | 
+ {3,NaN,5}                             | [(NaN,1),(NaN,90)]            | 
+ {NaN,NaN,NaN}                         | [(1,2),(3,4)]                 | 
+ {NaN,NaN,NaN}                         | [(0,0),(6,6)]                 | 
+ {NaN,NaN,NaN}                         | [(10,-10),(-3,-4)]            | 
+ {NaN,NaN,NaN}                         | [(-1000000,200),(300000,-40)] | 
+ {NaN,NaN,NaN}                         | [(11,22),(33,44)]             | 
+ {NaN,NaN,NaN}                         | [(-10,2),(-10,3)]             | 
+ {NaN,NaN,NaN}                         | [(0,-20),(30,-20)]            | 
+ {NaN,NaN,NaN}                         | [(NaN,1),(NaN,90)]            | 
+ {0,-1,3}                              | [(1,2),(3,4)]                 | (2,3)
+ {0,-1,3}                              | [(0,0),(6,6)]                 | (3,3)
+ {0,-1,3}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,-1,3}                              | [(-1000000,200),(300000,-40)] | (67083.3333333,3)
+ {0,-1,3}                              | [(11,22),(33,44)]             | (11,22)
+ {0,-1,3}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {0,-1,3}                              | [(0,-20),(30,-20)]            | 
+ {0,-1,3}                              | [(NaN,1),(NaN,90)]            | 
+ {-1,0,3}                              | [(1,2),(3,4)]                 | (3,4)
+ {-1,0,3}                              | [(0,0),(6,6)]                 | (3,3)
+ {-1,0,3}                              | [(10,-10),(-3,-4)]            | (3,-6.76923076923)
+ {-1,0,3}                              | [(-1000000,200),(300000,-40)] | (3,15.3840615385)
+ {-1,0,3}                              | [(11,22),(33,44)]             | (11,22)
+ {-1,0,3}                              | [(-10,2),(-10,3)]             | 
+ {-1,0,3}                              | [(0,-20),(30,-20)]            | (3,-20)
+ {-1,0,3}                              | [(NaN,1),(NaN,90)]            | 
+(80 rows)
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LINE_TBL l, BOX_TBL b;
+ERROR:  function "close_lb" not implemented
 --
 -- Line segments
 --
 -- intersection
 SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
    FROM LSEG_TBL l, POINT_TBL p;
 ERROR:  operator does not exist: lseg # point
 LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
                                            ^
 HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (-0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
+-- Length
+SELECT s, @-@ s FROM LSEG_TBL;
+               s               |   ?column?    
+-------------------------------+---------------
+ [(1,2),(3,4)]                 | 2.82842712475
+ [(0,0),(6,6)]                 | 8.48528137424
+ [(10,-10),(-3,-4)]            | 14.3178210633
+ [(-1000000,200),(300000,-40)] | 1300000.02215
+ [(11,22),(33,44)]             | 31.1126983722
+ [(-10,2),(-10,3)]             |             1
+ [(0,-20),(30,-20)]            |            30
+ [(NaN,1),(NaN,90)]            |           NaN
+(8 rows)
+
+-- Vertical
+SELECT s FROM LSEG_TBL WHERE ?| s;
+         s         
+-------------------
+ [(-10,2),(-10,3)]
+(1 row)
+
+-- Horizontal
+SELECT s FROM LSEG_TBL WHERE ?- s;
+         s          
+--------------------
+ [(0,-20),(30,-20)]
+(1 row)
+
+-- Center
+SELECT s, @@ s FROM LSEG_TBL;
+               s               |   ?column?   
+-------------------------------+--------------
+ [(1,2),(3,4)]                 | (2,3)
+ [(0,0),(6,6)]                 | (3,3)
+ [(10,-10),(-3,-4)]            | (3.5,-7)
+ [(-1000000,200),(300000,-40)] | (-350000,80)
+ [(11,22),(33,44)]             | (22,33)
+ [(-10,2),(-10,3)]             | (-10,2.5)
+ [(0,-20),(30,-20)]            | (15,-20)
+ [(NaN,1),(NaN,90)]            | (NaN,45.5)
+(8 rows)
+
+-- To point
+SELECT s, s::point FROM LSEG_TBL;
+               s               |      s       
+-------------------------------+--------------
+ [(1,2),(3,4)]                 | (2,3)
+ [(0,0),(6,6)]                 | (3,3)
+ [(10,-10),(-3,-4)]            | (3.5,-7)
+ [(-1000000,200),(300000,-40)] | (-350000,80)
+ [(11,22),(33,44)]             | (22,33)
+ [(-10,2),(-10,3)]             | (-10,2.5)
+ [(0,-20),(30,-20)]            | (15,-20)
+ [(NaN,1),(NaN,90)]            | (NaN,45.5)
+(8 rows)
+
+-- Has points less than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s < l2.s;
+         s          |               s               
+--------------------+-------------------------------
+ [(1,2),(3,4)]      | [(0,0),(6,6)]
+ [(1,2),(3,4)]      | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]      | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]      | [(11,22),(33,44)]
+ [(1,2),(3,4)]      | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]      | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]      | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]      | [(11,22),(33,44)]
+ [(0,0),(6,6)]      | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)] | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)] | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]  | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]  | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]  | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]  | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]  | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]  | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]  | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)] | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)] | [(11,22),(33,44)]
+(21 rows)
+
+-- Has points less than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s <= l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(28 rows)
+
+-- Has points equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s = l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]
+(8 rows)
+
+-- Has points greater than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s >= l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(28 rows)
+
+-- Has points greater than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s > l2.s;
+               s               |         s          
+-------------------------------+--------------------
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+(21 rows)
+
+-- Has points not equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s != l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)]
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]
+(56 rows)
+
+-- Parallel with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?|| l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(13 rows)
+
+-- Perpendicular with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?-| l2.s;
+         s          |         s          
+--------------------+--------------------
+ [(-10,2),(-10,3)]  | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)] | [(-10,2),(-10,3)]
+(2 rows)
+
+-- Distance to line
+SELECT l.s, l1.s, l.s <-> l1.s FROM LSEG_TBL l, LINE_TBL l1;
+               s               |                   s                   |    ?column?    
+-------------------------------+---------------------------------------+----------------
+ [(1,2),(3,4)]                 | {0,-1,5}                              |              1
+ [(0,0),(6,6)]                 | {0,-1,5}                              |              0
+ [(10,-10),(-3,-4)]            | {0,-1,5}                              |              9
+ [(-1000000,200),(300000,-40)] | {0,-1,5}                              |              0
+ [(11,22),(33,44)]             | {0,-1,5}                              |             17
+ [(-10,2),(-10,3)]             | {0,-1,5}                              |              2
+ [(0,-20),(30,-20)]            | {0,-1,5}                              |             25
+ [(NaN,1),(NaN,90)]            | {0,-1,5}                              |            NaN
+ [(1,2),(3,4)]                 | {1,0,5}                               |              6
+ [(0,0),(6,6)]                 | {1,0,5}                               |              5
+ [(10,-10),(-3,-4)]            | {1,0,5}                               |              2
+ [(-1000000,200),(300000,-40)] | {1,0,5}                               |              0
+ [(11,22),(33,44)]             | {1,0,5}                               |             16
+ [(-10,2),(-10,3)]             | {1,0,5}                               |              5
+ [(0,-20),(30,-20)]            | {1,0,5}                               |              5
+ [(NaN,1),(NaN,90)]            | {1,0,5}                               |            NaN
+ [(1,2),(3,4)]                 | {0,3,0}                               |              2
+ [(0,0),(6,6)]                 | {0,3,0}                               |              0
+ [(10,-10),(-3,-4)]            | {0,3,0}                               |              4
+ [(-1000000,200),(300000,-40)] | {0,3,0}                               |              0
+ [(11,22),(33,44)]             | {0,3,0}                               |             22
+ [(-10,2),(-10,3)]             | {0,3,0}                               |              2
+ [(0,-20),(30,-20)]            | {0,3,0}                               |             20
+ [(NaN,1),(NaN,90)]            | {0,3,0}                               |            NaN
+ [(1,2),(3,4)]                 | {1,-1,0}                              | 0.707106781187
+ [(0,0),(6,6)]                 | {1,-1,0}                              |              0
+ [(10,-10),(-3,-4)]            | {1,-1,0}                              | 0.707106781187
+ [(-1000000,200),(300000,-40)] | {1,-1,0}                              |              0
+ [(11,22),(33,44)]             | {1,-1,0}                              |  7.77817459305
+ [(-10,2),(-10,3)]             | {1,-1,0}                              |  8.48528137424
+ [(0,-20),(30,-20)]            | {1,-1,0}                              |  14.1421356237
+ [(NaN,1),(NaN,90)]            | {1,-1,0}                              |            NaN
+ [(1,2),(3,4)]                 | {-0.4,-1,-6}                          |  7.79920420344
+ [(0,0),(6,6)]                 | {-0.4,-1,-6}                          |  5.57086014531
+ [(10,-10),(-3,-4)]            | {-0.4,-1,-6}                          |              0
+ [(-1000000,200),(300000,-40)] | {-0.4,-1,-6}                          |              0
+ [(11,22),(33,44)]             | {-0.4,-1,-6}                          |  30.0826447847
+ [(-10,2),(-10,3)]             | {-0.4,-1,-6}                          |  3.71390676354
+ [(0,-20),(30,-20)]            | {-0.4,-1,-6}                          |  1.85695338177
+ [(NaN,1),(NaN,90)]            | {-0.4,-1,-6}                          |            NaN
+ [(1,2),(3,4)]                 | {-0.000184615384615,-1,15.3846153846} |  11.3840613445
+ [(0,0),(6,6)]                 | {-0.000184615384615,-1,15.3846153846} |   9.3835075324
+ [(10,-10),(-3,-4)]            | {-0.000184615384615,-1,15.3846153846} |  19.3851689004
+ [(-1000000,200),(300000,-40)] | {-0.000184615384615,-1,15.3846153846} |              0
+ [(11,22),(33,44)]             | {-0.000184615384615,-1,15.3846153846} |  6.61741527185
+ [(-10,2),(-10,3)]             | {-0.000184615384615,-1,15.3846153846} |  12.3864613274
+ [(0,-20),(30,-20)]            | {-0.000184615384615,-1,15.3846153846} |  35.3790763202
+ [(NaN,1),(NaN,90)]            | {-0.000184615384615,-1,15.3846153846} |            NaN
+ [(1,2),(3,4)]                 | {3,NaN,5}                             |            NaN
+ [(0,0),(6,6)]                 | {3,NaN,5}                             |            NaN
+ [(10,-10),(-3,-4)]            | {3,NaN,5}                             |            NaN
+ [(-1000000,200),(300000,-40)] | {3,NaN,5}                             |            NaN
+ [(11,22),(33,44)]             | {3,NaN,5}                             |            NaN
+ [(-10,2),(-10,3)]             | {3,NaN,5}                             |            NaN
+ [(0,-20),(30,-20)]            | {3,NaN,5}                             |            NaN
+ [(NaN,1),(NaN,90)]            | {3,NaN,5}                             |            NaN
+ [(1,2),(3,4)]                 | {NaN,NaN,NaN}                         |            NaN
+ [(0,0),(6,6)]                 | {NaN,NaN,NaN}                         |            NaN
+ [(10,-10),(-3,-4)]            | {NaN,NaN,NaN}                         |            NaN
+ [(-1000000,200),(300000,-40)] | {NaN,NaN,NaN}                         |            NaN
+ [(11,22),(33,44)]             | {NaN,NaN,NaN}                         |            NaN
+ [(-10,2),(-10,3)]             | {NaN,NaN,NaN}                         |            NaN
+ [(0,-20),(30,-20)]            | {NaN,NaN,NaN}                         |            NaN
+ [(NaN,1),(NaN,90)]            | {NaN,NaN,NaN}                         |            NaN
+ [(1,2),(3,4)]                 | {0,-1,3}                              |              0
+ [(0,0),(6,6)]                 | {0,-1,3}                              |              0
+ [(10,-10),(-3,-4)]            | {0,-1,3}                              |              7
+ [(-1000000,200),(300000,-40)] | {0,-1,3}                              |              0
+ [(11,22),(33,44)]             | {0,-1,3}                              |             19
+ [(-10,2),(-10,3)]             | {0,-1,3}                              |              0
+ [(0,-20),(30,-20)]            | {0,-1,3}                              |             23
+ [(NaN,1),(NaN,90)]            | {0,-1,3}                              |            NaN
+ [(1,2),(3,4)]                 | {-1,0,3}                              |              0
+ [(0,0),(6,6)]                 | {-1,0,3}                              |              0
+ [(10,-10),(-3,-4)]            | {-1,0,3}                              |              0
+ [(-1000000,200),(300000,-40)] | {-1,0,3}                              |              0
+ [(11,22),(33,44)]             | {-1,0,3}                              |              8
+ [(-10,2),(-10,3)]             | {-1,0,3}                              |             13
+ [(0,-20),(30,-20)]            | {-1,0,3}                              |              0
+ [(NaN,1),(NaN,90)]            | {-1,0,3}                              |            NaN
+(80 rows)
+
+-- Distance to line segment
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               |    ?column?    
+-------------------------------+-------------------------------+----------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 |              0
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 0.707106781187
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            |  7.12398901685
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] |  11.3840613445
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             |  19.6977156036
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             |             11
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            |             22
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            |            NaN
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 0.707106781187
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 |              0
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            |  4.88901207039
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] |   9.3835075324
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             |  16.7630546142
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             |  10.1980390272
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            |             20
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            |            NaN
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 |  7.12398901685
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 |  4.88901207039
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            |              0
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] |  19.3851689004
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             |  29.4737584815
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             |  9.21954445729
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            |             10
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            |            NaN
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 |  11.3840613445
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 |   9.3835075324
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            |  19.3851689004
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] |              0
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             |  6.61741527185
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             |  12.3864613274
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            |  35.3790763202
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            |            NaN
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 |  19.6977156036
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 |  16.7630546142
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            |  29.4737584815
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] |  6.61741527185
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             |              0
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             |   28.319604517
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            |             42
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            |            NaN
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 |             11
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 |  10.1980390272
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            |  9.21954445729
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] |  12.3864613274
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             |   28.319604517
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             |              0
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            |  24.1660919472
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            |            NaN
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 |             22
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 |             20
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            |             10
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] |  35.3790763202
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             |             42
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             |  24.1660919472
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            |              0
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 |            NaN
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 |            NaN
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] |            NaN
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             |            NaN
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             |            NaN
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            |            NaN
+(64 rows)
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LSEG_TBL l, BOX_TBL b;
+               s               |         f1          |    ?column?    
+-------------------------------+---------------------+----------------
+ [(1,2),(3,4)]                 | (2,2),(0,0)         |              0
+ [(1,2),(3,4)]                 | (3,3),(1,1)         |              0
+ [(1,2),(3,4)]                 | (-2,2),(-8,-10)     |              3
+ [(1,2),(3,4)]                 | (2.5,3.5),(2.5,2.5) |              0
+ [(1,2),(3,4)]                 | (3,3),(3,3)         | 0.707106781187
+ [(0,0),(6,6)]                 | (2,2),(0,0)         |              0
+ [(0,0),(6,6)]                 | (3,3),(1,1)         |              0
+ [(0,0),(6,6)]                 | (-2,2),(-8,-10)     |              2
+ [(0,0),(6,6)]                 | (2.5,3.5),(2.5,2.5) |              0
+ [(0,0),(6,6)]                 | (3,3),(3,3)         |              0
+ [(10,-10),(-3,-4)]            | (2,2),(0,0)         |  4.88901207039
+ [(10,-10),(-3,-4)]            | (3,3),(1,1)         |  6.21602963235
+ [(10,-10),(-3,-4)]            | (-2,2),(-8,-10)     |              0
+ [(10,-10),(-3,-4)]            | (2.5,3.5),(2.5,2.5) |  8.20655597529
+ [(10,-10),(-3,-4)]            | (3,3),(3,3)         |  8.87006475627
+ [(-1000000,200),(300000,-40)] | (2,2),(0,0)         |  13.3842459258
+ [(-1000000,200),(300000,-40)] | (3,3),(1,1)         |  12.3840613274
+ [(-1000000,200),(300000,-40)] | (-2,2),(-8,-10)     |  13.3849843873
+ [(-1000000,200),(300000,-40)] | (2.5,3.5),(2.5,2.5) |  11.8841536436
+ [(-1000000,200),(300000,-40)] | (3,3),(3,3)         |  12.3840613274
+ [(11,22),(33,44)]             | (2,2),(0,0)         |  21.9317121995
+ [(11,22),(33,44)]             | (3,3),(1,1)         |  20.6155281281
+ [(11,22),(33,44)]             | (-2,2),(-8,-10)     |  23.8537208838
+ [(11,22),(33,44)]             | (2.5,3.5),(2.5,2.5) |  20.3592730715
+ [(11,22),(33,44)]             | (3,3),(3,3)         |  20.6155281281
+ [(-10,2),(-10,3)]             | (2,2),(0,0)         |             10
+ [(-10,2),(-10,3)]             | (3,3),(1,1)         |             11
+ [(-10,2),(-10,3)]             | (-2,2),(-8,-10)     |              2
+ [(-10,2),(-10,3)]             | (2.5,3.5),(2.5,2.5) |           12.5
+ [(-10,2),(-10,3)]             | (3,3),(3,3)         |             13
+ [(0,-20),(30,-20)]            | (2,2),(0,0)         |             20
+ [(0,-20),(30,-20)]            | (3,3),(1,1)         |             21
+ [(0,-20),(30,-20)]            | (-2,2),(-8,-10)     |  10.1980390272
+ [(0,-20),(30,-20)]            | (2.5,3.5),(2.5,2.5) |           22.5
+ [(0,-20),(30,-20)]            | (3,3),(3,3)         |             23
+ [(NaN,1),(NaN,90)]            | (2,2),(0,0)         |            NaN
+ [(NaN,1),(NaN,90)]            | (3,3),(1,1)         |            NaN
+ [(NaN,1),(NaN,90)]            | (-2,2),(-8,-10)     |            NaN
+ [(NaN,1),(NaN,90)]            | (2.5,3.5),(2.5,2.5) |            NaN
+ [(NaN,1),(NaN,90)]            | (3,3),(3,3)         |            NaN
+(40 rows)
+
+-- Intersect with line segment
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s ?# l1.s;
+               s               |      s       
+-------------------------------+--------------
+ [(0,0),(6,6)]                 | {0,-1,5}
+ [(-1000000,200),(300000,-40)] | {0,-1,5}
+ [(-1000000,200),(300000,-40)] | {1,0,5}
+ [(0,0),(6,6)]                 | {0,3,0}
+ [(-1000000,200),(300000,-40)] | {0,3,0}
+ [(-1000000,200),(300000,-40)] | {1,-1,0}
+ [(10,-10),(-3,-4)]            | {-0.4,-1,-6}
+ [(-1000000,200),(300000,-40)] | {-0.4,-1,-6}
+ [(1,2),(3,4)]                 | {0,-1,3}
+ [(0,0),(6,6)]                 | {0,-1,3}
+ [(-1000000,200),(300000,-40)] | {0,-1,3}
+ [(-10,2),(-10,3)]             | {0,-1,3}
+ [(1,2),(3,4)]                 | {-1,0,3}
+ [(0,0),(6,6)]                 | {-1,0,3}
+ [(10,-10),(-3,-4)]            | {-1,0,3}
+ [(-1000000,200),(300000,-40)] | {-1,0,3}
+ [(0,-20),(30,-20)]            | {-1,0,3}
+(17 rows)
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+         s          |         f1          
+--------------------+---------------------
+ [(1,2),(3,4)]      | (2,2),(0,0)
+ [(1,2),(3,4)]      | (3,3),(1,1)
+ [(1,2),(3,4)]      | (2.5,3.5),(2.5,2.5)
+ [(0,0),(6,6)]      | (2,2),(0,0)
+ [(0,0),(6,6)]      | (3,3),(1,1)
+ [(0,0),(6,6)]      | (2.5,3.5),(2.5,2.5)
+ [(0,0),(6,6)]      | (3,3),(3,3)
+ [(10,-10),(-3,-4)] | (-2,2),(-8,-10)
+(8 rows)
+
+-- Intersection point with line segment
+SELECT l1.s, l2.s, l1.s # l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               | ?column? 
+-------------------------------+-------------------------------+----------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 | 
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            | 
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] | 
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             | 
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             | 
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            | 
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            | 
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 | 
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            | 
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] | 
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             | 
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             | 
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            | 
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            | 
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 | 
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 | 
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            | 
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] | 
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             | 
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             | 
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            | 
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            | 
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 | 
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 | 
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            | 
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] | 
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             | 
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             | 
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            | 
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            | 
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 | 
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 | 
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            | 
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] | 
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             | 
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             | 
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            | 
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            | 
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 | 
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 | 
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            | 
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] | 
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             | 
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             | 
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            | 
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            | 
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 | 
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 | 
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            | 
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] | 
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             | 
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             | 
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            | 
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            | 
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 | 
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 | 
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            | 
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] | 
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             | 
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             | 
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            | 
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            | 
+(64 rows)
+
+-- Closest point to line
+SELECT l.s, l1.s, l.s ## l1.s FROM LSEG_TBL l, LINE_TBL l1;
+ERROR:  function "close_sl" not implemented
+-- Closest point to line segment
+SELECT l1.s, l2.s, l1.s ## l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               |            ?column?             
+-------------------------------+-------------------------------+---------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 | 
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            | (-1.98536585366,-4.46829268293)
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] | (3.00210167283,15.3840611505)
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             | 
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             | (-10,2)
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            | (1,-20)
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            | 
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 | 
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] | (6.00173233982,15.3835073725)
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             | 
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             | (-10,2)
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            | (0,-20)
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            | 
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 | (1,2)
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 | (0,0)
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            | 
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] | (-2.99642119965,15.3851685701)
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             | (11,22)
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             | (-10,2)
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            | (10,-20)
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            | 
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 | (3,4)
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 | (6,6)
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            | (-3,-4)
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] | 
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             | (11,22)
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             | (-10,3)
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            | (30,-20)
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            | 
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 | 
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 | 
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            | (-1.3512195122,-4.76097560976)
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] | (10.9987783234,15.3825848409)
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             | 
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             | (-10,3)
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            | (11,-20)
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            | 
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 | (1,2)
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 | (0,0)
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            | (-3,-4)
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] | (-9.99771326872,15.3864611163)
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             | (11,22)
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             | 
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            | (0,-20)
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            | 
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 | (1,2)
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 | (0,0)
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            | (10,-10)
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] | (30.0065315217,15.3790757173)
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             | (11,22)
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             | (-10,2)
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            | 
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            | 
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 | 
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 | 
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            | 
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] | 
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             | 
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             | 
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            | 
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            | 
+(64 rows)
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LSEG_TBL l, BOX_TBL b;
+               s               |         f1          |  ?column?   
+-------------------------------+---------------------+-------------
+ [(1,2),(3,4)]                 | (2,2),(0,0)         | (1,2)
+ [(1,2),(3,4)]                 | (3,3),(1,1)         | (1.5,2.5)
+ [(1,2),(3,4)]                 | (-2,2),(-8,-10)     | (-2,2)
+ [(1,2),(3,4)]                 | (2.5,3.5),(2.5,2.5) | (2.25,3.25)
+ [(1,2),(3,4)]                 | (3,3),(3,3)         | (3,3)
+ [(0,0),(6,6)]                 | (2,2),(0,0)         | (1,1)
+ [(0,0),(6,6)]                 | (3,3),(1,1)         | (2,2)
+ [(0,0),(6,6)]                 | (-2,2),(-8,-10)     | (-2,0)
+ [(0,0),(6,6)]                 | (2.5,3.5),(2.5,2.5) | (2.75,2.75)
+ [(0,0),(6,6)]                 | (3,3),(3,3)         | (3,3)
+ [(10,-10),(-3,-4)]            | (2,2),(0,0)         | (0,0)
+ [(10,-10),(-3,-4)]            | (3,3),(1,1)         | (1,1)
+ [(10,-10),(-3,-4)]            | (-2,2),(-8,-10)     | (-3,-4)
+ [(10,-10),(-3,-4)]            | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ [(10,-10),(-3,-4)]            | (3,3),(3,3)         | (3,3)
+ [(-1000000,200),(300000,-40)] | (2,2),(0,0)         | (2,2)
+ [(-1000000,200),(300000,-40)] | (3,3),(1,1)         | (3,3)
+ [(-1000000,200),(300000,-40)] | (-2,2),(-8,-10)     | (-2,2)
+ [(-1000000,200),(300000,-40)] | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ [(-1000000,200),(300000,-40)] | (3,3),(3,3)         | (3,3)
+ [(11,22),(33,44)]             | (2,2),(0,0)         | (2,2)
+ [(11,22),(33,44)]             | (3,3),(1,1)         | (3,3)
+ [(11,22),(33,44)]             | (-2,2),(-8,-10)     | (-2,2)
+ [(11,22),(33,44)]             | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ [(11,22),(33,44)]             | (3,3),(3,3)         | (3,3)
+ [(-10,2),(-10,3)]             | (2,2),(0,0)         | (0,2)
+ [(-10,2),(-10,3)]             | (3,3),(1,1)         | (1,2)
+ [(-10,2),(-10,3)]             | (-2,2),(-8,-10)     | (-8,2)
+ [(-10,2),(-10,3)]             | (2.5,3.5),(2.5,2.5) | (2.5,3)
+ [(-10,2),(-10,3)]             | (3,3),(3,3)         | (3,3)
+ [(0,-20),(30,-20)]            | (2,2),(0,0)         | (0,0)
+ [(0,-20),(30,-20)]            | (3,3),(1,1)         | (1,1)
+ [(0,-20),(30,-20)]            | (-2,2),(-8,-10)     | (-2,-10)
+ [(0,-20),(30,-20)]            | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ [(0,-20),(30,-20)]            | (3,3),(3,3)         | (3,3)
+ [(NaN,1),(NaN,90)]            | (2,2),(0,0)         | 
+ [(NaN,1),(NaN,90)]            | (3,3),(1,1)         | 
+ [(NaN,1),(NaN,90)]            | (-2,2),(-8,-10)     | 
+ [(NaN,1),(NaN,90)]            | (2.5,3.5),(2.5,2.5) | 
+ [(NaN,1),(NaN,90)]            | (3,3),(3,3)         | 
+(40 rows)
+
+-- On line
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s <@ l1.s;
+               s               |                   s                   
+-------------------------------+---------------------------------------
+ [(0,0),(6,6)]                 | {1,-1,0}
+ [(-1000000,200),(300000,-40)] | {-0.000184615384615,-1,15.3846153846}
+(2 rows)
+
+-- On box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s <@ b.f1;
+ s | f1 
+---+----
+(0 rows)
 
 --
 -- Boxes
 --
 SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
  six |                              box                               
 -----+----------------------------------------------------------------
      | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
      | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
      | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
      | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
      | (107.071067812,207.071067812),(92.9289321881,192.928932188)
      | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
+     | (3,5),(3,5)
+     | (NaN,NaN),(NaN,NaN)
+(8 rows)
 
 -- translation
 SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
+ twentyfour |             translation             
+------------+-------------------------------------
             | (2,2),(0,0)
             | (3,3),(1,1)
+            | (-2,2),(-8,-10)
             | (2.5,3.5),(2.5,2.5)
             | (3,3),(3,3)
             | (-8,2),(-10,0)
             | (-7,3),(-9,1)
+            | (-12,2),(-18,-10)
             | (-7.5,3.5),(-7.5,2.5)
             | (-7,3),(-7,3)
             | (-1,6),(-3,4)
             | (0,7),(-2,5)
+            | (-5,6),(-11,-6)
             | (-0.5,7.5),(-0.5,6.5)
             | (0,7),(0,7)
             | (7.1,36.5),(5.1,34.5)
             | (8.1,37.5),(6.1,35.5)
+            | (3.1,36.5),(-2.9,24.5)
             | (7.6,38),(7.6,37)
             | (8.1,37.5),(8.1,37.5)
             | (-3,-10),(-5,-12)
             | (-2,-9),(-4,-11)
+            | (-7,-10),(-13,-22)
             | (-2.5,-8.5),(-2.5,-9.5)
             | (-2,-9),(-2,-9)
+            | (2,2),(1e-300,-1e-300)
+            | (3,3),(1,1)
+            | (-2,2),(-8,-10)
+            | (2.5,3.5),(2.5,2.5)
+            | (3,3),(3,3)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
             | (12,12),(10,10)
             | (13,13),(11,11)
+            | (8,12),(2,0)
             | (12.5,13.5),(12.5,12.5)
             | (13,13),(13,13)
-(24 rows)
+(45 rows)
 
 SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
+ twentyfour |               translation               
+------------+-----------------------------------------
             | (2,2),(0,0)
             | (3,3),(1,1)
+            | (-2,2),(-8,-10)
             | (2.5,3.5),(2.5,2.5)
             | (3,3),(3,3)
             | (12,2),(10,0)
             | (13,3),(11,1)
+            | (8,2),(2,-10)
             | (12.5,3.5),(12.5,2.5)
             | (13,3),(13,3)
             | (5,-2),(3,-4)
             | (6,-1),(4,-3)
+            | (1,-2),(-5,-14)
             | (5.5,-0.5),(5.5,-1.5)
             | (6,-1),(6,-1)
             | (-3.1,-32.5),(-5.1,-34.5)
             | (-2.1,-31.5),(-4.1,-33.5)
+            | (-7.1,-32.5),(-13.1,-44.5)
             | (-2.6,-31),(-2.6,-32)
             | (-2.1,-31.5),(-2.1,-31.5)
             | (7,14),(5,12)
             | (8,15),(6,13)
+            | (3,14),(-3,2)
             | (7.5,15.5),(7.5,14.5)
             | (8,15),(8,15)
+            | (2,2),(-1e-300,1e-300)
+            | (3,3),(1,1)
+            | (-2,2),(-8,-10)
+            | (2.5,3.5),(2.5,2.5)
+            | (3,3),(3,3)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
             | (-8,-8),(-10,-10)
             | (-7,-7),(-9,-9)
+            | (-12,-8),(-18,-20)
             | (-7.5,-6.5),(-7.5,-7.5)
             | (-7,-7),(-7,-7)
-(24 rows)
+(45 rows)
 
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (-0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (-0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,-0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
+-- Multiply with point
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+         f1          |     f1     |          ?column?           
+---------------------+------------+-----------------------------
+ (2,2),(0,0)         | (5.1,34.5) | (0,79.2),(-58.8,0)
+ (2,2),(0,0)         | (10,10)    | (0,40),(0,0)
+ (3,3),(1,1)         | (5.1,34.5) | (-29.4,118.8),(-88.2,39.6)
+ (3,3),(1,1)         | (10,10)    | (0,60),(0,20)
+ (-2,2),(-8,-10)     | (5.1,34.5) | (304.2,-58.8),(-79.2,-327)
+ (-2,2),(-8,-10)     | (10,10)    | (20,0),(-40,-180)
+ (2.5,3.5),(2.5,2.5) | (5.1,34.5) | (-73.5,104.1),(-108,99)
+ (2.5,3.5),(2.5,2.5) | (10,10)    | (0,60),(-10,50)
+ (3,3),(3,3)         | (5.1,34.5) | (-88.2,118.8),(-88.2,118.8)
+ (3,3),(3,3)         | (10,10)    | (0,60),(0,60)
+(10 rows)
 
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,-0),(-0.2,-0.2)
-        | (0.08,-0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (-0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
+-- Overflow error
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] > 1000;
+         f1          |        f1         |                  ?column?                  
+---------------------+-------------------+--------------------------------------------
+ (2,2),(0,0)         | (1e+300,Infinity) | (NaN,NaN),(-Infinity,Infinity)
+ (2,2),(0,0)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (3,3),(1,1)         | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (3,3),(1,1)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (-2,2),(-8,-10)     | (1e+300,Infinity) | (Infinity,-Infinity),(-Infinity,-Infinity)
+ (-2,2),(-8,-10)     | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (2.5,3.5),(2.5,2.5) | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (2.5,3.5),(2.5,2.5) | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (3,3),(3,3)         | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (3,3),(3,3)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+(10 rows)
 
+-- Divide by point
+SELECT b.f1, p.f1, b.f1 / p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+         f1          |     f1     |                               ?column?                               
+---------------------+------------+----------------------------------------------------------------------
+ (2,2),(0,0)         | (5.1,34.5) | (0.0651176557644,0),(0,-0.0483449262493)
+ (2,2),(0,0)         | (10,10)    | (0.2,0),(0,0)
+ (3,3),(1,1)         | (5.1,34.5) | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
+ (3,3),(1,1)         | (10,10)    | (0.3,0),(0.1,0)
+ (-2,2),(-8,-10)     | (5.1,34.5) | (0.0483449262493,0.18499334024),(-0.317201914064,0.0651176557644)
+ (-2,2),(-8,-10)     | (10,10)    | (0,0.2),(-0.9,-0.1)
+ (2.5,3.5),(2.5,2.5) | (5.1,34.5) | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
+ (2.5,3.5),(2.5,2.5) | (10,10)    | (0.3,0.05),(0.25,0)
+ (3,3),(3,3)         | (5.1,34.5) | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
+ (3,3),(3,3)         | (10,10)    | (0.3,0),(0.3,0)
+(10 rows)
+
+-- To box
 SELECT f1::box
 	FROM POINT_TBL;
-          f1           
------------------------
+                 f1                  
+-------------------------------------
  (0,0),(0,0)
  (-10,0),(-10,0)
  (-3,4),(-3,4)
  (5.1,34.5),(5.1,34.5)
  (-5,-12),(-5,-12)
+ (1e-300,-1e-300),(1e-300,-1e-300)
+ (1e+300,Infinity),(1e+300,Infinity)
+ (NaN,NaN),(NaN,NaN)
  (10,10),(10,10)
-(6 rows)
+(9 rows)
 
 SELECT bound_box(a.f1, b.f1)
 	FROM BOX_TBL a, BOX_TBL b;
       bound_box      
 ---------------------
  (2,2),(0,0)
  (3,3),(0,0)
+ (2,2),(-8,-10)
  (2.5,3.5),(0,0)
  (3,3),(0,0)
  (3,3),(0,0)
  (3,3),(1,1)
+ (3,3),(-8,-10)
  (3,3.5),(1,1)
  (3,3),(1,1)
+ (2,2),(-8,-10)
+ (3,3),(-8,-10)
+ (-2,2),(-8,-10)
+ (2.5,3.5),(-8,-10)
+ (3,3),(-8,-10)
  (2.5,3.5),(0,0)
  (3,3.5),(1,1)
+ (2.5,3.5),(-8,-10)
  (2.5,3.5),(2.5,2.5)
  (3,3.5),(2.5,2.5)
  (3,3),(0,0)
  (3,3),(1,1)
+ (3,3),(-8,-10)
  (3,3.5),(2.5,2.5)
  (3,3),(3,3)
-(16 rows)
+(25 rows)
+
+-- Below box
+SELECT b1.f1, b2.f1, b1.f1 <^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          | ?column? 
+---------------------+---------------------+----------
+ (2,2),(0,0)         | (2,2),(0,0)         | f
+ (2,2),(0,0)         | (3,3),(1,1)         | f
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | f
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | t
+ (2,2),(0,0)         | (3,3),(3,3)         | t
+ (3,3),(1,1)         | (2,2),(0,0)         | f
+ (3,3),(1,1)         | (3,3),(1,1)         | f
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | f
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(1,1)         | (3,3),(3,3)         | t
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | f
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | f
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | f
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | t
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | t
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | f
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | f
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | f
+ (3,3),(3,3)         | (2,2),(0,0)         | f
+ (3,3),(3,3)         | (3,3),(1,1)         | f
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | f
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(3,3)         | (3,3),(3,3)         | t
+(25 rows)
+
+-- Above box
+SELECT b1.f1, b2.f1, b1.f1 >^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          | ?column? 
+---------------------+---------------------+----------
+ (2,2),(0,0)         | (2,2),(0,0)         | f
+ (2,2),(0,0)         | (3,3),(1,1)         | f
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | f
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | f
+ (2,2),(0,0)         | (3,3),(3,3)         | f
+ (3,3),(1,1)         | (2,2),(0,0)         | f
+ (3,3),(1,1)         | (3,3),(1,1)         | f
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | f
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(1,1)         | (3,3),(3,3)         | f
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | f
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | f
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | f
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | f
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | f
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | t
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | f
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | t
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | f
+ (3,3),(3,3)         | (2,2),(0,0)         | t
+ (3,3),(3,3)         | (3,3),(1,1)         | t
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | t
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(3,3)         | (3,3),(3,3)         | t
+(25 rows)
+
+-- Intersection point with box
+SELECT b1.f1, b2.f1, b1.f1 # b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          |      ?column?       
+---------------------+---------------------+---------------------
+ (2,2),(0,0)         | (2,2),(0,0)         | (2,2),(0,0)
+ (2,2),(0,0)         | (3,3),(1,1)         | (2,2),(1,1)
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | 
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | 
+ (2,2),(0,0)         | (3,3),(3,3)         | 
+ (3,3),(1,1)         | (2,2),(0,0)         | (2,2),(1,1)
+ (3,3),(1,1)         | (3,3),(1,1)         | (3,3),(1,1)
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | 
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | (2.5,3),(2.5,2.5)
+ (3,3),(1,1)         | (3,3),(3,3)         | (3,3),(3,3)
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | 
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | 
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | (-2,2),(-8,-10)
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | 
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | 
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | 
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | (2.5,3),(2.5,2.5)
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | 
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5)
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | 
+ (3,3),(3,3)         | (2,2),(0,0)         | 
+ (3,3),(3,3)         | (3,3),(1,1)         | (3,3),(3,3)
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | 
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | 
+ (3,3),(3,3)         | (3,3),(3,3)         | (3,3),(3,3)
+(25 rows)
+
+-- Diagonal
+SELECT f1, diagonal(f1) FROM BOX_TBL;
+         f1          |       diagonal        
+---------------------+-----------------------
+ (2,2),(0,0)         | [(2,2),(0,0)]
+ (3,3),(1,1)         | [(3,3),(1,1)]
+ (-2,2),(-8,-10)     | [(-2,2),(-8,-10)]
+ (2.5,3.5),(2.5,2.5) | [(2.5,3.5),(2.5,2.5)]
+ (3,3),(3,3)         | [(3,3),(3,3)]
+(5 rows)
+
+-- Distance to box
+SELECT b1.f1, b2.f1, b1.f1 <-> b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          |   ?column?    
+---------------------+---------------------+---------------
+ (2,2),(0,0)         | (2,2),(0,0)         |             0
+ (2,2),(0,0)         | (3,3),(1,1)         | 1.41421356237
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | 7.81024967591
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) |           2.5
+ (2,2),(0,0)         | (3,3),(3,3)         | 2.82842712475
+ (3,3),(1,1)         | (2,2),(0,0)         | 1.41421356237
+ (3,3),(1,1)         | (3,3),(1,1)         |             0
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | 9.21954445729
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | 1.11803398875
+ (3,3),(1,1)         | (3,3),(3,3)         | 1.41421356237
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | 7.81024967591
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | 9.21954445729
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     |             0
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | 10.2591422643
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | 10.6301458127
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         |           2.5
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | 1.11803398875
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | 10.2591422643
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) |             0
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         |           0.5
+ (3,3),(3,3)         | (2,2),(0,0)         | 2.82842712475
+ (3,3),(3,3)         | (3,3),(1,1)         | 1.41421356237
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | 10.6301458127
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) |           0.5
+ (3,3),(3,3)         | (3,3),(3,3)         |             0
+(25 rows)
 
 --
 -- Paths
 --
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
+-- Points
+SELECT f1, npoints(f1) FROM PATH_TBL;
+            f1             | npoints 
+---------------------------+---------
+ [(1,2),(3,4)]             |       2
+ ((1,2),(3,4))             |       2
+ [(0,0),(3,0),(4,5),(1,6)] |       4
+ ((1,2),(3,4))             |       2
+ ((1,2),(3,4))             |       2
+ [(1,2),(3,4)]             |       2
+ ((10,20))                 |       1
+ [(11,12),(13,14)]         |       2
+ ((11,12),(13,14))         |       2
+(9 rows)
 
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
+-- Area
+SELECT f1, area(f1) FROM PATH_TBL;
+            f1             | area 
+---------------------------+------
+ [(1,2),(3,4)]             |     
+ ((1,2),(3,4))             |    0
+ [(0,0),(3,0),(4,5),(1,6)] |     
+ ((1,2),(3,4))             |    0
+ ((1,2),(3,4))             |    0
+ [(1,2),(3,4)]             |     
+ ((10,20))                 |    0
+ [(11,12),(13,14)]         |     
+ ((11,12),(13,14))         |    0
+(9 rows)
 
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
+-- Length
+SELECT f1, @-@ f1 FROM PATH_TBL;
+            f1             |   ?column?    
+---------------------------+---------------
+ [(1,2),(3,4)]             | 2.82842712475
+ ((1,2),(3,4))             | 5.65685424949
+ [(0,0),(3,0),(4,5),(1,6)] | 11.2612971738
+ ((1,2),(3,4))             | 5.65685424949
+ ((1,2),(3,4))             | 5.65685424949
+ [(1,2),(3,4)]             | 2.82842712475
+ ((10,20))                 |             0
+ [(11,12),(13,14)]         | 2.82842712475
+ ((11,12),(13,14))         | 5.65685424949
+(9 rows)
 
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
+-- Center
+SELECT f1, @@ f1 FROM PATH_TBL;
+ERROR:  function "path_center" not implemented
+-- To polygon
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isclosed(f1);
+        f1         |        f1         
+-------------------+-------------------
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((10,20))         | ((10,20))
+ ((11,12),(13,14)) | ((11,12),(13,14))
+(5 rows)
+
+-- Open path cannot be converted to polygon error
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isopen(f1);
+ERROR:  open path cannot be converted to polygon
+-- Has points less than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 < p2.f1;
+        f1         |            f1             
+-------------------+---------------------------
+ [(1,2),(3,4)]     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]     | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))         | [(1,2),(3,4)]
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | [(1,2),(3,4)]
+ ((10,20))         | [(11,12),(13,14)]
+ ((10,20))         | ((11,12),(13,14))
+ [(11,12),(13,14)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((11,12),(13,14)) | [(0,0),(3,0),(4,5),(1,6)]
+(15 rows)
+
+-- Has points less than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 <= p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | [(1,2),(3,4)]
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | [(1,2),(3,4)]
+ ((10,20))                 | ((10,20))
+ ((10,20))                 | [(11,12),(13,14)]
+ ((10,20))                 | ((11,12),(13,14))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(66 rows)
+
+-- Has points equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 = p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | ((10,20))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(51 rows)
+
+-- Has points greater than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 >= p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | ((10,20))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((10,20))
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((10,20))
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(66 rows)
+
+-- Has points greater than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 > p2.f1;
+            f1             |        f1         
+---------------------------+-------------------
+ [(1,2),(3,4)]             | ((10,20))
+ ((1,2),(3,4))             | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | ((10,20))
+ [(1,2),(3,4)]             | ((10,20))
+ [(11,12),(13,14)]         | ((10,20))
+ ((11,12),(13,14))         | ((10,20))
+(15 rows)
+
+-- Add path
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+            f1             |            f1             |                     ?column?                      
+---------------------------+---------------------------+---------------------------------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4),(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))                 | 
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         | [(1,2),(3,4),(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6),(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6),(0,0),(3,0),(4,5),(1,6)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6),(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))                 | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6),(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4),(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))                 | 
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         | [(1,2),(3,4),(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))         | 
+ ((10,20))                 | [(1,2),(3,4)]             | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | [(1,2),(3,4)]             | 
+ ((10,20))                 | ((10,20))                 | 
+ ((10,20))                 | [(11,12),(13,14)]         | 
+ ((10,20))                 | ((11,12),(13,14))         | 
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             | [(11,12),(13,14),(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14),(0,0),(3,0),(4,5),(1,6)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             | [(11,12),(13,14),(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((10,20))                 | 
+ [(11,12),(13,14)]         | [(11,12),(13,14)]         | [(11,12),(13,14),(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))         | 
+ ((11,12),(13,14))         | [(1,2),(3,4)]             | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | [(1,2),(3,4)]             | 
+ ((11,12),(13,14))         | ((10,20))                 | 
+ ((11,12),(13,14))         | [(11,12),(13,14)]         | 
+ ((11,12),(13,14))         | ((11,12),(13,14))         | 
+(81 rows)
+
+-- Add point
+SELECT p.f1, p1.f1, p.f1 + p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                                 ?column?                                  
+---------------------------+-------------------+---------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((10,20))                 | (0,0)             | ((10,20))
+ [(11,12),(13,14)]         | (0,0)             | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (0,0)             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (-10,0)           | [(-9,2),(-7,4)]
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(-10,0),(-7,0),(-6,5),(-9,6)]
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ [(1,2),(3,4)]             | (-10,0)           | [(-9,2),(-7,4)]
+ ((10,20))                 | (-10,0)           | ((0,20))
+ [(11,12),(13,14)]         | (-10,0)           | [(1,12),(3,14)]
+ ((11,12),(13,14))         | (-10,0)           | ((1,12),(3,14))
+ [(1,2),(3,4)]             | (-3,4)            | [(-2,6),(0,8)]
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(-3,4),(0,4),(1,9),(-2,10)]
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ [(1,2),(3,4)]             | (-3,4)            | [(-2,6),(0,8)]
+ ((10,20))                 | (-3,4)            | ((7,24))
+ [(11,12),(13,14)]         | (-3,4)            | [(8,16),(10,18)]
+ ((11,12),(13,14))         | (-3,4)            | ((8,16),(10,18))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(6.1,36.5),(8.1,38.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(5.1,34.5),(8.1,34.5),(9.1,39.5),(6.1,40.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(6.1,36.5),(8.1,38.5)]
+ ((10,20))                 | (5.1,34.5)        | ((15.1,54.5))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(16.1,46.5),(18.1,48.5)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((16.1,46.5),(18.1,48.5))
+ [(1,2),(3,4)]             | (-5,-12)          | [(-4,-10),(-2,-8)]
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(-5,-12),(-2,-12),(-1,-7),(-4,-6)]
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ [(1,2),(3,4)]             | (-5,-12)          | [(-4,-10),(-2,-8)]
+ ((10,20))                 | (-5,-12)          | ((5,8))
+ [(11,12),(13,14)]         | (-5,-12)          | [(6,0),(8,2)]
+ ((11,12),(13,14))         | (-5,-12)          | ((6,0),(8,2))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(1e-300,-1e-300),(3,-1e-300),(4,5),(1,6)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((10,20))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity),(1e+300,Infinity),(1e+300,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((1e+300,Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(11,12),(13,14)]
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(10,10),(13,10),(14,15),(11,16)]
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (10,10)           | [(11,12),(13,14)]
+ ((10,20))                 | (10,10)           | ((20,30))
+ [(11,12),(13,14)]         | (10,10)           | [(21,22),(23,24)]
+ ((11,12),(13,14))         | (10,10)           | ((21,22),(23,24))
+(81 rows)
+
+-- Subtract point
+SELECT p.f1, p1.f1, p.f1 - p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                                     ?column?                                      
+---------------------------+-------------------+-----------------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((10,20))                 | (0,0)             | ((10,20))
+ [(11,12),(13,14)]         | (0,0)             | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (0,0)             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (-10,0)           | [(11,2),(13,4)]
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(10,0),(13,0),(14,5),(11,6)]
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ [(1,2),(3,4)]             | (-10,0)           | [(11,2),(13,4)]
+ ((10,20))                 | (-10,0)           | ((20,20))
+ [(11,12),(13,14)]         | (-10,0)           | [(21,12),(23,14)]
+ ((11,12),(13,14))         | (-10,0)           | ((21,12),(23,14))
+ [(1,2),(3,4)]             | (-3,4)            | [(4,-2),(6,0)]
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(3,-4),(6,-4),(7,1),(4,2)]
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ [(1,2),(3,4)]             | (-3,4)            | [(4,-2),(6,0)]
+ ((10,20))                 | (-3,4)            | ((13,16))
+ [(11,12),(13,14)]         | (-3,4)            | [(14,8),(16,10)]
+ ((11,12),(13,14))         | (-3,4)            | ((14,8),(16,10))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-4.1,-32.5),(-2.1,-30.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(-5.1,-34.5),(-2.1,-34.5),(-1.1,-29.5),(-4.1,-28.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-4.1,-32.5),(-2.1,-30.5)]
+ ((10,20))                 | (5.1,34.5)        | ((4.9,-14.5))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(5.9,-22.5),(7.9,-20.5)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((5.9,-22.5),(7.9,-20.5))
+ [(1,2),(3,4)]             | (-5,-12)          | [(6,14),(8,16)]
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(5,12),(8,12),(9,17),(6,18)]
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ [(1,2),(3,4)]             | (-5,-12)          | [(6,14),(8,16)]
+ ((10,20))                 | (-5,-12)          | ((15,32))
+ [(11,12),(13,14)]         | (-5,-12)          | [(16,24),(18,26)]
+ ((11,12),(13,14))         | (-5,-12)          | ((16,24),(18,26))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(-1e-300,1e-300),(3,1e-300),(4,5),(1,6)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((10,20))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity),(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((-1e+300,-Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(-9,-8),(-7,-6)]
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(-10,-10),(-7,-10),(-6,-5),(-9,-4)]
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ [(1,2),(3,4)]             | (10,10)           | [(-9,-8),(-7,-6)]
+ ((10,20))                 | (10,10)           | ((0,10))
+ [(11,12),(13,14)]         | (10,10)           | [(1,2),(3,4)]
+ ((11,12),(13,14))         | (10,10)           | ((1,2),(3,4))
+(81 rows)
+
+-- Multiply with point
+SELECT p.f1, p1.f1, p.f1 * p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                               ?column?                               
+---------------------------+-------------------+----------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(0,0),(0,0)]
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(0,0),(0,0),(0,0)]
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ [(1,2),(3,4)]             | (0,0)             | [(0,0),(0,0)]
+ ((10,20))                 | (0,0)             | ((0,0))
+ [(11,12),(13,14)]         | (0,0)             | [(0,0),(0,0)]
+ ((11,12),(13,14))         | (0,0)             | ((0,0),(0,0))
+ [(1,2),(3,4)]             | (-10,0)           | [(-10,-20),(-30,-40)]
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(0,0),(-30,0),(-40,-50),(-10,-60)]
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ [(1,2),(3,4)]             | (-10,0)           | [(-10,-20),(-30,-40)]
+ ((10,20))                 | (-10,0)           | ((-100,-200))
+ [(11,12),(13,14)]         | (-10,0)           | [(-110,-120),(-130,-140)]
+ ((11,12),(13,14))         | (-10,0)           | ((-110,-120),(-130,-140))
+ [(1,2),(3,4)]             | (-3,4)            | [(-11,-2),(-25,0)]
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(0,0),(-9,12),(-32,1),(-27,-14)]
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ [(1,2),(3,4)]             | (-3,4)            | [(-11,-2),(-25,0)]
+ ((10,20))                 | (-3,4)            | ((-110,-20))
+ [(11,12),(13,14)]         | (-3,4)            | [(-81,8),(-95,10)]
+ ((11,12),(13,14))         | (-3,4)            | ((-81,8),(-95,10))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-63.9,44.7),(-122.7,123.9)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(0,0),(15.3,103.5),(-152.1,163.5),(-201.9,65.1)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-63.9,44.7),(-122.7,123.9)]
+ ((10,20))                 | (5.1,34.5)        | ((-639,447))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(-357.9,440.7),(-416.7,519.9)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((-357.9,440.7),(-416.7,519.9))
+ [(1,2),(3,4)]             | (-5,-12)          | [(19,-22),(33,-56)]
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(0,0),(-15,-36),(40,-73),(67,-42)]
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ [(1,2),(3,4)]             | (-5,-12)          | [(19,-22),(33,-56)]
+ ((10,20))                 | (-5,-12)          | ((190,-220))
+ [(11,12),(13,14)]         | (-5,-12)          | [(89,-192),(103,-226)]
+ ((11,12),(13,14))         | (-5,-12)          | ((89,-192),(103,-226))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(3e-300,1e-300),(7e-300,1e-300)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(0,0),(3e-300,-3e-300),(9e-300,1e-300),(7e-300,5e-300)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(3e-300,1e-300),(7e-300,1e-300)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((3e-299,1e-299))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(2.3e-299,1e-300),(2.7e-299,1e-300)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((2.3e-299,1e-300),(2.7e-299,1e-300))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(NaN,NaN),(NaN,Infinity),(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((-Infinity,Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(-10,30),(-10,70)]
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(0,0),(30,30),(-10,90),(-50,70)]
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ [(1,2),(3,4)]             | (10,10)           | [(-10,30),(-10,70)]
+ ((10,20))                 | (10,10)           | ((-100,300))
+ [(11,12),(13,14)]         | (10,10)           | [(-10,230),(-10,270)]
+ ((11,12),(13,14))         | (10,10)           | ((-10,230),(-10,270))
+(81 rows)
+
+-- Divide by point
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+            f1             |     f1     |                                                    ?column?                                                     
+---------------------------+------------+-----------------------------------------------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (5.1,34.5) | [(0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952)]
+ [(1,2),(3,4)]             | (10,10)    | [(0.15,0.05),(0.35,0.05)]
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5) | [(0,0),(0.0125795471363,-0.0850969365103),(0.158600957032,-0.0924966701199),(0.174387055399,-0.00320655123082)]
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)    | [(0,0),(0.15,-0.15),(0.45,0.05),(0.35,0.25)]
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ [(1,2),(3,4)]             | (5.1,34.5) | [(0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952)]
+ [(1,2),(3,4)]             | (10,10)    | [(0.15,0.05),(0.35,0.05)]
+ ((10,20))                 | (5.1,34.5) | ((0.609244733856,-0.199792807459))
+ ((10,20))                 | (10,10)    | ((1.5,0.5))
+ [(11,12),(13,14)]         | (5.1,34.5) | [(0.386512752208,-0.261703911993),(0.451630407972,-0.310048838242)]
+ [(11,12),(13,14)]         | (10,10)    | [(1.15,0.05),(1.35,0.05)]
+ ((11,12),(13,14))         | (5.1,34.5) | ((0.386512752208,-0.261703911993),(0.451630407972,-0.310048838242))
+ ((11,12),(13,14))         | (10,10)    | ((1.15,0.05),(1.35,0.05))
+(18 rows)
+
+-- Division by 0 error
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to path
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+            f1             |            f1             |    ?column?    
+---------------------------+---------------------------+----------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((10,20))                 |  17.4642491966
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         |   11.313708499
+ [(1,2),(3,4)]             | ((11,12),(13,14))         |   11.313708499
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)] |              0
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))                 |  16.1554944214
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]         |  9.89949493661
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))         |  9.89949493661
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((10,20))                 |  17.4642491966
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         |   11.313708499
+ [(1,2),(3,4)]             | ((11,12),(13,14))         |   11.313708499
+ ((10,20))                 | [(1,2),(3,4)]             |  17.4642491966
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)] |  16.1554944214
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | [(1,2),(3,4)]             |  17.4642491966
+ ((10,20))                 | ((10,20))                 |              0
+ ((10,20))                 | [(11,12),(13,14)]         |   6.7082039325
+ ((10,20))                 | ((11,12),(13,14))         |   6.7082039325
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             |   11.313708499
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)] |  9.89949493661
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             |   11.313708499
+ [(11,12),(13,14)]         | ((10,20))                 |   6.7082039325
+ [(11,12),(13,14)]         | [(11,12),(13,14)]         |              0
+ [(11,12),(13,14)]         | ((11,12),(13,14))         |              0
+ ((11,12),(13,14))         | [(1,2),(3,4)]             |   11.313708499
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)] |  9.89949493661
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | [(1,2),(3,4)]             |   11.313708499
+ ((11,12),(13,14))         | ((10,20))                 |   6.7082039325
+ ((11,12),(13,14))         | [(11,12),(13,14)]         |              0
+ ((11,12),(13,14))         | ((11,12),(13,14))         |              0
+(81 rows)
 
 --
 -- Polygons
 --
 -- containment
 SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
    FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
+ twentyfour |        f1         |             f1             | contains 
+------------+-------------------+----------------------------+----------
+            | (0,0)             | ((2,0),(2,4),(0,0))        | t
+            | (0,0)             | ((3,1),(3,3),(1,0))        | f
+            | (0,0)             | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (0,0)             | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (0,0)             | ((0,0))                    | t
+            | (0,0)             | ((0,1),(0,1))              | f
+            | (-10,0)           | ((2,0),(2,4),(0,0))        | f
+            | (-10,0)           | ((3,1),(3,3),(1,0))        | f
+            | (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-10,0)           | ((0,0))                    | f
+            | (-10,0)           | ((0,1),(0,1))              | f
+            | (-3,4)            | ((2,0),(2,4),(0,0))        | f
+            | (-3,4)            | ((3,1),(3,3),(1,0))        | f
+            | (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-3,4)            | ((0,0))                    | f
+            | (-3,4)            | ((0,1),(0,1))              | f
+            | (5.1,34.5)        | ((2,0),(2,4),(0,0))        | f
+            | (5.1,34.5)        | ((3,1),(3,3),(1,0))        | f
+            | (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (5.1,34.5)        | ((0,0))                    | f
+            | (5.1,34.5)        | ((0,1),(0,1))              | f
+            | (-5,-12)          | ((2,0),(2,4),(0,0))        | f
+            | (-5,-12)          | ((3,1),(3,3),(1,0))        | f
+            | (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-5,-12)          | ((0,0))                    | f
+            | (-5,-12)          | ((0,1),(0,1))              | f
+            | (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        | t
+            | (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        | f
+            | (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e-300,-1e-300)  | ((0,0))                    | t
+            | (1e-300,-1e-300)  | ((0,1),(0,1))              | f
+            | (1e+300,Infinity) | ((2,0),(2,4),(0,0))        | f
+            | (1e+300,Infinity) | ((3,1),(3,3),(1,0))        | f
+            | (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e+300,Infinity) | ((0,0))                    | f
+            | (1e+300,Infinity) | ((0,1),(0,1))              | f
+            | (NaN,NaN)         | ((2,0),(2,4),(0,0))        | t
+            | (NaN,NaN)         | ((3,1),(3,3),(1,0))        | t
+            | (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  | t
+            | (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  | t
+            | (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) | t
+            | (NaN,NaN)         | ((0,0))                    | t
+            | (NaN,NaN)         | ((0,1),(0,1))              | t
+            | (10,10)           | ((2,0),(2,4),(0,0))        | f
+            | (10,10)           | ((3,1),(3,3),(1,0))        | f
+            | (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (10,10)           | ((0,0))                    | f
+            | (10,10)           | ((0,1),(0,1))              | f
+(63 rows)
 
 SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
    FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
+ twentyfour |        f1         |             f1             | contained 
+------------+-------------------+----------------------------+-----------
+            | (0,0)             | ((2,0),(2,4),(0,0))        | t
+            | (0,0)             | ((3,1),(3,3),(1,0))        | f
+            | (0,0)             | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (0,0)             | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (0,0)             | ((0,0))                    | t
+            | (0,0)             | ((0,1),(0,1))              | f
+            | (-10,0)           | ((2,0),(2,4),(0,0))        | f
+            | (-10,0)           | ((3,1),(3,3),(1,0))        | f
+            | (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-10,0)           | ((0,0))                    | f
+            | (-10,0)           | ((0,1),(0,1))              | f
+            | (-3,4)            | ((2,0),(2,4),(0,0))        | f
+            | (-3,4)            | ((3,1),(3,3),(1,0))        | f
+            | (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-3,4)            | ((0,0))                    | f
+            | (-3,4)            | ((0,1),(0,1))              | f
+            | (5.1,34.5)        | ((2,0),(2,4),(0,0))        | f
+            | (5.1,34.5)        | ((3,1),(3,3),(1,0))        | f
+            | (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (5.1,34.5)        | ((0,0))                    | f
+            | (5.1,34.5)        | ((0,1),(0,1))              | f
+            | (-5,-12)          | ((2,0),(2,4),(0,0))        | f
+            | (-5,-12)          | ((3,1),(3,3),(1,0))        | f
+            | (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-5,-12)          | ((0,0))                    | f
+            | (-5,-12)          | ((0,1),(0,1))              | f
+            | (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        | t
+            | (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        | f
+            | (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e-300,-1e-300)  | ((0,0))                    | t
+            | (1e-300,-1e-300)  | ((0,1),(0,1))              | f
+            | (1e+300,Infinity) | ((2,0),(2,4),(0,0))        | f
+            | (1e+300,Infinity) | ((3,1),(3,3),(1,0))        | f
+            | (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e+300,Infinity) | ((0,0))                    | f
+            | (1e+300,Infinity) | ((0,1),(0,1))              | f
+            | (NaN,NaN)         | ((2,0),(2,4),(0,0))        | t
+            | (NaN,NaN)         | ((3,1),(3,3),(1,0))        | t
+            | (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  | t
+            | (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  | t
+            | (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) | t
+            | (NaN,NaN)         | ((0,0))                    | t
+            | (NaN,NaN)         | ((0,1),(0,1))              | t
+            | (10,10)           | ((2,0),(2,4),(0,0))        | f
+            | (10,10)           | ((3,1),(3,3),(1,0))        | f
+            | (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (10,10)           | ((0,0))                    | f
+            | (10,10)           | ((0,1),(0,1))              | f
+(63 rows)
 
 SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
    FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
+ four | npoints |          polygon           
+------+---------+----------------------------
       |       3 | ((2,0),(2,4),(0,0))
       |       3 | ((3,1),(3,3),(1,0))
+      |       4 | ((1,2),(3,4),(5,6),(7,8))
+      |       4 | ((7,8),(5,6),(3,4),(1,2))
+      |       4 | ((1,2),(7,8),(5,6),(3,-4))
       |       1 | ((0,0))
       |       2 | ((0,1),(0,1))
-(4 rows)
+(7 rows)
 
 SELECT '' AS four, polygon(f1)
    FROM BOX_TBL;
  four |                  polygon                  
 ------+-------------------------------------------
       | ((0,0),(0,2),(2,2),(2,0))
       | ((1,1),(1,3),(3,3),(3,1))
+      | ((-8,-10),(-8,2),(-2,2),(-2,-10))
       | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
       | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, polygon(f1)
    FROM PATH_TBL WHERE isclosed(f1);
  four |      polygon      
 ------+-------------------
       | ((1,2),(3,4))
       | ((1,2),(3,4))
       | ((1,2),(3,4))
+      | ((10,20))
       | ((11,12),(13,14))
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
    FROM PATH_TBL
    WHERE isopen(f1);
  four |         open_path         |          polygon          
 ------+---------------------------+---------------------------
       | [(1,2),(3,4)]             | ((1,2),(3,4))
       | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
       | [(1,2),(3,4)]             | ((1,2),(3,4))
       | [(11,12),(13,14)]         | ((11,12),(13,14))
 (4 rows)
 
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
+-- To box
+SELECT f1, f1::box FROM POLYGON_TBL;
+             f1             |      f1      
+----------------------------+--------------
+ ((2,0),(2,4),(0,0))        | (2,4),(0,0)
+ ((3,1),(3,3),(1,0))        | (3,3),(1,0)
+ ((1,2),(3,4),(5,6),(7,8))  | (7,8),(1,2)
+ ((7,8),(5,6),(3,4),(1,2))  | (7,8),(1,2)
+ ((1,2),(7,8),(5,6),(3,-4)) | (7,8),(1,-4)
+ ((0,0))                    | (0,0),(0,0)
+ ((0,1),(0,1))              | (0,1),(0,1)
+(7 rows)
 
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
+-- To path
+SELECT f1, f1::path FROM POLYGON_TBL;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(7 rows)
 
+-- Same as polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 ~= p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(9 rows)
+
+-- Contained by polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <@ p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(12 rows)
+
+-- Contains polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 @> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(12 rows)
+
+-- Overlap with polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 && p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(25 rows)
+
+-- Left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 << p2.f1;
+      f1       |             f1             
+---------------+----------------------------
+ ((0,0))       | ((3,1),(3,3),(1,0))
+ ((0,0))       | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))       | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))       | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1)) | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1)) | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1)) | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1)) | ((1,2),(7,8),(5,6),(3,-4))
+(8 rows)
+
+-- Overlap of left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &< p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))                    | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1))              | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(32 rows)
+
+-- Right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 >> p2.f1;
+             f1             |      f1       
+----------------------------+---------------
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((0,1),(0,1))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1))
+(8 rows)
+
+-- Overlap of right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((2,0),(2,4),(0,0))        | ((0,1),(0,1))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((0,1),(0,1))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((3,1),(3,3),(1,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(37 rows)
+
+-- Below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <<| p2.f1;
+      f1       |            f1             
+---------------+---------------------------
+ ((0,0))       | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))       | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))       | ((0,1),(0,1))
+ ((0,1),(0,1)) | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1)) | ((7,8),(5,6),(3,4),(1,2))
+(5 rows)
+
+-- Overlap or below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &<| p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))                    | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1))              | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(31 rows)
+
+-- Above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |>> p2.f1;
+            f1             |      f1       
+---------------------------+---------------
+ ((1,2),(3,4),(5,6),(7,8)) | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8)) | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2)) | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2)) | ((0,1),(0,1))
+ ((0,1),(0,1))             | ((0,0))
+(5 rows)
+
+-- Overlap or above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |&> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((3,1),(3,3),(1,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(32 rows)
+
+-- Distance to polygon
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2;
+ERROR:  function "poly_distance" not implemented
 --
 -- Circles
 --
 SELECT '' AS six, circle(f1, 50.0)
    FROM POINT_TBL;
- six |     circle      
------+-----------------
+ six |         circle         
+-----+------------------------
      | <(0,0),50>
      | <(-10,0),50>
      | <(-3,4),50>
      | <(5.1,34.5),50>
      | <(-5,-12),50>
+     | <(1e-300,-1e-300),50>
+     | <(1e+300,Infinity),50>
+     | <(NaN,NaN),50>
      | <(10,10),50>
-(6 rows)
+(9 rows)
 
 SELECT '' AS four, circle(f1)
    FROM BOX_TBL;
- four |        circle         
-------+-----------------------
+ four |         circle         
+------+------------------------
       | <(1,1),1.41421356237>
       | <(2,2),1.41421356237>
+      | <(-5,-4),6.7082039325>
       | <(2.5,3),0.5>
       | <(3,3),0>
-(4 rows)
+(5 rows)
 
 SELECT '' AS two, circle(f1)
    FROM POLYGON_TBL
    WHERE (# f1) >= 3;
  two |                    circle                     
 -----+-----------------------------------------------
      | <(1.33333333333,1.33333333333),2.04168905064>
      | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
+     | <(4,5),2.82842712475>
+     | <(4,5),2.82842712475>
+     | <(4,3),4.80664375676>
+(5 rows)
 
 SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
    FROM CIRCLE_TBL c1, POINT_TBL p1
    WHERE (p1.f1 <-> c1.f1) > 0
    ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
+ twentyfour |     circle     |       point       |   distance    
+------------+----------------+-------------------+---------------
+            | <(1,2),3>      | (-3,4)            |   1.472135955
+            | <(5,1),3>      | (0,0)             | 2.09901951359
+            | <(5,1),3>      | (1e-300,-1e-300)  | 2.09901951359
+            | <(5,1),3>      | (-3,4)            | 5.54400374532
+            | <(3,5),0>      | (0,0)             | 5.83095189485
+            | <(3,5),0>      | (1e-300,-1e-300)  | 5.83095189485
+            | <(3,5),0>      | (-3,4)            |  6.0827625303
+            | <(1,3),5>      | (-10,0)           | 6.40175425099
+            | <(1,3),5>      | (10,10)           | 6.40175425099
+            | <(5,1),3>      | (10,10)           | 7.29563014099
+            | <(1,2),3>      | (-10,0)           |  8.1803398875
+            | <(3,5),0>      | (10,10)           | 8.60232526704
+            | <(1,2),3>      | (10,10)           | 9.04159457879
+            | <(1,3),5>      | (-5,-12)          | 11.1554944214
+            | <(5,1),3>      | (-10,0)           | 12.0332963784
+            | <(1,2),3>      | (-5,-12)          | 12.2315462117
+            | <(5,1),3>      | (-5,-12)          | 13.4012194669
+            | <(3,5),0>      | (-10,0)           | 13.9283882772
+            | <(3,5),0>      | (-5,-12)          | 18.7882942281
+            | <(1,3),5>      | (5.1,34.5)        | 26.7657047773
+            | <(3,5),0>      | (5.1,34.5)        | 29.5746513082
+            | <(1,2),3>      | (5.1,34.5)        | 29.7575945393
+            | <(5,1),3>      | (5.1,34.5)        | 30.5001492534
+            | <(100,200),10> | (5.1,34.5)        | 180.778038568
+            | <(100,200),10> | (10,10)           | 200.237960416
+            | <(100,200),10> | (-3,4)            | 211.415898255
+            | <(100,200),10> | (0,0)             |  213.60679775
+            | <(100,200),10> | (1e-300,-1e-300)  |  213.60679775
+            | <(100,200),10> | (-10,0)           |  218.25424421
+            | <(100,200),10> | (-5,-12)          | 226.577682802
+            | <(3,5),0>      | (1e+300,Infinity) |      Infinity
+            | <(1,2),3>      | (1e+300,Infinity) |      Infinity
+            | <(5,1),3>      | (1e+300,Infinity) |      Infinity
+            | <(1,3),5>      | (1e+300,Infinity) |      Infinity
+            | <(100,200),10> | (1e+300,Infinity) |      Infinity
+            | <(1,2),100>    | (1e+300,Infinity) |      Infinity
+            | <(100,1),115>  | (1e+300,Infinity) |      Infinity
+            | <(3,5),0>      | (NaN,NaN)         |           NaN
+            | <(1,2),3>      | (NaN,NaN)         |           NaN
+            | <(5,1),3>      | (NaN,NaN)         |           NaN
+            | <(1,3),5>      | (NaN,NaN)         |           NaN
+            | <(100,200),10> | (NaN,NaN)         |           NaN
+            | <(1,2),100>    | (NaN,NaN)         |           NaN
+            | <(100,1),115>  | (NaN,NaN)         |           NaN
+            | <(3,5),NaN>    | (-10,0)           |           NaN
+            | <(3,5),NaN>    | (-5,-12)          |           NaN
+            | <(3,5),NaN>    | (-3,4)            |           NaN
+            | <(3,5),NaN>    | (0,0)             |           NaN
+            | <(3,5),NaN>    | (1e-300,-1e-300)  |           NaN
+            | <(3,5),NaN>    | (5.1,34.5)        |           NaN
+            | <(3,5),NaN>    | (10,10)           |           NaN
+            | <(3,5),NaN>    | (1e+300,Infinity) |           NaN
+            | <(3,5),NaN>    | (NaN,NaN)         |           NaN
+(53 rows)
+
+-- To polygon
+SELECT f1, f1::polygon FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+       f1       |                                                                                                          f1                                                                                                          
+----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ <(5,1),3>      | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
+ <(1,2),100>    | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
+ <(1,3),5>      | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
+ <(1,2),3>      | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
+ <(100,200),10> | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
+ <(100,1),115>  | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
+(6 rows)
+
+-- To polygon with less points
+SELECT f1, polygon(8, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+       f1       |                                                                             polygon                                                                              
+----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ <(5,1),3>      | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
+ <(1,2),100>    | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
+ <(1,3),5>      | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
+ <(1,2),3>      | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
+ <(100,200),10> | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
+ <(100,1),115>  | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
+(6 rows)
+
+-- Too less points error
+SELECT f1, polygon(1, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+ERROR:  must request at least 2 points
+-- Zero radius error
+SELECT f1, polygon(10, f1) FROM CIRCLE_TBL WHERE f1 < '<(0,0),1>';
+ERROR:  cannot convert circle with radius zero to polygon
+-- Same as circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 ~= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+ <(3,5),NaN>    | <(3,5),0>
+ <(3,5),NaN>    | <(3,5),NaN>
+(9 rows)
+
+-- Overlap with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 && c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,1),115>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(100,1),115>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(33 rows)
+
+-- Overlap or left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &< c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(28 rows)
+
+-- Left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 << c2.f1;
+    f1     |       f1       
+-----------+----------------
+ <(5,1),3> | <(100,200),10>
+ <(1,3),5> | <(100,200),10>
+ <(1,2),3> | <(100,200),10>
+ <(3,5),0> | <(100,200),10>
+(4 rows)
+
+-- Right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >> c2.f1;
+       f1       |    f1     
+----------------+-----------
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(3,5),0>
+(4 rows)
+
+-- Overlap or right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(28 rows)
+
+-- Contained by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <@ c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(17 rows)
+
+-- Contain by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 @> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(3,5),0>
+(17 rows)
+
+-- Below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <<| c2.f1;
+      f1       |       f1       
+---------------+----------------
+ <(5,1),3>     | <(100,200),10>
+ <(5,1),3>     | <(3,5),0>
+ <(1,2),100>   | <(100,200),10>
+ <(1,3),5>     | <(100,200),10>
+ <(1,2),3>     | <(100,200),10>
+ <(100,1),115> | <(100,200),10>
+ <(3,5),0>     | <(100,200),10>
+(7 rows)
+
+-- Above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |>> c2.f1;
+       f1       |      f1       
+----------------+---------------
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(3,5),0>      | <(5,1),3>
+(7 rows)
+
+-- Overlap or below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &<| c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Overlap or above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |&> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 = c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(9 rows)
+
+-- Area not equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 != c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(40 rows)
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 > c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(3,5),0>
+(20 rows)
+
+-- Area less than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area greater than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Add point
+SELECT c.f1, p.f1, c.f1 + p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |        ?column?         
+----------------+-------------------+-------------------------
+ <(5,1),3>      | (0,0)             | <(5,1),3>
+ <(1,2),100>    | (0,0)             | <(1,2),100>
+ <(1,3),5>      | (0,0)             | <(1,3),5>
+ <(1,2),3>      | (0,0)             | <(1,2),3>
+ <(100,200),10> | (0,0)             | <(100,200),10>
+ <(100,1),115>  | (0,0)             | <(100,1),115>
+ <(3,5),0>      | (0,0)             | <(3,5),0>
+ <(3,5),NaN>    | (0,0)             | <(3,5),NaN>
+ <(5,1),3>      | (-10,0)           | <(-5,1),3>
+ <(1,2),100>    | (-10,0)           | <(-9,2),100>
+ <(1,3),5>      | (-10,0)           | <(-9,3),5>
+ <(1,2),3>      | (-10,0)           | <(-9,2),3>
+ <(100,200),10> | (-10,0)           | <(90,200),10>
+ <(100,1),115>  | (-10,0)           | <(90,1),115>
+ <(3,5),0>      | (-10,0)           | <(-7,5),0>
+ <(3,5),NaN>    | (-10,0)           | <(-7,5),NaN>
+ <(5,1),3>      | (-3,4)            | <(2,5),3>
+ <(1,2),100>    | (-3,4)            | <(-2,6),100>
+ <(1,3),5>      | (-3,4)            | <(-2,7),5>
+ <(1,2),3>      | (-3,4)            | <(-2,6),3>
+ <(100,200),10> | (-3,4)            | <(97,204),10>
+ <(100,1),115>  | (-3,4)            | <(97,5),115>
+ <(3,5),0>      | (-3,4)            | <(0,9),0>
+ <(3,5),NaN>    | (-3,4)            | <(0,9),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(10.1,35.5),3>
+ <(1,2),100>    | (5.1,34.5)        | <(6.1,36.5),100>
+ <(1,3),5>      | (5.1,34.5)        | <(6.1,37.5),5>
+ <(1,2),3>      | (5.1,34.5)        | <(6.1,36.5),3>
+ <(100,200),10> | (5.1,34.5)        | <(105.1,234.5),10>
+ <(100,1),115>  | (5.1,34.5)        | <(105.1,35.5),115>
+ <(3,5),0>      | (5.1,34.5)        | <(8.1,39.5),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(8.1,39.5),NaN>
+ <(5,1),3>      | (-5,-12)          | <(0,-11),3>
+ <(1,2),100>    | (-5,-12)          | <(-4,-10),100>
+ <(1,3),5>      | (-5,-12)          | <(-4,-9),5>
+ <(1,2),3>      | (-5,-12)          | <(-4,-10),3>
+ <(100,200),10> | (-5,-12)          | <(95,188),10>
+ <(100,1),115>  | (-5,-12)          | <(95,-11),115>
+ <(3,5),0>      | (-5,-12)          | <(-2,-7),0>
+ <(3,5),NaN>    | (-5,-12)          | <(-2,-7),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(5,1),3>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(1,2),100>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(1,3),5>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(1,2),3>
+ <(100,200),10> | (1e-300,-1e-300)  | <(100,200),10>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(100,1),115>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(3,5),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(3,5),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(1e+300,Infinity),3>
+ <(1,2),100>    | (1e+300,Infinity) | <(1e+300,Infinity),100>
+ <(1,3),5>      | (1e+300,Infinity) | <(1e+300,Infinity),5>
+ <(1,2),3>      | (1e+300,Infinity) | <(1e+300,Infinity),3>
+ <(100,200),10> | (1e+300,Infinity) | <(1e+300,Infinity),10>
+ <(100,1),115>  | (1e+300,Infinity) | <(1e+300,Infinity),115>
+ <(3,5),0>      | (1e+300,Infinity) | <(1e+300,Infinity),0>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(1e+300,Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),100>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),5>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),10>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),115>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),0>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(15,11),3>
+ <(1,2),100>    | (10,10)           | <(11,12),100>
+ <(1,3),5>      | (10,10)           | <(11,13),5>
+ <(1,2),3>      | (10,10)           | <(11,12),3>
+ <(100,200),10> | (10,10)           | <(110,210),10>
+ <(100,1),115>  | (10,10)           | <(110,11),115>
+ <(3,5),0>      | (10,10)           | <(13,15),0>
+ <(3,5),NaN>    | (10,10)           | <(13,15),NaN>
+(72 rows)
+
+-- Subtract point
+SELECT c.f1, p.f1, c.f1 - p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |         ?column?          
+----------------+-------------------+---------------------------
+ <(5,1),3>      | (0,0)             | <(5,1),3>
+ <(1,2),100>    | (0,0)             | <(1,2),100>
+ <(1,3),5>      | (0,0)             | <(1,3),5>
+ <(1,2),3>      | (0,0)             | <(1,2),3>
+ <(100,200),10> | (0,0)             | <(100,200),10>
+ <(100,1),115>  | (0,0)             | <(100,1),115>
+ <(3,5),0>      | (0,0)             | <(3,5),0>
+ <(3,5),NaN>    | (0,0)             | <(3,5),NaN>
+ <(5,1),3>      | (-10,0)           | <(15,1),3>
+ <(1,2),100>    | (-10,0)           | <(11,2),100>
+ <(1,3),5>      | (-10,0)           | <(11,3),5>
+ <(1,2),3>      | (-10,0)           | <(11,2),3>
+ <(100,200),10> | (-10,0)           | <(110,200),10>
+ <(100,1),115>  | (-10,0)           | <(110,1),115>
+ <(3,5),0>      | (-10,0)           | <(13,5),0>
+ <(3,5),NaN>    | (-10,0)           | <(13,5),NaN>
+ <(5,1),3>      | (-3,4)            | <(8,-3),3>
+ <(1,2),100>    | (-3,4)            | <(4,-2),100>
+ <(1,3),5>      | (-3,4)            | <(4,-1),5>
+ <(1,2),3>      | (-3,4)            | <(4,-2),3>
+ <(100,200),10> | (-3,4)            | <(103,196),10>
+ <(100,1),115>  | (-3,4)            | <(103,-3),115>
+ <(3,5),0>      | (-3,4)            | <(6,1),0>
+ <(3,5),NaN>    | (-3,4)            | <(6,1),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(-0.1,-33.5),3>
+ <(1,2),100>    | (5.1,34.5)        | <(-4.1,-32.5),100>
+ <(1,3),5>      | (5.1,34.5)        | <(-4.1,-31.5),5>
+ <(1,2),3>      | (5.1,34.5)        | <(-4.1,-32.5),3>
+ <(100,200),10> | (5.1,34.5)        | <(94.9,165.5),10>
+ <(100,1),115>  | (5.1,34.5)        | <(94.9,-33.5),115>
+ <(3,5),0>      | (5.1,34.5)        | <(-2.1,-29.5),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(-2.1,-29.5),NaN>
+ <(5,1),3>      | (-5,-12)          | <(10,13),3>
+ <(1,2),100>    | (-5,-12)          | <(6,14),100>
+ <(1,3),5>      | (-5,-12)          | <(6,15),5>
+ <(1,2),3>      | (-5,-12)          | <(6,14),3>
+ <(100,200),10> | (-5,-12)          | <(105,212),10>
+ <(100,1),115>  | (-5,-12)          | <(105,13),115>
+ <(3,5),0>      | (-5,-12)          | <(8,17),0>
+ <(3,5),NaN>    | (-5,-12)          | <(8,17),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(5,1),3>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(1,2),100>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(1,3),5>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(1,2),3>
+ <(100,200),10> | (1e-300,-1e-300)  | <(100,200),10>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(100,1),115>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(3,5),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(3,5),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(-1e+300,-Infinity),3>
+ <(1,2),100>    | (1e+300,Infinity) | <(-1e+300,-Infinity),100>
+ <(1,3),5>      | (1e+300,Infinity) | <(-1e+300,-Infinity),5>
+ <(1,2),3>      | (1e+300,Infinity) | <(-1e+300,-Infinity),3>
+ <(100,200),10> | (1e+300,Infinity) | <(-1e+300,-Infinity),10>
+ <(100,1),115>  | (1e+300,Infinity) | <(-1e+300,-Infinity),115>
+ <(3,5),0>      | (1e+300,Infinity) | <(-1e+300,-Infinity),0>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(-1e+300,-Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),100>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),5>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),10>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),115>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),0>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(-5,-9),3>
+ <(1,2),100>    | (10,10)           | <(-9,-8),100>
+ <(1,3),5>      | (10,10)           | <(-9,-7),5>
+ <(1,2),3>      | (10,10)           | <(-9,-8),3>
+ <(100,200),10> | (10,10)           | <(90,190),10>
+ <(100,1),115>  | (10,10)           | <(90,-9),115>
+ <(3,5),0>      | (10,10)           | <(-7,-5),0>
+ <(3,5),NaN>    | (10,10)           | <(-7,-5),NaN>
+(72 rows)
+
+-- Multiply with point
+SELECT c.f1, p.f1, c.f1 * p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |                  ?column?                  
+----------------+-------------------+--------------------------------------------
+ <(5,1),3>      | (0,0)             | <(0,0),0>
+ <(1,2),100>    | (0,0)             | <(0,0),0>
+ <(1,3),5>      | (0,0)             | <(0,0),0>
+ <(1,2),3>      | (0,0)             | <(0,0),0>
+ <(100,200),10> | (0,0)             | <(0,0),0>
+ <(100,1),115>  | (0,0)             | <(0,0),0>
+ <(3,5),0>      | (0,0)             | <(0,0),0>
+ <(3,5),NaN>    | (0,0)             | <(0,0),NaN>
+ <(5,1),3>      | (-10,0)           | <(-50,-10),30>
+ <(1,2),100>    | (-10,0)           | <(-10,-20),1000>
+ <(1,3),5>      | (-10,0)           | <(-10,-30),50>
+ <(1,2),3>      | (-10,0)           | <(-10,-20),30>
+ <(100,200),10> | (-10,0)           | <(-1000,-2000),100>
+ <(100,1),115>  | (-10,0)           | <(-1000,-10),1150>
+ <(3,5),0>      | (-10,0)           | <(-30,-50),0>
+ <(3,5),NaN>    | (-10,0)           | <(-30,-50),NaN>
+ <(5,1),3>      | (-3,4)            | <(-19,17),15>
+ <(1,2),100>    | (-3,4)            | <(-11,-2),500>
+ <(1,3),5>      | (-3,4)            | <(-15,-5),25>
+ <(1,2),3>      | (-3,4)            | <(-11,-2),15>
+ <(100,200),10> | (-3,4)            | <(-1100,-200),50>
+ <(100,1),115>  | (-3,4)            | <(-304,397),575>
+ <(3,5),0>      | (-3,4)            | <(-29,-3),0>
+ <(3,5),NaN>    | (-3,4)            | <(-29,-3),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(-9,177.6),104.624758064>
+ <(1,2),100>    | (5.1,34.5)        | <(-63.9,44.7),3487.49193547>
+ <(1,3),5>      | (5.1,34.5)        | <(-98.4,49.8),174.374596774>
+ <(1,2),3>      | (5.1,34.5)        | <(-63.9,44.7),104.624758064>
+ <(100,200),10> | (5.1,34.5)        | <(-6390,4470),348.749193547>
+ <(100,1),115>  | (5.1,34.5)        | <(475.5,3455.1),4010.6157258>
+ <(3,5),0>      | (5.1,34.5)        | <(-157.2,129),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(-157.2,129),NaN>
+ <(5,1),3>      | (-5,-12)          | <(-13,-65),39>
+ <(1,2),100>    | (-5,-12)          | <(19,-22),1300>
+ <(1,3),5>      | (-5,-12)          | <(31,-27),65>
+ <(1,2),3>      | (-5,-12)          | <(19,-22),39>
+ <(100,200),10> | (-5,-12)          | <(1900,-2200),130>
+ <(100,1),115>  | (-5,-12)          | <(-488,-1205),1495>
+ <(3,5),0>      | (-5,-12)          | <(45,-61),0>
+ <(3,5),NaN>    | (-5,-12)          | <(45,-61),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(6e-300,-4e-300),4.24264068712e-300>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(3e-300,1e-300),1.41421356237e-298>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(4e-300,2e-300),7.07106781187e-300>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(3e-300,1e-300),4.24264068712e-300>
+ <(100,200),10> | (1e-300,-1e-300)  | <(3e-298,1e-298),1.41421356237e-299>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(1.01e-298,-9.9e-299),1.62634559673e-298>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(8e-300,2e-300),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(8e-300,2e-300),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,2),100>    | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,3),5>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,2),3>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(100,200),10> | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(100,1),115>  | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(3,5),0>      | (1e+300,Infinity) | <(-Infinity,Infinity),NaN>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(-Infinity,Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(40,60),42.4264068712>
+ <(1,2),100>    | (10,10)           | <(-10,30),1414.21356237>
+ <(1,3),5>      | (10,10)           | <(-20,40),70.7106781187>
+ <(1,2),3>      | (10,10)           | <(-10,30),42.4264068712>
+ <(100,200),10> | (10,10)           | <(-1000,3000),141.421356237>
+ <(100,1),115>  | (10,10)           | <(990,1010),1626.34559673>
+ <(3,5),0>      | (10,10)           | <(-20,80),0>
+ <(3,5),NaN>    | (10,10)           | <(-20,80),NaN>
+(72 rows)
+
+-- Divide by point
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+       f1       |     f1     |                       ?column?                       
+----------------+------------+------------------------------------------------------
+ <(5,1),3>      | (5.1,34.5) | <(0.0493315573973,-0.137635045138),0.0860217042937>
+ <(5,1),3>      | (10,10)    | <(0.3,-0.2),0.212132034356>
+ <(1,2),100>    | (5.1,34.5) | <(0.0609244733856,-0.0199792807459),2.86739014312>
+ <(1,2),100>    | (10,10)    | <(0.15,0.05),7.07106781187>
+ <(1,3),5>      | (5.1,34.5) | <(0.0892901188891,-0.0157860983671),0.143369507156>
+ <(1,3),5>      | (10,10)    | <(0.2,0.1),0.353553390593>
+ <(1,2),3>      | (5.1,34.5) | <(0.0609244733856,-0.0199792807459),0.0860217042937>
+ <(1,2),3>      | (10,10)    | <(0.15,0.05),0.212132034356>
+ <(100,200),10> | (5.1,34.5) | <(6.09244733856,-1.99792807459),0.286739014312>
+ <(100,200),10> | (10,10)    | <(15,5),0.707106781187>
+ <(100,1),115>  | (5.1,34.5) | <(0.44768388338,-2.83237136796),3.29749866459>
+ <(100,1),115>  | (10,10)    | <(5.05,-4.95),8.13172798365>
+ <(3,5),0>      | (5.1,34.5) | <(0.154407774653,-0.0641310246164),0>
+ <(3,5),0>      | (10,10)    | <(0.4,0.1),0>
+ <(3,5),NaN>    | (5.1,34.5) | <(0.154407774653,-0.0641310246164),NaN>
+ <(3,5),NaN>    | (10,10)    | <(0.4,0.1),NaN>
+(16 rows)
+
+-- Overflow error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] > 1000;
+ERROR:  value out of range: overflow
+-- Division by 0 error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to polygon
+SELECT c.f1, p.f1, c.f1 <-> p.f1 FROM CIRCLE_TBL c, POLYGON_TBL p;
+       f1       |             f1             |    ?column?    
+----------------+----------------------------+----------------
+ <(5,1),3>      | ((2,0),(2,4),(0,0))        |              0
+ <(5,1),3>      | ((3,1),(3,3),(1,0))        |              0
+ <(5,1),3>      | ((1,2),(3,4),(5,6),(7,8))  | 0.535533905933
+ <(5,1),3>      | ((7,8),(5,6),(3,4),(1,2))  | 0.535533905933
+ <(5,1),3>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(5,1),3>      | ((0,0))                    |  2.09901951359
+ <(5,1),3>      | ((0,1),(0,1))              |              2
+ <(1,2),100>    | ((2,0),(2,4),(0,0))        |              0
+ <(1,2),100>    | ((3,1),(3,3),(1,0))        |              0
+ <(1,2),100>    | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,2),100>    | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,2),100>    | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,2),100>    | ((0,0))                    |              0
+ <(1,2),100>    | ((0,1),(0,1))              |              0
+ <(1,3),5>      | ((2,0),(2,4),(0,0))        |              0
+ <(1,3),5>      | ((3,1),(3,3),(1,0))        |              0
+ <(1,3),5>      | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,3),5>      | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,3),5>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,3),5>      | ((0,0))                    |              0
+ <(1,3),5>      | ((0,1),(0,1))              |              0
+ <(1,2),3>      | ((2,0),(2,4),(0,0))        |              0
+ <(1,2),3>      | ((3,1),(3,3),(1,0))        |              0
+ <(1,2),3>      | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,2),3>      | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,2),3>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,2),3>      | ((0,0))                    |              0
+ <(1,2),3>      | ((0,1),(0,1))              |              0
+ <(100,200),10> | ((2,0),(2,4),(0,0))        |  209.134661795
+ <(100,200),10> | ((3,1),(3,3),(1,0))        |  209.585974051
+ <(100,200),10> | ((1,2),(3,4),(5,6),(7,8))  |  203.337760371
+ <(100,200),10> | ((7,8),(5,6),(3,4),(1,2))  |  203.337760371
+ <(100,200),10> | ((1,2),(7,8),(5,6),(3,-4)) |  203.337760371
+ <(100,200),10> | ((0,0))                    |   213.60679775
+ <(100,200),10> | ((0,1),(0,1))              |  212.712819568
+ <(100,1),115>  | ((2,0),(2,4),(0,0))        |              0
+ <(100,1),115>  | ((3,1),(3,3),(1,0))        |              0
+ <(100,1),115>  | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(100,1),115>  | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(100,1),115>  | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(100,1),115>  | ((0,0))                    |              0
+ <(100,1),115>  | ((0,1),(0,1))              |              0
+ <(3,5),0>      | ((2,0),(2,4),(0,0))        |  1.41421356237
+ <(3,5),0>      | ((3,1),(3,3),(1,0))        |              2
+ <(3,5),0>      | ((1,2),(3,4),(5,6),(7,8))  | 0.707106781187
+ <(3,5),0>      | ((7,8),(5,6),(3,4),(1,2))  | 0.707106781187
+ <(3,5),0>      | ((1,2),(7,8),(5,6),(3,-4)) | 0.707106781187
+ <(3,5),0>      | ((0,0))                    |  5.83095189485
+ <(3,5),0>      | ((0,1),(0,1))              |              5
+ <(3,5),NaN>    | ((2,0),(2,4),(0,0))        |            NaN
+ <(3,5),NaN>    | ((3,1),(3,3),(1,0))        |            NaN
+ <(3,5),NaN>    | ((1,2),(3,4),(5,6),(7,8))  |            NaN
+ <(3,5),NaN>    | ((7,8),(5,6),(3,4),(1,2))  |            NaN
+ <(3,5),NaN>    | ((1,2),(7,8),(5,6),(3,-4)) |            NaN
+ <(3,5),NaN>    | ((0,0))                    |            NaN
+ <(3,5),NaN>    | ((0,1),(0,1))              |            NaN
+(56 rows)
 
diff --git a/src/test/regress/expected/geometry_1.out b/src/test/regress/expected/geometry_1.out
deleted file mode 100644
index 3b92e23059..0000000000
--- a/src/test/regress/expected/geometry_1.out
+++ /dev/null
@@ -1,563 +0,0 @@
---
--- GEOMETRY
---
--- Back off displayed precision a little bit to reduce platform-to-platform
--- variation in results.
-SET extra_float_digits TO -3;
---
--- Points
---
-SELECT '' AS four, center(f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS four, (@@ f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS six, point(f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS six, (@@ f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS two, (@@ f1) AS center
-   FROM POLYGON_TBL
-   WHERE (# f1) > 2;
- two |            center             
------+-------------------------------
-     | (1.33333333333,1.33333333333)
-     | (2.33333333333,1.33333333333)
-(2 rows)
-
--- "is horizontal" function
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is horizontal" operator
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is vertical" function
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE isvertical(p1.f1, point '(5.1,34.5)');
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
--- "is vertical" operator
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?| point '(5.1,34.5)';
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
---
--- Line segments
---
--- intersection
-SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-   FROM LSEG_TBL l, POINT_TBL p;
-ERROR:  operator does not exist: lseg # point
-LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-                                           ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
-
---
--- Boxes
---
-SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
- six |                              box                               
------+----------------------------------------------------------------
-     | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
-     | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
-     | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
-     | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
-     | (107.071067812,207.071067812),(92.9289321881,192.928932188)
-     | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
-
--- translation
-SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (-8,2),(-10,0)
-            | (-7,3),(-9,1)
-            | (-7.5,3.5),(-7.5,2.5)
-            | (-7,3),(-7,3)
-            | (-1,6),(-3,4)
-            | (0,7),(-2,5)
-            | (-0.5,7.5),(-0.5,6.5)
-            | (0,7),(0,7)
-            | (7.1,36.5),(5.1,34.5)
-            | (8.1,37.5),(6.1,35.5)
-            | (7.6,38),(7.6,37)
-            | (8.1,37.5),(8.1,37.5)
-            | (-3,-10),(-5,-12)
-            | (-2,-9),(-4,-11)
-            | (-2.5,-8.5),(-2.5,-9.5)
-            | (-2,-9),(-2,-9)
-            | (12,12),(10,10)
-            | (13,13),(11,11)
-            | (12.5,13.5),(12.5,12.5)
-            | (13,13),(13,13)
-(24 rows)
-
-SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (12,2),(10,0)
-            | (13,3),(11,1)
-            | (12.5,3.5),(12.5,2.5)
-            | (13,3),(13,3)
-            | (5,-2),(3,-4)
-            | (6,-1),(4,-3)
-            | (5.5,-0.5),(5.5,-1.5)
-            | (6,-1),(6,-1)
-            | (-3.1,-32.5),(-5.1,-34.5)
-            | (-2.1,-31.5),(-4.1,-33.5)
-            | (-2.6,-31),(-2.6,-32)
-            | (-2.1,-31.5),(-2.1,-31.5)
-            | (7,14),(5,12)
-            | (8,15),(6,13)
-            | (7.5,15.5),(7.5,14.5)
-            | (8,15),(8,15)
-            | (-8,-8),(-10,-10)
-            | (-7,-7),(-9,-9)
-            | (-7.5,-6.5),(-7.5,-7.5)
-            | (-7,-7),(-7,-7)
-(24 rows)
-
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
-
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,0),(-0.2,-0.2)
-        | (0.08,0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
-
-SELECT f1::box
-	FROM POINT_TBL;
-          f1           
------------------------
- (0,0),(0,0)
- (-10,0),(-10,0)
- (-3,4),(-3,4)
- (5.1,34.5),(5.1,34.5)
- (-5,-12),(-5,-12)
- (10,10),(10,10)
-(6 rows)
-
-SELECT bound_box(a.f1, b.f1)
-	FROM BOX_TBL a, BOX_TBL b;
-      bound_box      
----------------------
- (2,2),(0,0)
- (3,3),(0,0)
- (2.5,3.5),(0,0)
- (3,3),(0,0)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(1,1)
- (3,3),(1,1)
- (2.5,3.5),(0,0)
- (3,3.5),(1,1)
- (2.5,3.5),(2.5,2.5)
- (3,3.5),(2.5,2.5)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(2.5,2.5)
- (3,3),(3,3)
-(16 rows)
-
---
--- Paths
---
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
-
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
-
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
-
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
-
---
--- Polygons
---
--- containment
-SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
-   FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
-      |       3 | ((2,0),(2,4),(0,0))
-      |       3 | ((3,1),(3,3),(1,0))
-      |       1 | ((0,0))
-      |       2 | ((0,1),(0,1))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM BOX_TBL;
- four |                  polygon                  
-------+-------------------------------------------
-      | ((0,0),(0,2),(2,2),(2,0))
-      | ((1,1),(1,3),(3,3),(3,1))
-      | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
-      | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM PATH_TBL WHERE isclosed(f1);
- four |      polygon      
-------+-------------------
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((11,12),(13,14))
-(4 rows)
-
-SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
-   FROM PATH_TBL
-   WHERE isopen(f1);
- four |         open_path         |          polygon          
-------+---------------------------+---------------------------
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(11,12),(13,14)]         | ((11,12),(13,14))
-(4 rows)
-
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
-
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
-
---
--- Circles
---
-SELECT '' AS six, circle(f1, 50.0)
-   FROM POINT_TBL;
- six |     circle      
------+-----------------
-     | <(0,0),50>
-     | <(-10,0),50>
-     | <(-3,4),50>
-     | <(5.1,34.5),50>
-     | <(-5,-12),50>
-     | <(10,10),50>
-(6 rows)
-
-SELECT '' AS four, circle(f1)
-   FROM BOX_TBL;
- four |        circle         
-------+-----------------------
-      | <(1,1),1.41421356237>
-      | <(2,2),1.41421356237>
-      | <(2.5,3),0.5>
-      | <(3,3),0>
-(4 rows)
-
-SELECT '' AS two, circle(f1)
-   FROM POLYGON_TBL
-   WHERE (# f1) >= 3;
- two |                    circle                     
------+-----------------------------------------------
-     | <(1.33333333333,1.33333333333),2.04168905064>
-     | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
-
-SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
-   FROM CIRCLE_TBL c1, POINT_TBL p1
-   WHERE (p1.f1 <-> c1.f1) > 0
-   ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
-
diff --git a/src/test/regress/expected/geometry_2.out b/src/test/regress/expected/geometry_2.out
deleted file mode 100644
index 5a922bcd3f..0000000000
--- a/src/test/regress/expected/geometry_2.out
+++ /dev/null
@@ -1,563 +0,0 @@
---
--- GEOMETRY
---
--- Back off displayed precision a little bit to reduce platform-to-platform
--- variation in results.
-SET extra_float_digits TO -3;
---
--- Points
---
-SELECT '' AS four, center(f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS four, (@@ f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS six, point(f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS six, (@@ f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS two, (@@ f1) AS center
-   FROM POLYGON_TBL
-   WHERE (# f1) > 2;
- two |            center             
------+-------------------------------
-     | (1.33333333333,1.33333333333)
-     | (2.33333333333,1.33333333333)
-(2 rows)
-
--- "is horizontal" function
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is horizontal" operator
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is vertical" function
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE isvertical(p1.f1, point '(5.1,34.5)');
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
--- "is vertical" operator
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?| point '(5.1,34.5)';
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
---
--- Line segments
---
--- intersection
-SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-   FROM LSEG_TBL l, POINT_TBL p;
-ERROR:  operator does not exist: lseg # point
-LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-                                           ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
-
---
--- Boxes
---
-SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
- six |                              box                               
------+----------------------------------------------------------------
-     | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
-     | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
-     | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
-     | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
-     | (107.071067812,207.071067812),(92.9289321881,192.928932188)
-     | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
-
--- translation
-SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (-8,2),(-10,0)
-            | (-7,3),(-9,1)
-            | (-7.5,3.5),(-7.5,2.5)
-            | (-7,3),(-7,3)
-            | (-1,6),(-3,4)
-            | (0,7),(-2,5)
-            | (-0.5,7.5),(-0.5,6.5)
-            | (0,7),(0,7)
-            | (7.1,36.5),(5.1,34.5)
-            | (8.1,37.5),(6.1,35.5)
-            | (7.6,38),(7.6,37)
-            | (8.1,37.5),(8.1,37.5)
-            | (-3,-10),(-5,-12)
-            | (-2,-9),(-4,-11)
-            | (-2.5,-8.5),(-2.5,-9.5)
-            | (-2,-9),(-2,-9)
-            | (12,12),(10,10)
-            | (13,13),(11,11)
-            | (12.5,13.5),(12.5,12.5)
-            | (13,13),(13,13)
-(24 rows)
-
-SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (12,2),(10,0)
-            | (13,3),(11,1)
-            | (12.5,3.5),(12.5,2.5)
-            | (13,3),(13,3)
-            | (5,-2),(3,-4)
-            | (6,-1),(4,-3)
-            | (5.5,-0.5),(5.5,-1.5)
-            | (6,-1),(6,-1)
-            | (-3.1,-32.5),(-5.1,-34.5)
-            | (-2.1,-31.5),(-4.1,-33.5)
-            | (-2.6,-31),(-2.6,-32)
-            | (-2.1,-31.5),(-2.1,-31.5)
-            | (7,14),(5,12)
-            | (8,15),(6,13)
-            | (7.5,15.5),(7.5,14.5)
-            | (8,15),(8,15)
-            | (-8,-8),(-10,-10)
-            | (-7,-7),(-9,-9)
-            | (-7.5,-6.5),(-7.5,-7.5)
-            | (-7,-7),(-7,-7)
-(24 rows)
-
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (-0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (-0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,-0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
-
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,-0),(-0.2,-0.2)
-        | (0.08,-0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (-0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
-
-SELECT f1::box
-	FROM POINT_TBL;
-          f1           
------------------------
- (0,0),(0,0)
- (-10,0),(-10,0)
- (-3,4),(-3,4)
- (5.1,34.5),(5.1,34.5)
- (-5,-12),(-5,-12)
- (10,10),(10,10)
-(6 rows)
-
-SELECT bound_box(a.f1, b.f1)
-	FROM BOX_TBL a, BOX_TBL b;
-      bound_box      
----------------------
- (2,2),(0,0)
- (3,3),(0,0)
- (2.5,3.5),(0,0)
- (3,3),(0,0)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(1,1)
- (3,3),(1,1)
- (2.5,3.5),(0,0)
- (3,3.5),(1,1)
- (2.5,3.5),(2.5,2.5)
- (3,3.5),(2.5,2.5)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(2.5,2.5)
- (3,3),(3,3)
-(16 rows)
-
---
--- Paths
---
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
-
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
-
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
-
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
-
---
--- Polygons
---
--- containment
-SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
-   FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
-      |       3 | ((2,0),(2,4),(0,0))
-      |       3 | ((3,1),(3,3),(1,0))
-      |       1 | ((0,0))
-      |       2 | ((0,1),(0,1))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM BOX_TBL;
- four |                  polygon                  
-------+-------------------------------------------
-      | ((0,0),(0,2),(2,2),(2,0))
-      | ((1,1),(1,3),(3,3),(3,1))
-      | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
-      | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM PATH_TBL WHERE isclosed(f1);
- four |      polygon      
-------+-------------------
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((11,12),(13,14))
-(4 rows)
-
-SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
-   FROM PATH_TBL
-   WHERE isopen(f1);
- four |         open_path         |          polygon          
-------+---------------------------+---------------------------
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(11,12),(13,14)]         | ((11,12),(13,14))
-(4 rows)
-
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
-
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
-
---
--- Circles
---
-SELECT '' AS six, circle(f1, 50.0)
-   FROM POINT_TBL;
- six |     circle      
------+-----------------
-     | <(0,0),50>
-     | <(-10,0),50>
-     | <(-3,4),50>
-     | <(5.1,34.5),50>
-     | <(-5,-12),50>
-     | <(10,10),50>
-(6 rows)
-
-SELECT '' AS four, circle(f1)
-   FROM BOX_TBL;
- four |        circle         
-------+-----------------------
-      | <(1,1),1.41421356237>
-      | <(2,2),1.41421356237>
-      | <(2.5,3),0.5>
-      | <(3,3),0>
-(4 rows)
-
-SELECT '' AS two, circle(f1)
-   FROM POLYGON_TBL
-   WHERE (# f1) >= 3;
- two |                    circle                     
------+-----------------------------------------------
-     | <(1.33333333333,1.33333333333),2.04168905064>
-     | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
-
-SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
-   FROM CIRCLE_TBL c1, POINT_TBL p1
-   WHERE (p1.f1 <-> c1.f1) > 0
-   ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
-
diff --git a/src/test/regress/expected/line.out b/src/test/regress/expected/line.out
index f20abdc430..bf780daa2c 100644
--- a/src/test/regress/expected/line.out
+++ b/src/test/regress/expected/line.out
@@ -1,271 +1,87 @@
 --
 -- LINE
 -- Infinite lines
 --
 --DROP TABLE LINE_TBL;
 CREATE TABLE LINE_TBL (s line);
-INSERT INTO LINE_TBL VALUES ('{1,-1,1}');
-INSERT INTO LINE_TBL VALUES ('(0,0),(6,6)');
+INSERT INTO LINE_TBL VALUES ('{0,-1,5}');	-- A == 0
+INSERT INTO LINE_TBL VALUES ('{1,0,5}');	-- B == 0
+INSERT INTO LINE_TBL VALUES ('{0,3,0}');	-- A == C == 0
+INSERT INTO LINE_TBL VALUES (' (0,0), (6,6)');
 INSERT INTO LINE_TBL VALUES ('10,-10 ,-5,-4');
 INSERT INTO LINE_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LINE_TBL VALUES ('(11,22,33,44)');
-INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
-ERROR:  invalid line specification: must be two distinct points
-LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
-                                     ^
+INSERT INTO LINE_TBL VALUES ('{3,NaN,5}');
+INSERT INTO LINE_TBL VALUES ('{NaN,NaN,NaN}');
 -- horizontal
 INSERT INTO LINE_TBL VALUES ('[(1,3),(2,3)]');
 -- vertical
-INSERT INTO LINE_TBL VALUES ('[(3,1),(3,2)]');
+INSERT INTO LINE_TBL VALUES (line(point '(3,1)', point '(3,2)'));
 -- bad values for parser testing
+INSERT INTO LINE_TBL VALUES ('{}');
+ERROR:  invalid input syntax for type line: "{}"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{}');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0');
+ERROR:  invalid input syntax for type line: "{0"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0,0}');
+ERROR:  invalid input syntax for type line: "{0,0}"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0}');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0,0,1');
+ERROR:  invalid input syntax for type line: "{0,0,1"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1');
+                                     ^
 INSERT INTO LINE_TBL VALUES ('{0,0,1}');
 ERROR:  invalid line specification: A and B cannot both be zero
 LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1}');
                                      ^
+INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
+ERROR:  invalid input syntax for type line: "{0,0,1} x"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
+                                     ^
 INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
 ERROR:  invalid input syntax for type line: "(3asdf,2 ,3,4r2)"
 LINE 1: INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
                                      ^
 INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
 ERROR:  invalid input syntax for type line: "[1,2,3, 4"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
                                      ^
 INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
 ERROR:  invalid input syntax for type line: "[(,2),(3,4)]"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
                                      ^
 INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
 ERROR:  invalid input syntax for type line: "[(1,2),(3,4)"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
                                      ^
+INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
+ERROR:  invalid line specification: must be two distinct points
+LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
+                                     ^
+INSERT INTO LINE_TBL VALUES (line(point '(1,0)', point '(1,0)'));
+ERROR:  invalid line specification: must be two distinct points
 select * from LINE_TBL;
                       s                      
 ---------------------------------------------
- {1,-1,1}
+ {0,-1,5}
+ {1,0,5}
+ {0,3,0}
  {1,-1,0}
  {-0.4,-1,-6}
  {-0.000184615384615385,-1,15.3846153846154}
- {1,-1,11}
+ {3,NaN,5}
+ {NaN,NaN,NaN}
  {0,-1,3}
  {-1,0,3}
-(7 rows)
+(10 rows)
 
--- functions and operators
-SELECT * FROM LINE_TBL WHERE (s <-> line '[(1,2),(3,4)]') < 10;
-                      s                      
----------------------------------------------
- {1,-1,1}
- {1,-1,0}
- {-0.4,-1,-6}
- {-0.000184615384615385,-1,15.3846153846154}
- {1,-1,11}
- {0,-1,3}
- {-1,0,3}
-(7 rows)
-
-SELECT * FROM LINE_TBL WHERE (point '(0.1,0.1)' <-> s) < 1;
-    s     
-----------
- {1,-1,1}
- {1,-1,0}
-(2 rows)
-
-SELECT * FROM LINE_TBL WHERE (lseg '[(0.1,0.1),(0.2,0.2)]' <-> s) < 1;
-    s     
-----------
- {1,-1,1}
- {1,-1,0}
-(2 rows)
-
-SELECT line '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
- ?column? 
-----------
-        2
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
- ?column? 
-----------
-        2
-(1 row)
-
-SELECT point '(-1,1)' <-> line '[(-3,0),(-4,0)]';
- ?column? 
-----------
-        1
-(1 row)
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(2,0),(0,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# box '(0,0,2,2)';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(3,0),(4,1)]' ?# box '(0,0,2,2)';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(1,1)' <@ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT point '(1,1)' <@ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(1,1)' @ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT point '(1,1)' @ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT lseg '[(1,1),(2,2)]' <@ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' <@ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT lseg '[(1,1),(2,2)]' @ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' @ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(0,1)' ## line '[(0,0),(1,1)]';
- ?column?  
------------
- (0.5,0.5)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ## lseg '[(1,0),(2,0)]';
- ?column? 
-----------
- (1,0)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(2,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(1,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(2,1)]';
- ?column? 
-----------
- 
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(1,1)]';
- ?column? 
-----------
- (1,1)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(2,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,0)]' ?-| line '[(0,0),(0,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?-| line '[(1,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT ?- line '[(0,0),(1,0)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT ?- line '[(0,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT ?| line '[(0,0),(0,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT ?| line '[(0,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line(point '(1,2)', point '(3,4)');
-   line   
-----------
- {1,-1,1}
-(1 row)
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,5)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,4)]';  -- false
- ?column? 
-----------
- f
+select '{nan, 1, nan}'::line = '{nan, 1, nan}'::line as true,
+	   '{nan, 1, nan}'::line = '{nan, 2, nan}'::line as false;
+ true | false 
+------+-------
+ t    | f
 (1 row)
 
diff --git a/src/test/regress/expected/lseg.out b/src/test/regress/expected/lseg.out
index bba1f3ee80..7e878b5577 100644
--- a/src/test/regress/expected/lseg.out
+++ b/src/test/regress/expected/lseg.out
@@ -1,21 +1,24 @@
 --
 -- LSEG
 -- Line segments
 --
 --DROP TABLE LSEG_TBL;
 CREATE TABLE LSEG_TBL (s lseg);
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('(0,0),(6,6)');
 INSERT INTO LSEG_TBL VALUES ('10,-10 ,-3,-4');
 INSERT INTO LSEG_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LSEG_TBL VALUES ('(11,22,33,44)');
+INSERT INTO LSEG_TBL VALUES (lseg(point(11, 22), point(33,44)));
+INSERT INTO LSEG_TBL VALUES ('[(-10,2),(-10,3)]');	-- vertical
+INSERT INTO LSEG_TBL VALUES ('[(0,-20),(30,-20)]');	-- horizontal
+INSERT INTO LSEG_TBL VALUES ('[(NaN,1),(NaN,90)]');	-- NaN
 -- bad values for parser testing
 INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
 ERROR:  invalid input syntax for type lseg: "(3asdf,2 ,3,4r2)"
 LINE 1: INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
                                      ^
 INSERT INTO LSEG_TBL VALUES ('[1,2,3, 4');
 ERROR:  invalid input syntax for type lseg: "[1,2,3, 4"
 LINE 1: INSERT INTO LSEG_TBL VALUES ('[1,2,3, 4');
                                      ^
 INSERT INTO LSEG_TBL VALUES ('[(,2),(3,4)]');
@@ -27,26 +30,15 @@ ERROR:  invalid input syntax for type lseg: "[(1,2),(3,4)"
 LINE 1: INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)');
                                      ^
 select * from LSEG_TBL;
                s               
 -------------------------------
  [(1,2),(3,4)]
  [(0,0),(6,6)]
  [(10,-10),(-3,-4)]
  [(-1000000,200),(300000,-40)]
  [(11,22),(33,44)]
-(5 rows)
-
-SELECT * FROM LSEG_TBL WHERE s <= lseg '[(1,2),(3,4)]';
-       s       
----------------
- [(1,2),(3,4)]
-(1 row)
-
-SELECT * FROM LSEG_TBL WHERE (s <-> lseg '[(1,2),(3,4)]') < 10;
-         s          
---------------------
- [(1,2),(3,4)]
- [(0,0),(6,6)]
- [(10,-10),(-3,-4)]
-(3 rows)
+ [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]
+ [(NaN,1),(NaN,90)]
+(8 rows)
 
diff --git a/src/test/regress/expected/path.out b/src/test/regress/expected/path.out
index 08d6d61dda..bd6e467752 100644
--- a/src/test/regress/expected/path.out
+++ b/src/test/regress/expected/path.out
@@ -1,79 +1,82 @@
 --
 -- PATH
 --
 --DROP TABLE PATH_TBL;
 CREATE TABLE PATH_TBL (f1 path);
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)]');
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
-INSERT INTO PATH_TBL VALUES ('[(0,0),(3,0),(4,5),(1,6)]');
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
-INSERT INTO PATH_TBL VALUES ('1,2 ,3,4');
-INSERT INTO PATH_TBL VALUES ('[1,2,3, 4]');
-INSERT INTO PATH_TBL VALUES ('[11,12,13,14]');
-INSERT INTO PATH_TBL VALUES ('(11,12,13,14)');
+INSERT INTO PATH_TBL VALUES (' ( ( 1 , 2 ) , ( 3 , 4 ) ) ');
+INSERT INTO PATH_TBL VALUES ('[ (0,0),(3,0),(4,5),(1,6) ]');
+INSERT INTO PATH_TBL VALUES ('((1,2) ,(3,4 ))');
+INSERT INTO PATH_TBL VALUES ('1,2 ,3,4 ');
+INSERT INTO PATH_TBL VALUES (' [1,2,3, 4] ');
+INSERT INTO PATH_TBL VALUES ('((10,20))');	-- Only one point
+INSERT INTO PATH_TBL VALUES ('[ 11,12,13,14 ]');
+INSERT INTO PATH_TBL VALUES ('( 11,12,13,14) ');
 -- bad values for parser testing
+INSERT INTO PATH_TBL VALUES ('[]');
+ERROR:  invalid input syntax for type path: "[]"
+LINE 1: INSERT INTO PATH_TBL VALUES ('[]');
+                                     ^
 INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
 ERROR:  invalid input syntax for type path: "[(,2),(3,4)]"
 LINE 1: INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
                                      ^
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
 ERROR:  invalid input syntax for type path: "[(1,2),(3,4)"
 LINE 1: INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
                                      ^
-SELECT f1 FROM PATH_TBL;
-            f1             
----------------------------
- [(1,2),(3,4)]
- ((1,2),(3,4))
- [(0,0),(3,0),(4,5),(1,6)]
- ((1,2),(3,4))
- ((1,2),(3,4))
- [(1,2),(3,4)]
- [(11,12),(13,14)]
- ((11,12),(13,14))
-(8 rows)
-
+INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+ERROR:  invalid input syntax for type path: "(1,2,3,4"
+LINE 1: INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+                                     ^
+INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
+ERROR:  invalid input syntax for type path: "(1,2),(3,4)]"
+LINE 1: INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
+                                     ^
 SELECT '' AS count, f1 AS open_path FROM PATH_TBL WHERE isopen(f1);
  count |         open_path         
 -------+---------------------------
        | [(1,2),(3,4)]
        | [(0,0),(3,0),(4,5),(1,6)]
        | [(1,2),(3,4)]
        | [(11,12),(13,14)]
 (4 rows)
 
 SELECT '' AS count, f1 AS closed_path FROM PATH_TBL WHERE isclosed(f1);
  count |    closed_path    
 -------+-------------------
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
+       | ((10,20))
        | ((11,12),(13,14))
-(4 rows)
+(5 rows)
 
 SELECT '' AS count, pclose(f1) AS closed_path FROM PATH_TBL;
  count |        closed_path        
 -------+---------------------------
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((0,0),(3,0),(4,5),(1,6))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
+       | ((10,20))
        | ((11,12),(13,14))
        | ((11,12),(13,14))
-(8 rows)
+(9 rows)
 
 SELECT '' AS count, popen(f1) AS open_path FROM PATH_TBL;
  count |         open_path         
 -------+---------------------------
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
        | [(0,0),(3,0),(4,5),(1,6)]
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
+       | [(10,20)]
        | [(11,12),(13,14)]
        | [(11,12),(13,14)]
-(8 rows)
+(9 rows)
 
diff --git a/src/test/regress/expected/point.out b/src/test/regress/expected/point.out
index bfc0962749..c18e865370 100644
--- a/src/test/regress/expected/point.out
+++ b/src/test/regress/expected/point.out
@@ -1,43 +1,57 @@
 --
 -- POINT
 --
 CREATE TABLE POINT_TBL(f1 point);
 INSERT INTO POINT_TBL(f1) VALUES ('(0.0,0.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-10.0,0.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-3.0,4.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(5.1, 34.5)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-5.0,-12.0)');
+INSERT INTO POINT_TBL(f1) VALUES ('(1e-300,-1e-300)');	-- To underflow
+INSERT INTO POINT_TBL(f1) VALUES ('(1e+300,Inf)');		-- To overflow
+INSERT INTO POINT_TBL(f1) VALUES (' ( Nan , NaN ) ');
 -- bad format points
 INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
 ERROR:  invalid input syntax for type point: "asdfasdf"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
                                           ^
 INSERT INTO POINT_TBL(f1) VALUES ('10.0,10.0');
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
 ERROR:  invalid input syntax for type point: "(10.0 10.0)"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
                                           ^
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+ERROR:  invalid input syntax for type point: "(10.0, 10.0) x"
+LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+                                          ^
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
 ERROR:  invalid input syntax for type point: "(10.0,10.0"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
                                           ^
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');	-- Out of range
+ERROR:  "1e+500" is out of range for type double precision
+LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');
+                                          ^
 SELECT '' AS six, * FROM POINT_TBL;
- six |     f1     
------+------------
+ six |        f1         
+-----+-------------------
      | (0,0)
      | (-10,0)
      | (-3,4)
      | (5.1,34.5)
      | (-5,-12)
+     | (1e-300,-1e-300)
+     | (1e+300,Infinity)
+     | (NaN,NaN)
      | (10,10)
-(6 rows)
+(9 rows)
 
 -- left of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE p.f1 << '(0.0, 0.0)';
  three |    f1    
 -------+----------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
 (3 rows)
 
@@ -85,172 +99,282 @@ 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    
--------+----------
+ three |        f1         
+-------+-------------------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
-(3 rows)
+       | (1e-300,-1e-300)
+       | (1e+300,Infinity)
+       | (NaN,NaN)
+(6 rows)
 
 SELECT '' AS two, p.* FROM POINT_TBL p
    WHERE p.f1 <@ path '[(0,0),(-10,0),(-10,10)]';
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 SELECT '' AS three, p.* FROM POINT_TBL p
    WHERE not box '(0,0,100,100)' @> p.f1;
- three |    f1    
--------+----------
+ three |        f1         
+-------+-------------------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
-(3 rows)
+       | (1e-300,-1e-300)
+       | (1e+300,Infinity)
+       | (NaN,NaN)
+(6 rows)
 
 SELECT '' AS six, p.f1, p.f1 <-> point '(0,0)' AS dist
    FROM POINT_TBL p
    ORDER BY dist;
- six |     f1     |       dist       
------+------------+------------------
-     | (0,0)      |                0
-     | (-3,4)     |                5
-     | (-10,0)    |               10
-     | (-5,-12)   |               13
-     | (10,10)    |  14.142135623731
-     | (5.1,34.5) | 34.8749193547455
-(6 rows)
+ six |        f1         |         dist         
+-----+-------------------+----------------------
+     | (0,0)             |                    0
+     | (1e-300,-1e-300)  | 1.4142135623731e-300
+     | (-3,4)            |                    5
+     | (-10,0)           |                   10
+     | (-5,-12)          |                   13
+     | (10,10)           |      14.142135623731
+     | (5.1,34.5)        |     34.8749193547455
+     | (1e+300,Infinity) |             Infinity
+     | (NaN,NaN)         |                  NaN
+(9 rows)
 
 SELECT '' AS thirtysix, p1.f1 AS point1, p2.f1 AS point2, p1.f1 <-> p2.f1 AS dist
    FROM POINT_TBL p1, POINT_TBL p2
    ORDER BY dist, p1.f1[0], p2.f1[0];
- thirtysix |   point1   |   point2   |       dist       
------------+------------+------------+------------------
-           | (-10,0)    | (-10,0)    |                0
-           | (-5,-12)   | (-5,-12)   |                0
-           | (-3,4)     | (-3,4)     |                0
-           | (0,0)      | (0,0)      |                0
-           | (5.1,34.5) | (5.1,34.5) |                0
-           | (10,10)    | (10,10)    |                0
-           | (-3,4)     | (0,0)      |                5
-           | (0,0)      | (-3,4)     |                5
-           | (-10,0)    | (-3,4)     | 8.06225774829855
-           | (-3,4)     | (-10,0)    | 8.06225774829855
-           | (-10,0)    | (0,0)      |               10
-           | (0,0)      | (-10,0)    |               10
-           | (-10,0)    | (-5,-12)   |               13
-           | (-5,-12)   | (-10,0)    |               13
-           | (-5,-12)   | (0,0)      |               13
-           | (0,0)      | (-5,-12)   |               13
-           | (0,0)      | (10,10)    |  14.142135623731
-           | (10,10)    | (0,0)      |  14.142135623731
-           | (-3,4)     | (10,10)    | 14.3178210632764
-           | (10,10)    | (-3,4)     | 14.3178210632764
-           | (-5,-12)   | (-3,4)     | 16.1245154965971
-           | (-3,4)     | (-5,-12)   | 16.1245154965971
-           | (-10,0)    | (10,10)    | 22.3606797749979
-           | (10,10)    | (-10,0)    | 22.3606797749979
-           | (5.1,34.5) | (10,10)    | 24.9851956166046
-           | (10,10)    | (5.1,34.5) | 24.9851956166046
-           | (-5,-12)   | (10,10)    | 26.6270539113887
-           | (10,10)    | (-5,-12)   | 26.6270539113887
-           | (-3,4)     | (5.1,34.5) | 31.5572495632937
-           | (5.1,34.5) | (-3,4)     | 31.5572495632937
-           | (0,0)      | (5.1,34.5) | 34.8749193547455
-           | (5.1,34.5) | (0,0)      | 34.8749193547455
-           | (-10,0)    | (5.1,34.5) | 37.6597928831267
-           | (5.1,34.5) | (-10,0)    | 37.6597928831267
-           | (-5,-12)   | (5.1,34.5) | 47.5842410888311
-           | (5.1,34.5) | (-5,-12)   | 47.5842410888311
-(36 rows)
+ thirtysix |      point1       |      point2       |         dist         
+-----------+-------------------+-------------------+----------------------
+           | (-10,0)           | (-10,0)           |                    0
+           | (-5,-12)          | (-5,-12)          |                    0
+           | (-3,4)            | (-3,4)            |                    0
+           | (0,0)             | (0,0)             |                    0
+           | (1e-300,-1e-300)  | (1e-300,-1e-300)  |                    0
+           | (5.1,34.5)        | (5.1,34.5)        |                    0
+           | (10,10)           | (10,10)           |                    0
+           | (0,0)             | (1e-300,-1e-300)  | 1.4142135623731e-300
+           | (1e-300,-1e-300)  | (0,0)             | 1.4142135623731e-300
+           | (-3,4)            | (0,0)             |                    5
+           | (-3,4)            | (1e-300,-1e-300)  |                    5
+           | (0,0)             | (-3,4)            |                    5
+           | (1e-300,-1e-300)  | (-3,4)            |                    5
+           | (-10,0)           | (-3,4)            |     8.06225774829855
+           | (-3,4)            | (-10,0)           |     8.06225774829855
+           | (-10,0)           | (0,0)             |                   10
+           | (-10,0)           | (1e-300,-1e-300)  |                   10
+           | (0,0)             | (-10,0)           |                   10
+           | (1e-300,-1e-300)  | (-10,0)           |                   10
+           | (-10,0)           | (-5,-12)          |                   13
+           | (-5,-12)          | (-10,0)           |                   13
+           | (-5,-12)          | (0,0)             |                   13
+           | (-5,-12)          | (1e-300,-1e-300)  |                   13
+           | (0,0)             | (-5,-12)          |                   13
+           | (1e-300,-1e-300)  | (-5,-12)          |                   13
+           | (0,0)             | (10,10)           |      14.142135623731
+           | (1e-300,-1e-300)  | (10,10)           |      14.142135623731
+           | (10,10)           | (0,0)             |      14.142135623731
+           | (10,10)           | (1e-300,-1e-300)  |      14.142135623731
+           | (-3,4)            | (10,10)           |     14.3178210632764
+           | (10,10)           | (-3,4)            |     14.3178210632764
+           | (-5,-12)          | (-3,4)            |     16.1245154965971
+           | (-3,4)            | (-5,-12)          |     16.1245154965971
+           | (-10,0)           | (10,10)           |     22.3606797749979
+           | (10,10)           | (-10,0)           |     22.3606797749979
+           | (5.1,34.5)        | (10,10)           |     24.9851956166046
+           | (10,10)           | (5.1,34.5)        |     24.9851956166046
+           | (-5,-12)          | (10,10)           |     26.6270539113887
+           | (10,10)           | (-5,-12)          |     26.6270539113887
+           | (-3,4)            | (5.1,34.5)        |     31.5572495632937
+           | (5.1,34.5)        | (-3,4)            |     31.5572495632937
+           | (0,0)             | (5.1,34.5)        |     34.8749193547455
+           | (1e-300,-1e-300)  | (5.1,34.5)        |     34.8749193547455
+           | (5.1,34.5)        | (0,0)             |     34.8749193547455
+           | (5.1,34.5)        | (1e-300,-1e-300)  |     34.8749193547455
+           | (-10,0)           | (5.1,34.5)        |     37.6597928831267
+           | (5.1,34.5)        | (-10,0)           |     37.6597928831267
+           | (-5,-12)          | (5.1,34.5)        |     47.5842410888311
+           | (5.1,34.5)        | (-5,-12)          |     47.5842410888311
+           | (-10,0)           | (1e+300,Infinity) |             Infinity
+           | (-5,-12)          | (1e+300,Infinity) |             Infinity
+           | (-3,4)            | (1e+300,Infinity) |             Infinity
+           | (0,0)             | (1e+300,Infinity) |             Infinity
+           | (1e-300,-1e-300)  | (1e+300,Infinity) |             Infinity
+           | (5.1,34.5)        | (1e+300,Infinity) |             Infinity
+           | (10,10)           | (1e+300,Infinity) |             Infinity
+           | (1e+300,Infinity) | (-10,0)           |             Infinity
+           | (1e+300,Infinity) | (-5,-12)          |             Infinity
+           | (1e+300,Infinity) | (-3,4)            |             Infinity
+           | (1e+300,Infinity) | (0,0)             |             Infinity
+           | (1e+300,Infinity) | (1e-300,-1e-300)  |             Infinity
+           | (1e+300,Infinity) | (5.1,34.5)        |             Infinity
+           | (1e+300,Infinity) | (10,10)           |             Infinity
+           | (-10,0)           | (NaN,NaN)         |                  NaN
+           | (-5,-12)          | (NaN,NaN)         |                  NaN
+           | (-3,4)            | (NaN,NaN)         |                  NaN
+           | (0,0)             | (NaN,NaN)         |                  NaN
+           | (1e-300,-1e-300)  | (NaN,NaN)         |                  NaN
+           | (5.1,34.5)        | (NaN,NaN)         |                  NaN
+           | (10,10)           | (NaN,NaN)         |                  NaN
+           | (1e+300,Infinity) | (1e+300,Infinity) |                  NaN
+           | (1e+300,Infinity) | (NaN,NaN)         |                  NaN
+           | (NaN,NaN)         | (-10,0)           |                  NaN
+           | (NaN,NaN)         | (-5,-12)          |                  NaN
+           | (NaN,NaN)         | (-3,4)            |                  NaN
+           | (NaN,NaN)         | (0,0)             |                  NaN
+           | (NaN,NaN)         | (1e-300,-1e-300)  |                  NaN
+           | (NaN,NaN)         | (5.1,34.5)        |                  NaN
+           | (NaN,NaN)         | (10,10)           |                  NaN
+           | (NaN,NaN)         | (1e+300,Infinity) |                  NaN
+           | (NaN,NaN)         | (NaN,NaN)         |                  NaN
+(81 rows)
 
 SELECT '' AS thirty, p1.f1 AS point1, p2.f1 AS point2
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3;
- thirty |   point1   |   point2   
---------+------------+------------
-        | (0,0)      | (-10,0)
-        | (0,0)      | (-3,4)
-        | (0,0)      | (5.1,34.5)
-        | (0,0)      | (-5,-12)
-        | (0,0)      | (10,10)
-        | (-10,0)    | (0,0)
-        | (-10,0)    | (-3,4)
-        | (-10,0)    | (5.1,34.5)
-        | (-10,0)    | (-5,-12)
-        | (-10,0)    | (10,10)
-        | (-3,4)     | (0,0)
-        | (-3,4)     | (-10,0)
-        | (-3,4)     | (5.1,34.5)
-        | (-3,4)     | (-5,-12)
-        | (-3,4)     | (10,10)
-        | (5.1,34.5) | (0,0)
-        | (5.1,34.5) | (-10,0)
-        | (5.1,34.5) | (-3,4)
-        | (5.1,34.5) | (-5,-12)
-        | (5.1,34.5) | (10,10)
-        | (-5,-12)   | (0,0)
-        | (-5,-12)   | (-10,0)
-        | (-5,-12)   | (-3,4)
-        | (-5,-12)   | (5.1,34.5)
-        | (-5,-12)   | (10,10)
-        | (10,10)    | (0,0)
-        | (10,10)    | (-10,0)
-        | (10,10)    | (-3,4)
-        | (10,10)    | (5.1,34.5)
-        | (10,10)    | (-5,-12)
-(30 rows)
+ thirty |      point1       |      point2       
+--------+-------------------+-------------------
+        | (0,0)             | (-10,0)
+        | (0,0)             | (-3,4)
+        | (0,0)             | (5.1,34.5)
+        | (0,0)             | (-5,-12)
+        | (0,0)             | (1e+300,Infinity)
+        | (0,0)             | (NaN,NaN)
+        | (0,0)             | (10,10)
+        | (-10,0)           | (0,0)
+        | (-10,0)           | (-3,4)
+        | (-10,0)           | (5.1,34.5)
+        | (-10,0)           | (-5,-12)
+        | (-10,0)           | (1e-300,-1e-300)
+        | (-10,0)           | (1e+300,Infinity)
+        | (-10,0)           | (NaN,NaN)
+        | (-10,0)           | (10,10)
+        | (-3,4)            | (0,0)
+        | (-3,4)            | (-10,0)
+        | (-3,4)            | (5.1,34.5)
+        | (-3,4)            | (-5,-12)
+        | (-3,4)            | (1e-300,-1e-300)
+        | (-3,4)            | (1e+300,Infinity)
+        | (-3,4)            | (NaN,NaN)
+        | (-3,4)            | (10,10)
+        | (5.1,34.5)        | (0,0)
+        | (5.1,34.5)        | (-10,0)
+        | (5.1,34.5)        | (-3,4)
+        | (5.1,34.5)        | (-5,-12)
+        | (5.1,34.5)        | (1e-300,-1e-300)
+        | (5.1,34.5)        | (1e+300,Infinity)
+        | (5.1,34.5)        | (NaN,NaN)
+        | (5.1,34.5)        | (10,10)
+        | (-5,-12)          | (0,0)
+        | (-5,-12)          | (-10,0)
+        | (-5,-12)          | (-3,4)
+        | (-5,-12)          | (5.1,34.5)
+        | (-5,-12)          | (1e-300,-1e-300)
+        | (-5,-12)          | (1e+300,Infinity)
+        | (-5,-12)          | (NaN,NaN)
+        | (-5,-12)          | (10,10)
+        | (1e-300,-1e-300)  | (-10,0)
+        | (1e-300,-1e-300)  | (-3,4)
+        | (1e-300,-1e-300)  | (5.1,34.5)
+        | (1e-300,-1e-300)  | (-5,-12)
+        | (1e-300,-1e-300)  | (1e+300,Infinity)
+        | (1e-300,-1e-300)  | (NaN,NaN)
+        | (1e-300,-1e-300)  | (10,10)
+        | (1e+300,Infinity) | (0,0)
+        | (1e+300,Infinity) | (-10,0)
+        | (1e+300,Infinity) | (-3,4)
+        | (1e+300,Infinity) | (5.1,34.5)
+        | (1e+300,Infinity) | (-5,-12)
+        | (1e+300,Infinity) | (1e-300,-1e-300)
+        | (1e+300,Infinity) | (1e+300,Infinity)
+        | (1e+300,Infinity) | (NaN,NaN)
+        | (1e+300,Infinity) | (10,10)
+        | (NaN,NaN)         | (0,0)
+        | (NaN,NaN)         | (-10,0)
+        | (NaN,NaN)         | (-3,4)
+        | (NaN,NaN)         | (5.1,34.5)
+        | (NaN,NaN)         | (-5,-12)
+        | (NaN,NaN)         | (1e-300,-1e-300)
+        | (NaN,NaN)         | (1e+300,Infinity)
+        | (NaN,NaN)         | (NaN,NaN)
+        | (NaN,NaN)         | (10,10)
+        | (10,10)           | (0,0)
+        | (10,10)           | (-10,0)
+        | (10,10)           | (-3,4)
+        | (10,10)           | (5.1,34.5)
+        | (10,10)           | (-5,-12)
+        | (10,10)           | (1e-300,-1e-300)
+        | (10,10)           | (1e+300,Infinity)
+        | (10,10)           | (NaN,NaN)
+(72 rows)
 
 -- put distance result into output to allow sorting with GEQ optimizer - tgl 97/05/10
 SELECT '' AS fifteen, p1.f1 AS point1, p2.f1 AS point2, (p1.f1 <-> p2.f1) AS distance
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3 and p1.f1 << p2.f1
    ORDER BY distance, p1.f1[0], p2.f1[0];
- fifteen |   point1   |   point2   |     distance     
----------+------------+------------+------------------
-         | (-3,4)     | (0,0)      |                5
-         | (-10,0)    | (-3,4)     | 8.06225774829855
-         | (-10,0)    | (0,0)      |               10
-         | (-10,0)    | (-5,-12)   |               13
-         | (-5,-12)   | (0,0)      |               13
-         | (0,0)      | (10,10)    |  14.142135623731
-         | (-3,4)     | (10,10)    | 14.3178210632764
-         | (-5,-12)   | (-3,4)     | 16.1245154965971
-         | (-10,0)    | (10,10)    | 22.3606797749979
-         | (5.1,34.5) | (10,10)    | 24.9851956166046
-         | (-5,-12)   | (10,10)    | 26.6270539113887
-         | (-3,4)     | (5.1,34.5) | 31.5572495632937
-         | (0,0)      | (5.1,34.5) | 34.8749193547455
-         | (-10,0)    | (5.1,34.5) | 37.6597928831267
-         | (-5,-12)   | (5.1,34.5) | 47.5842410888311
-(15 rows)
+ fifteen |      point1      |      point2       |     distance     
+---------+------------------+-------------------+------------------
+         | (-3,4)           | (0,0)             |                5
+         | (-3,4)           | (1e-300,-1e-300)  |                5
+         | (-10,0)          | (-3,4)            | 8.06225774829855
+         | (-10,0)          | (0,0)             |               10
+         | (-10,0)          | (1e-300,-1e-300)  |               10
+         | (-10,0)          | (-5,-12)          |               13
+         | (-5,-12)         | (0,0)             |               13
+         | (-5,-12)         | (1e-300,-1e-300)  |               13
+         | (0,0)            | (10,10)           |  14.142135623731
+         | (1e-300,-1e-300) | (10,10)           |  14.142135623731
+         | (-3,4)           | (10,10)           | 14.3178210632764
+         | (-5,-12)         | (-3,4)            | 16.1245154965971
+         | (-10,0)          | (10,10)           | 22.3606797749979
+         | (5.1,34.5)       | (10,10)           | 24.9851956166046
+         | (-5,-12)         | (10,10)           | 26.6270539113887
+         | (-3,4)           | (5.1,34.5)        | 31.5572495632937
+         | (0,0)            | (5.1,34.5)        | 34.8749193547455
+         | (1e-300,-1e-300) | (5.1,34.5)        | 34.8749193547455
+         | (-10,0)          | (5.1,34.5)        | 37.6597928831267
+         | (-5,-12)         | (5.1,34.5)        | 47.5842410888311
+         | (-10,0)          | (1e+300,Infinity) |         Infinity
+         | (-5,-12)         | (1e+300,Infinity) |         Infinity
+         | (-3,4)           | (1e+300,Infinity) |         Infinity
+         | (0,0)            | (1e+300,Infinity) |         Infinity
+         | (1e-300,-1e-300) | (1e+300,Infinity) |         Infinity
+         | (5.1,34.5)       | (1e+300,Infinity) |         Infinity
+         | (10,10)          | (1e+300,Infinity) |         Infinity
+(27 rows)
 
 -- put distance result into output to allow sorting with GEQ optimizer - tgl 97/05/10
 SELECT '' AS three, p1.f1 AS point1, p2.f1 AS point2, (p1.f1 <-> p2.f1) AS distance
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3 and p1.f1 << p2.f1 and p1.f1 >^ p2.f1
    ORDER BY distance;
- three |   point1   |  point2  |     distance     
--------+------------+----------+------------------
-       | (-3,4)     | (0,0)    |                5
-       | (-10,0)    | (-5,-12) |               13
-       | (5.1,34.5) | (10,10)  | 24.9851956166046
-(3 rows)
+ three |   point1   |      point2      |     distance     
+-------+------------+------------------+------------------
+       | (-3,4)     | (0,0)            |                5
+       | (-3,4)     | (1e-300,-1e-300) |                5
+       | (-10,0)    | (-5,-12)         |               13
+       | (5.1,34.5) | (10,10)          | 24.9851956166046
+(4 rows)
 
 -- Test that GiST indexes provide same behavior as sequential scan
 CREATE TEMP TABLE point_gist_tbl(f1 point);
 INSERT INTO point_gist_tbl SELECT '(0,0)' FROM generate_series(0,1000);
 CREATE INDEX point_gist_tbl_index ON point_gist_tbl USING gist (f1);
 INSERT INTO point_gist_tbl VALUES ('(0.0000009,0.0000009)');
 SET enable_seqscan TO true;
 SET enable_indexscan TO false;
 SET enable_bitmapscan TO false;
 SELECT COUNT(*) FROM point_gist_tbl WHERE f1 ~= '(0.0000009,0.0000009)'::point;
diff --git a/src/test/regress/expected/polygon.out b/src/test/regress/expected/polygon.out
index 4a1f60427a..be5f76bf9d 100644
--- a/src/test/regress/expected/polygon.out
+++ b/src/test/regress/expected/polygon.out
@@ -1,18 +1,21 @@
 --
 -- POLYGON
 --
 -- polygon logic
 --
 CREATE TABLE POLYGON_TBL(f1 polygon);
 INSERT INTO POLYGON_TBL(f1) VALUES ('(2.0,0.0),(2.0,4.0),(0.0,0.0)');
 INSERT INTO POLYGON_TBL(f1) VALUES ('(3.0,1.0),(3.0,3.0),(1.0,0.0)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(3,4),(5,6),(7,8)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(7,8),(5,6),(3,4),(1,2)'); -- Reverse
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(7,8),(5,6),(3,-4)');
 -- degenerate polygons
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,0.0)');
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,1.0),(0.0,1.0)');
 -- bad polygon input strings
 INSERT INTO POLYGON_TBL(f1) VALUES ('0.0');
 ERROR:  invalid input syntax for type polygon: "0.0"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('0.0');
                                             ^
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0 0.0');
 ERROR:  invalid input syntax for type polygon: "(0.0 0.0"
@@ -24,215 +27,30 @@ LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2)');
                                             ^
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2,3');
 ERROR:  invalid input syntax for type polygon: "(0,1,2,3"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2,3');
                                             ^
 INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
 ERROR:  invalid input syntax for type polygon: "asdf"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
                                             ^
 SELECT '' AS four, * FROM POLYGON_TBL;
- four |         f1          
-------+---------------------
+ four |             f1             
+------+----------------------------
       | ((2,0),(2,4),(0,0))
       | ((3,1),(3,3),(1,0))
+      | ((1,2),(3,4),(5,6),(7,8))
+      | ((7,8),(5,6),(3,4),(1,2))
+      | ((1,2),(7,8),(5,6),(3,-4))
       | ((0,0))
       | ((0,1),(0,1))
-(4 rows)
-
--- overlap
-SELECT '' AS three, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 && '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- three |         f1          
--------+---------------------
-       | ((2,0),(2,4),(0,0))
-       | ((3,1),(3,3),(1,0))
-(2 rows)
-
--- left overlap
-SELECT '' AS four, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &< '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- four |         f1          
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
-
--- right overlap
-SELECT '' AS two, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- two |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- left of
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 << '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |      f1       
------+---------------
-     | ((0,0))
-     | ((0,1),(0,1))
-(2 rows)
-
--- right of
-SELECT '' AS zero, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 >> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- zero | f1 
-------+----
-(0 rows)
-
--- contained
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- same
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- contains
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
---
--- polygon logic
---
--- left of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- left overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
- true 
-------
- f
-(1 row)
-
--- right overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' &> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- right of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' >> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- contained in
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- contains
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((0,4),(6,4),(3,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
-SELECT '((1,1),(1,4),(5,4),(5,3),(2,3),(2,2),(5,2),(5,1))'::polygon @> '((3,2),(3,3),(4,3),(4,2))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((0,0),(0,3),(3,3),(3,0))'::polygon @> '((2,1),(2,2),(3,2),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
--- same
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' && polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
- true 
-------
- t
-(1 row)
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon && '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
-SELECT '((1,4),(1,1),(4,1),(4,2),(2,2),(2,4),(1,4))'::polygon && '((3,3),(4,3),(4,4),(3,4),(3,3))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((200,800),(800,800),(800,200),(200,200))' &&  '(1000,1000,0,0)'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
--- distance from a point
-SELECT	'(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
-	'(1,1)'::point <-> '((0,0),(2,2),(1,3))'::polygon as on_segment,
-	'(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;
- on_corner | on_segment | inside |   near_corner   | near_segment 
------------+------------+--------+-----------------+--------------
-         0 |          0 |      0 | 1.4142135623731 |          3.2
-(1 row)
+(7 rows)
 
 --
 -- 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
diff --git a/src/test/regress/sql/box.sql b/src/test/regress/sql/box.sql
index 135ac108eb..6710fc90f5 100644
--- a/src/test/regress/sql/box.sql
+++ b/src/test/regress/sql/box.sql
@@ -18,29 +18,38 @@
 
 -- boxes are specified by two points, given by four floats x1,y1,x2,y2
 
 
 CREATE TABLE BOX_TBL (f1 box);
 
 INSERT INTO BOX_TBL (f1) VALUES ('(2.0,2.0,0.0,0.0)');
 
 INSERT INTO BOX_TBL (f1) VALUES ('(1.0,1.0,3.0,3.0)');
 
+INSERT INTO BOX_TBL (f1) VALUES ('((-8, 2), (-2, -10))');
+
+
 -- degenerate cases where the box is a line or a point
 -- note that lines and points boxes all have zero area
 INSERT INTO BOX_TBL (f1) VALUES ('(2.5, 2.5, 2.5,3.5)');
 
 INSERT INTO BOX_TBL (f1) VALUES ('(3.0, 3.0,3.0,3.0)');
 
 -- badly formatted box inputs
 INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
 
+INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+
 INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
 
 
 SELECT '' AS four, * FROM BOX_TBL;
 
 SELECT '' AS four, b.*, area(b.f1) as barea
    FROM BOX_TBL b;
 
 -- overlap
 SELECT '' AS three, b.f1
diff --git a/src/test/regress/sql/circle.sql b/src/test/regress/sql/circle.sql
index c0284b2b59..46c96e1400 100644
--- a/src/test/regress/sql/circle.sql
+++ b/src/test/regress/sql/circle.sql
@@ -7,26 +7,34 @@ CREATE TABLE CIRCLE_TBL (f1 circle);
 INSERT INTO CIRCLE_TBL VALUES ('<(5,1),3>');
 
 INSERT INTO CIRCLE_TBL VALUES ('<(1,2),100>');
 
 INSERT INTO CIRCLE_TBL VALUES ('1,3,5');
 
 INSERT INTO CIRCLE_TBL VALUES ('((1,2),3)');
 
 INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10>');
 
-INSERT INTO CIRCLE_TBL VALUES ('<(100,1),115>');
+INSERT INTO CIRCLE_TBL VALUES (' < ( 100 , 1 ) , 115 > ');
+
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),0>');	-- Zero radius
+
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),NaN>');	-- NaN radius
 
 -- bad values
 
 INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
 
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+
 INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
 
 INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
 
 SELECT * FROM CIRCLE_TBL;
 
 SELECT '' AS six, center(f1) AS center
   FROM CIRCLE_TBL;
 
 SELECT '' AS six, radius(f1) AS radius
diff --git a/src/test/regress/sql/geometry.sql b/src/test/regress/sql/geometry.sql
index 1429ee772a..ce98b3e90c 100644
--- a/src/test/regress/sql/geometry.sql
+++ b/src/test/regress/sql/geometry.sql
@@ -39,74 +39,298 @@ SELECT '' AS two, p1.f1
 -- "is vertical" function
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE isvertical(p1.f1, point '(5.1,34.5)');
 
 -- "is vertical" operator
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?| point '(5.1,34.5)';
 
+-- Slope
+SELECT p1.f1, p2.f1, slope(p1.f1, p2.f1) FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Add point
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Subtract point
+SELECT p1.f1, p2.f1, p1.f1 - p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Multiply with point
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+
+-- Underflow error
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] < 1;
+
+-- Divide by point
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] BETWEEN 1 AND 1000;
+
+-- Overflow error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] > 1000;
+
+-- Division by 0 error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1 ~= '(0,0)'::point;
+
+-- Distance to line
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LINE_TBL l;
+
+-- Distance to line segment
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LSEG_TBL l;
+
+-- Distance to box
+SELECT p.f1, b.f1, p.f1 <-> b.f1 FROM POINT_TBL p, BOX_TBL b;
+
+-- Distance to path
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, PATH_TBL p1;
+
+-- Distance to polygon
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, POLYGON_TBL p1;
+
+-- Closest point to line
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LINE_TBL l;
+
+-- Closest point to line segment
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LSEG_TBL l;
+
+-- Closest point to box
+SELECT p.f1, b.f1, p.f1 ## b.f1 FROM POINT_TBL p, BOX_TBL b;
+
+-- On line
+SELECT p.f1, l.s FROM POINT_TBL p, LINE_TBL l WHERE p.f1 <@ l.s;
+
+-- On line segment
+SELECT p.f1, l.s FROM POINT_TBL p, LSEG_TBL l WHERE p.f1 <@ l.s;
+
+-- On path
+SELECT p.f1, p1.f1 FROM POINT_TBL p, PATH_TBL p1 WHERE p.f1 <@ p1.f1;
+
+--
+-- Lines
+--
+
+-- Vertical
+SELECT s FROM LINE_TBL WHERE ?| s;
+
+-- Horizontal
+SELECT s FROM LINE_TBL WHERE ?- s;
+
+-- Same as line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s = l2.s;
+
+-- Parallel to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?|| l2.s;
+
+-- Perpendicular to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?-| l2.s;
+
+-- Distance to line
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2;
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LINE_TBL l, BOX_TBL b;
+
+-- Intersect with line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?# l2.s;
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LINE_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+
+-- Intersection point with line
+SELECT l1.s, l2.s, l1.s # l2.s FROM LINE_TBL l1, LINE_TBL l2;
+
+-- Closest point to line segment
+SELECT l.s, l1.s, l.s ## l1.s FROM LINE_TBL l, LSEG_TBL l1;
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LINE_TBL l, BOX_TBL b;
+
 --
 -- Line segments
 --
 
 -- intersection
 SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
    FROM LSEG_TBL l, POINT_TBL p;
 
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
+-- Length
+SELECT s, @-@ s FROM LSEG_TBL;
+
+-- Vertical
+SELECT s FROM LSEG_TBL WHERE ?| s;
+
+-- Horizontal
+SELECT s FROM LSEG_TBL WHERE ?- s;
+
+-- Center
+SELECT s, @@ s FROM LSEG_TBL;
+
+-- To point
+SELECT s, s::point FROM LSEG_TBL;
+
+-- Has points less than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s < l2.s;
+
+-- Has points less than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s <= l2.s;
+
+-- Has points equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s = l2.s;
+
+-- Has points greater than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s >= l2.s;
+
+-- Has points greater than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s > l2.s;
+
+-- Has points not equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s != l2.s;
+
+-- Parallel with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?|| l2.s;
+
+-- Perpendicular with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?-| l2.s;
+
+-- Distance to line
+SELECT l.s, l1.s, l.s <-> l1.s FROM LSEG_TBL l, LINE_TBL l1;
+
+-- Distance to line segment
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LSEG_TBL l, BOX_TBL b;
+
+-- Intersect with line segment
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s ?# l1.s;
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+
+-- Intersection point with line segment
+SELECT l1.s, l2.s, l1.s # l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Closest point to line
+SELECT l.s, l1.s, l.s ## l1.s FROM LSEG_TBL l, LINE_TBL l1;
+
+-- Closest point to line segment
+SELECT l1.s, l2.s, l1.s ## l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LSEG_TBL l, BOX_TBL b;
+
+-- On line
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s <@ l1.s;
+
+-- On box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s <@ b.f1;
 
 --
 -- Boxes
 --
 
 SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
 
 -- translation
 SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
 
 SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
 
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
+-- Multiply with point
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
 
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
+-- Overflow error
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] > 1000;
 
+-- Divide by point
+SELECT b.f1, p.f1, b.f1 / p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+
+-- To box
 SELECT f1::box
 	FROM POINT_TBL;
 
 SELECT bound_box(a.f1, b.f1)
 	FROM BOX_TBL a, BOX_TBL b;
 
+-- Below box
+SELECT b1.f1, b2.f1, b1.f1 <^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Above box
+SELECT b1.f1, b2.f1, b1.f1 >^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Intersection point with box
+SELECT b1.f1, b2.f1, b1.f1 # b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Diagonal
+SELECT f1, diagonal(f1) FROM BOX_TBL;
+
+-- Distance to box
+SELECT b1.f1, b2.f1, b1.f1 <-> b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
 --
 -- Paths
 --
 
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
+-- Points
+SELECT f1, npoints(f1) FROM PATH_TBL;
 
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
+-- Area
+SELECT f1, area(f1) FROM PATH_TBL;
 
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
+-- Length
+SELECT f1, @-@ f1 FROM PATH_TBL;
 
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
+-- Center
+SELECT f1, @@ f1 FROM PATH_TBL;
+
+-- To polygon
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isclosed(f1);
+
+-- Open path cannot be converted to polygon error
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isopen(f1);
+
+-- Has points less than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 < p2.f1;
+
+-- Has points less than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 <= p2.f1;
+
+-- Has points equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 = p2.f1;
+
+-- Has points greater than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 >= p2.f1;
+
+-- Has points greater than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 > p2.f1;
+
+-- Add path
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+
+-- Add point
+SELECT p.f1, p1.f1, p.f1 + p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+
+-- Subtract point
+SELECT p.f1, p1.f1, p.f1 - p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+
+-- Multiply with point
+SELECT p.f1, p1.f1, p.f1 * p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+
+-- Divide by point
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+
+-- Division by 0 error
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1 ~= '(0,0)'::point;
+
+-- Distance to path
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
 
 --
 -- Polygons
 --
 
 -- containment
 SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
    FROM POLYGON_TBL poly, POINT_TBL p;
 
 SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
@@ -118,36 +342,166 @@ SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
 SELECT '' AS four, polygon(f1)
    FROM BOX_TBL;
 
 SELECT '' AS four, polygon(f1)
    FROM PATH_TBL WHERE isclosed(f1);
 
 SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
    FROM PATH_TBL
    WHERE isopen(f1);
 
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
+-- To box
+SELECT f1, f1::box FROM POLYGON_TBL;
 
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
+-- To path
+SELECT f1, f1::path FROM POLYGON_TBL;
+
+-- Same as polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 ~= p2.f1;
+
+-- Contained by polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <@ p2.f1;
+
+-- Contains polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 @> p2.f1;
+
+-- Overlap with polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 && p2.f1;
+
+-- Left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 << p2.f1;
+
+-- Overlap of left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &< p2.f1;
+
+-- Right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 >> p2.f1;
+
+-- Overlap of right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &> p2.f1;
+
+-- Below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <<| p2.f1;
+
+-- Overlap or below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &<| p2.f1;
+
+-- Above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |>> p2.f1;
+
+-- Overlap or above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |&> p2.f1;
+
+-- Distance to polygon
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2;
 
 --
 -- Circles
 --
 
 SELECT '' AS six, circle(f1, 50.0)
    FROM POINT_TBL;
 
 SELECT '' AS four, circle(f1)
    FROM BOX_TBL;
 
 SELECT '' AS two, circle(f1)
    FROM POLYGON_TBL
    WHERE (# f1) >= 3;
 
 SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
    FROM CIRCLE_TBL c1, POINT_TBL p1
    WHERE (p1.f1 <-> c1.f1) > 0
    ORDER BY distance, area(c1.f1), p1.f1[0];
+
+-- To polygon
+SELECT f1, f1::polygon FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+
+-- To polygon with less points
+SELECT f1, polygon(8, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+
+-- Too less points error
+SELECT f1, polygon(1, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+
+-- Zero radius error
+SELECT f1, polygon(10, f1) FROM CIRCLE_TBL WHERE f1 < '<(0,0),1>';
+
+-- Same as circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 ~= c2.f1;
+
+-- Overlap with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 && c2.f1;
+
+-- Overlap or left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &< c2.f1;
+
+-- Left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 << c2.f1;
+
+-- Right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >> c2.f1;
+
+-- Overlap or right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &> c2.f1;
+
+-- Contained by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <@ c2.f1;
+
+-- Contain by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 @> c2.f1;
+
+-- Below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <<| c2.f1;
+
+-- Above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |>> c2.f1;
+
+-- Overlap or below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &<| c2.f1;
+
+-- Overlap or above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |&> c2.f1;
+
+-- Area equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 = c2.f1;
+
+-- Area not equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 != c2.f1;
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 > c2.f1;
+
+-- Area less than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <= c2.f1;
+
+-- Area greater than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >= c2.f1;
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+
+-- Add point
+SELECT c.f1, p.f1, c.f1 + p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Subtract point
+SELECT c.f1, p.f1, c.f1 - p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Multiply with point
+SELECT c.f1, p.f1, c.f1 * p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Divide by point
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+
+-- Overflow error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] > 1000;
+
+-- Division by 0 error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1 ~= '(0,0)'::point;
+
+-- Distance to polygon
+SELECT c.f1, p.f1, c.f1 <-> p.f1 FROM CIRCLE_TBL c, POLYGON_TBL p;
diff --git a/src/test/regress/sql/line.sql b/src/test/regress/sql/line.sql
index 94067b0cee..f589ffecc8 100644
--- a/src/test/regress/sql/line.sql
+++ b/src/test/regress/sql/line.sql
@@ -1,87 +1,42 @@
 --
 -- LINE
 -- Infinite lines
 --
 
 --DROP TABLE LINE_TBL;
 CREATE TABLE LINE_TBL (s line);
 
-INSERT INTO LINE_TBL VALUES ('{1,-1,1}');
-INSERT INTO LINE_TBL VALUES ('(0,0),(6,6)');
+INSERT INTO LINE_TBL VALUES ('{0,-1,5}');	-- A == 0
+INSERT INTO LINE_TBL VALUES ('{1,0,5}');	-- B == 0
+INSERT INTO LINE_TBL VALUES ('{0,3,0}');	-- A == C == 0
+INSERT INTO LINE_TBL VALUES (' (0,0), (6,6)');
 INSERT INTO LINE_TBL VALUES ('10,-10 ,-5,-4');
 INSERT INTO LINE_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LINE_TBL VALUES ('(11,22,33,44)');
 
-INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
+INSERT INTO LINE_TBL VALUES ('{3,NaN,5}');
+INSERT INTO LINE_TBL VALUES ('{NaN,NaN,NaN}');
 
 -- horizontal
 INSERT INTO LINE_TBL VALUES ('[(1,3),(2,3)]');
 -- vertical
-INSERT INTO LINE_TBL VALUES ('[(3,1),(3,2)]');
+INSERT INTO LINE_TBL VALUES (line(point '(3,1)', point '(3,2)'));
 
 -- bad values for parser testing
+INSERT INTO LINE_TBL VALUES ('{}');
+INSERT INTO LINE_TBL VALUES ('{0');
+INSERT INTO LINE_TBL VALUES ('{0,0}');
+INSERT INTO LINE_TBL VALUES ('{0,0,1');
 INSERT INTO LINE_TBL VALUES ('{0,0,1}');
+INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
 INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
 INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
 INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
 INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
+INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
+
+INSERT INTO LINE_TBL VALUES (line(point '(1,0)', point '(1,0)'));
 
 select * from LINE_TBL;
 
-
--- functions and operators
-
-SELECT * FROM LINE_TBL WHERE (s <-> line '[(1,2),(3,4)]') < 10;
-
-SELECT * FROM LINE_TBL WHERE (point '(0.1,0.1)' <-> s) < 1;
-
-SELECT * FROM LINE_TBL WHERE (lseg '[(0.1,0.1),(0.2,0.2)]' <-> s) < 1;
-
-SELECT line '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
-SELECT lseg '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
-SELECT point '(-1,1)' <-> line '[(-3,0),(-4,0)]';
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(2,0),(0,2)]';  -- true
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(0,0),(1,0)]';  -- false
-
-SELECT line '[(0,0),(1,1)]' ?# box '(0,0,2,2)';  -- true
-SELECT line '[(3,0),(4,1)]' ?# box '(0,0,2,2)';  -- false
-
-SELECT point '(1,1)' <@ line '[(0,0),(2,2)]';  -- true
-SELECT point '(1,1)' <@ line '[(0,0),(1,0)]';  -- false
-
-SELECT point '(1,1)' @ line '[(0,0),(2,2)]';  -- true
-SELECT point '(1,1)' @ line '[(0,0),(1,0)]';  -- false
-
-SELECT lseg '[(1,1),(2,2)]' <@ line '[(0,0),(2,2)]';  -- true
-SELECT lseg '[(1,1),(2,1)]' <@ line '[(0,0),(1,0)]';  -- false
-
-SELECT lseg '[(1,1),(2,2)]' @ line '[(0,0),(2,2)]';  -- true
-SELECT lseg '[(1,1),(2,1)]' @ line '[(0,0),(1,0)]';  -- false
-
-SELECT point '(0,1)' ## line '[(0,0),(1,1)]';
-
-SELECT line '[(0,0),(1,1)]' ## lseg '[(1,0),(2,0)]';
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(2,1)]';  -- false
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(1,1)]';  -- true
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(2,1)]';
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(1,1)]';
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(2,1)]';  -- true
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(1,1)]';  -- false
-
-SELECT line '[(0,0),(1,0)]' ?-| line '[(0,0),(0,1)]';  -- true
-SELECT line '[(0,0),(1,1)]' ?-| line '[(1,0),(1,1)]';  -- false
-
-SELECT ?- line '[(0,0),(1,0)]';  -- true
-SELECT ?- line '[(0,0),(1,1)]';  -- false
-
-SELECT ?| line '[(0,0),(0,1)]';  -- true
-SELECT ?| line '[(0,0),(1,1)]';  -- false
-
-SELECT line(point '(1,2)', point '(3,4)');
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,5)]';  -- true
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,4)]';  -- false
+select '{nan, 1, nan}'::line = '{nan, 1, nan}'::line as true,
+	   '{nan, 1, nan}'::line = '{nan, 2, nan}'::line as false;
diff --git a/src/test/regress/sql/lseg.sql b/src/test/regress/sql/lseg.sql
index 07c5a29e0a..f266ca3e09 100644
--- a/src/test/regress/sql/lseg.sql
+++ b/src/test/regress/sql/lseg.sql
@@ -3,23 +3,22 @@
 -- Line segments
 --
 
 --DROP TABLE LSEG_TBL;
 CREATE TABLE LSEG_TBL (s lseg);
 
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('(0,0),(6,6)');
 INSERT INTO LSEG_TBL VALUES ('10,-10 ,-3,-4');
 INSERT INTO LSEG_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LSEG_TBL VALUES ('(11,22,33,44)');
+INSERT INTO LSEG_TBL VALUES (lseg(point(11, 22), point(33,44)));
+INSERT INTO LSEG_TBL VALUES ('[(-10,2),(-10,3)]');	-- vertical
+INSERT INTO LSEG_TBL VALUES ('[(0,-20),(30,-20)]');	-- horizontal
+INSERT INTO LSEG_TBL VALUES ('[(NaN,1),(NaN,90)]');	-- NaN
 
 -- bad values for parser testing
 INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
 INSERT INTO LSEG_TBL VALUES ('[1,2,3, 4');
 INSERT INTO LSEG_TBL VALUES ('[(,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)');
 
 select * from LSEG_TBL;
-
-SELECT * FROM LSEG_TBL WHERE s <= lseg '[(1,2),(3,4)]';
-
-SELECT * FROM LSEG_TBL WHERE (s <-> lseg '[(1,2),(3,4)]') < 10;
diff --git a/src/test/regress/sql/path.sql b/src/test/regress/sql/path.sql
index 7e69b539ad..318decf974 100644
--- a/src/test/regress/sql/path.sql
+++ b/src/test/regress/sql/path.sql
@@ -1,38 +1,44 @@
 --
 -- PATH
 --
 
 --DROP TABLE PATH_TBL;
 
 CREATE TABLE PATH_TBL (f1 path);
 
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)]');
 
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
+INSERT INTO PATH_TBL VALUES (' ( ( 1 , 2 ) , ( 3 , 4 ) ) ');
 
-INSERT INTO PATH_TBL VALUES ('[(0,0),(3,0),(4,5),(1,6)]');
+INSERT INTO PATH_TBL VALUES ('[ (0,0),(3,0),(4,5),(1,6) ]');
 
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
+INSERT INTO PATH_TBL VALUES ('((1,2) ,(3,4 ))');
 
-INSERT INTO PATH_TBL VALUES ('1,2 ,3,4');
+INSERT INTO PATH_TBL VALUES ('1,2 ,3,4 ');
 
-INSERT INTO PATH_TBL VALUES ('[1,2,3, 4]');
+INSERT INTO PATH_TBL VALUES (' [1,2,3, 4] ');
 
-INSERT INTO PATH_TBL VALUES ('[11,12,13,14]');
+INSERT INTO PATH_TBL VALUES ('((10,20))');	-- Only one point
 
-INSERT INTO PATH_TBL VALUES ('(11,12,13,14)');
+INSERT INTO PATH_TBL VALUES ('[ 11,12,13,14 ]');
+
+INSERT INTO PATH_TBL VALUES ('( 11,12,13,14) ');
 
 -- bad values for parser testing
+INSERT INTO PATH_TBL VALUES ('[]');
+
 INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
 
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
 
-SELECT f1 FROM PATH_TBL;
+INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+
+INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
 
 SELECT '' AS count, f1 AS open_path FROM PATH_TBL WHERE isopen(f1);
 
 SELECT '' AS count, f1 AS closed_path FROM PATH_TBL WHERE isclosed(f1);
 
 SELECT '' AS count, pclose(f1) AS closed_path FROM PATH_TBL;
 
 SELECT '' AS count, popen(f1) AS open_path FROM PATH_TBL;
diff --git a/src/test/regress/sql/point.sql b/src/test/regress/sql/point.sql
index 63a803a809..a209f3bfeb 100644
--- a/src/test/regress/sql/point.sql
+++ b/src/test/regress/sql/point.sql
@@ -7,29 +7,39 @@ CREATE TABLE POINT_TBL(f1 point);
 INSERT INTO POINT_TBL(f1) VALUES ('(0.0,0.0)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-10.0,0.0)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-3.0,4.0)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(5.1, 34.5)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-5.0,-12.0)');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(1e-300,-1e-300)');	-- To underflow
+
+INSERT INTO POINT_TBL(f1) VALUES ('(1e+300,Inf)');		-- To overflow
+
+INSERT INTO POINT_TBL(f1) VALUES (' ( Nan , NaN ) ');
+
 -- bad format points
 INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
 
 INSERT INTO POINT_TBL(f1) VALUES ('10.0,10.0');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');	-- Out of range
+
 
 SELECT '' AS six, * FROM POINT_TBL;
 
 -- left of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE p.f1 << '(0.0, 0.0)';
 
 -- right of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE '(0.0,0.0)' >> p.f1;
 
 -- above
diff --git a/src/test/regress/sql/polygon.sql b/src/test/regress/sql/polygon.sql
index 7e8cb08cd8..d3d2fe3457 100644
--- a/src/test/regress/sql/polygon.sql
+++ b/src/test/regress/sql/polygon.sql
@@ -4,126 +4,43 @@
 -- polygon logic
 --
 
 CREATE TABLE POLYGON_TBL(f1 polygon);
 
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(2.0,0.0),(2.0,4.0),(0.0,0.0)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(3.0,1.0),(3.0,3.0),(1.0,0.0)');
 
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(3,4),(5,6),(7,8)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(7,8),(5,6),(3,4),(1,2)'); -- Reverse
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(7,8),(5,6),(3,-4)');
+
 -- degenerate polygons
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,0.0)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,1.0),(0.0,1.0)');
 
 -- bad polygon input strings
 INSERT INTO POLYGON_TBL(f1) VALUES ('0.0');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0 0.0');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2,3');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
 
 
 SELECT '' AS four, * FROM POLYGON_TBL;
 
--- overlap
-SELECT '' AS three, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 && '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- left overlap
-SELECT '' AS four, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &< '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- right overlap
-SELECT '' AS two, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- left of
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 << '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- right of
-SELECT '' AS zero, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 >> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- contained
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- same
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- contains
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
---
--- polygon logic
---
--- left of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- left overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
-
--- right overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' &> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- right of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' >> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- contained in
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- contains
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "false";
-
-SELECT '((0,4),(6,4),(3,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
-
-SELECT '((1,1),(1,4),(5,4),(5,3),(2,3),(2,2),(5,2),(5,1))'::polygon @> '((3,2),(3,3),(4,3),(4,2))'::polygon AS "false";
-
-SELECT '((0,0),(0,3),(3,3),(3,0))'::polygon @> '((2,1),(2,2),(3,2),(3,1))'::polygon AS "true";
-
--- same
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' && polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon && '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
-
-SELECT '((1,4),(1,1),(4,1),(4,2),(2,2),(2,4),(1,4))'::polygon && '((3,3),(4,3),(4,4),(3,4),(3,3))'::polygon AS "false";
-SELECT '((200,800),(800,800),(800,200),(200,200))' &&  '(1000,1000,0,0)'::polygon AS "true";
-
--- distance from a point
-SELECT	'(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
-	'(1,1)'::point <-> '((0,0),(2,2),(1,3))'::polygon as on_segment,
-	'(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;
-- 
2.14.3 (Apple Git-98)

#60Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Emre Hasegeli (#59)
Re: [PATCH] Improve geometric types

Hi Emre,

Thanks for the rebased patch. I remember reviewing the patch in the last
CF, and it seems in a pretty good shape. I plan to look at it again in
the next commitfest, but it seems to have been reviewed by other
experienced people so I'm not worried about this part.

The main remaining question I have is what do do with back-branches.
Shall we back-patch this or not?

The trouble is that while the patch is essentially a bugfix, it
refactors quite significant amount of code to make the fixes practical.
If it was possible to back-patch just the fixes without the refactoring,
that would be ideal, but unfortunately that's not the case. Based on
discussion with Emre in Ottawa that would be rather impractical due to
the nature of the bugs and low code reuse.

I do believe we should back-patch - after all, it fixes real bugs. It's
true the bugs were there for years and no one noticed/reported them, but
it's still buggy and that's not fun.

Opinions?

regards

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

#61Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tomas Vondra (#60)
Re: [PATCH] Improve geometric types

Tomas Vondra <tomas.vondra@2ndquadrant.com> writes:

The main remaining question I have is what do do with back-branches.
Shall we back-patch this or not?

Given the behavioral changes involved, I'd say "no way". That's
reinforced by the lack of field complaints; if there were lots of
complaints, maybe we'd be willing to break backwards compatibility,
but ...

regards, tom lane

#62Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Tom Lane (#61)
Re: [PATCH] Improve geometric types

On 06/03/2018 11:50 PM, Tom Lane wrote:

Tomas Vondra <tomas.vondra@2ndquadrant.com> writes:

The main remaining question I have is what do do with back-branches.
Shall we back-patch this or not?

Given the behavioral changes involved, I'd say "no way". That's
reinforced by the lack of field complaints; if there were lots of
complaints, maybe we'd be willing to break backwards compatibility,
but ...

Fair enough, I tend to over-estimate importance of bugfixes and
under-estimate breakage due to behavior change. But if we don't want to
back-patch this, I'm fine with that. I was a bit worried about making
future backpatches more painful, but this code received only ~20 commits
over the past files, half of that due tot pgindent, so that seems to be
a non-issue.

But now I'm wondering what does this mean for existing indexes? Doesn't
this effectively mean those are unlikely to give meaningful responses
(in the old or new semantics)?

regards

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

#63Emre Hasegeli
emre@hasegeli.com
In reply to: Tomas Vondra (#62)
Re: [PATCH] Improve geometric types

But now I'm wondering what does this mean for existing indexes? Doesn't this
effectively mean those are unlikely to give meaningful responses (in the old
or new semantics)?

The patches shouldn't cause any change to the indexable operators.
The fixes are mostly around the lines and the line segments which
doesn't have index support.

#64Thomas Munro
thomas.munro@enterprisedb.com
In reply to: Emre Hasegeli (#59)
Re: [PATCH] Improve geometric types

On Sun, Jun 3, 2018 at 12:58 PM, Emre Hasegeli <emre@hasegeli.com> wrote:

Rebased versions are attached.

Hi Emre,

This produces build errors on Windows[1]http://cfbot.cputube.org/emre-hasegeli.html[2]https://ci.appveyor.com/project/postgresql-cfbot/postgresql/build/1.0.1022:

C:\projects\postgresql\src\include\utils/float.h(136): warning
C4013: '_fpclass' undefined; assuming extern returning int
[C:\projects\postgresql\postgres.vcxproj]
C:\projects\postgresql\src\include\utils/float.h(297): warning
C4013: '_isnan' undefined; assuming extern returning int
[C:\projects\postgresql\postgres.vcxproj]
C:\projects\postgresql\src\include\utils/float.h(136): error C2065:
'_FPCLASS_PINF' : undeclared identifier
[C:\projects\postgresql\postgres.vcxproj]
C:\projects\postgresql\src\include\utils/float.h(136): error C2065:
'_FPCLASS_NINF' : undeclared identifier
[C:\projects\postgresql\postgres.vcxproj]
2778

This is apparently coming from the expansion of the following macros
from src/include/port/win32_port.h:

#if (_MSC_VER < 1800)
#define isinf(x) ((_fpclass(x) == _FPCLASS_PINF) || (_fpclass(x) ==
_FPCLASS_NINF))
#define isnan(x) _isnan(x)
#endif

Those underscore-prefixed names are defined in Microsoft's
<float.h>[3]https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/fpclass-fpclassf[4]https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/isnan-isnan-isnanf. So now I'm wondering if win32_port.h needs to
#include <float.h> if (_MSC_VER < 1800).

[1]: http://cfbot.cputube.org/emre-hasegeli.html
[2]: https://ci.appveyor.com/project/postgresql-cfbot/postgresql/build/1.0.1022
[3]: https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/fpclass-fpclassf
[4]: https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/isnan-isnan-isnanf

--
Thomas Munro
http://www.enterprisedb.com

#65Emre Hasegeli
emre@hasegeli.com
In reply to: Thomas Munro (#64)
Re: [PATCH] Improve geometric types

Those underscore-prefixed names are defined in Microsoft's
<float.h>[3][4]. So now I'm wondering if win32_port.h needs to
#include <float.h> if (_MSC_VER < 1800).

I don't have the C experience to decide the correct way. There are
currently many .c files that are including float.h conditionally or
unconditionally. The condition they use is "#ifdef _MSC_VER" without
a version.

One idea is to include float.h from the new utils/float.h file
together with math.h, and remove those includes from the .c files
which would include utils/float.h. We can do this only, or together
with what you suggest, or by also keeping the includes on the .c
files. Which way do you think is the proper?

#66Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Emre Hasegeli (#65)
Re: [PATCH] Improve geometric types

On 06/05/2018 06:32 PM, Emre Hasegeli wrote:

Those underscore-prefixed names are defined in Microsoft's
<float.h>[3][4]. So now I'm wondering if win32_port.h needs to
#include <float.h> if (_MSC_VER < 1800).

I don't have the C experience to decide the correct way. There are
currently many .c files that are including float.h conditionally or
unconditionally. The condition they use is "#ifdef _MSC_VER" without
a version.

One idea is to include float.h from the new utils/float.h file
together with math.h, and remove those includes from the .c files
which would include utils/float.h. We can do this only, or together
with what you suggest, or by also keeping the includes on the .c
files. Which way do you think is the proper?

Do we have any solution to the float.h include issues on Windows? I
don't have any Windows box at hand so I can't verify it, but just using
"#ifdef _MSC_VER" seems OK to me (and it's used elsewhere). Thomas, why
do you think the version number restriction is needed here? I don't see
the version mentioned in the MS docs you linked either.

Once this gets resolved, I'd like to get this committed ... so if you
have other objections, please speak now.

regards

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

#67Thomas Munro
thomas.munro@enterprisedb.com
In reply to: Tomas Vondra (#66)
Re: [PATCH] Improve geometric types

On Tue, Jul 10, 2018 at 7:21 AM, Tomas Vondra
<tomas.vondra@2ndquadrant.com> wrote:

On 06/05/2018 06:32 PM, Emre Hasegeli wrote:

Those underscore-prefixed names are defined in Microsoft's
<float.h>[3][4]. So now I'm wondering if win32_port.h needs to
#include <float.h> if (_MSC_VER < 1800).

I don't have the C experience to decide the correct way. There are
currently many .c files that are including float.h conditionally or
unconditionally. The condition they use is "#ifdef _MSC_VER" without
a version.

One idea is to include float.h from the new utils/float.h file
together with math.h, and remove those includes from the .c files
which would include utils/float.h. We can do this only, or together
with what you suggest, or by also keeping the includes on the .c
files. Which way do you think is the proper?

Do we have any solution to the float.h include issues on Windows? I
don't have any Windows box at hand so I can't verify it, but just using
"#ifdef _MSC_VER" seems OK to me (and it's used elsewhere). Thomas, why
do you think the version number restriction is needed here? I don't see
the version mentioned in the MS docs you linked either.

The version number restriction isn't strictly needed. I only
suggested it because it'd match the #if that wraps the code that's
actually using those macros, introduced by commit cec8394b5ccd. That
was presumably done because versions >= 1800 (= Visual Studio 2013)
have their own definitions of isinf() and isnan(), and I guess that
our definitions were probably breaking stuff on that compiler.

Once this gets resolved, I'd like to get this committed ... so if you
have other objections, please speak now.

+1, no objections.

--
Thomas Munro
http://www.enterprisedb.com

#68Emre Hasegeli
emre@hasegeli.com
In reply to: Thomas Munro (#67)
Re: [PATCH] Improve geometric types

The version number restriction isn't strictly needed. I only
suggested it because it'd match the #if that wraps the code that's
actually using those macros, introduced by commit cec8394b5ccd. That
was presumably done because versions >= 1800 (= Visual Studio 2013)
have their own definitions of isinf() and isnan(), and I guess that
our definitions were probably breaking stuff on that compiler.

Now I understand what you mean. win32_port.h defines isnan(x) as
_isnan(x) if (_MSC_VER < 1800). It doesn't look right to have the
definition in here but not include <float.h> as _isnan() is coming
from there. I am preparing an additional patch to add the include and
remove it from files where it is obviously put to work around this
problem.

#69Emre Hasegeli
emre@hasegeli.com
In reply to: Emre Hasegeli (#68)
6 attachment(s)
Re: [PATCH] Improve geometric types

Now I understand what you mean. win32_port.h defines isnan(x) as
_isnan(x) if (_MSC_VER < 1800). It doesn't look right to have the
definition in here but not include <float.h> as _isnan() is coming
from there. I am preparing an additional patch to add the include and
remove it from files where it is obviously put to work around this
problem.

I posted this to another thread. Until this is sorted out I made the
new float header patch include <float.h>, so they are not dependent.
New versions are attached.

Attachments:

0001-geo-funcs-v10.patchapplication/octet-stream; name=0001-geo-funcs-v10.patchDownload
From dd5236c294b02f5fbe1c88e78e8782ada52df8ec Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 27 May 2017 11:27:18 -0400
Subject: [PATCH 1/6] geo-funcs-v10

Refactor geometric functions and operators code

Most of the geometric types were not using functions of each other's.
I believe the reason behind this is simpler types line point and line
being developed after more complicated ones.  This patch reduces
duplicate code and makes functions of different datatypes more
compatible.  The changes can be summarised as:

* Eliminate SQL level function calls
* Re-use more functions to implement others
* Unify internal function names and signatures
* Remove private functions from geo_decls.h
* Replace not-possible checks with Assert()
* Add comments to describe some functions
* Remove some unreachable code
* Define delimiter symbols of line datatype like the other ones
* Remove debugging print()s from the refactored functions
* Unify code style of a few oddly formatted lines

This commits aims to not cause any user visible changes, but it is
almost impossible to stay completely bug-compatible with the old code.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com
---
 src/backend/utils/adt/geo_ops.c    | 1908 +++++++++++++++++-------------------
 src/backend/utils/adt/geo_spgist.c |    3 +-
 src/include/utils/geo_decls.h      |    4 -
 src/test/regress/regress.c         |    7 +-
 4 files changed, 883 insertions(+), 1039 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index f57380a4df..3e7519015d 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -31,75 +31,104 @@
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
+/* Routines for points */
+static inline void point_construct(Point *result, float8 x, float8 y);
+static inline void point_add_point(Point *result, Point *pt1, Point *pt2);
+static inline void point_sub_point(Point *result, Point *pt1, Point *pt2);
+static inline void point_mul_point(Point *result, Point *pt1, Point *pt2);
+static inline void point_div_point(Point *result, Point *pt1, Point *pt2);
+static inline bool point_eq_point(Point *pt1, Point *pt2);
+static inline float8 point_dt(Point *pt1, Point *pt2);
+static inline float8 point_sl(Point *pt1, Point *pt2);
 static int	point_inside(Point *p, int npts, Point *plist);
+
+/* Routines for lines */
+static inline void line_construct(LINE *result, Point *pt, float8 m);
+static inline float8 line_invsl(LINE *line);
+static bool	line_interpt_line(Point *result, LINE *l1, LINE *l2);
+static bool line_contain_point(LINE *line, Point *point);
+static float8 line_closept_point(Point *result, LINE *line, Point *pt);
+
+/* Routines for line segments */
+static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
+static inline float8 lseg_sl(LSEG *lseg);
+static inline float8 lseg_invsl(LSEG *lseg);
+static bool	lseg_interpt_line(Point *result, LSEG *lseg, LINE *line);
+static bool	lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2);
 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_fill(BOX *result, double x1, double x2, double y1, double y2);
+static bool	lseg_contain_point(LSEG *lseg, Point *point);
+static float8 lseg_closept_point(Point *result, LSEG *lseg, Point *pt);
+static float8 lseg_closept_line(Point *result, LSEG *lseg, LINE *line);
+static float8 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2);
+
+/* Routines for boxes */
+static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
+static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
+static double box_ar(BOX *box);
 static double box_ht(BOX *box);
 static double box_wd(BOX *box);
+static bool box_contain_point(BOX *box, Point *point);
+static bool box_contain_box(BOX *box1, BOX *box2);
+static bool box_contain_lseg(BOX *box, LSEG *lseg);
+static bool box_interpt_lseg(Point *result, BOX *box, LSEG *lseg);
+static float8 box_closept_point(Point *result, BOX *box, Point *point);
+static float8 box_closept_lseg(Point *result, BOX *box, LSEG *lseg);
+
+/* Routines for circles */
 static double circle_ar(CIRCLE *circle);
-static CIRCLE *circle_copy(CIRCLE *circle);
-static LINE *line_construct_pm(Point *pt, double m);
-static void line_construct_pts(LINE *line, Point *pt1, Point *pt2);
-static bool lseg_intersect_internal(LSEG *l1, LSEG *l2);
-static double lseg_dt(LSEG *l1, LSEG *l2);
-static bool on_ps_internal(Point *pt, LSEG *lseg);
+
+/* Routines for polygons */
 static void make_bound_box(POLYGON *poly);
+static void poly_to_circle(CIRCLE *result, POLYGON *poly);
+static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
+static bool poly_contain_poly(POLYGON *polya, POLYGON *polyb);
 static bool plist_same(int npts, Point *p1, Point *p2);
-static Point *point_construct(double x, double y);
-static Point *point_copy(Point *pt);
+static float8 dist_ppoly_internal(Point *pt, POLYGON *poly);
+
+/* Routines for encoding and decoding */
 static double single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
 static void pair_decode(char *str, double *x, double *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
 static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
-static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
-static double box_ar(BOX *box);
-static void box_cn(Point *center, BOX *box);
-static Point *interpt_sl(LSEG *lseg, LINE *line);
-static bool has_interpt_sl(LSEG *lseg, LINE *line);
-static double dist_pl_internal(Point *pt, LINE *line);
-static double dist_ps_internal(Point *pt, LSEG *lseg);
-static Point *line_interpt_internal(LINE *l1, LINE *l2);
-static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
-static Point *lseg_interpt_internal(LSEG *l1, LSEG *l2);
-static double dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 
 /*
  * Delimiters for input and output strings.
  * LDELIM, RDELIM, and DELIM are left, right, and separator delimiters, respectively.
  * LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints.
  */
 
 #define LDELIM			'('
 #define RDELIM			')'
 #define DELIM			','
 #define LDELIM_EP		'['
 #define RDELIM_EP		']'
 #define LDELIM_C		'<'
 #define RDELIM_C		'>'
+#define LDELIM_L		'{'
+#define RDELIM_L		'}'
 
 
 /*
  * Geometric data types are composed of points.
  * This code tries to support a common format throughout the data types,
  *	to allow for more predictable usage and data type conversion.
  * The fundamental unit is the point. Other units are line segments,
  *	open paths, boxes, closed paths, and polygons (which should be considered
  *	non-intersecting closed paths).
  *
@@ -229,26 +258,23 @@ path_decode(char *str, bool opentype, int npts, Point *p,
 	}
 
 	for (i = 0; i < npts; i++)
 	{
 		pair_decode(str, &(p->x), &(p->y), &str, type_name, orig_string);
 		if (*str == DELIM)
 			str++;
 		p++;
 	}
 
-	while (isspace((unsigned char) *str))
-		str++;
 	while (depth > 0)
 	{
-		if ((*str == RDELIM)
-			|| ((*str == RDELIM_EP) && (*isopen) && (depth == 1)))
+		if (*str == RDELIM || (*str == RDELIM_EP && *isopen && depth == 1))
 		{
 			depth--;
 			str++;
 			while (isspace((unsigned char) *str))
 				str++;
 		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
@@ -433,89 +459,61 @@ box_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, box->high.x);
 	pq_sendfloat8(&buf, box->high.y);
 	pq_sendfloat8(&buf, box->low.x);
 	pq_sendfloat8(&buf, box->low.y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*		box_construct	-		fill in a new box.
  */
-static BOX *
-box_construct(double x1, double x2, double y1, double y2)
+static inline void
+box_construct(BOX *result, Point *pt1, Point *pt2)
 {
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	return box_fill(result, x1, x2, y1, y2);
-}
-
-
-/*		box_fill		-		fill in a given box struct
- */
-static BOX *
-box_fill(BOX *result, double x1, double x2, double y1, double y2)
-{
-	if (x1 > x2)
+	if (pt1->x > pt2->x)
 	{
-		result->high.x = x1;
-		result->low.x = x2;
+		result->high.x = pt1->x;
+		result->low.x = pt2->x;
 	}
 	else
 	{
-		result->high.x = x2;
-		result->low.x = x1;
+		result->high.x = pt2->x;
+		result->low.x = pt1->x;
 	}
-	if (y1 > y2)
+	if (pt1->y > pt2->y)
 	{
-		result->high.y = y1;
-		result->low.y = y2;
+		result->high.y = pt1->y;
+		result->low.y = pt2->y;
 	}
 	else
 	{
-		result->high.y = y2;
-		result->low.y = y1;
+		result->high.y = pt2->y;
+		result->low.y = pt1->y;
 	}
-
-	return result;
-}
-
-
-/*		box_copy		-		copy a box
- */
-BOX *
-box_copy(BOX *box)
-{
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	memcpy((char *) result, (char *) box, sizeof(BOX));
-
-	return result;
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for BOXes.
  *		<, >, <=, >=, and == are based on box area.
  *---------------------------------------------------------*/
 
 /*		box_same		-		are two boxes identical?
  */
 Datum
 box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPeq(box1->high.x, box2->high.x) &&
-				   FPeq(box1->low.x, box2->low.x) &&
-				   FPeq(box1->high.y, box2->high.y) &&
-				   FPeq(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(point_eq_point(&box1->high, &box2->high) &&
+				   point_eq_point(&box1->low, &box2->low));
 }
 
 /*		box_overlap		-		does box1 overlap box2?
  */
 Datum
 box_overlap(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
@@ -630,38 +628,44 @@ box_overabove(PG_FUNCTION_ARGS)
 }
 
 /*		box_contained	-		is box1 contained by box2?
  */
 Datum
 box_contained(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPle(box1->high.x, box2->high.x) &&
-				   FPge(box1->low.x, box2->low.x) &&
-				   FPle(box1->high.y, box2->high.y) &&
-				   FPge(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(box_contain_box(box2, box1));
 }
 
 /*		box_contain		-		does box1 contain box2?
  */
 Datum
 box_contain(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPge(box1->high.x, box2->high.x) &&
-				   FPle(box1->low.x, box2->low.x) &&
-				   FPge(box1->high.y, box2->high.y) &&
-				   FPle(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(box_contain_box(box1, box2));
+}
+
+/*
+ * Check whether the box is in the box or on its border
+ */
+static bool
+box_contain_box(BOX *box1, BOX *box2)
+{
+	return FPge(box1->high.x, box2->high.x) &&
+		   FPle(box1->low.x, box2->low.x) &&
+		   FPge(box1->high.y, box2->high.y) &&
+		   FPle(box1->low.y, box2->low.y);
 }
 
 
 /*		box_positionop	-
  *				is box1 entirely {above,below} box2?
  *
  * box_below_eq and box_above_eq are obsolete versions that (probably
  * erroneously) accept the equal-boundaries case.  Since these are not
  * in sync with the box_left and box_right code, they are deprecated and
  * not supported in the PG 8.1 rtree operator class extension.
@@ -750,51 +754,51 @@ box_area(PG_FUNCTION_ARGS)
 
 
 /*		box_width		-		returns the width of the box
  *								  (horizontal magnitude).
  */
 Datum
 box_width(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.x - box->low.x);
+	PG_RETURN_FLOAT8(box_wd(box));
 }
 
 
 /*		box_height		-		returns the height of the box
  *								  (vertical magnitude).
  */
 Datum
 box_height(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.y - box->low.y);
+	PG_RETURN_FLOAT8(box_ht(box));
 }
 
 
 /*		box_distance	-		returns the distance between the
  *								  center points of two boxes.
  */
 Datum
 box_distance(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 	Point		a,
 				b;
 
 	box_cn(&a, box1);
 	box_cn(&b, box2);
 
-	PG_RETURN_FLOAT8(HYPOT(a.x - b.x, a.y - b.y));
+	PG_RETURN_FLOAT8(point_dt(&a, &b));
 }
 
 
 /*		box_center		-		returns the center point of the box.
  */
 Datum
 box_center(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *result = (Point *) palloc(sizeof(Point));
@@ -898,76 +902,77 @@ static bool
 line_decode(char *s, const char *str, LINE *line)
 {
 	/* s was already advanced over leading '{' */
 	line->A = single_decode(s, &s, "line", str);
 	if (*s++ != DELIM)
 		return false;
 	line->B = single_decode(s, &s, "line", str);
 	if (*s++ != DELIM)
 		return false;
 	line->C = single_decode(s, &s, "line", str);
-	if (*s++ != '}')
+	if (*s++ != RDELIM_L)
 		return false;
 	while (isspace((unsigned char) *s))
 		s++;
 	if (*s != '\0')
 		return false;
 	return true;
 }
 
 Datum
 line_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	LINE	   *line = (LINE *) palloc(sizeof(LINE));
 	LSEG		lseg;
 	bool		isopen;
 	char	   *s;
 
 	s = str;
 	while (isspace((unsigned char) *s))
 		s++;
-	if (*s == '{')
+	if (*s == LDELIM_L)
 	{
 		if (!line_decode(s + 1, str, line))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
 							"line", str)));
 		if (FPzero(line->A) && FPzero(line->B))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: A and B cannot both be zero")));
 	}
 	else
 	{
-		path_decode(s, true, 2, &(lseg.p[0]), &isopen, NULL, "line", str);
-		if (FPeq(lseg.p[0].x, lseg.p[1].x) && FPeq(lseg.p[0].y, lseg.p[1].y))
+		path_decode(s, true, 2, &lseg.p[0], &isopen, NULL, "line", str);
+		if (point_eq_point(&lseg.p[0], &lseg.p[1]))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: must be two distinct points")));
-		line_construct_pts(line, &lseg.p[0], &lseg.p[1]);
+		line_construct(line, &lseg.p[0], lseg_sl(&lseg));
 	}
 
 	PG_RETURN_LINE_P(line);
 }
 
 
 Datum
 line_out(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	char	   *astr = float8out_internal(line->A);
 	char	   *bstr = float8out_internal(line->B);
 	char	   *cstr = float8out_internal(line->C);
 
-	PG_RETURN_CSTRING(psprintf("{%s,%s,%s}", astr, bstr, cstr));
+	PG_RETURN_CSTRING(psprintf("%c%s%c%s%c%s%c", LDELIM_L, astr, DELIM, bstr,
+							   DELIM, cstr, RDELIM_L));
 }
 
 /*
  *		line_recv			- converts external binary format to line
  */
 Datum
 line_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LINE	   *line;
@@ -996,128 +1001,78 @@ line_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, line->C);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*----------------------------------------------------------
  *	Conversion routines from one line formula to internal.
  *		Internal form:	Ax+By+C=0
  *---------------------------------------------------------*/
 
-/* line_construct_pm()
- * point-slope
+/*
+ * Fill already-allocated LINE struct from the point and the slope
  */
-static LINE *
-line_construct_pm(Point *pt, double m)
+static inline void
+line_construct(LINE *result, Point *pt, float8 m)
 {
-	LINE	   *result = (LINE *) palloc(sizeof(LINE));
-
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
 		result->A = -1;
 		result->B = 0;
 		result->C = pt->x;
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
 		result->C = pt->y - m * pt->x;
 	}
-
-	return result;
-}
-
-/*
- * Fill already-allocated LINE struct from two points on the line
- */
-static void
-line_construct_pts(LINE *line, Point *pt1, Point *pt2)
-{
-	if (FPeq(pt1->x, pt2->x))
-	{							/* vertical */
-		/* use "x = C" */
-		line->A = -1;
-		line->B = 0;
-		line->C = pt1->x;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is vertical\n");
-#endif
-	}
-	else if (FPeq(pt1->y, pt2->y))
-	{							/* horizontal */
-		/* use "y = C" */
-		line->A = 0;
-		line->B = -1;
-		line->C = pt1->y;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is horizontal\n");
-#endif
-	}
-	else
-	{
-		/* use "mx - y + yinter = 0" */
-		line->A = (pt2->y - pt1->y) / (pt2->x - pt1->x);
-		line->B = -1.0;
-		line->C = pt1->y - line->A * pt1->x;
-		/* on some platforms, the preceding expression tends to produce -0 */
-		if (line->C == 0.0)
-			line->C = 0.0;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is neither vertical nor horizontal (diffs x=%.*g, y=%.*g\n",
-			   DBL_DIG, (pt2->x - pt1->x), DBL_DIG, (pt2->y - pt1->y));
-#endif
-	}
 }
 
 /* line_construct_pp()
  * two points
  */
 Datum
 line_construct_pp(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 	LINE	   *result = (LINE *) palloc(sizeof(LINE));
 
-	line_construct_pts(result, pt1, pt2);
+	line_construct(result, pt1, point_sl(pt1, pt2));
+
 	PG_RETURN_LINE_P(result);
 }
 
 
 /*----------------------------------------------------------
  *	Relative position routines.
  *---------------------------------------------------------*/
 
 Datum
 line_intersect(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(!DatumGetBool(DirectFunctionCall2(line_parallel,
-													 LinePGetDatum(l1),
-													 LinePGetDatum(l2))));
+	PG_RETURN_BOOL(line_interpt_line(NULL, l1, l2));
 }
 
 Datum
 line_parallel(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
-	if (FPzero(l1->B))
-		PG_RETURN_BOOL(FPzero(l2->B));
-
-	PG_RETURN_BOOL(FPeq(l2->A, l1->A * (l2->B / l1->B)));
+	PG_RETURN_BOOL(!line_interpt_line(NULL, l1, l2));
 }
 
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
@@ -1162,105 +1117,114 @@ line_eq(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(FPeq(l1->A, k * l2->A) &&
 				   FPeq(l1->B, k * l2->B) &&
 				   FPeq(l1->C, k * l2->C));
 }
 
 
 /*----------------------------------------------------------
  *	Line arithmetic routines.
  *---------------------------------------------------------*/
 
+/*
+ * Return inverse slope of the line
+ */
+static inline float8
+line_invsl(LINE *line)
+{
+	if (FPzero(line->A))
+		return DBL_MAX;
+	if (FPzero(line->B))
+		return 0.0;
+	return line->B / line->A;
+}
+
+
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
-	Point	   *tmp;
+	Point		tmp;
 
-	if (!DatumGetBool(DirectFunctionCall2(line_parallel,
-										  LinePGetDatum(l1),
-										  LinePGetDatum(l2))))
+	if (line_interpt_line(NULL, l1, l2))	/* intersecting? */
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
 		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
-	tmp = point_construct(0.0, l1->C);
-	result = dist_pl_internal(tmp, l2);
+	point_construct(&tmp, 0.0, l1->C);
+	result = line_closept_point(NULL, l2, &tmp);
 	PG_RETURN_FLOAT8(result);
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
-	result = line_interpt_internal(l1, l2);
+	result = (Point *) palloc(sizeof(Point));
 
-	if (result == NULL)
+	if (!line_interpt_line(result, l1, l2))
 		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
 
 /*
  * Internal version of line_interpt
  *
- * returns a NULL pointer if no intersection point
+ * This returns true if two lines intersect (they do, if they are not
+ * parallel), false if they do not.  This also sets the intersection point
+ * to *result, if it is not NULL.
+ *
+ * NOTE: If the lines are identical then we will find they are parallel
+ * and report "no intersection".  This is a little weird, but since
+ * there's no *unique* intersection, maybe it's appropriate behavior.
  */
-static Point *
-line_interpt_internal(LINE *l1, LINE *l2)
+static bool
+line_interpt_line(Point *result, LINE *l1, LINE *l2)
 {
-	Point	   *result;
 	double		x,
 				y;
 
-	/*
-	 * NOTE: if the lines are identical then we will find they are parallel
-	 * and report "no intersection".  This is a little weird, but since
-	 * there's no *unique* intersection, maybe it's appropriate behavior.
-	 */
-	if (DatumGetBool(DirectFunctionCall2(line_parallel,
-										 LinePGetDatum(l1),
-										 LinePGetDatum(l2))))
-		return NULL;
-
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
+		if (FPzero(l2->B))		/* l2 vertical? */
+			return false;
+
 		x = l1->C;
 		y = (l2->A * x + l2->C);
 	}
 	else if (FPzero(l2->B))		/* l2 vertical? */
 	{
 		x = l2->C;
 		y = (l1->A * x + l1->C);
 	}
 	else
 	{
+		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+			return false;
+
 		x = (l1->C - l2->C) / (l2->A - l1->A);
 		y = (l1->A * x + l1->C);
 	}
-	result = point_construct(x, y);
 
-#ifdef GEODEBUG
-	printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
-		   DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
-	printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
-#endif
+	if (result != NULL)
+		point_construct(result, x, y);
 
-	return result;
+	return true;
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D paths (sequences of line segments, also
  **				called `polylines').
  **
  **				This is not a general package for geometric paths,
  **				which of course include polygons; the emphasis here
@@ -1555,22 +1519,21 @@ path_inter(PG_FUNCTION_ARGS)
 {
 	PATH	   *p1 = PG_GETARG_PATH_P(0);
 	PATH	   *p2 = PG_GETARG_PATH_P(1);
 	BOX			b1,
 				b2;
 	int			i,
 				j;
 	LSEG		seg1,
 				seg2;
 
-	if (p1->npts <= 0 || p2->npts <= 0)
-		PG_RETURN_BOOL(false);
+	Assert(p1->npts > 0 && p2->npts > 0);
 
 	b1.high.x = b1.low.x = p1->p[0].x;
 	b1.high.y = b1.low.y = p1->p[0].y;
 	for (i = 1; i < p1->npts; i++)
 	{
 		b1.high.x = Max(p1->p[i].x, b1.high.x);
 		b1.high.y = Max(p1->p[i].y, b1.high.y);
 		b1.low.x = Min(p1->p[i].x, b1.low.x);
 		b1.low.y = Min(p1->p[i].y, b1.low.y);
 	}
@@ -1608,21 +1571,21 @@ path_inter(PG_FUNCTION_ARGS)
 				jprev = j - 1;
 			else
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
-			if (lseg_intersect_internal(&seg1, &seg2))
+			if (lseg_interpt_lseg(NULL, &seg1, &seg2))
 				PG_RETURN_BOOL(true);
 		}
 	}
 
 	/* if we dropped through, no two segs intersected */
 	PG_RETURN_BOOL(false);
 }
 
 /* path_distance()
  * This essentially does a cartesian product of the lsegs in the
@@ -1663,23 +1626,21 @@ path_distance(PG_FUNCTION_ARGS)
 			else
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
-			tmp = DatumGetFloat8(DirectFunctionCall2(lseg_distance,
-													 LsegPGetDatum(&seg1),
-													 LsegPGetDatum(&seg2)));
+			tmp = lseg_closept_lseg(NULL, &seg1, &seg2);
 			if (!have_min || tmp < min)
 			{
 				min = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	if (!have_min)
 		PG_RETURN_NULL();
@@ -1773,44 +1734,28 @@ point_send(PG_FUNCTION_ARGS)
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	StringInfoData buf;
 
 	pq_begintypsend(&buf);
 	pq_sendfloat8(&buf, pt->x);
 	pq_sendfloat8(&buf, pt->y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
-static Point *
-point_construct(double x, double y)
+/*
+ * Initialize a point
+ */
+static inline void
+point_construct(Point *result, float8 x, float8 y)
 {
-	Point	   *result = (Point *) palloc(sizeof(Point));
-
 	result->x = x;
 	result->y = y;
-	return result;
-}
-
-
-static Point *
-point_copy(Point *pt)
-{
-	Point	   *result;
-
-	if (!PointerIsValid(pt))
-		return NULL;
-
-	result = (Point *) palloc(sizeof(Point));
-
-	result->x = pt->x;
-	result->y = pt->y;
-	return result;
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for Points.
  *		Since we do have a sense of coordinates being
  *		"equal" to a given accuracy (point_vert, point_horiz),
  *		the other ops must preserve that sense.  This means
  *		that results may, strictly speaking, be a lie (unless
  *		EPSILON = 0.0).
@@ -1869,71 +1814,97 @@ point_horiz(PG_FUNCTION_ARGS)
 
 	PG_RETURN_BOOL(FPeq(pt1->y, pt2->y));
 }
 
 Datum
 point_eq(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y));
+	PG_RETURN_BOOL(point_eq_point(pt1, pt2));
 }
 
 Datum
 point_ne(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPne(pt1->x, pt2->x) || FPne(pt1->y, pt2->y));
+	PG_RETURN_BOOL(!point_eq_point(pt1, pt2));
 }
 
+static inline bool
+point_eq_point(Point *pt1, Point *pt2)
+{
+	return FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y);
+}
+
+
 /*----------------------------------------------------------
  *	"Arithmetic" operators on points.
  *---------------------------------------------------------*/
 
 Datum
 point_distance(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_FLOAT8(HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
+	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
-double
+static inline float8
 point_dt(Point *pt1, Point *pt2)
 {
-#ifdef GEODEBUG
-	printf("point_dt- segment (%f,%f),(%f,%f) length is %f\n",
-		   pt1->x, pt1->y, pt2->x, pt2->y, HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
-#endif
 	return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
 }
 
 Datum
 point_slope(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_sl(pt1, pt2));
 }
 
 
-double
+/*
+ * Return slope of two points
+ *
+ * Note that this function returns DBL_MAX when the points are the same.
+ */
+static inline float8
 point_sl(Point *pt1, Point *pt2)
 {
-	return (FPeq(pt1->x, pt2->x)
-			? (double) DBL_MAX
-			: (pt1->y - pt2->y) / (pt1->x - pt2->x));
+	if (FPeq(pt1->x, pt2->x))
+		return DBL_MAX;
+	if (FPeq(pt1->y, pt2->y))
+		return 0.0;
+	return (pt1->y - pt2->y) / (pt1->x - pt2->x);
+}
+
+
+/*
+ * Return inverse slope of two points
+ *
+ * Note that this function returns 0.0 when the points are the same.
+ */
+static inline float8
+point_invsl(Point *pt1, Point *pt2)
+{
+	if (FPeq(pt1->x, pt2->x))
+		return 0.0;
+	if (FPeq(pt1->y, pt2->y))
+		return DBL_MAX;
+	return (pt1->x - pt2->x) / (pt2->y - pt1->y);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D line segments.
  **
  ***********************************************************************/
 
 /*----------------------------------------------------------
@@ -1945,31 +1916,31 @@ point_sl(Point *pt1, Point *pt2)
  *		(old form)		"(x1, y1, x2, y2)"
  *---------------------------------------------------------*/
 
 Datum
 lseg_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	LSEG	   *lseg = (LSEG *) palloc(sizeof(LSEG));
 	bool		isopen;
 
-	path_decode(str, true, 2, &(lseg->p[0]), &isopen, NULL, "lseg", str);
+	path_decode(str, true, 2, &lseg->p[0], &isopen, NULL, "lseg", str);
 	PG_RETURN_LSEG_P(lseg);
 }
 
 
 Datum
 lseg_out(PG_FUNCTION_ARGS)
 {
 	LSEG	   *ls = PG_GETARG_LSEG_P(0);
 
-	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, (Point *) &(ls->p[0])));
+	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, &ls->p[0]));
 }
 
 /*
  *		lseg_recv			- converts external binary format to lseg
  */
 Datum
 lseg_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LSEG	   *lseg;
@@ -2005,38 +1976,56 @@ lseg_send(PG_FUNCTION_ARGS)
 /* lseg_construct -
  *		form a LSEG from two Points.
  */
 Datum
 lseg_construct(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 	LSEG	   *result = (LSEG *) palloc(sizeof(LSEG));
 
-	result->p[0].x = pt1->x;
-	result->p[0].y = pt1->y;
-	result->p[1].x = pt2->x;
-	result->p[1].y = pt2->y;
+	statlseg_construct(result, pt1, pt2);
 
 	PG_RETURN_LSEG_P(result);
 }
 
 /* like lseg_construct, but assume space already allocated */
-static void
+static inline void
 statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2)
 {
 	lseg->p[0].x = pt1->x;
 	lseg->p[0].y = pt1->y;
 	lseg->p[1].x = pt2->x;
 	lseg->p[1].y = pt2->y;
 }
 
+
+/*
+ * Return slope of the line segment
+ */
+static inline float8
+lseg_sl(LSEG *lseg)
+{
+	return point_sl(&lseg->p[0], &lseg->p[1]);
+}
+
+
+/*
+ * Return inverse slope of the line segment
+ */
+static inline float8
+lseg_invsl(LSEG *lseg)
+{
+	return point_invsl(&lseg->p[0], &lseg->p[1]);
+}
+
+
 Datum
 lseg_length(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 
 	PG_RETURN_FLOAT8(point_dt(&lseg->p[0], &lseg->p[1]));
 }
 
 /*----------------------------------------------------------
  *	Relative position routines.
@@ -2045,79 +2034,43 @@ lseg_length(PG_FUNCTION_ARGS)
 /*
  **  find intersection of the two lines, and see if it falls on
  **  both segments.
  */
 Datum
 lseg_intersect(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(lseg_intersect_internal(l1, l2));
+	PG_RETURN_BOOL(lseg_interpt_lseg(NULL, l1, l2));
 }
 
-static bool
-lseg_intersect_internal(LSEG *l1, LSEG *l2)
-{
-	LINE		ln;
-	Point	   *interpt;
-	bool		retval;
-
-	line_construct_pts(&ln, &l2->p[0], &l2->p[1]);
-	interpt = interpt_sl(l1, &ln);
-
-	if (interpt != NULL && on_ps_internal(interpt, l2))
-		retval = true;			/* interpt on l1 and l2 */
-	else
-		retval = false;
-	return retval;
-}
 
 Datum
 lseg_parallel(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPeq(point_sl(&l1->p[0], &l1->p[1]),
-						point_sl(&l2->p[0], &l2->p[1])));
+	PG_RETURN_BOOL(FPeq(lseg_sl(l1), lseg_sl(l2)));
 }
 
-/* lseg_perp()
+/*
  * Determine if two line segments are perpendicular.
- *
- * This code did not get the correct answer for
- *	'((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg
- * So, modified it to check explicitly for slope of vertical line
- *	returned by point_sl() and the results seem better.
- * - thomas 1998-01-31
  */
 Datum
 lseg_perp(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	double		m1,
-				m2;
 
-	m1 = point_sl(&(l1->p[0]), &(l1->p[1]));
-	m2 = point_sl(&(l2->p[0]), &(l2->p[1]));
-
-#ifdef GEODEBUG
-	printf("lseg_perp- slopes are %g and %g\n", m1, m2);
-#endif
-	if (FPzero(m1))
-		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
-	else if (FPzero(m2))
-		PG_RETURN_BOOL(FPeq(m1, DBL_MAX));
-
-	PG_RETURN_BOOL(FPeq(m1 / m2, -1.0));
+	PG_RETURN_BOOL(FPeq(lseg_sl(l1), lseg_invsl(l2)));
 }
 
 Datum
 lseg_vertical(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 
 	PG_RETURN_BOOL(FPeq(lseg->p[0].x, lseg->p[1].x));
 }
 
@@ -2129,36 +2082,32 @@ lseg_horizontal(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(FPeq(lseg->p[0].y, lseg->p[1].y));
 }
 
 
 Datum
 lseg_eq(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPeq(l1->p[0].x, l2->p[0].x) &&
-				   FPeq(l1->p[0].y, l2->p[0].y) &&
-				   FPeq(l1->p[1].x, l2->p[1].x) &&
-				   FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(point_eq_point(&l1->p[0], &l2->p[0]) &&
+				   point_eq_point(&l1->p[1], &l2->p[1]));
 }
 
 Datum
 lseg_ne(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(!FPeq(l1->p[0].x, l2->p[0].x) ||
-				   !FPeq(l1->p[0].y, l2->p[0].y) ||
-				   !FPeq(l1->p[1].x, l2->p[1].x) ||
-				   !FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(!point_eq_point(&l1->p[0], &l2->p[0]) ||
+				   !point_eq_point(&l1->p[1], &l2->p[1]));
 }
 
 Datum
 lseg_lt(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_BOOL(FPlt(point_dt(&l1->p[0], &l1->p[1]),
 						point_dt(&l2->p[0], &l2->p[1])));
@@ -2203,126 +2152,81 @@ lseg_ge(PG_FUNCTION_ARGS)
  *		If two segments don't intersect, then the closest
  *		point will be from one of the endpoints to the other
  *		segment.
  */
 Datum
 lseg_distance(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_FLOAT8(lseg_dt(l1, l2));
-}
-
-/* lseg_dt()
- * Distance between two line segments.
- * Must check both sets of endpoints to ensure minimum distance is found.
- * - thomas 1998-02-01
- */
-static double
-lseg_dt(LSEG *l1, LSEG *l2)
-{
-	double		result,
-				d;
-
-	if (lseg_intersect_internal(l1, l2))
-		return 0.0;
-
-	d = dist_ps_internal(&l1->p[0], l2);
-	result = d;
-	d = dist_ps_internal(&l1->p[1], l2);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[0], l1);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[1], l1);
-	result = Min(result, d);
-
-	return result;
+	PG_RETURN_FLOAT8(lseg_closept_lseg(NULL, l1, l2));
 }
 
 
 Datum
 lseg_center(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
 	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
 
 	PG_RETURN_POINT_P(result);
 }
 
-static Point *
-lseg_interpt_internal(LSEG *l1, LSEG *l2)
+
+/*
+ *		Find the intersection point of two segments (if any).
+ *
+ * This returns true if two line segments intersect, false if they do not.
+ * This also sets the intersection point to *result, if it is not NULL.
+ * This function is almost perfectly symmetric, even though it doesn't look
+ * like it.  See lseg_interpt_line() for the other half of it.
+ */
+static bool
+lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2)
 {
-	Point	   *result;
-	LINE		tmp1,
-				tmp2;
+	Point		interpt;
+	LINE		tmp;
+
+	line_construct(&tmp, &l2->p[0], lseg_sl(l2));
+	if (!lseg_interpt_line(&interpt, l1, &tmp))
+		return false;
 
 	/*
-	 * Find the intersection of the appropriate lines, if any.
+	 * If the line intersection point isn't within l2, there is no valid
+	 * segment intersection point at all.
 	 */
-	line_construct_pts(&tmp1, &l1->p[0], &l1->p[1]);
-	line_construct_pts(&tmp2, &l2->p[0], &l2->p[1]);
-	result = line_interpt_internal(&tmp1, &tmp2);
-	if (!PointerIsValid(result))
-		return NULL;
+	if (!lseg_contain_point(l2, &interpt))
+		return false;
 
-	/*
-	 * If the line intersection point isn't within l1 (or equivalently l2),
-	 * there is no valid segment intersection point at all.
-	 */
-	if (!on_ps_internal(result, l1) ||
-		!on_ps_internal(result, l2))
-	{
-		pfree(result);
-		return NULL;
-	}
+	if (result != NULL)
+		*result = interpt;
 
-	/*
-	 * If there is an intersection, then check explicitly for matching
-	 * endpoints since there may be rounding effects with annoying lsb
-	 * residue. - tgl 1997-07-09
-	 */
-	if ((FPeq(l1->p[0].x, l2->p[0].x) && FPeq(l1->p[0].y, l2->p[0].y)) ||
-		(FPeq(l1->p[0].x, l2->p[1].x) && FPeq(l1->p[0].y, l2->p[1].y)))
-	{
-		result->x = l1->p[0].x;
-		result->y = l1->p[0].y;
-	}
-	else if ((FPeq(l1->p[1].x, l2->p[0].x) && FPeq(l1->p[1].y, l2->p[0].y)) ||
-			 (FPeq(l1->p[1].x, l2->p[1].x) && FPeq(l1->p[1].y, l2->p[1].y)))
-	{
-		result->x = l1->p[1].x;
-		result->y = l1->p[1].y;
-	}
-
-	return result;
+	return true;
 }
 
-/* lseg_interpt -
- *		Find the intersection point of two segments (if any).
- */
 Datum
 lseg_interpt(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
-	result = lseg_interpt_internal(l1, l2);
-	if (!PointerIsValid(result))
-		PG_RETURN_NULL();
+	result = (Point *) palloc(sizeof(Point));
 
+	if (!lseg_interpt_lseg(result, l1, l2))
+		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
 
 /***********************************************************************
  **
  **		Routines for position comparisons of differently-typed
  **				2D objects.
  **
  ***********************************************************************/
 
@@ -2333,215 +2237,128 @@ lseg_interpt(PG_FUNCTION_ARGS)
 
 /*
  * Distance from a point to a line
  */
 Datum
 dist_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_FLOAT8(dist_pl_internal(pt, line));
+	PG_RETURN_FLOAT8(line_closept_point(NULL, line, pt));
 }
 
-static double
-dist_pl_internal(Point *pt, LINE *line)
-{
-	return fabs((line->A * pt->x + line->B * pt->y + line->C) /
-				HYPOT(line->A, line->B));
-}
 
 /*
  * Distance from a point to a lseg
  */
 Datum
 dist_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_FLOAT8(dist_ps_internal(pt, lseg));
-}
-
-static double
-dist_ps_internal(Point *pt, LSEG *lseg)
-{
-	double		m;				/* slope of perp. */
-	LINE	   *ln;
-	double		result,
-				tmpdist;
-	Point	   *ip;
-
-	/*
-	 * Construct a line perpendicular to the input segment and through the
-	 * input point
-	 */
-	if (lseg->p[1].x == lseg->p[0].x)
-		m = 0;
-	else if (lseg->p[1].y == lseg->p[0].y)
-		m = (double) DBL_MAX;	/* slope is infinite */
-	else
-		m = (lseg->p[0].x - lseg->p[1].x) / (lseg->p[1].y - lseg->p[0].y);
-	ln = line_construct_pm(pt, m);
-
-#ifdef GEODEBUG
-	printf("dist_ps- line is A=%g B=%g C=%g from (point) slope (%f,%f) %g\n",
-		   ln->A, ln->B, ln->C, pt->x, pt->y, m);
-#endif
-
-	/*
-	 * Calculate distance to the line segment or to the nearest endpoint of
-	 * the segment.
-	 */
-
-	/* intersection is on the line segment? */
-	if ((ip = interpt_sl(lseg, ln)) != NULL)
-	{
-		/* yes, so use distance to the intersection point */
-		result = point_dt(pt, ip);
-#ifdef GEODEBUG
-		printf("dist_ps- distance is %f to intersection point is (%f,%f)\n",
-			   result, ip->x, ip->y);
-#endif
-	}
-	else
-	{
-		/* no, so use distance to the nearer endpoint */
-		result = point_dt(pt, &lseg->p[0]);
-		tmpdist = point_dt(pt, &lseg->p[1]);
-		if (tmpdist < result)
-			result = tmpdist;
-	}
-
-	return result;
+	PG_RETURN_FLOAT8(lseg_closept_point(NULL, lseg, pt));
 }
 
 /*
  * Distance from a point to a path
  */
 Datum
 dist_ppath(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	PATH	   *path = PG_GETARG_PATH_P(1);
 	float8		result = 0.0;	/* keep compiler quiet */
 	bool		have_min = false;
 	float8		tmp;
 	int			i;
 	LSEG		lseg;
 
-	switch (path->npts)
+	Assert(path->npts > 0);
+
+	/*
+	 * The distance from a point to a path is the smallest distance
+	 * from the point to any of its constituent segments.
+	 */
+	for (i = 0; i < path->npts; i++)
 	{
-		case 0:
-			/* no points in path? then result is undefined... */
-			PG_RETURN_NULL();
-		case 1:
-			/* one point in path? then get distance between two points... */
-			result = point_dt(pt, &path->p[0]);
-			break;
-		default:
-			/* make sure the path makes sense... */
-			Assert(path->npts > 1);
+		int			iprev;
 
-			/*
-			 * the distance from a point to a path is the smallest distance
-			 * from the point to any of its constituent segments.
-			 */
-			for (i = 0; i < path->npts; i++)
-			{
-				int			iprev;
+		if (i > 0)
+			iprev = i - 1;
+		else
+		{
+			if (!path->closed)
+				continue;
+			iprev = path->npts - 1; /* Include the closure segment */
+		}
 
-				if (i > 0)
-					iprev = i - 1;
-				else
-				{
-					if (!path->closed)
-						continue;
-					iprev = path->npts - 1; /* include the closure segment */
-				}
-
-				statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
-				tmp = dist_ps_internal(pt, &lseg);
-				if (!have_min || tmp < result)
-				{
-					result = tmp;
-					have_min = true;
-				}
-			}
-			break;
+		statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
+		tmp = lseg_closept_point(NULL, &lseg, pt);
+		if (!have_min || tmp < result)
+		{
+			result = tmp;
+			have_min = true;
+		}
 	}
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a point to a box
  */
 Datum
 dist_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
-	float8		result;
-	Point	   *near;
 
-	near = DatumGetPointP(DirectFunctionCall2(close_pb,
-											  PointPGetDatum(pt),
-											  BoxPGetDatum(box)));
-	result = point_dt(near, pt);
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(box_closept_point(NULL, box, pt));
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	float8		result,
 				d2;
 
-	if (has_interpt_sl(lseg, line))
+	if (lseg_interpt_line(NULL, lseg, line))
 		result = 0.0;
 	else
 	{
-		result = dist_pl_internal(&lseg->p[0], line);
-		d2 = dist_pl_internal(&lseg->p[1], line);
+		result = line_closept_point(NULL, line, &lseg->p[0]);
+		d2 = line_closept_point(NULL, line, &lseg->p[1]);
 		/* XXX shouldn't we take the min not max? */
 		if (d2 > result)
 			result = d2;
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
-	Point	   *tmp;
-	Datum		result;
 
-	tmp = DatumGetPointP(DirectFunctionCall2(close_sb,
-											 LsegPGetDatum(lseg),
-											 BoxPGetDatum(box)));
-	result = DirectFunctionCall2(dist_pb,
-								 PointPGetDatum(tmp),
-								 BoxPGetDatum(box));
-
-	PG_RETURN_DATUM(result);
+	PG_RETURN_FLOAT8(box_closept_lseg(NULL, box, lseg));
 }
 
 /*
  * Distance from a line to a box
  */
 Datum
 dist_lb(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -2577,37 +2394,31 @@ dist_cpoly(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a point to a polygon
  */
 Datum
 dist_ppoly(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	POLYGON    *poly = PG_GETARG_POLYGON_P(1);
-	float8		result;
 
-	result = dist_ppoly_internal(point, poly);
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(dist_ppoly_internal(point, poly));
 }
 
 Datum
 dist_polyp(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	float8		result;
 
-	result = dist_ppoly_internal(point, poly);
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(dist_ppoly_internal(point, poly));
 }
 
 static double
 dist_ppoly_internal(Point *pt, POLYGON *poly)
 {
 	float8		result;
 	float8		d;
 	int			i;
 	LSEG		seg;
 
@@ -2617,498 +2428,481 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
 		printf("dist_ppoly_internal- point inside of polygon\n");
 #endif
 		return 0.0;
 	}
 
 	/* initialize distance with segment between first and last points */
 	seg.p[0].x = poly->p[0].x;
 	seg.p[0].y = poly->p[0].y;
 	seg.p[1].x = poly->p[poly->npts - 1].x;
 	seg.p[1].y = poly->p[poly->npts - 1].y;
-	result = dist_ps_internal(pt, &seg);
+	result = lseg_closept_point(NULL, &seg, pt);
 #ifdef GEODEBUG
 	printf("dist_ppoly_internal- segment 0/n distance is %f\n", result);
 #endif
 
 	/* check distances for other segments */
-	for (i = 0; (i < poly->npts - 1); i++)
+	for (i = 0; i < poly->npts - 1; i++)
 	{
 		seg.p[0].x = poly->p[i].x;
 		seg.p[0].y = poly->p[i].y;
 		seg.p[1].x = poly->p[i + 1].x;
 		seg.p[1].y = poly->p[i + 1].y;
-		d = dist_ps_internal(pt, &seg);
+		d = lseg_closept_point(NULL, &seg, pt);
 #ifdef GEODEBUG
 		printf("dist_ppoly_internal- segment %d distance is %f\n", (i + 1), d);
 #endif
 		if (d < result)
 			result = d;
 	}
 
 	return result;
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
  *				Intersection point of objects.
  *				We choose to ignore the "point" of intersection between
  *				  lines and boxes, since there are typically two.
  *-------------------------------------------------------------------*/
 
-/* Get intersection point of lseg and line; returns NULL if no intersection */
-static Point *
-interpt_sl(LSEG *lseg, LINE *line)
-{
-	LINE		tmp;
-	Point	   *p;
-
-	line_construct_pts(&tmp, &lseg->p[0], &lseg->p[1]);
-	p = line_interpt_internal(&tmp, line);
-#ifdef GEODEBUG
-	printf("interpt_sl- segment is (%.*g %.*g) (%.*g %.*g)\n",
-		   DBL_DIG, lseg->p[0].x, DBL_DIG, lseg->p[0].y, DBL_DIG, lseg->p[1].x, DBL_DIG, lseg->p[1].y);
-	printf("interpt_sl- segment becomes line A=%.*g B=%.*g C=%.*g\n",
-		   DBL_DIG, tmp.A, DBL_DIG, tmp.B, DBL_DIG, tmp.C);
-#endif
-	if (PointerIsValid(p))
-	{
-#ifdef GEODEBUG
-		printf("interpt_sl- intersection point is (%.*g %.*g)\n", DBL_DIG, p->x, DBL_DIG, p->y);
-#endif
-		if (on_ps_internal(p, lseg))
-		{
-#ifdef GEODEBUG
-			printf("interpt_sl- intersection point is on segment\n");
-#endif
-		}
-		else
-			p = NULL;
-	}
-
-	return p;
-}
-
-/* variant: just indicate if intersection point exists */
+/*
+ * Check if the line segment intersects with the line
+ *
+ * This returns true if line segment intersects with line, false if they
+ * do not.  This also sets the intersection point to *result, if it is not
+ * NULL.
+ */
 static bool
-has_interpt_sl(LSEG *lseg, LINE *line)
+lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
 {
-	Point	   *tmp;
+	Point		interpt;
+	LINE		tmp;
 
-	tmp = interpt_sl(lseg, line);
-	if (tmp)
+	/*
+	 * First, we promote the line segment to a line, because we know how
+	 * to find the intersection point of two lines.  If they don't have
+	 * an intersection point, we are done.
+	 */
+	line_construct(&tmp, &lseg->p[0], lseg_sl(lseg));
+	if (!line_interpt_line(&interpt, &tmp, line))
+		return false;
+
+	/*
+	 * Then, we check whether the intersection point is actually on the line
+	 * segment.
+	 */
+	if (!lseg_contain_point(lseg, &interpt))
+		return false;
+
+	if (result == NULL)
 		return true;
-	return false;
+
+	/*
+	 * If there is an intersection, then check explicitly for matching
+	 * endpoints since there may be rounding effects with annoying LSB
+	 * residue.
+	 */
+	if (point_eq_point(&lseg->p[0], &interpt))
+		*result = lseg->p[0];
+	else if (point_eq_point(&lseg->p[1], &interpt))
+		*result = lseg->p[1];
+	else
+		*result = interpt;
+
+	return true;
 }
 
 /*---------------------------------------------------------------------
  *		close_
  *				Point of closest proximity between objects.
  *-------------------------------------------------------------------*/
 
-/* close_pl -
+/*
  *		The intersection point of a perpendicular of the line
  *		through the point.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
+static float8
+line_closept_point(Point *result, LINE *line, Point *point)
+{
+	bool		retval;
+	Point       closept;
+	LINE		tmp;
+
+	/* We drop a perpendicular to find the intersection point. */
+	line_construct(&tmp, point, line_invsl(line));
+	retval = line_interpt_line(&closept, line, &tmp);
+	Assert(retval);		/* XXX: We need something better. */
+
+	if (result != NULL)
+		*result = closept;
+
+	/* Then we calculate the distance between the points. */
+	return point_dt(&closept, point);
+}
+
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
-	LINE	   *tmp;
-	double		invm;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	if (FPzero(line->B))		/* vertical? */
-	{
-		result->x = line->C;
-		result->y = pt->y;
-		PG_RETURN_POINT_P(result);
-	}
-	if (FPzero(line->A))		/* horizontal? */
-	{
-		result->x = pt->x;
-		result->y = line->C;
-		PG_RETURN_POINT_P(result);
-	}
-	/* drop a perpendicular and find the intersection point */
+	line_closept_point(result, line, pt);
 
-	/* invert and flip the sign on the slope to get a perpendicular */
-	invm = line->B / line->A;
-	tmp = line_construct_pm(pt, invm);
-	result = line_interpt_internal(tmp, line);
-	Assert(result != NULL);
 	PG_RETURN_POINT_P(result);
 }
 
 
-/* close_ps()
+/*
  * Closest point on line segment to specified point.
- * Take the closest endpoint if the point is left, right,
- *	above, or below the segment, otherwise find the intersection
- *	point of the segment and its perpendicular through the point.
  *
- * Some tricky code here, relying on boolean expressions
- *	evaluating to only zero or one to use as an array index.
- *		bug fixes by gthaker@atl.lmco.com; May 1, 1998
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
+static float8
+lseg_closept_point(Point *result, LSEG *lseg, Point *pt)
+{
+	Point		closept;
+	LINE		tmp;
+
+	/*
+	 * To find the closest point, we draw a perpendicular line from the point
+	 * to the line segment.
+	 */
+	line_construct(&tmp, pt, point_invsl(&lseg->p[0], &lseg->p[1]));
+	lseg_closept_line(&closept, lseg, &tmp);
+
+	if (result != NULL)
+		*result = closept;
+
+	return point_dt(&closept, pt);
+}
+
 Datum
 close_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
-	LINE	   *tmp;
-	double		invm;
-	int			xh,
-				yh;
+	Point	   *result;
 
-#ifdef GEODEBUG
-	printf("close_sp:pt->x %f pt->y %f\nlseg(0).x %f lseg(0).y %f  lseg(1).x %f lseg(1).y %f\n",
-		   pt->x, pt->y, lseg->p[0].x, lseg->p[0].y,
-		   lseg->p[1].x, lseg->p[1].y);
-#endif
+	result = (Point *) palloc(sizeof(Point));
 
-	/* xh (or yh) is the index of upper x( or y) end point of lseg */
-	/* !xh (or !yh) is the index of lower x( or y) end point of lseg */
-	xh = lseg->p[0].x < lseg->p[1].x;
-	yh = lseg->p[0].y < lseg->p[1].y;
-
-	if (FPeq(lseg->p[0].x, lseg->p[1].x))	/* vertical? */
-	{
-#ifdef GEODEBUG
-		printf("close_ps- segment is vertical\n");
-#endif
-		/* first check if point is below or above the entire lseg. */
-		if (pt->y < lseg->p[!yh].y)
-			result = point_copy(&lseg->p[!yh]); /* below the lseg */
-		else if (pt->y > lseg->p[yh].y)
-			result = point_copy(&lseg->p[yh]);	/* above the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
-
-		/* point lines along (to left or right) of the vertical lseg. */
-
-		result = (Point *) palloc(sizeof(Point));
-		result->x = lseg->p[0].x;
-		result->y = pt->y;
-		PG_RETURN_POINT_P(result);
-	}
-	else if (FPeq(lseg->p[0].y, lseg->p[1].y))	/* horizontal? */
-	{
-#ifdef GEODEBUG
-		printf("close_ps- segment is horizontal\n");
-#endif
-		/* first check if point is left or right of the entire lseg. */
-		if (pt->x < lseg->p[!xh].x)
-			result = point_copy(&lseg->p[!xh]); /* left of the lseg */
-		else if (pt->x > lseg->p[xh].x)
-			result = point_copy(&lseg->p[xh]);	/* right of the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
-
-		/* point lines along (at top or below) the horiz. lseg. */
-		result = (Point *) palloc(sizeof(Point));
-		result->x = pt->x;
-		result->y = lseg->p[0].y;
-		PG_RETURN_POINT_P(result);
-	}
-
-	/*
-	 * vert. and horiz. cases are down, now check if the closest point is one
-	 * of the end points or someplace on the lseg.
-	 */
-
-	invm = -1.0 / point_sl(&(lseg->p[0]), &(lseg->p[1]));
-	tmp = line_construct_pm(&lseg->p[!yh], invm);	/* lower edge of the
-													 * "band" */
-	if (pt->y < (tmp->A * pt->x + tmp->C))
-	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[!yh]); /* below the lseg, take lower end
-											 * pt */
-#ifdef GEODEBUG
-		printf("close_ps below: tmp A %f  B %f   C %f\n",
-			   tmp->A, tmp->B, tmp->C);
-#endif
-		PG_RETURN_POINT_P(result);
-	}
-	tmp = line_construct_pm(&lseg->p[yh], invm);	/* upper edge of the
-													 * "band" */
-	if (pt->y > (tmp->A * pt->x + tmp->C))
-	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[yh]);	/* above the lseg, take higher end
-											 * pt */
-#ifdef GEODEBUG
-		printf("close_ps above: tmp A %f  B %f   C %f\n",
-			   tmp->A, tmp->B, tmp->C);
-#endif
-		PG_RETURN_POINT_P(result);
-	}
-
-	/*
-	 * at this point the "normal" from point will hit lseg. The closest point
-	 * will be somewhere on the lseg
-	 */
-	tmp = line_construct_pm(pt, invm);
-#ifdef GEODEBUG
-	printf("close_ps- tmp A %f  B %f   C %f\n",
-		   tmp->A, tmp->B, tmp->C);
-#endif
-	result = interpt_sl(lseg, tmp);
-
-	/*
-	 * ordinarily we should always find an intersection point, but that could
-	 * fail in the presence of NaN coordinates, and perhaps even from simple
-	 * roundoff issues.  Return a SQL NULL if so.
-	 */
-	if (result == NULL)
+	if (isnan(lseg_closept_point(result, lseg, pt)))
 		PG_RETURN_NULL();
 
-#ifdef GEODEBUG
-	printf("close_ps- result.x %f  result.y %f\n", result->x, result->y);
-#endif
 	PG_RETURN_POINT_P(result);
 }
 
 
-/* close_lseg()
- * Closest point to l1 on l2.
+/*
+ * Closest point on line segment to line segment
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
+static float8
+lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
+{
+	Point		point;
+	double		dist;
+	double		d;
+
+	d = lseg_closept_point(NULL, l1, &l2->p[0]);
+	dist = d;
+	if (result != NULL)
+		*result = l2->p[0];
+
+	d = lseg_closept_point(NULL, l1, &l2->p[1]);
+	if (d < dist)
+	{
+		dist = d;
+		if (result != NULL)
+			*result = l2->p[1];
+	}
+
+	if (lseg_closept_point(&point, l2, &l1->p[0]) < dist)
+		d = lseg_closept_point(result, l1, &point);
+
+	if (lseg_closept_point(&point, l2, &l1->p[1]) < dist)
+		d = lseg_closept_point(result, l1, &point);
+
+	if (d < dist)
+		dist = d;
+
+	return dist;
+}
+
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
-	Point		point;
-	double		dist;
-	double		d;
+	Point	   *result;
 
-	d = dist_ps_internal(&l1->p[0], l2);
-	dist = d;
-	memcpy(&point, &l1->p[0], sizeof(Point));
+	result = (Point *) palloc(sizeof(Point));
 
-	if ((d = dist_ps_internal(&l1->p[1], l2)) < dist)
-	{
-		dist = d;
-		memcpy(&point, &l1->p[1], sizeof(Point));
-	}
-
-	if (dist_ps_internal(&l2->p[0], l1) < dist)
-	{
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&l2->p[0]),
-													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
-													LsegPGetDatum(l2)));
-	}
-
-	if (dist_ps_internal(&l2->p[1], l1) < dist)
-	{
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&l2->p[1]),
-													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
-													LsegPGetDatum(l2)));
-	}
-
-	if (result == NULL)
-		result = point_copy(&point);
+	lseg_closept_lseg(result, l2, l1);
 
 	PG_RETURN_POINT_P(result);
 }
 
-/* close_pb()
+
+/*
  * Closest point on or in box to specified point.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
-Datum
-close_pb(PG_FUNCTION_ARGS)
+static float8
+box_closept_point(Point *result, BOX *box, Point *pt)
 {
-	Point	   *pt = PG_GETARG_POINT_P(0);
-	BOX		   *box = PG_GETARG_BOX_P(1);
-	LSEG		lseg,
-				seg;
-	Point		point;
+	LSEG		lseg;
+	Point		point,
+				closept;
 	double		dist,
 				d;
 
-	if (DatumGetBool(DirectFunctionCall2(on_pb,
-										 PointPGetDatum(pt),
-										 BoxPGetDatum(box))))
-		PG_RETURN_POINT_P(pt);
+	if (box_contain_point(box, pt))
+	{
+		if (result != NULL)
+			*result = *pt;
+
+		return 0.0;
+	}
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&lseg, &box->low, &point);
-	dist = dist_ps_internal(pt, &lseg);
+	dist = lseg_closept_point(result, &lseg, pt);
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	statlseg_construct(&lseg, &box->high, &point);
+	d = lseg_closept_point(&closept, &lseg, pt);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&lseg, &seg, sizeof(lseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
-	statlseg_construct(&seg, &box->low, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	statlseg_construct(&lseg, &box->low, &point);
+	d = lseg_closept_point(&closept, &lseg, pt);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&lseg, &seg, sizeof(lseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	statlseg_construct(&lseg, &box->high, &point);
+	d = lseg_closept_point(&closept, &lseg, pt);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&lseg, &seg, sizeof(lseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
-										PointPGetDatum(pt),
-										LsegPGetDatum(&lseg)));
+	return dist;
 }
 
+Datum
+close_pb(PG_FUNCTION_ARGS)
+{
+	Point	   *pt = PG_GETARG_POINT_P(0);
+	BOX		   *box = PG_GETARG_BOX_P(1);
+	Point	   *result;
+
+	result = (Point *) palloc(sizeof(Point));
+
+	box_closept_point(result, box, pt);
+
+	PG_RETURN_POINT_P(result);
+}
+
+
 /* close_sl()
  * Closest point on line to line segment.
  *
  * XXX THIS CODE IS WRONG
  * The code is actually calculating the point on the line segment
  *	which is backwards from the routine naming convention.
  * Copied code to new routine close_ls() but haven't fixed this one yet.
  * - thomas 1998-01-31
  */
 Datum
 close_sl(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 	float8		d1,
 				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
+	result = (Point *) palloc(sizeof(Point));
+
+	if (lseg_interpt_line(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
-	d1 = dist_pl_internal(&lseg->p[0], line);
-	d2 = dist_pl_internal(&lseg->p[1], line);
+	d1 = line_closept_point(NULL, line, &lseg->p[0]);
+	d2 = line_closept_point(NULL, line, &lseg->p[1]);
 	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
+		*result = lseg->p[0];
 	else
-		result = point_copy(&lseg->p[1]);
+		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
 
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_sl\" not implemented")));
 
 	PG_RETURN_NULL();
 }
 
-/* close_ls()
+/*
  * Closest point on line segment to line.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
+ *
+ * NOTE: When the lines are parallel, endpoints of one of the line segment
+ * are FPeq(), in presence of NaN or Infinitive coordinates, or perhaps =
+ * even because of simple roundoff issues, there may not be a single closest
+ * point.  We are likely to set the result to the second endpoint in these
+ * cases.
  */
+static float8
+lseg_closept_line(Point *result, LSEG *lseg, LINE *line)
+{
+	float8		dist1,
+				dist2;
+
+	if (lseg_interpt_line(result, lseg, line))
+		return 0.0;
+
+	dist1 = line_closept_point(NULL, line, &lseg->p[0]);
+	dist2 = line_closept_point(NULL, line, &lseg->p[1]);
+
+	if (dist1 < dist2)
+	{
+		if (result != NULL)
+			*result = lseg->p[0];
+
+		return dist1;
+	}
+	else
+	{
+		if (result != NULL)
+			*result = lseg->p[1];
+
+		return dist2;
+	}
+}
+
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
-	float8		d1,
-				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
-		PG_RETURN_POINT_P(result);
+	result = (Point *) palloc(sizeof(Point));
 
-	d1 = dist_pl_internal(&lseg->p[0], line);
-	d2 = dist_pl_internal(&lseg->p[1], line);
-	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
-	else
-		result = point_copy(&lseg->p[1]);
+	lseg_closept_line(result, lseg, line);
 
 	PG_RETURN_POINT_P(result);
 }
 
-/* close_sb()
+
+/*
  * Closest point on or in box to line segment.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
-Datum
-close_sb(PG_FUNCTION_ARGS)
+static float8
+box_closept_lseg(Point *result, BOX *box, LSEG *lseg)
 {
-	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
-	BOX		   *box = PG_GETARG_BOX_P(1);
-	Point		point;
-	LSEG		bseg,
-				seg;
+	Point		point,
+				closept;
+	LSEG		bseg;
 	double		dist,
 				d;
 
-	/* segment intersects box? then just return closest point to center */
-	if (DatumGetBool(DirectFunctionCall2(inter_sb,
-										 LsegPGetDatum(lseg),
-										 BoxPGetDatum(box))))
-	{
-		box_cn(&point, box);
-		PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
-											PointPGetDatum(&point),
-											LsegPGetDatum(lseg)));
-	}
+	if (box_interpt_lseg(result, box, lseg))
+		return 0.0;
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	dist = lseg_dt(lseg, &bseg);
+	dist = lseg_closept_lseg(result, &bseg, lseg);
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	statlseg_construct(&bseg, &box->high, &point);
+	d = lseg_closept_lseg(&closept, &bseg, lseg);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&bseg, &seg, sizeof(bseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
-	statlseg_construct(&seg, &box->low, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	statlseg_construct(&bseg, &box->low, &point);
+	d = lseg_closept_lseg(&closept, &bseg, lseg);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&bseg, &seg, sizeof(bseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	statlseg_construct(&bseg, &box->high, &point);
+	d = lseg_closept_lseg(&closept, &bseg, lseg);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&bseg, &seg, sizeof(bseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	/* OK, we now have the closest line segment on the box boundary */
-	PG_RETURN_DATUM(DirectFunctionCall2(close_lseg,
-										LsegPGetDatum(lseg),
-										LsegPGetDatum(&bseg)));
+	return dist;
 }
 
+Datum
+close_sb(PG_FUNCTION_ARGS)
+{
+	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
+	BOX		   *box = PG_GETARG_BOX_P(1);
+	Point	   *result;
+
+	result = (Point *) palloc(sizeof(Point));
+
+	box_closept_lseg(result, box, lseg);
+
+	PG_RETURN_POINT_P(result);
+}
+
+
 Datum
 close_lb(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 #endif
 
 	/* think about this one for a while */
 	ereport(ERROR,
@@ -3116,71 +2910,87 @@ close_lb(PG_FUNCTION_ARGS)
 			 errmsg("function \"close_lb\" not implemented")));
 
 	PG_RETURN_NULL();
 }
 
 /*---------------------------------------------------------------------
  *		on_
  *				Whether one object lies completely within another.
  *-------------------------------------------------------------------*/
 
-/* on_pl -
+/*
  *		Does the point satisfy the equation?
  */
+static bool
+line_contain_point(LINE *line, Point *point)
+{
+	return FPzero(line->A * point->x + line->B * point->y + line->C);
+}
+
 Datum
 on_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(FPzero(line->A * pt->x + line->B * pt->y + line->C));
+	PG_RETURN_BOOL(line_contain_point(line, pt));
 }
 
 
-/* on_ps -
+/*
  *		Determine colinearity by detecting a triangle inequality.
  * This algorithm seems to behave nicely even with lsb residues - tgl 1997-07-09
  */
+static bool
+lseg_contain_point(LSEG *lseg, Point *pt)
+{
+	return FPeq(point_dt(pt, &lseg->p[0]) +
+				point_dt(pt, &lseg->p[1]),
+				point_dt(&lseg->p[0], &lseg->p[1]));
+}
+
 Datum
 on_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(on_ps_internal(pt, lseg));
+	PG_RETURN_BOOL(lseg_contain_point(lseg, pt));
 }
 
+
+/*
+ * Check whether the point is in the box or on its border
+ */
 static bool
-on_ps_internal(Point *pt, LSEG *lseg)
+box_contain_point(BOX *box, Point *point)
 {
-	return FPeq(point_dt(pt, &lseg->p[0]) + point_dt(pt, &lseg->p[1]),
-				point_dt(&lseg->p[0], &lseg->p[1]));
+	return box->high.x >= point->x && box->low.x <= point->x &&
+		   box->high.y >= point->y && box->low.y <= point-> y;
 }
 
 Datum
 on_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_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);
+	PG_RETURN_BOOL(box_contain_point(box, pt));
 }
 
 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);
+	PG_RETURN_BOOL(box_contain_point(box, pt));
 }
 
 /* on_ppath -
  *		Whether a point lies within (on) a polyline.
  *		If open, we have to (groan) check each segment.
  * (uses same algorithm as for point intersecting segment - tgl 1997-07-09)
  *		If closed, we use the old O(n) ray method for point-in-polygon.
  *				The ray is horizontal, from pt out to the right.
  *				Each segment that crosses the ray counts as an
  *				intersection; note that an endpoint or edge may touch
@@ -3210,158 +3020,184 @@ on_ppath(PG_FUNCTION_ARGS)
 				PG_RETURN_BOOL(true);
 			a = b;
 		}
 		PG_RETURN_BOOL(false);
 	}
 
 	/*-- CLOSED --*/
 	PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
 }
 
+
+/*
+ * Check whether the line segment is on the line or close enough
+ *
+ * It is, if both of its points are on the line or close enough.
+ */
 Datum
 on_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(DatumGetBool(DirectFunctionCall2(on_pl,
-													PointPGetDatum(&lseg->p[0]),
-													LinePGetDatum(line))) &&
-				   DatumGetBool(DirectFunctionCall2(on_pl,
-													PointPGetDatum(&lseg->p[1]),
-													LinePGetDatum(line))));
+	PG_RETURN_BOOL(line_contain_point(line, &lseg->p[0]) &&
+				   line_contain_point(line, &lseg->p[1]));
+}
+
+
+/*
+ * Check whether the line segment is in the box or on its border
+ *
+ * It is, if both of its points are in the box or on its border.
+ */
+static bool
+box_contain_lseg(BOX *box, LSEG *lseg)
+{
+	return box_contain_point(box, &lseg->p[0]) &&
+		   box_contain_point(box, &lseg->p[1]);
 }
 
 Datum
 on_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(DatumGetBool(DirectFunctionCall2(on_pb,
-													PointPGetDatum(&lseg->p[0]),
-													BoxPGetDatum(box))) &&
-				   DatumGetBool(DirectFunctionCall2(on_pb,
-													PointPGetDatum(&lseg->p[1]),
-													BoxPGetDatum(box))));
+	PG_RETURN_BOOL(box_contain_lseg(box, lseg));
 }
 
 /*---------------------------------------------------------------------
  *		inter_
  *				Whether one object intersects another.
  *-------------------------------------------------------------------*/
 
 Datum
 inter_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(has_interpt_sl(lseg, line));
+	PG_RETURN_BOOL(lseg_interpt_line(NULL, lseg, line));
 }
 
-/* inter_sb()
+
+/*
  * Do line segment and box intersect?
  *
  * Segment completely inside box counts as intersection.
  * If you want only segments crossing box boundaries,
  *	try converting box to path first.
  *
+ * This function also sets the *result to the closest point on the line
+ * segment to the center of the box when they overlap and the result is
+ * not NULL.  It is somewhat arbitrary, but maybe the best we can do as
+ * there are typically two points they intersect.
+ *
  * Optimize for non-intersection by checking for box intersection first.
  * - thomas 1998-01-30
  */
-Datum
-inter_sb(PG_FUNCTION_ARGS)
+static bool
+box_interpt_lseg(Point *result, BOX *box, LSEG *lseg)
 {
-	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
-	BOX		   *box = PG_GETARG_BOX_P(1);
 	BOX			lbox;
 	LSEG		bseg;
 	Point		point;
 
 	lbox.low.x = Min(lseg->p[0].x, lseg->p[1].x);
 	lbox.low.y = Min(lseg->p[0].y, lseg->p[1].y);
 	lbox.high.x = Max(lseg->p[0].x, lseg->p[1].x);
 	lbox.high.y = Max(lseg->p[0].y, lseg->p[1].y);
 
 	/* nothing close to overlap? then not going to intersect */
 	if (!box_ov(&lbox, box))
-		PG_RETURN_BOOL(false);
+		return false;
+
+	if (result != NULL)
+	{
+		box_cn(&point, box);
+		lseg_closept_point(result, lseg, &point);
+	}
 
 	/* an endpoint of segment is inside box? then clearly intersects */
-	if (DatumGetBool(DirectFunctionCall2(on_pb,
-										 PointPGetDatum(&lseg->p[0]),
-										 BoxPGetDatum(box))) ||
-		DatumGetBool(DirectFunctionCall2(on_pb,
-										 PointPGetDatum(&lseg->p[1]),
-										 BoxPGetDatum(box))))
-		PG_RETURN_BOOL(true);
+	if (box_contain_point(box, &lseg->p[0]) ||
+		box_contain_point(box, &lseg->p[1]))
+		return true;
 
 	/* pairwise check lseg intersections */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	/* if we dropped through, no two segs intersected */
-	PG_RETURN_BOOL(false);
+	return false;
 }
 
+Datum
+inter_sb(PG_FUNCTION_ARGS)
+{
+	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
+	BOX		   *box = PG_GETARG_BOX_P(1);
+
+	PG_RETURN_BOOL(box_interpt_lseg(NULL, box, lseg));
+}
+
+
 /* inter_lb()
  * Do line and box intersect?
  */
 Datum
 inter_lb(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	LSEG		bseg;
 	Point		p1,
 				p2;
 
 	/* pairwise check lseg intersections */
 	p1.x = box->low.x;
 	p1.y = box->low.y;
 	p2.x = box->low.x;
 	p2.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->high.x;
 	p1.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p2.x = box->high.x;
 	p2.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->low.x;
 	p1.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 
 	/* if we dropped through, no intersection */
 	PG_RETURN_BOOL(false);
 }
 
 /*------------------------------------------------------------------
  * The following routines define a data type and operator class for
  * POLYGONS .... Part of which (the polygon's bounding box) is built on
  * top of the BOX data type.
@@ -3374,42 +3210,40 @@ inter_lb(PG_FUNCTION_ARGS)
  *---------------------------------------------------------------------*/
 static void
 make_bound_box(POLYGON *poly)
 {
 	int			i;
 	double		x1,
 				y1,
 				x2,
 				y2;
 
-	if (poly->npts > 0)
-	{
-		x2 = x1 = poly->p[0].x;
-		y2 = y1 = poly->p[0].y;
-		for (i = 1; i < poly->npts; i++)
-		{
-			if (poly->p[i].x < x1)
-				x1 = poly->p[i].x;
-			if (poly->p[i].x > x2)
-				x2 = poly->p[i].x;
-			if (poly->p[i].y < y1)
-				y1 = poly->p[i].y;
-			if (poly->p[i].y > y2)
-				y2 = poly->p[i].y;
-		}
+	Assert(poly->npts > 0);
 
-		box_fill(&(poly->boundbox), x1, x2, y1, y2);
+	x1 = x2 = poly->p[0].x;
+	y2 = y1 = poly->p[0].y;
+	for (i = 1; i < poly->npts; i++)
+	{
+		if (poly->p[i].x < x1)
+			x1 = poly->p[i].x;
+		if (poly->p[i].x > x2)
+			x2 = poly->p[i].x;
+		if (poly->p[i].y < y1)
+			y1 = poly->p[i].y;
+		if (poly->p[i].y > y2)
+			y2 = poly->p[i].y;
 	}
-	else
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot create bounding box for empty polygon")));
+
+	poly->boundbox.low.x = x1;
+	poly->boundbox.high.x = x2;
+	poly->boundbox.low.y = y1;
+	poly->boundbox.high.y = y2;
 }
 
 /*------------------------------------------------------------------
  * poly_in - read in the polygon from a string specification
  *
  *		External format:
  *				"((x0,y0),...,(xn,yn))"
  *				"x0,y0,...,xn,yn"
  *				also supports the older style "(x1,...,xn,y1,...yn)"
  *------------------------------------------------------------------*/
@@ -3739,65 +3573,65 @@ poly_same(PG_FUNCTION_ARGS)
 /*-----------------------------------------------------------------
  * Determine if polygon A overlaps polygon B
  *-----------------------------------------------------------------*/
 Datum
 poly_overlap(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
+	Assert(polya->npts > 0 && polyb->npts > 0);
+
 	/* Quick check by bounding box */
-	result = (polya->npts > 0 && polyb->npts > 0 &&
-			  box_ov(&polya->boundbox, &polyb->boundbox)) ? true : false;
+	result = box_ov(&polya->boundbox, &polyb->boundbox);
 
 	/*
 	 * Brute-force algorithm - try to find intersected edges, if so then
 	 * polygons are overlapped else check is one polygon inside other or not
 	 * by testing single point of them.
 	 */
 	if (result)
 	{
 		int			ia,
 					ib;
 		LSEG		sa,
 					sb;
 
 		/* Init first of polya's edge with last point */
 		sa.p[0] = polya->p[polya->npts - 1];
 		result = false;
 
-		for (ia = 0; ia < polya->npts && result == false; ia++)
+		for (ia = 0; ia < polya->npts && !result; ia++)
 		{
 			/* Second point of polya's edge is a current one */
 			sa.p[1] = polya->p[ia];
 
 			/* Init first of polyb's edge with last point */
 			sb.p[0] = polyb->p[polyb->npts - 1];
 
-			for (ib = 0; ib < polyb->npts && result == false; ib++)
+			for (ib = 0; ib < polyb->npts && !result; ib++)
 			{
 				sb.p[1] = polyb->p[ib];
-				result = lseg_intersect_internal(&sa, &sb);
+				result = lseg_interpt_lseg(NULL, &sa, &sb);
 				sb.p[0] = sb.p[1];
 			}
 
 			/*
 			 * move current endpoint to the first point of next edge
 			 */
 			sa.p[0] = sa.p[1];
 		}
 
-		if (result == false)
+		if (!result)
 		{
-			result = (point_inside(polya->p, polyb->npts, polyb->p)
-					  ||
+			result = (point_inside(polya->p, polyb->npts, polyb->p) ||
 					  point_inside(polyb->p, polya->npts, polya->p));
 		}
 	}
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
@@ -3817,36 +3651,35 @@ poly_overlap(PG_FUNCTION_ARGS)
 
 static bool
 touched_lseg_inside_poly(Point *a, Point *b, LSEG *s, POLYGON *poly, int start)
 {
 	/* point a is on s, b is not */
 	LSEG		t;
 
 	t.p[0] = *a;
 	t.p[1] = *b;
 
-#define POINTEQ(pt1, pt2)	(FPeq((pt1)->x, (pt2)->x) && FPeq((pt1)->y, (pt2)->y))
-	if (POINTEQ(a, s->p))
+	if (point_eq_point(a, s->p))
 	{
-		if (on_ps_internal(s->p + 1, &t))
+		if (lseg_contain_point(&t, s->p + 1))
 			return lseg_inside_poly(b, s->p + 1, poly, start);
 	}
-	else if (POINTEQ(a, s->p + 1))
+	else if (point_eq_point(a, s->p + 1))
 	{
-		if (on_ps_internal(s->p, &t))
+		if (lseg_contain_point(&t, s->p))
 			return lseg_inside_poly(b, s->p, poly, start);
 	}
-	else if (on_ps_internal(s->p, &t))
+	else if (lseg_contain_point(&t, s->p))
 	{
 		return lseg_inside_poly(b, s->p, poly, start);
 	}
-	else if (on_ps_internal(s->p + 1, &t))
+	else if (lseg_contain_point(&t, s->p + 1))
 	{
 		return lseg_inside_poly(b, s->p + 1, poly, start);
 	}
 
 	return true;				/* may be not true, but that will check later */
 }
 
 /*
  * Returns true if segment (a,b) is in polygon, option
  * start is used for optimization - function checks
@@ -3860,50 +3693,49 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 	int			i;
 	bool		res = true,
 				intersection = false;
 
 	t.p[0] = *a;
 	t.p[1] = *b;
 	s.p[0] = poly->p[(start == 0) ? (poly->npts - 1) : (start - 1)];
 
 	for (i = start; i < poly->npts && res; i++)
 	{
-		Point	   *interpt;
+		Point		interpt;
 
 		CHECK_FOR_INTERRUPTS();
 
 		s.p[1] = poly->p[i];
 
-		if (on_ps_internal(t.p, &s))
+		if (lseg_contain_point(&s, t.p))
 		{
-			if (on_ps_internal(t.p + 1, &s))
+			if (lseg_contain_point(&s, t.p + 1))
 				return true;	/* t is contained by s */
 
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p, t.p + 1, &s, poly, i + 1);
 		}
-		else if (on_ps_internal(t.p + 1, &s))
+		else if (lseg_contain_point(&s, t.p + 1))
 		{
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p + 1, t.p, &s, poly, i + 1);
 		}
-		else if ((interpt = lseg_interpt_internal(&t, &s)) != NULL)
+		else if (lseg_interpt_lseg(&interpt, &t, &s))
 		{
 			/*
 			 * segments are X-crossing, go to check each subsegment
 			 */
 
 			intersection = true;
-			res = lseg_inside_poly(t.p, interpt, poly, i + 1);
+			res = lseg_inside_poly(t.p, &interpt, poly, i + 1);
 			if (res)
-				res = lseg_inside_poly(t.p + 1, interpt, poly, i + 1);
-			pfree(interpt);
+				res = lseg_inside_poly(t.p + 1, &interpt, poly, i + 1);
 		}
 
 		s.p[0] = s.p[1];
 	}
 
 	if (res && !intersection)
 	{
 		Point		p;
 
 		/*
@@ -3915,74 +3747,86 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 
 		res = point_inside(&p, poly->npts, poly->p);
 	}
 
 	return res;
 }
 
 /*-----------------------------------------------------------------
  * Determine if polygon A contains polygon B.
  *-----------------------------------------------------------------*/
+static bool
+poly_contain_poly(POLYGON *polya, POLYGON *polyb)
+{
+	int			i;
+	LSEG		s;
+
+	Assert(polya->npts > 0 && polyb->npts > 0);
+
+	/*
+	 * Quick check to see if bounding box is contained.
+	 */
+	if (!box_contain_box(&polya->boundbox, &polyb->boundbox))
+		return false;
+
+	s.p[0] = polyb->p[polyb->npts - 1];
+
+	for (i = 0; i < polyb->npts; i++)
+	{
+		s.p[1] = polyb->p[i];
+		if (!lseg_inside_poly(s.p, s.p + 1, polya, 0))
+			return false;
+		s.p[0] = s.p[1];
+	}
+
+	return true;
+}
+
 Datum
 poly_contain(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	/*
-	 * Quick check to see if bounding box is contained.
-	 */
-	if (polya->npts > 0 && polyb->npts > 0 &&
-		DatumGetBool(DirectFunctionCall2(box_contain,
-										 BoxPGetDatum(&polya->boundbox),
-										 BoxPGetDatum(&polyb->boundbox))))
-	{
-		int			i;
-		LSEG		s;
-
-		s.p[0] = polyb->p[polyb->npts - 1];
-		result = true;
-
-		for (i = 0; i < polyb->npts && result; i++)
-		{
-			s.p[1] = polyb->p[i];
-			result = lseg_inside_poly(s.p, s.p + 1, polya, 0);
-			s.p[0] = s.p[1];
-		}
-	}
-	else
-	{
-		result = false;
-	}
+	result = poly_contain_poly(polya, polyb);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
 
 /*-----------------------------------------------------------------
  * Determine if polygon A is contained by polygon B
  *-----------------------------------------------------------------*/
 Datum
 poly_contained(PG_FUNCTION_ARGS)
 {
-	Datum		polya = PG_GETARG_DATUM(0);
-	Datum		polyb = PG_GETARG_DATUM(1);
+	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
+	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
+	bool		result;
 
 	/* Just switch the arguments and pass it off to poly_contain */
-	PG_RETURN_DATUM(DirectFunctionCall2(poly_contain, polyb, polya));
+	result = poly_contain_poly(polyb, polya);
+
+	/*
+	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
+	 */
+	PG_FREE_IF_COPY(polya, 0);
+	PG_FREE_IF_COPY(polyb, 1);
+
+	PG_RETURN_BOOL(result);
 }
 
 
 Datum
 poly_contain_pt(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_BOOL(point_inside(p, poly->npts, poly->p) != 0);
@@ -4018,170 +3862,215 @@ poly_distance(PG_FUNCTION_ARGS)
  **
  **		Routines for 2D points.
  **
  ***********************************************************************/
 
 Datum
 construct_point(PG_FUNCTION_ARGS)
 {
 	float8		x = PG_GETARG_FLOAT8(0);
 	float8		y = PG_GETARG_FLOAT8(1);
+	Point	   *result;
 
-	PG_RETURN_POINT_P(point_construct(x, y));
+	result = (Point *) palloc(sizeof(Point));
+
+	point_construct(result, x, y);
+
+	PG_RETURN_POINT_P(result);
+}
+
+
+static inline void
+point_add_point(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x + pt2->x,
+					pt1->y + pt2->y);
 }
 
 Datum
 point_add(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x + p2->x);
-	result->y = (p1->y + p2->y);
+	point_add_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+
+static inline void
+point_sub_point(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x - pt2->x,
+					pt1->y - pt2->y);
+}
+
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x - p2->x);
-	result->y = (p1->y - p2->y);
+	point_sub_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+
+static inline void
+point_mul_point(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					(pt1->x * pt2->x) - (pt1->y * pt2->y),
+					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+}
+
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x * p2->x) - (p1->y * p2->y);
-	result->y = (p1->x * p2->y) + (p1->y * p2->x);
+	point_mul_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+
+static inline void
+point_div_point(Point *result, Point *pt1, Point *pt2)
+{
+	double		div;
+
+	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
+
+	if (div == 0.0)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	point_construct(result,
+					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
+					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+}
+
 Datum
 point_div(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
-	double		div;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	div = (p2->x * p2->x) + (p2->y * p2->y);
-
-	if (div == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result->x = ((p1->x * p2->x) + (p1->y * p2->y)) / div;
-	result->y = ((p2->x * p1->y) - (p2->y * p1->x)) / div;
+	point_div_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D boxes.
  **
  ***********************************************************************/
 
 Datum
 points_box(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct(p1->x, p2->x, p1->y, p2->y));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	box_construct(result, p1, p2);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_add(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct((box->high.x + p->x),
-								  (box->low.x + p->x),
-								  (box->high.y + p->y),
-								  (box->low.y + p->y)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_add_point(&result->high, &box->high, p);
+	point_add_point(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_sub(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct((box->high.x - p->x),
-								  (box->low.x - p->x),
-								  (box->high.y - p->y),
-								  (box->low.y - p->y)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_sub_point(&result->high, &box->high, p);
+	point_sub_point(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_mul(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
 
-	high = DatumGetPointP(DirectFunctionCall2(point_mul,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_mul,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	result = (BOX *) palloc(sizeof(BOX));
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	point_mul_point(&high, &box->high, p);
+	point_mul_point(&low, &box->low, p);
+
+	box_construct(result, &high, &low);
 
 	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_div(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
 
-	high = DatumGetPointP(DirectFunctionCall2(point_div,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_div,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	result = (BOX *) palloc(sizeof(BOX));
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	point_div_point(&high, &box->high, p);
+	point_div_point(&low, &box->low, p);
+
+	box_construct(result, &high, &low);
 
 	PG_RETURN_BOX_P(result);
 }
 
 /*
  * Convert point to empty box
  */
 Datum
 point_box(PG_FUNCTION_ARGS)
 {
@@ -4277,83 +4166,63 @@ path_add(PG_FUNCTION_ARGS)
  * Translation operators.
  */
 Datum
 path_add_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x += point->x;
-		path->p[i].y += point->y;
-	}
+		point_add_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_sub_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x -= point->x;
-		path->p[i].y -= point->y;
-	}
+		point_sub_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 /* path_mul_pt()
  * Rotation and scaling operators.
  */
 Datum
 path_mul_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_mul,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_mul_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_div_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_div,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_div_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 
 Datum
 path_center(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	PATH	   *path = PG_GETARG_PATH_P(0);
@@ -4414,42 +4283,40 @@ poly_npoints(PG_FUNCTION_ARGS)
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 
 	PG_RETURN_INT32(poly->npts);
 }
 
 
 Datum
 poly_center(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
-	Datum		result;
-	CIRCLE	   *circle;
+	Point	   *result;
+	CIRCLE		circle;
 
-	circle = DatumGetCircleP(DirectFunctionCall1(poly_circle,
-												 PolygonPGetDatum(poly)));
-	result = DirectFunctionCall1(circle_center,
-								 CirclePGetDatum(circle));
+	result = (Point *) palloc(sizeof(Point));
 
-	PG_RETURN_DATUM(result);
+	poly_to_circle(&circle, poly);
+	*result = circle.center;
+
+	PG_RETURN_POINT_P(result);
 }
 
 
 Datum
 poly_box(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	BOX		   *box;
 
-	if (poly->npts < 1)
-		PG_RETURN_NULL();
-
-	box = box_copy(&poly->boundbox);
+	box = (BOX *) palloc(sizeof(BOX));
+	*box = poly->boundbox;
 
 	PG_RETURN_BOX_P(box);
 }
 
 
 /* box_poly()
  * Convert a box to a polygon.
  */
 Datum
 box_poly(PG_FUNCTION_ARGS)
@@ -4467,22 +4334,21 @@ box_poly(PG_FUNCTION_ARGS)
 
 	poly->p[0].x = box->low.x;
 	poly->p[0].y = box->low.y;
 	poly->p[1].x = box->low.x;
 	poly->p[1].y = box->high.y;
 	poly->p[2].x = box->high.x;
 	poly->p[2].y = box->high.y;
 	poly->p[3].x = box->high.x;
 	poly->p[3].y = box->low.y;
 
-	box_fill(&poly->boundbox, box->high.x, box->low.x,
-			 box->high.y, box->low.y);
+	box_construct(&poly->boundbox, &box->high, &box->low);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
 
 Datum
 poly_path(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	PATH	   *path;
@@ -4557,22 +4423,21 @@ circle_in(PG_FUNCTION_ARGS)
 
 	circle->radius = single_decode(s, &s, "circle", str);
 	if (circle->radius < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
 
 	while (depth > 0)
 	{
-		if ((*s == RDELIM)
-			|| ((*s == RDELIM_C) && (depth == 1)))
+		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
 			s++;
 			while (isspace((unsigned char) *s))
 				s++;
 		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
@@ -4656,22 +4521,21 @@ circle_send(PG_FUNCTION_ARGS)
 
 /*		circles identical?
  */
 Datum
 circle_same(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPeq(circle1->radius, circle2->radius) &&
-				   FPeq(circle1->center.x, circle2->center.x) &&
-				   FPeq(circle1->center.y, circle2->center.y));
+				   point_eq_point(&circle1->center, &circle2->center));
 }
 
 /*		circle_overlap	-		does circle1 overlap circle2?
  */
 Datum
 circle_overlap(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
@@ -4730,32 +4594,34 @@ circle_overright(PG_FUNCTION_ARGS)
 }
 
 /*		circle_contained		-		is circle1 contained by circle2?
  */
 Datum
 circle_contained(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle1->radius), circle2->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						circle2->radius - circle1->radius));
 }
 
 /*		circle_contain	-		does circle1 contain circle2?
  */
 Datum
 circle_contain(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle2->radius), circle1->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						circle1->radius - circle2->radius));
 }
 
 
 /*		circle_below		-		is circle1 strictly below circle2?
  */
 Datum
 circle_below(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
@@ -4858,107 +4724,83 @@ circle_ge(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPge(circle_ar(circle1), circle_ar(circle2)));
 }
 
 
 /*----------------------------------------------------------
  *	"Arithmetic" operators on circles.
  *---------------------------------------------------------*/
 
-static CIRCLE *
-circle_copy(CIRCLE *circle)
-{
-	CIRCLE	   *result;
-
-	if (!PointerIsValid(circle))
-		return NULL;
-
-	result = (CIRCLE *) palloc(sizeof(CIRCLE));
-	memcpy((char *) result, (char *) circle, sizeof(CIRCLE));
-	return result;
-}
-
-
 /* circle_add_pt()
  * Translation operator.
  */
 Datum
 circle_add_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x += point->x;
-	result->center.y += point->y;
+	point_add_point(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_sub_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x -= point->x;
-	result->center.y -= point->y;
+	point_sub_point(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /* circle_mul_pt()
  * Rotation and scaling operators.
  */
 Datum
 circle_mul_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_mul,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
-	result->radius *= HYPOT(point->x, point->y);
+	point_mul_point(&result->center, &circle->center, point);
+	result->radius = circle->radius * HYPOT(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_div_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_div,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
-	result->radius /= HYPOT(point->x, point->y);
+	point_div_point(&result->center, &circle->center, point);
+	result->radius = circle->radius / HYPOT(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /*		circle_area		-		returns the area of the circle.
  */
 Datum
 circle_area(PG_FUNCTION_ARGS)
 {
@@ -4993,22 +4835,22 @@ circle_radius(PG_FUNCTION_ARGS)
 /*		circle_distance -		returns the distance between
  *								  two circles.
  */
 Datum
 circle_distance(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(&circle1->center, &circle2->center)
-		- (circle1->radius + circle2->radius);
+	result = point_dt(&circle1->center, &circle2->center) -
+		(circle1->radius + circle2->radius);
 	if (result < 0)
 		result = 0;
 	PG_RETURN_FLOAT8(result);
 }
 
 
 Datum
 circle_contain_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
@@ -5190,56 +5032,60 @@ circle_poly(PG_FUNCTION_ARGS)
 		angle = i * anglestep;
 		poly->p[i].x = circle->center.x - (circle->radius * cos(angle));
 		poly->p[i].y = circle->center.y + (circle->radius * sin(angle));
 	}
 
 	make_bound_box(poly);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
-/*		poly_circle		- convert polygon to circle
+/*
+ * Convert polygon to circle
+ *
+ * The result must be preallocated.
  *
  * XXX This algorithm should use weighted means of line segments
  *	rather than straight average values of points - tgl 97/01/21.
  */
+static void
+poly_to_circle(CIRCLE *result, POLYGON *poly)
+{
+	int			i;
+
+	Assert(poly->npts > 0);
+
+	result->center.x = 0;
+	result->center.y = 0;
+	result->radius = 0;
+
+	for (i = 0; i < poly->npts; i++)
+		point_add_point(&result->center, &result->center, &poly->p[i]);
+	result->center.x /= poly->npts;
+	result->center.y /= poly->npts;
+
+	for (i = 0; i < poly->npts; i++)
+		result->radius += point_dt(&poly->p[i], &result->center);
+	result->radius /= poly->npts;
+}
+
 Datum
 poly_circle(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
-	CIRCLE	   *circle;
-	int			i;
+	CIRCLE	   *result;
 
-	if (poly->npts < 1)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot convert empty polygon to circle")));
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
+	poly_to_circle(result, poly);
 
-	circle->center.x = 0;
-	circle->center.y = 0;
-	circle->radius = 0;
-
-	for (i = 0; i < poly->npts; i++)
-	{
-		circle->center.x += poly->p[i].x;
-		circle->center.y += poly->p[i].y;
-	}
-	circle->center.x /= poly->npts;
-	circle->center.y /= poly->npts;
-
-	for (i = 0; i < poly->npts; i++)
-		circle->radius += point_dt(&poly->p[i], &circle->center);
-	circle->radius /= poly->npts;
-
-	PG_RETURN_CIRCLE_P(circle);
+	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /***********************************************************************
  **
  **		Private routines for multiple types.
  **
  ***********************************************************************/
 
 /*
@@ -5261,22 +5107,21 @@ point_inside(Point *p, int npts, Point *plist)
 	double		x0,
 				y0;
 	double		prev_x,
 				prev_y;
 	int			i = 0;
 	double		x,
 				y;
 	int			cross,
 				total_cross = 0;
 
-	if (npts <= 0)
-		return 0;
+	Assert(npts > 0);
 
 	/* compute first polygon point relative to single point */
 	x0 = plist[0].x - p->x;
 	y0 = plist[0].y - p->y;
 
 	prev_x = x0;
 	prev_y = y0;
 	/* loop over polygon points and aggregate total_cross */
 	for (i = 1; i < npts; i++)
 	{
@@ -5371,51 +5216,48 @@ lseg_crossing(double x, double y, double prev_x, double prev_y)
 static bool
 plist_same(int npts, Point *p1, Point *p2)
 {
 	int			i,
 				ii,
 				j;
 
 	/* find match for first point */
 	for (i = 0; i < npts; i++)
 	{
-		if ((FPeq(p2[i].x, p1[0].x))
-			&& (FPeq(p2[i].y, p1[0].y)))
+		if (point_eq_point(&p2[i], &p1[0]))
 		{
 
 			/* match found? then look forward through remaining points */
 			for (ii = 1, j = i + 1; ii < npts; ii++, j++)
 			{
 				if (j >= npts)
 					j = 0;
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_point(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed forward match with %d\n", j, ii);
 #endif
 					break;
 				}
 			}
 #ifdef GEODEBUG
 			printf("plist_same- ii = %d/%d after forward match\n", ii, npts);
 #endif
 			if (ii == npts)
 				return true;
 
 			/* match not found forwards? then look backwards */
 			for (ii = 1, j = i - 1; ii < npts; ii++, j--)
 			{
 				if (j < 0)
 					j = (npts - 1);
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_point(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed reverse match with %d\n", j, ii);
 #endif
 					break;
 				}
 			}
 #ifdef GEODEBUG
 			printf("plist_same- ii = %d/%d after reverse match\n", ii, npts);
 #endif
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index 06411aea9e..d7c807f8d9 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -786,14 +786,15 @@ spg_bbox_quad_config(PG_FUNCTION_ARGS)
 
 /*
  * 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);
+	box = (BOX *) palloc(sizeof(BOX));
+	*box = polygon->boundbox;
 
 	PG_RETURN_BOX_P(box);
 }
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index a589e4239f..0e066894cd 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -171,17 +171,13 @@ typedef struct
 #define DatumGetCircleP(X)	  ((CIRCLE *) DatumGetPointer(X))
 #define CirclePGetDatum(X)	  PointerGetDatum(X)
 #define PG_GETARG_CIRCLE_P(n) DatumGetCircleP(PG_GETARG_DATUM(n))
 #define PG_RETURN_CIRCLE_P(x) return CirclePGetDatum(x)
 
 
 /*
  * 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/regress.c b/src/test/regress/regress.c
index 7060b6fbf3..c3a833cc56 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -170,22 +170,27 @@ widget_out(PG_FUNCTION_ARGS)
 	PG_RETURN_CSTRING(str);
 }
 
 PG_FUNCTION_INFO_V1(pt_in_widget);
 
 Datum
 pt_in_widget(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	WIDGET	   *widget = (WIDGET *) PG_GETARG_POINTER(1);
+	float8		distance;
 
-	PG_RETURN_BOOL(point_dt(point, &widget->center) < widget->radius);
+	distance = DatumGetFloat8(DirectFunctionCall2(point_distance,
+												  PointPGetDatum(point),
+											PointPGetDatum(&widget->center)));
+
+	PG_RETURN_BOOL(distance < widget->radius);
 }
 
 PG_FUNCTION_INFO_V1(reverse_name);
 
 Datum
 reverse_name(PG_FUNCTION_ARGS)
 {
 	char	   *string = PG_GETARG_CSTRING(0);
 	int			i;
 	int			len;
-- 
2.14.3 (Apple Git-98)

0002-float-header-v14.patchapplication/octet-stream; name=0002-float-header-v14.patchDownload
From 4c3242431efa5983b51727892905c073f8fe3499 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 28 May 2016 18:16:05 +0200
Subject: [PATCH 2/6] float-header-v14

Provide header file for built-in float datatypes

Even though, some datatypes under adt/ have separate header files,
most of the simple ones do not.  Their public functions were on
the builtins.h.  We would need to make more functions of floats public
to let the geometric types built on top of them.  This is a good
opportunity to make a separate header file for floats.

1acf7572554515b99ef6e783750aaea8777524ec made _cmp functions public
to solve NaN problem locally for GiST indexes.  This patch reworks it
in favour of a more extensive API.  The API uses inline functions
instead of macros, as they are easier to use compared to macros,
and avoid double-evaluation hazards.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com
---
 contrib/btree_gin/btree_gin.c                 |   1 +
 contrib/btree_gist/btree_ts.c                 |   1 +
 contrib/cube/cube.c                           |   2 +-
 contrib/cube/cubeparse.y                      |   2 +-
 contrib/postgres_fdw/postgres_fdw.c           |   1 +
 src/backend/access/gist/gistget.c             |   2 +-
 src/backend/access/gist/gistproc.c            |  55 +--
 src/backend/access/gist/gistutil.c            |   2 +-
 src/backend/utils/adt/float.c                 | 589 ++++++--------------------
 src/backend/utils/adt/formatting.c            |   1 +
 src/backend/utils/adt/geo_ops.c               |   6 +-
 src/backend/utils/adt/geo_spgist.c            |   2 +-
 src/backend/utils/adt/numeric.c               |   1 +
 src/backend/utils/adt/rangetypes_gist.c       |   3 +-
 src/backend/utils/adt/rangetypes_selfuncs.c   |   3 +-
 src/backend/utils/adt/rangetypes_typanalyze.c |   3 +-
 src/backend/utils/adt/timestamp.c             |   1 +
 src/backend/utils/misc/guc.c                  |   1 +
 src/include/utils/builtins.h                  |  14 -
 src/include/utils/float.h                     | 377 +++++++++++++++++
 src/include/utils/geo_decls.h                 |   1 +
 21 files changed, 555 insertions(+), 513 deletions(-)
 create mode 100644 src/include/utils/float.h

diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index b6d22d2b00..2ecf7a2d87 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -3,20 +3,21 @@
  */
 #include "postgres.h"
 
 #include <limits.h>
 
 #include "access/stratnum.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/cash.h"
 #include "utils/date.h"
+#include "utils/float.h"
 #include "utils/inet.h"
 #include "utils/numeric.h"
 #include "utils/timestamp.h"
 #include "utils/varbit.h"
 #include "utils/uuid.h"
 
 PG_MODULE_MAGIC;
 
 typedef struct QueryInfo
 {
diff --git a/contrib/btree_gist/btree_ts.c b/contrib/btree_gist/btree_ts.c
index 18740cad38..49d1849d88 100644
--- a/contrib/btree_gist/btree_ts.c
+++ b/contrib/btree_gist/btree_ts.c
@@ -2,20 +2,21 @@
  * contrib/btree_gist/btree_ts.c
  */
 #include "postgres.h"
 
 #include <limits.h>
 
 #include "btree_gist.h"
 #include "btree_utils_num.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 typedef struct
 {
 	Timestamp	lower;
 	Timestamp	upper;
 } tsKEY;
 
 /*
 ** timestamp ops
 */
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c
index 092ef149cf..c3f7410eab 100644
--- a/contrib/cube/cube.c
+++ b/contrib/cube/cube.c
@@ -7,21 +7,21 @@
 ******************************************************************************/
 
 #include "postgres.h"
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 
 #include "cubedata.h"
 
 PG_MODULE_MAGIC;
 
 /*
  * Taken from the intarray contrib header
  */
 #define ARRPTR(x)  ( (double *) ARR_DATA_PTR(x) )
 #define ARRNELEMS(x)  ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x))
diff --git a/contrib/cube/cubeparse.y b/contrib/cube/cubeparse.y
index 1b65fa967c..deb2efdc0d 100644
--- a/contrib/cube/cubeparse.y
+++ b/contrib/cube/cubeparse.y
@@ -1,20 +1,20 @@
 %{
 /* contrib/cube/cubeparse.y */
 
 /* NdBox = [(lowerleft),(upperright)] */
 /* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */
 
 #include "postgres.h"
 
 #include "cubedata.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 
 /* All grammar constructs return strings */
 #define YYSTYPE char *
 
 /*
  * Bison doesn't allocate anything that needs to live across parser calls,
  * so we can easily have it use palloc instead of malloc.  This prevents
  * memory leaks if we error out during parsing.  Note this only works with
  * bison >= 2.0.  However, in bison 1.875 the default is to use alloca()
  * if possible, so there's not really much problem anyhow, at least if
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 5699252091..0803c30a48 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -28,20 +28,21 @@
 #include "optimizer/cost.h"
 #include "optimizer/clauses.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
 #include "optimizer/planmain.h"
 #include "optimizer/restrictinfo.h"
 #include "optimizer/var.h"
 #include "optimizer/tlist.h"
 #include "parser/parsetree.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 #include "utils/sampling.h"
 #include "utils/selfuncs.h"
 
 PG_MODULE_MAGIC;
 
 /* Default CPU cost to start up a foreign query. */
diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c
index c4e8a3b913..ad07b9e63c 100644
--- a/src/backend/access/gist/gistget.c
+++ b/src/backend/access/gist/gistget.c
@@ -15,21 +15,21 @@
 #include "postgres.h"
 
 #include "access/gist_private.h"
 #include "access/relscan.h"
 #include "catalog/pg_type.h"
 #include "miscadmin.h"
 #include "storage/lmgr.h"
 #include "storage/predicate.h"
 #include "pgstat.h"
 #include "lib/pairingheap.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 
 /*
  * gistkillitems() -- set LP_DEAD state for items an indexscan caller has
  * told us were killed.
  *
  * We re-read page here, so it's important to check page LSN. If the page
  * has been modified since the last read (as determined by LSN), we cannot
  * flag any entries because it is possible that the old entry was vacuumed
diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index 97e6dc9910..4bbfdadf9f 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -27,62 +27,53 @@
 
 
 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
 						 StrategyNumber strategy);
 static bool rtree_internal_consistent(BOX *key, BOX *query,
 						  StrategyNumber strategy);
 
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
 
-/* Convenience macros for NaN-aware comparisons */
-#define FLOAT8_EQ(a,b)	(float8_cmp_internal(a, b) == 0)
-#define FLOAT8_LT(a,b)	(float8_cmp_internal(a, b) < 0)
-#define FLOAT8_LE(a,b)	(float8_cmp_internal(a, b) <= 0)
-#define FLOAT8_GT(a,b)	(float8_cmp_internal(a, b) > 0)
-#define FLOAT8_GE(a,b)	(float8_cmp_internal(a, b) >= 0)
-#define FLOAT8_MAX(a,b)  (FLOAT8_GT(a, b) ? (a) : (b))
-#define FLOAT8_MIN(a,b)  (FLOAT8_LT(a, b) ? (a) : (b))
-
 
 /**************************************************
  * Box ops
  **************************************************/
 
 /*
  * Calculates union of two boxes, a and b. The result is stored in *n.
  */
 static void
 rt_box_union(BOX *n, const BOX *a, const BOX *b)
 {
-	n->high.x = FLOAT8_MAX(a->high.x, b->high.x);
-	n->high.y = FLOAT8_MAX(a->high.y, b->high.y);
-	n->low.x = FLOAT8_MIN(a->low.x, b->low.x);
-	n->low.y = FLOAT8_MIN(a->low.y, b->low.y);
+	n->high.x = float8_max(a->high.x, b->high.x);
+	n->high.y = float8_max(a->high.y, b->high.y);
+	n->low.x = float8_min(a->low.x, b->low.x);
+	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
 static double
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
-	if (FLOAT8_LE(box->high.x, box->low.x) ||
-		FLOAT8_LE(box->high.y, box->low.y))
+	if (float8_le(box->high.x, box->low.x) ||
+		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
 	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
@@ -137,27 +128,27 @@ gist_box_consistent(PG_FUNCTION_ARGS)
 												 query,
 												 strategy));
 }
 
 /*
  * Increase BOX b to include addon.
  */
 static void
 adjustBox(BOX *b, const BOX *addon)
 {
-	if (FLOAT8_LT(b->high.x, addon->high.x))
+	if (float8_lt(b->high.x, addon->high.x))
 		b->high.x = addon->high.x;
-	if (FLOAT8_GT(b->low.x, addon->low.x))
+	if (float8_gt(b->low.x, addon->low.x))
 		b->low.x = addon->low.x;
-	if (FLOAT8_LT(b->high.y, addon->high.y))
+	if (float8_lt(b->high.y, addon->high.y))
 		b->high.y = addon->high.y;
-	if (FLOAT8_GT(b->low.y, addon->low.y))
+	if (float8_gt(b->low.y, addon->low.y))
 		b->low.y = addon->low.y;
 }
 
 /*
  * The GiST Union method for boxes
  *
  * returns the minimal bounding box that encloses all the entries in entryvec
  */
 Datum
 gist_box_union(PG_FUNCTION_ARGS)
@@ -609,36 +600,36 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		i1 = 0;
 		i2 = 0;
 		rightLower = intervalsLower[i1].lower;
 		leftUpper = intervalsUpper[i2].lower;
 		while (true)
 		{
 			/*
 			 * Find next lower bound of right group.
 			 */
 			while (i1 < nentries &&
-				   FLOAT8_EQ(rightLower, intervalsLower[i1].lower))
+				   float8_eq(rightLower, intervalsLower[i1].lower))
 			{
-				if (FLOAT8_LT(leftUpper, intervalsLower[i1].upper))
+				if (float8_lt(leftUpper, intervalsLower[i1].upper))
 					leftUpper = intervalsLower[i1].upper;
 				i1++;
 			}
 			if (i1 >= nentries)
 				break;
 			rightLower = intervalsLower[i1].lower;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * left group.
 			 */
 			while (i2 < nentries &&
-				   FLOAT8_LE(intervalsUpper[i2].upper, leftUpper))
+				   float8_le(intervalsUpper[i2].upper, leftUpper))
 				i2++;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim, rightLower, i1, leftUpper, i2);
 		}
 
 		/*
 		 * Iterate over upper bound of left group finding greatest possible
@@ -646,35 +637,35 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		 */
 		i1 = nentries - 1;
 		i2 = nentries - 1;
 		rightLower = intervalsLower[i1].upper;
 		leftUpper = intervalsUpper[i2].upper;
 		while (true)
 		{
 			/*
 			 * Find next upper bound of left group.
 			 */
-			while (i2 >= 0 && FLOAT8_EQ(leftUpper, intervalsUpper[i2].upper))
+			while (i2 >= 0 && float8_eq(leftUpper, intervalsUpper[i2].upper))
 			{
-				if (FLOAT8_GT(rightLower, intervalsUpper[i2].lower))
+				if (float8_gt(rightLower, intervalsUpper[i2].lower))
 					rightLower = intervalsUpper[i2].lower;
 				i2--;
 			}
 			if (i2 < 0)
 				break;
 			leftUpper = intervalsUpper[i2].upper;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * right group.
 			 */
-			while (i1 >= 0 && FLOAT8_GE(intervalsLower[i1].lower, rightLower))
+			while (i1 >= 0 && float8_ge(intervalsLower[i1].lower, rightLower))
 				i1--;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim,
 								 rightLower, i1 + 1, leftUpper, i2 + 1);
 		}
 	}
 
@@ -748,42 +739,42 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
 		}
 		else
 		{
 			lower = box->low.y;
 			upper = box->high.y;
 		}
 
-		if (FLOAT8_LE(upper, context.leftUpper))
+		if (float8_le(upper, context.leftUpper))
 		{
 			/* Fits to the left group */
-			if (FLOAT8_GE(lower, context.rightLower))
+			if (float8_ge(lower, context.rightLower))
 			{
 				/* Fits also to the right group, so "common entry" */
 				commonEntries[commonEntriesCount++].index = i;
 			}
 			else
 			{
 				/* Doesn't fit to the right group, so join to the left group */
 				PLACE_LEFT(box, i);
 			}
 		}
 		else
 		{
 			/*
 			 * Each entry should fit on either left or right group. Since this
 			 * entry didn't fit on the left group, it better fit in the right
 			 * group.
 			 */
-			Assert(FLOAT8_GE(lower, context.rightLower));
+			Assert(float8_ge(lower, context.rightLower));
 
 			/* Doesn't fit to the left group, so join to the right group */
 			PLACE_RIGHT(box, i);
 		}
 	}
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
@@ -853,24 +844,24 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
  * equivalent to box_same().
  */
 Datum
 gist_box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *b1 = PG_GETARG_BOX_P(0);
 	BOX		   *b2 = PG_GETARG_BOX_P(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
 	if (b1 && b2)
-		*result = (FLOAT8_EQ(b1->low.x, b2->low.x) &&
-				   FLOAT8_EQ(b1->low.y, b2->low.y) &&
-				   FLOAT8_EQ(b1->high.x, b2->high.x) &&
-				   FLOAT8_EQ(b1->high.y, b2->high.y));
+		*result = (float8_eq(b1->low.x, b2->low.x) &&
+				   float8_eq(b1->low.y, b2->low.y) &&
+				   float8_eq(b1->high.x, b2->high.x) &&
+				   float8_eq(b1->high.y, b2->high.y));
 	else
 		*result = (b1 == NULL && b2 == NULL);
 	PG_RETURN_POINTER(result);
 }
 
 /*
  * Leaf-level consistency for boxes: just apply the query operator
  */
 static bool
 gist_box_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy)
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 55cccd247a..7e43b8fc87 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -15,21 +15,21 @@
 
 #include <float.h>
 #include <math.h>
 
 #include "access/gist_private.h"
 #include "access/htup_details.h"
 #include "access/reloptions.h"
 #include "catalog/pg_opclass.h"
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/syscache.h"
 
 
 /*
  * Write itup vector to page, has no control of free space.
  */
 void
 gistfillbuffer(Page page, IndexTuple *itup, int len, OffsetNumber off)
 {
 	OffsetNumber l = InvalidOffsetNumber;
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index b86205b098..df35557b73 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -16,58 +16,25 @@
 
 #include <ctype.h>
 #include <float.h>
 #include <math.h>
 #include <limits.h>
 
 #include "catalog/pg_type.h"
 #include "common/int.h"
 #include "libpq/pqformat.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/sortsupport.h"
 
 
-#ifndef M_PI
-/* from my RH5.2 gcc math.h file - thomas 2000-04-03 */
-#define M_PI 3.14159265358979323846
-#endif
-
-/* Radians per degree, a.k.a. PI / 180 */
-#define RADIANS_PER_DEGREE 0.0174532925199432957692
-
-/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0.  NAN definition from
- * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfNotNumberNANItems.asp
- */
-#if defined(WIN32) && !defined(NAN)
-static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
-
-#define NAN (*(const double *) nan)
-#endif
-
-/*
- * check to see if a float4/8 val has underflowed or overflowed
- */
-#define CHECKFLOATVAL(val, inf_is_valid, zero_is_valid)			\
-do {															\
-	if (isinf(val) && !(inf_is_valid))							\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		  errmsg("value out of range: overflow")));				\
-																\
-	if ((val) == 0.0 && !(zero_is_valid))						\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		 errmsg("value out of range: underflow")));				\
-} while(0)
-
-
 /* Configurable GUC parameter */
 int			extra_float_digits = 0; /* Added to DBL_DIG or FLT_DIG */
 
 /* Cached constants for degree-based trig functions */
 static bool degree_consts_set = false;
 static float8 sin_30 = 0;
 static float8 one_minus_cos_60 = 0;
 static float8 asin_0_5 = 0;
 static float8 acos_0_5 = 0;
 static float8 atan_1_0 = 0;
@@ -98,100 +65,20 @@ static void init_degree_constants(void);
  * function, which causes configure to not set HAVE_CBRT.  Furthermore,
  * their compilers spit up at the mismatch between extern declaration
  * and static definition.  We work around that here by the expedient
  * of a #define to make the actual name of the static function different.
  */
 #define cbrt my_cbrt
 static double cbrt(double x);
 #endif							/* HAVE_CBRT */
 
 
-/*
- * Routines to provide reasonably platform-independent handling of
- * infinity and NaN.  We assume that isinf() and isnan() are available
- * and work per spec.  (On some platforms, we have to supply our own;
- * see src/port.)  However, generating an Infinity or NaN in the first
- * place is less well standardized; pre-C99 systems tend not to have C99's
- * INFINITY and NAN macros.  We centralize our workarounds for this here.
- */
-
-double
-get_float8_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (double) INFINITY;
-#else
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (double) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-/*
-* The funny placements of the two #pragmas is necessary because of a
-* long lived bug in the Microsoft compilers.
-* See http://support.microsoft.com/kb/120968/en-us for details
-*/
-#if (_MSC_VER >= 1800)
-#pragma warning(disable:4756)
-#endif
-float
-get_float4_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (float) INFINITY;
-#else
-#if (_MSC_VER >= 1800)
-#pragma warning(default:4756)
-#endif
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (float) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-double
-get_float8_nan(void)
-{
-	/* (double) NAN doesn't work on some NetBSD/MIPS releases */
-#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
-	/* C99 standard way */
-	return (double) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (double) (0.0 / 0.0);
-#endif
-}
-
-float
-get_float4_nan(void)
-{
-#ifdef NAN
-	/* C99 standard way */
-	return (float) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (float) (0.0 / 0.0);
-#endif
-}
-
-
 /*
  * Returns -1 if 'val' represents negative infinity, 1 if 'val'
  * represents (positive) infinity, and 0 otherwise. On some platforms,
  * this is equivalent to the isinf() macro, but not everywhere: C99
  * does not specify that isinf() needs to distinguish between positive
  * and negative infinity.
  */
 int
 is_infinite(double val)
 {
@@ -336,21 +223,21 @@ float4in(PG_FUNCTION_ARGS)
 	if (*endptr != '\0')
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"real", orig_num)));
 
 	/*
 	 * if we get here, we have a legal double, still need to check to see if
 	 * it's a legal float4
 	 */
-	CHECKFLOATVAL((float4) val, isinf(val), val == 0);
+	check_float4_val((float4) val, isinf(val), val == 0);
 
 	PG_RETURN_FLOAT4((float4) val);
 }
 
 /*
  *		float4out		- converts a float4 number to a string
  *						  using a standard output format
  */
 Datum
 float4out(PG_FUNCTION_ARGS)
@@ -686,35 +573,35 @@ float4up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT4(arg);
 }
 
 Datum
 float4larger(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) > 0)
+	if (float4_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 Datum
 float4smaller(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) < 0)
+	if (float4_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 /*
  *		======================
  *		FLOAT8 BASE OPERATIONS
  *		======================
@@ -753,35 +640,35 @@ float8up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT8(arg);
 }
 
 Datum
 float8larger(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) > 0)
+	if (float8_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 Datum
 float8smaller(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) < 0)
+	if (float8_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		====================
  *		ARITHMETIC OPERATORS
@@ -792,234 +679,165 @@ float8smaller(PG_FUNCTION_ARGS)
  *		float4pl		- returns arg1 + arg2
  *		float4mi		- returns arg1 - arg2
  *		float4mul		- returns arg1 * arg2
  *		float4div		- returns arg1 / arg2
  */
 Datum
 float4pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 + arg2;
-
-	/*
-	 * There isn't any way to check for underflow of addition/subtraction
-	 * because numbers near the underflow value have already been rounded to
-	 * the point where we can't detect that the two values were originally
-	 * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
-	 * 1.4013e-45.
-	 */
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_pl(arg1, arg2));
 }
 
 Datum
 float4mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mi(arg1, arg2));
 }
 
 Datum
 float4mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mul(arg1, arg2));
 }
 
 Datum
 float4div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_div(arg1, arg2));
 }
 
 /*
  *		float8pl		- returns arg1 + arg2
  *		float8mi		- returns arg1 - arg2
  *		float8mul		- returns arg1 * arg2
  *		float8div		- returns arg1 / arg2
  */
 Datum
 float8pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 + arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, arg2));
 }
 
 Datum
 float8mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 - arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, arg2));
 }
 
 Datum
 float8mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 * arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, arg2));
 }
 
 Datum
 float8div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, arg2));
 }
 
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float4{eq,ne,lt,le,gt,ge}		- float4/float4 comparison operations
  */
 int
 float4_cmp_internal(float4 a, float4 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float4_gt(a, b))
+		return 1;
+	if (float4_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
 float4eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float4_eq(arg1, arg2));
 }
 
 Datum
 float4ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float4_ne(arg1, arg2));
 }
 
 Datum
 float4lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float4_lt(arg1, arg2));
 }
 
 Datum
 float4le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float4_le(arg1, arg2));
 }
 
 Datum
 float4gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float4_gt(arg1, arg2));
 }
 
 Datum
 float4ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float4_ge(arg1, arg2));
 }
 
 Datum
 btfloat4cmp(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
 	PG_RETURN_INT32(float4_cmp_internal(arg1, arg2));
 }
@@ -1041,99 +859,79 @@ btfloat4sortsupport(PG_FUNCTION_ARGS)
 	ssup->comparator = btfloat4fastcmp;
 	PG_RETURN_VOID();
 }
 
 /*
  *		float8{eq,ne,lt,le,gt,ge}		- float8/float8 comparison operations
  */
 int
 float8_cmp_internal(float8 a, float8 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float8_gt(a, b))
+		return 1;
+	if (float8_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
 float8eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, arg2));
 }
 
 Datum
 float8ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, arg2));
 }
 
 Datum
 float8lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, arg2));
 }
 
 Datum
 float8le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, arg2));
 }
 
 Datum
 float8gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, arg2));
 }
 
 Datum
 float8ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, arg2));
 }
 
 Datum
 btfloat8cmp(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
 	PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
 }
@@ -1334,21 +1132,21 @@ ftod(PG_FUNCTION_ARGS)
 
 
 /*
  *		dtof			- converts a float8 number to a float4 number
  */
 Datum
 dtof(PG_FUNCTION_ARGS)
 {
 	float8		num = PG_GETARG_FLOAT8(0);
 
-	CHECKFLOATVAL((float4) num, isinf(num), num == 0);
+	check_float4_val((float4) num, isinf(num), num == 0);
 
 	PG_RETURN_FLOAT4((float4) num);
 }
 
 
 /*
  *		dtoi4			- converts a float8 number to an int4 number
  */
 Datum
 dtoi4(PG_FUNCTION_ARGS)
@@ -1559,36 +1357,36 @@ dsqrt(PG_FUNCTION_ARGS)
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
 				 errmsg("cannot take square root of a negative number")));
 
 	result = sqrt(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcbrt			- returns cube root of arg1
  */
 Datum
 dcbrt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	result = cbrt(arg1);
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dpow			- returns pow(arg1,arg2)
  */
 Datum
 dpow(PG_FUNCTION_ARGS)
 {
@@ -1646,40 +1444,40 @@ dpow(PG_FUNCTION_ARGS)
 			/* The sign of Inf is not significant in this case. */
 			result = get_float8_infinity();
 		else if (fabs(arg1) != 1)
 			result = 0;
 		else
 			result = 1;
 	}
 	else if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
+	check_float8_val(result, isinf(arg1) || isinf(arg2), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dexp			- returns the exponential function of arg1
  */
 Datum
 dexp(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	errno = 0;
 	result = exp(arg1);
 	if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1), false);
+	check_float8_val(result, isinf(arg1), false);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dlog1			- returns the natural logarithm of arg1
  */
 Datum
 dlog1(PG_FUNCTION_ARGS)
 {
@@ -1694,21 +1492,21 @@ dlog1(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of zero")));
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of a negative number")));
 
 	result = log(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dlog10			- returns the base 10 logarithm of arg1
  */
 Datum
 dlog10(PG_FUNCTION_ARGS)
 {
@@ -1724,21 +1522,21 @@ dlog10(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of zero")));
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of a negative number")));
 
 	result = log10(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dacos			- returns the arccos of arg1 (radians)
  */
 Datum
 dacos(PG_FUNCTION_ARGS)
 {
@@ -1754,21 +1552,21 @@ dacos(PG_FUNCTION_ARGS)
 	 * range [-1, 1] to values in the range [0, Pi], so we should reject any
 	 * inputs outside that range and the result will always be finite.
 	 */
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = acos(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dasin			- returns the arcsin of arg1 (radians)
  */
 Datum
 dasin(PG_FUNCTION_ARGS)
 {
@@ -1784,21 +1582,21 @@ dasin(PG_FUNCTION_ARGS)
 	 * range [-1, 1] to values in the range [-Pi/2, Pi/2], so we should reject
 	 * any inputs outside that range and the result will always be finite.
 	 */
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = asin(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		datan			- returns the arctan of arg1 (radians)
  */
 Datum
 datan(PG_FUNCTION_ARGS)
 {
@@ -1809,21 +1607,21 @@ datan(PG_FUNCTION_ARGS)
 	if (isnan(arg1))
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/*
 	 * The principal branch of the inverse tangent function maps all inputs to
 	 * values in the range [-Pi/2, Pi/2], so the result should always be
 	 * finite, even if the input is infinite.
 	 */
 	result = atan(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		atan2			- returns the arctan of arg1/arg2 (radians)
  */
 Datum
 datan2(PG_FUNCTION_ARGS)
 {
@@ -1834,21 +1632,21 @@ datan2(PG_FUNCTION_ARGS)
 	/* Per the POSIX spec, return NaN if either input is NaN */
 	if (isnan(arg1) || isnan(arg2))
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/*
 	 * atan2 maps all inputs to values in the range [-Pi, Pi], so the result
 	 * should always be finite, even if the inputs are infinite.
 	 */
 	result = atan2(arg1, arg2);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcos			- returns the cosine of arg1 (radians)
  */
 Datum
 dcos(PG_FUNCTION_ARGS)
 {
@@ -1874,21 +1672,21 @@ dcos(PG_FUNCTION_ARGS)
 	 * platform reports via errno, so also explicitly test for infinite
 	 * inputs.
 	 */
 	errno = 0;
 	result = cos(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcot			- returns the cotangent of arg1 (radians)
  */
 Datum
 dcot(PG_FUNCTION_ARGS)
 {
@@ -1901,21 +1699,21 @@ dcot(PG_FUNCTION_ARGS)
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = tan(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = 1.0 / result;
-	CHECKFLOATVAL(result, true /* cot(0) == Inf */ , true);
+	check_float8_val(result, true /* cot(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dsin			- returns the sine of arg1 (radians)
  */
 Datum
 dsin(PG_FUNCTION_ARGS)
 {
@@ -1927,21 +1725,21 @@ dsin(PG_FUNCTION_ARGS)
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = sin(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dtan			- returns the tangent of arg1 (radians)
  */
 Datum
 dtan(PG_FUNCTION_ARGS)
 {
@@ -1953,21 +1751,21 @@ dtan(PG_FUNCTION_ARGS)
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = tan(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, true /* tan(pi/2) == Inf */ , true);
+	check_float8_val(result, true /* tan(pi/2) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /* ========== DEGREE-BASED TRIGONOMETRIC FUNCTIONS ========== */
 
 
 /*
  * Initialize the cached constants declared at the head of this file
  * (sin_30 etc).  The fact that we need those at all, let alone need this
@@ -2105,21 +1903,21 @@ dacosd(PG_FUNCTION_ARGS)
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	if (arg1 >= 0.0)
 		result = acosd_q1(arg1);
 	else
 		result = 90.0 + asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dasind			- returns the arcsin of arg1 (degrees)
  */
 Datum
 dasind(PG_FUNCTION_ARGS)
 {
@@ -2140,21 +1938,21 @@ dasind(PG_FUNCTION_ARGS)
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	if (arg1 >= 0.0)
 		result = asind_q1(arg1);
 	else
 		result = -asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		datand			- returns the arctan of arg1 (degrees)
  */
 Datum
 datand(PG_FUNCTION_ARGS)
 {
@@ -2170,21 +1968,21 @@ datand(PG_FUNCTION_ARGS)
 
 	/*
 	 * The principal branch of the inverse tangent function maps all inputs to
 	 * values in the range [-90, 90], so the result should always be finite,
 	 * even if the input is infinite.  Additionally, we take care to ensure
 	 * than when arg1 is 1, the result is exactly 45.
 	 */
 	atan_arg1 = atan(arg1);
 	result = (atan_arg1 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		atan2d			- returns the arctan of arg1/arg2 (degrees)
  */
 Datum
 datan2d(PG_FUNCTION_ARGS)
 {
@@ -2204,21 +2002,21 @@ datan2d(PG_FUNCTION_ARGS)
 	 * result should always be finite, even if the inputs are infinite.
 	 *
 	 * Note: this coding assumes that atan(1.0) is a suitable scaling constant
 	 * to get an exact result from atan2().  This might well fail on us at
 	 * some point, requiring us to decide exactly what inputs we think we're
 	 * going to guarantee an exact result for.
 	 */
 	atan2_arg1_arg2 = atan2(arg1, arg2);
 	result = (atan2_arg1_arg2 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		sind_0_to_30	- returns the sine of an angle that lies between 0 and
  *						  30 degrees.  This will return exactly 0 when x is 0,
  *						  and exactly 0.5 when x is 30 degrees.
  */
 static double
@@ -2325,21 +2123,21 @@ dcosd(PG_FUNCTION_ARGS)
 
 	if (arg1 > 90.0)
 	{
 		/* cosd(180-x) = -cosd(x) */
 		arg1 = 180.0 - arg1;
 		sign = -sign;
 	}
 
 	result = sign * cosd_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcotd			- returns the cotangent of arg1 (degrees)
  */
 Datum
 dcotd(PG_FUNCTION_ARGS)
 {
@@ -2390,21 +2188,21 @@ dcotd(PG_FUNCTION_ARGS)
 	result = sign * (cot_arg1 / cot_45);
 
 	/*
 	 * On some machines we get cotd(270) = minus zero, but this isn't always
 	 * true.  For portability, and because the user constituency for this
 	 * function probably doesn't want minus zero, force it to plain zero.
 	 */
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* cotd(0) == Inf */ , true);
+	check_float8_val(result, true /* cotd(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dsind			- returns the sine of arg1 (degrees)
  */
 Datum
 dsind(PG_FUNCTION_ARGS)
 {
@@ -2444,21 +2242,21 @@ dsind(PG_FUNCTION_ARGS)
 	}
 
 	if (arg1 > 90.0)
 	{
 		/* sind(180-x) = sind(x) */
 		arg1 = 180.0 - arg1;
 	}
 
 	result = sign * sind_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dtand			- returns the tangent of arg1 (degrees)
  */
 Datum
 dtand(PG_FUNCTION_ARGS)
 {
@@ -2509,64 +2307,56 @@ dtand(PG_FUNCTION_ARGS)
 	result = sign * (tan_arg1 / tan_45);
 
 	/*
 	 * On some machines we get tand(180) = minus zero, but this isn't always
 	 * true.  For portability, and because the user constituency for this
 	 * function probably doesn't want minus zero, force it to plain zero.
 	 */
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* tand(90) == Inf */ , true);
+	check_float8_val(result, true /* tand(90) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		degrees		- returns degrees converted from radians
  */
 Datum
 degrees(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
 
-	result = arg1 / RADIANS_PER_DEGREE;
-
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, RADIANS_PER_DEGREE));
 }
 
 
 /*
  *		dpi				- returns the constant PI
  */
 Datum
 dpi(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_FLOAT8(M_PI);
 }
 
 
 /*
  *		radians		- returns radians converted from degrees
  */
 Datum
 radians(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
 
-	result = arg1 * RADIANS_PER_DEGREE;
-
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, RADIANS_PER_DEGREE));
 }
 
 
 /*
  *		drandom		- returns a random number
  */
 Datum
 drandom(PG_FUNCTION_ARGS)
 {
 	float8		result;
@@ -2644,144 +2434,105 @@ check_float8_array(ArrayType *transarray, const char *caller, int n)
  * This function is used only in two stage aggregation and
  * shouldn't be called outside aggregate context.
  */
 Datum
 float8_combine(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_combine", 3);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-
 	transvalues2 = check_float8_array(transarray2, "float8_combine", 3);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
 
 Datum
 float8_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8		newval = PG_GETARG_FLOAT8(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float8_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
 	else
 	{
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
 								 sizeof(float8), FLOAT8PASSBYVAL, 'd');
 
 		PG_RETURN_ARRAYTYPE_P(result);
 	}
 }
 
 Datum
 float4_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 
 	/* do computations as float8 */
 	float8		newval = PG_GETARG_FLOAT4(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float4_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
 	else
 	{
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
 								 sizeof(float8), FLOAT8PASSBYVAL, 'd');
 
 		PG_RETURN_ARRAYTYPE_P(result);
 	}
 }
 
 Datum
@@ -2817,21 +2568,21 @@ float8_var_pop(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_var_pop", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Population variance is undefined when N is 0, so return NULL */
 	if (N == 0.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / (N * N));
 }
 
 Datum
 float8_var_samp(PG_FUNCTION_ARGS)
@@ -2846,21 +2597,21 @@ float8_var_samp(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_var_samp", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Sample variance is undefined when N is 0 or 1, so return NULL */
 	if (N <= 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
 }
 
 Datum
 float8_stddev_pop(PG_FUNCTION_ARGS)
@@ -2875,21 +2626,21 @@ float8_stddev_pop(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_stddev_pop", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Population stddev is undefined when N is 0, so return NULL */
 	if (N == 0.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(sqrt(numerator / (N * N)));
 }
 
 Datum
 float8_stddev_samp(PG_FUNCTION_ARGS)
@@ -2904,21 +2655,21 @@ float8_stddev_samp(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_stddev_samp", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Sample stddev is undefined when N is 0 or 1, so return NULL */
 	if (N <= 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(sqrt(numerator / (N * (N - 1.0))));
 }
 
 /*
  *		=========================
@@ -2953,30 +2704,30 @@ float8_regr_accum(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_accum", 6);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	N += 1.0;
 	sumX += newvalX;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
+	check_float8_val(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
 	sumX2 += newvalX * newvalX;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
+	check_float8_val(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
 	sumY += newvalY;
-	CHECKFLOATVAL(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
+	check_float8_val(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
 	sumY2 += newvalY * newvalY;
-	CHECKFLOATVAL(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
+	check_float8_val(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
 	sumXY += newvalX * newvalY;
-	CHECKFLOATVAL(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
-				  isinf(newvalY), true);
+	check_float8_val(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
+					 isinf(newvalY), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
 		transvalues[0] = N;
 		transvalues[1] = sumX;
@@ -3015,63 +2766,33 @@ float8_regr_accum(PG_FUNCTION_ARGS)
  * This function is used only in two stage aggregation and
  * shouldn't be called outside aggregate context.
  */
 Datum
 float8_regr_combine(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2,
-				sumY,
-				sumY2,
-				sumXY;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_regr_combine", 6);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-	sumY = transvalues1[3];
-	sumY2 = transvalues1[4];
-	sumXY = transvalues1[5];
-
 	transvalues2 = check_float8_array(transarray2, "float8_regr_combine", 6);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-	sumY += transvalues2[3];
-	CHECKFLOATVAL(sumY, isinf(transvalues1[3]) || isinf(transvalues2[3]),
-				  true);
-	sumY2 += transvalues2[4];
-	CHECKFLOATVAL(sumY2, isinf(transvalues1[4]) || isinf(transvalues2[4]),
-				  true);
-	sumXY += transvalues2[5];
-	CHECKFLOATVAL(sumXY, isinf(transvalues1[5]) || isinf(transvalues2[5]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
-	transvalues1[3] = sumY;
-	transvalues1[4] = sumY2;
-	transvalues1[5] = sumXY;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
+	transvalues1[3] = float8_pl(transvalues1[3], transvalues2[3]);
+	transvalues1[4] = float8_pl(transvalues1[4], transvalues2[4]);
+	transvalues1[5] = float8_pl(transvalues1[5], transvalues2[5]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
 
 
 Datum
 float8_regr_sxx(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
@@ -3083,21 +2804,21 @@ float8_regr_sxx(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_sxx", 6);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_syy(PG_FUNCTION_ARGS)
@@ -3112,21 +2833,21 @@ float8_regr_syy(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_syy", 6);
 	N = transvalues[0];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumY2) || isinf(sumY), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_sxy(PG_FUNCTION_ARGS)
@@ -3143,22 +2864,22 @@ float8_regr_sxy(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	/* A negative result is valid here */
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_avgx(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3211,22 +2932,22 @@ float8_covar_pop(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * N));
 }
 
 Datum
 float8_covar_samp(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
 	float8		N,
@@ -3239,22 +2960,22 @@ float8_covar_samp(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is <= 1 we should return NULL */
 	if (N < 2.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
 }
 
 Datum
 float8_corr(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
 	float8		N,
@@ -3273,26 +2994,26 @@ float8_corr(PG_FUNCTION_ARGS)
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0 || numeratorY <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXY / sqrt(numeratorX * numeratorY));
 }
 
 Datum
 float8_regr_r2(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3313,26 +3034,26 @@ float8_regr_r2(PG_FUNCTION_ARGS)
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 	/* per spec, horizontal line produces 1.0 */
 	if (numeratorY <= 0)
 		PG_RETURN_FLOAT8(1.0);
 
 	PG_RETURN_FLOAT8((numeratorXY * numeratorXY) /
 					 (numeratorX * numeratorY));
 }
 
@@ -3354,24 +3075,24 @@ float8_regr_slope(PG_FUNCTION_ARGS)
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXY / numeratorX);
 }
 
 Datum
 float8_regr_intercept(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3389,24 +3110,24 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXXY = sumY * sumX2 - sumX * sumXY;
-	CHECKFLOATVAL(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
-				  isinf(sumX) || isinf(sumXY), true);
+	check_float8_val(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
+					 isinf(sumX) || isinf(sumXY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXXY / numeratorX);
 }
 
 
 /*
  *		====================================
  *		MIXED-PRECISION ARITHMETIC OPERATORS
@@ -3417,251 +3138,211 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
  *		float48pl		- returns arg1 + arg2
  *		float48mi		- returns arg1 - arg2
  *		float48mul		- returns arg1 * arg2
  *		float48div		- returns arg1 / arg2
  */
 Datum
 float48pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 + arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl((float8) arg1, arg2));
 }
 
 Datum
 float48mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi((float8) arg1, arg2));
 }
 
 Datum
 float48mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul((float8) arg1, arg2));
 }
 
 Datum
 float48div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div((float8) arg1, arg2));
 }
 
 /*
  *		float84pl		- returns arg1 + arg2
  *		float84mi		- returns arg1 - arg2
  *		float84mul		- returns arg1 * arg2
  *		float84div		- returns arg1 / arg2
  */
 Datum
 float84pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 + arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, (float8) arg2));
 }
 
 Datum
 float84mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 - arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, (float8) arg2));
 }
 
 Datum
 float84mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 * arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, (float8) arg2));
 }
 
 Datum
 float84div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, (float8) arg2));
 }
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float48{eq,ne,lt,le,gt,ge}		- float4/float8 comparison operations
  */
 Datum
 float48eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq((float8) arg1, arg2));
 }
 
 Datum
 float48ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne((float8) arg1, arg2));
 }
 
 Datum
 float48lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt((float8) arg1, arg2));
 }
 
 Datum
 float48le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le((float8) arg1, arg2));
 }
 
 Datum
 float48gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt((float8) arg1, arg2));
 }
 
 Datum
 float48ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge((float8) arg1, arg2));
 }
 
 /*
  *		float84{eq,ne,lt,le,gt,ge}		- float8/float4 comparison operations
  */
 Datum
 float84eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, (float8) arg2));
 }
 
 Datum
 float84ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, (float8) arg2));
 }
 
 Datum
 float84lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, (float8) arg2));
 }
 
 Datum
 float84le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, (float8) arg2));
 }
 
 Datum
 float84gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, (float8) arg2));
 }
 
 Datum
 float84ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, (float8) arg2));
 }
 
 /*
  * Implements the float8 version of the width_bucket() function
  * defined by SQL2003. See also width_bucket_numeric().
  *
  * 'bound1' and 'bound2' are the lower and upper bounds of the
  * histogram's range, respectively. 'count' is the number of buckets
  * in the histogram. width_bucket() returns an integer indicating the
  * bucket number that 'operand' belongs to in an equiwidth histogram
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c
index a345c65605..30696e3575 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -84,20 +84,21 @@
 
 #ifdef USE_ICU
 #include <unicode/ustring.h>
 #endif
 
 #include "catalog/pg_collation.h"
 #include "mb/pg_wchar.h"
 #include "utils/builtins.h"
 #include "utils/date.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 #include "utils/formatting.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/pg_locale.h"
 
 /* ----------
  * Routines type
  * ----------
  */
 #define DCH_TYPE		1		/* DATE-TIME version	*/
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 3e7519015d..0f12684478 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -14,27 +14,23 @@
  */
 #include "postgres.h"
 
 #include <math.h>
 #include <limits.h>
 #include <float.h>
 #include <ctype.h>
 
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
-#include "utils/builtins.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index d7c807f8d9..5489ed9585 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -69,21 +69,21 @@
  *			src/backend/utils/adt/geo_spgist.c
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
 
 #include "access/spgist.h"
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
  * is going only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 82a14295ee..5a21160eb0 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -29,20 +29,21 @@
 #include "access/hash.h"
 #include "catalog/pg_type.h"
 #include "common/int.h"
 #include "funcapi.h"
 #include "lib/hyperloglog.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/sortsupport.h"
 
 /* ----------
  * Uncomment the following to enable compilation of dump_numeric()
  * and dump_var() and to get a dump of any result produced by make_result().
  * ----------
 #define NUMERIC_DEBUG
diff --git a/src/backend/utils/adt/rangetypes_gist.c b/src/backend/utils/adt/rangetypes_gist.c
index 2fe61043d9..450479e31c 100644
--- a/src/backend/utils/adt/rangetypes_gist.c
+++ b/src/backend/utils/adt/rangetypes_gist.c
@@ -9,21 +9,22 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_gist.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/gist.h"
 #include "access/stratnum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/datum.h"
 #include "utils/rangetypes.h"
 
 
 /*
  * Range class properties used to segregate different classes of ranges in
  * GiST.  Each unique combination of properties is a class.  CLS_EMPTY cannot
  * be combined with anything else.
  */
 #define CLS_NORMAL			0	/* Ordinary finite range (no bits set) */
diff --git a/src/backend/utils/adt/rangetypes_selfuncs.c b/src/backend/utils/adt/rangetypes_selfuncs.c
index 59761ecf34..f9a5117492 100644
--- a/src/backend/utils/adt/rangetypes_selfuncs.c
+++ b/src/backend/utils/adt/rangetypes_selfuncs.c
@@ -14,21 +14,22 @@
  *	  src/backend/utils/adt/rangetypes_selfuncs.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/htup_details.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 #include "utils/selfuncs.h"
 #include "utils/typcache.h"
 
 static double calc_rangesel(TypeCacheEntry *typcache, VariableStatData *vardata,
 			  RangeType *constval, Oid operator);
 static double default_range_selectivity(Oid operator);
 static double calc_hist_selectivity(TypeCacheEntry *typcache,
 					  VariableStatData *vardata, RangeType *constval,
diff --git a/src/backend/utils/adt/rangetypes_typanalyze.c b/src/backend/utils/adt/rangetypes_typanalyze.c
index f2c11f54bc..9c50e4c1be 100644
--- a/src/backend/utils/adt/rangetypes_typanalyze.c
+++ b/src/backend/utils/adt/rangetypes_typanalyze.c
@@ -19,21 +19,22 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_typanalyze.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "catalog/pg_operator.h"
 #include "commands/vacuum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 
 static int	float8_qsort_cmp(const void *a1, const void *a2);
 static int	range_bound_qsort_cmp(const void *a1, const void *a2, void *arg);
 static void compute_range_stats(VacAttrStats *stats,
 					AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows);
 
 /*
  * range_typanalyze -- typanalyze function for range columns
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 1d75caebe1..e7a4ee5ac7 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -27,20 +27,21 @@
 #include "common/int128.h"
 #include "funcapi.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
 #include "parser/scansup.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 /*
  * gcc's -ffast-math switch breaks routines that expect exact results from
  * expressions like timeval / SECS_PER_HOUR, where timeval is double.
  */
 #ifdef __FAST_MATH__
 #error -ffast-math is known to break this code
 #endif
 
 #define SAMESIGN(a,b)	(((a) < 0) == ((b) < 0))
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 17292e04fe..9484657030 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -73,20 +73,21 @@
 #include "storage/fd.h"
 #include "storage/large_object.h"
 #include "storage/pg_shmem.h"
 #include "storage/proc.h"
 #include "storage/predicate.h"
 #include "tcop/tcopprot.h"
 #include "tsearch/ts_cache.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/guc_tables.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/pg_locale.h"
 #include "utils/plancache.h"
 #include "utils/portal.h"
 #include "utils/ps_status.h"
 #include "utils/rls.h"
 #include "utils/snapmgr.h"
 #include "utils/tzparser.h"
 #include "utils/varlena.h"
 #include "utils/xml.h"
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index d0416e90fc..b83a22767a 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -43,34 +43,20 @@ extern int	namestrcmp(Name name, const char *str);
 
 /* numutils.c */
 extern int32 pg_atoi(const char *s, int size, int c);
 extern void pg_itoa(int16 i, char *a);
 extern void pg_ltoa(int32 l, char *a);
 extern void pg_lltoa(int64 ll, char *a);
 extern char *pg_ltostr_zeropad(char *str, int32 value, int32 minwidth);
 extern char *pg_ltostr(char *str, int32 value);
 extern uint64 pg_strtouint64(const char *str, char **endptr, int base);
 
-/* float.c */
-extern PGDLLIMPORT int extra_float_digits;
-
-extern double get_float8_infinity(void);
-extern float get_float4_infinity(void);
-extern double get_float8_nan(void);
-extern float get_float4_nan(void);
-extern int	is_infinite(double val);
-extern double float8in_internal(char *num, char **endptr_p,
-				  const char *type_name, const char *orig_string);
-extern char *float8out_internal(double num);
-extern int	float4_cmp_internal(float4 a, float4 b);
-extern int	float8_cmp_internal(float8 a, float8 b);
-
 /* oid.c */
 extern oidvector *buildoidvector(const Oid *oids, int n);
 extern Oid	oidparse(Node *node);
 extern int	oid_cmp(const void *p1, const void *p2);
 
 /* regexp.c */
 extern char *regexp_fixed_prefix(text *text_re, bool case_insensitive,
 					Oid collation, bool *exact);
 
 /* ruleutils.c */
diff --git a/src/include/utils/float.h b/src/include/utils/float.h
new file mode 100644
index 0000000000..48a16f491c
--- /dev/null
+++ b/src/include/utils/float.h
@@ -0,0 +1,377 @@
+/*-------------------------------------------------------------------------
+ *
+ * float.h
+ *	  Definitions for the built-in floating-point types
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/include/utils/float.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef FLOAT_H
+#define FLOAT_H
+
+#include <float.h>
+#include <math.h>
+
+#ifndef M_PI
+/* From my RH5.2 gcc math.h file - thomas 2000-04-03 */
+#define M_PI 3.14159265358979323846
+#endif
+
+/* Radians per degree, a.k.a. PI / 180 */
+#define RADIANS_PER_DEGREE 0.0174532925199432957692
+
+/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0. */
+#if defined(WIN32) && !defined(NAN)
+static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
+
+#define NAN (*(const float8 *) nan)
+#endif
+
+extern PGDLLIMPORT int extra_float_digits;
+
+/*
+ * Utility functions in float.c
+ */
+extern int	is_infinite(float8 val);
+extern float8 float8in_internal(char *num, char **endptr_p,
+				  const char *type_name, const char *orig_string);
+extern char *float8out_internal(float8 num);
+extern int	float4_cmp_internal(float4 a, float4 b);
+extern int	float8_cmp_internal(float8 a, float8 b);
+
+/*
+ * Routines to provide reasonably platform-independent handling of
+ * infinity and NaN
+ *
+ * We assume that isinf() and isnan() are available and work per spec.
+ * (On some platforms, we have to supply our own; see src/port.)  However,
+ * generating an Infinity or NaN in the first place is less well standardized;
+ * pre-C99 systems tend not to have C99's INFINITY and NaN macros.  We
+ * centralize our workarounds for this here.
+ */
+
+/*
+ * The funny placements of the two #pragmas is necessary because of a
+ * long lived bug in the Microsoft compilers.
+ * See http://support.microsoft.com/kb/120968/en-us for details
+ */
+#if (_MSC_VER >= 1800)
+#pragma warning(disable:4756)
+#endif
+static inline float4
+get_float4_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float4) INFINITY;
+#else
+#if (_MSC_VER >= 1800)
+#pragma warning(default:4756)
+#endif
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float4) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float8
+get_float8_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float8) INFINITY;
+#else
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float8) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float4
+get_float4_nan(void)
+{
+#ifdef NAN
+	/* C99 standard way */
+	return (float4) NAN;
+#else
+	/* Assume we can get a NAN via zero divide */
+	return (float4) (0.0 / 0.0);
+#endif
+}
+
+static inline float8
+get_float8_nan(void)
+{
+	/* (float8) NAN doesn't work on some NetBSD/MIPS releases */
+#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
+	/* C99 standard way */
+	return (float8) NAN;
+#else
+	/* Assume we can get a NaN via zero divide */
+	return (float8) (0.0 / 0.0);
+#endif
+}
+
+/*
+ * Checks to see if a float4/8 val has underflowed or overflowed
+ */
+
+static inline void
+check_float4_val(const float4 val, const bool inf_is_valid,
+				 const bool zero_is_valid)
+{
+	if (!inf_is_valid && unlikely(isinf(val)))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if (!zero_is_valid && unlikely(val == 0.0))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+static inline void
+check_float8_val(const float8 val, const bool inf_is_valid,
+				 const bool zero_is_valid)
+{
+	if (!inf_is_valid && unlikely(isinf(val)))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if (!zero_is_valid && unlikely(val == 0.0))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+/*
+ * Routines for operations with the checks above
+ *
+ * There isn't any way to check for underflow of addition/subtraction
+ * because numbers near the underflow value have already been rounded to
+ * the point where we can't detect that the two values were originally
+ * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
+ * 1.4013e-45.
+ */
+
+static inline float4
+float4_pl(const float4 val1, const float4 val2)
+{
+	float4		result;
+
+	result = val1 + val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_pl(const float8 val1, const float8 val2)
+{
+	float8		result;
+
+	result = val1 + val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mi(const float4 val1, const float4 val2)
+{
+	float4		result;
+
+	result = val1 - val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_mi(const float8 val1, const float8 val2)
+{
+	float8		result;
+
+	result = val1 - val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mul(const float4 val1, const float4 val2)
+{
+	float4		result;
+
+	result = val1 * val2;
+	check_float4_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0f || val2 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_mul(const float8 val1, const float8 val2)
+{
+	float8		result;
+
+	result = val1 * val2;
+	check_float8_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0 || val2 == 0.0);
+
+	return result;
+}
+
+static inline float4
+float4_div(const float4 val1, const float4 val2)
+{
+	float4		result;
+
+	if (val2 == 0.0f)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), val1 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_div(const float8 val1, const float8 val2)
+{
+	float8		result;
+
+	if (val2 == 0.0)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
+
+	return result;
+}
+
+/*
+ * Routines for NaN-aware comparisons
+ *
+ * We consider all NaNs to be equal and larger than any non-NaN. This is
+ * somewhat arbitrary; the important thing is to have a consistent sort
+ * order.
+ */
+
+static inline bool
+float4_eq(const float4 val1, const float4 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float8_eq(const float8 val1, const float8 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float4_ne(const float4 val1, const float4 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float8_ne(const float8 val1, const float8 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float4_lt(const float4 val1, const float4 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float8_lt(const float8 val1, const float8 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float4_le(const float4 val1, const float4 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float8_le(const float8 val1, const float8 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float4_gt(const float4 val1, const float4 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float8_gt(const float8 val1, const float8 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float4_ge(const float4 val1, const float4 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline bool
+float8_ge(const float8 val1, const float8 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline float4
+float4_min(const float4 val1, const float4 val2)
+{
+	return float4_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_min(const float8 val1, const float8 val2)
+{
+	return float8_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float4
+float4_max(const float4 val1, const float4 val2)
+{
+	return float4_gt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_max(const float8 val1, const float8 val2)
+{
+	return float8_gt(val1, val2) ? val1 : val2;
+}
+
+#endif							/* FLOAT_H */
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 0e066894cd..aeb31515e4 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -17,20 +17,21 @@
  *		and data types. There are still some more to do. - tgl 97/04/19
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEO_DECLS_H
 #define GEO_DECLS_H
 
 #include <math.h>
 
 #include "fmgr.h"
+#include "utils/float.h"
 
 /*--------------------------------------------------------------------
  * Useful floating point utilities and constants.
  *-------------------------------------------------------------------*/
 
 
 #define EPSILON					1.0E-06
 
 #ifdef EPSILON
 #define FPzero(A)				(fabs(A) <= EPSILON)
-- 
2.14.3 (Apple Git-98)

0003-geo-float-v11.patchapplication/octet-stream; name=0003-geo-float-v11.patchDownload
From 9e6024069cde94c16e6b7552f2405789d6d4a167 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 27 May 2017 16:17:42 -0400
Subject: [PATCH 3/6] geo-float-v11

Use the built-in float datatype to implement geometric types

This patch makes the geometric operators and functions use the exported
function of the float datatype.  The main reason of doing so is to check
for underflow and overflow, and to handle NaNs consciously.

The float datatypes consider NaNs to be equal and greater than any
non-NaN.  This change considers NaNs equal only for the equality
operators.  The placement operators, contains, overlaps, left/right of
etc. continues to return false when NaNs are involved.  We don't need
to worry about them being considered greater than any-NaN because there
aren't any basic comparison operators like less/greater than for the
geometric datatypes.

All changes can be summarised as:

* Check for underflow and overflow
* Check for division by zero
* Let the objects with NaN values to be the same
* Return NULL when the distance is NaN for all closest point operators
* Favour not-NaN over NaN where it makes sense

The patch also replaces all occurrences of "double" as "float8".  They
are the same, but were randomly spread on the same file.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com

Parallel discussions:

* https://www.postgresql.org/message-id/28685.1468246504%40sss.pgh.pa.us
---
 src/backend/access/gist/gistproc.c |  94 +++----
 src/backend/access/gist/gistutil.c |   3 -
 src/backend/utils/adt/float.c      |   2 -
 src/backend/utils/adt/formatting.c |   1 -
 src/backend/utils/adt/geo_ops.c    | 499 ++++++++++++++++++++-----------------
 src/backend/utils/adt/geo_spgist.c |  28 +--
 src/backend/utils/adt/numeric.c    |   2 -
 src/backend/utils/adt/timestamp.c  |   2 -
 src/backend/utils/misc/guc.c       |   2 -
 src/include/utils/geo_decls.h      |  19 +-
 10 files changed, 341 insertions(+), 311 deletions(-)

diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index 4bbfdadf9f..5e416ccfa7 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -10,26 +10,24 @@
  * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
  *	src/backend/access/gist/gistproc.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
-#include <float.h>
-#include <math.h>
-
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/geo_decls.h"
 
 
 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
 						 StrategyNumber strategy);
 static bool rtree_internal_consistent(BOX *key, BOX *query,
 						  StrategyNumber strategy);
 
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
@@ -48,55 +46,56 @@ rt_box_union(BOX *n, const BOX *a, const BOX *b)
 	n->high.x = float8_max(a->high.x, b->high.x);
 	n->high.y = float8_max(a->high.y, b->high.y);
 	n->low.x = float8_min(a->low.x, b->low.x);
 	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
 	if (float8_le(box->high.x, box->low.x) ||
 		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
-	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
+	return float8_mul(float8_mi(box->high.x, box->low.x),
+					  float8_mi(box->high.y, box->low.y));
 }
 
 /*
  * Return amount by which the union of the two boxes is larger than
  * the original BOX's area.  The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 box_penalty(const BOX *original, const BOX *new)
 {
 	BOX			unionbox;
 
 	rt_box_union(&unionbox, original, new);
-	return size_box(&unionbox) - size_box(original);
+	return float8_mi(size_box(&unionbox), size_box(original));
 }
 
 /*
  * The GiST Consistent method for boxes
  *
  * Should return false if for all data items x below entry,
  * the predicate x op query must be false, where op is the oper
  * corresponding to strategy in the pg_amop table.
  */
 Datum
@@ -256,74 +255,74 @@ fallbackSplit(GistEntryVector *entryvec, GIST_SPLITVEC *v)
 
 /*
  * Represents information about an entry that can be placed to either group
  * without affecting overlap over selected axis ("common entry").
  */
 typedef struct
 {
 	/* Index of entry in the initial array */
 	int			index;
 	/* Delta between penalties of entry insertion into different groups */
-	double		delta;
+	float8		delta;
 } CommonEntry;
 
 /*
  * Context for g_box_consider_split. Contains information about currently
  * selected split and some general information.
  */
 typedef struct
 {
 	int			entriesCount;	/* total number of entries being split */
 	BOX			boundingBox;	/* minimum bounding box across all entries */
 
 	/* Information about currently selected split follows */
 
 	bool		first;			/* true if no split was selected yet */
 
-	double		leftUpper;		/* upper bound of left interval */
-	double		rightLower;		/* lower bound of right interval */
+	float8		leftUpper;		/* upper bound of left interval */
+	float8		rightLower;		/* lower bound of right interval */
 
 	float4		ratio;
 	float4		overlap;
 	int			dim;			/* axis of this split */
-	double		range;			/* width of general MBR projection to the
+	float8		range;			/* width of general MBR projection to the
 								 * selected axis */
 } ConsiderSplitContext;
 
 /*
  * Interval represents projection of box to axis.
  */
 typedef struct
 {
-	double		lower,
+	float8		lower,
 				upper;
 } SplitInterval;
 
 /*
  * Interval comparison function by lower bound of the interval;
  */
 static int
 interval_cmp_lower(const void *i1, const void *i2)
 {
-	double		lower1 = ((const SplitInterval *) i1)->lower,
+	float8		lower1 = ((const SplitInterval *) i1)->lower,
 				lower2 = ((const SplitInterval *) i2)->lower;
 
 	return float8_cmp_internal(lower1, lower2);
 }
 
 /*
  * Interval comparison function by upper bound of the interval;
  */
 static int
 interval_cmp_upper(const void *i1, const void *i2)
 {
-	double		upper1 = ((const SplitInterval *) i1)->upper,
+	float8		upper1 = ((const SplitInterval *) i1)->upper,
 				upper2 = ((const SplitInterval *) i2)->upper;
 
 	return float8_cmp_internal(upper1, upper2);
 }
 
 /*
  * Replace negative (or NaN) value with zero.
  */
 static inline float
 non_negative(float val)
@@ -332,28 +331,28 @@ non_negative(float val)
 		return val;
 	else
 		return 0.0f;
 }
 
 /*
  * Consider replacement of currently selected split with the better one.
  */
 static inline void
 g_box_consider_split(ConsiderSplitContext *context, int dimNum,
-					 double rightLower, int minLeftCount,
-					 double leftUpper, int maxLeftCount)
+					 float8 rightLower, int minLeftCount,
+					 float8 leftUpper, int maxLeftCount)
 {
 	int			leftCount,
 				rightCount;
 	float4		ratio,
 				overlap;
-	double		range;
+	float8		range;
 
 	/*
 	 * Calculate entries distribution ratio assuming most uniform distribution
 	 * of common entries.
 	 */
 	if (minLeftCount >= (context->entriesCount + 1) / 2)
 	{
 		leftCount = minLeftCount;
 	}
 	else
@@ -362,40 +361,41 @@ g_box_consider_split(ConsiderSplitContext *context, int dimNum,
 			leftCount = maxLeftCount;
 		else
 			leftCount = context->entriesCount / 2;
 	}
 	rightCount = context->entriesCount - leftCount;
 
 	/*
 	 * Ratio of split - quotient between size of lesser group and total
 	 * entries count.
 	 */
-	ratio = ((float4) Min(leftCount, rightCount)) /
-		((float4) context->entriesCount);
+	ratio = float4_div(Min(leftCount, rightCount), context->entriesCount);
 
 	if (ratio > LIMIT_RATIO)
 	{
 		bool		selectthis = false;
 
 		/*
 		 * The ratio is acceptable, so compare current split with previously
 		 * selected one. Between splits of one dimension we search for minimal
 		 * overlap (allowing negative values) and minimal ration (between same
 		 * overlaps. We switch dimension if find less overlap (non-negative)
 		 * or less range with same overlap.
 		 */
 		if (dimNum == 0)
-			range = context->boundingBox.high.x - context->boundingBox.low.x;
+			range = float8_mi(context->boundingBox.high.x,
+							  context->boundingBox.low.x);
 		else
-			range = context->boundingBox.high.y - context->boundingBox.low.y;
+			range = float8_mi(context->boundingBox.high.y,
+							  context->boundingBox.low.y);
 
-		overlap = (leftUpper - rightLower) / range;
+		overlap = float8_div(float8_mi(leftUpper, rightLower), range);
 
 		/* If there is no previous selection, select this */
 		if (context->first)
 			selectthis = true;
 		else if (context->dim == dimNum)
 		{
 			/*
 			 * Within the same dimension, choose the new split if it has a
 			 * smaller overlap, or same overlap but better ratio.
 			 */
@@ -524,21 +524,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		else
 			adjustBox(&context.boundingBox, box);
 	}
 
 	/*
 	 * Iterate over axes for optimal split searching.
 	 */
 	context.first = true;		/* nothing selected yet */
 	for (dim = 0; dim < 2; dim++)
 	{
-		double		leftUpper,
+		float8		leftUpper,
 					rightLower;
 		int			i1,
 					i2;
 
 		/* Project each entry as an interval on the selected axis. */
 		for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 		{
 			box = DatumGetBoxP(entryvec->vector[i].key);
 			if (dim == 0)
 			{
@@ -721,21 +721,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 			*rightBox = *(box);					\
 		v->spl_right[v->spl_nright++] = off;	\
 	} while(0)
 
 	/*
 	 * Distribute entries which can be distributed unambiguously, and collect
 	 * common entries.
 	 */
 	for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 	{
-		double		lower,
+		float8		lower,
 					upper;
 
 		/*
 		 * Get upper and lower bounds along selected axis.
 		 */
 		box = DatumGetBoxP(entryvec->vector[i].key);
 		if (context.dim == 0)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
@@ -776,31 +776,31 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
 	{
 		/*
 		 * Calculate minimum number of entries that must be placed in both
 		 * groups, to reach LIMIT_RATIO.
 		 */
-		int			m = ceil(LIMIT_RATIO * (double) nentries);
+		int			m = ceil(LIMIT_RATIO * (float8) nentries);
 
 		/*
 		 * Calculate delta between penalties of join "common entries" to
 		 * different groups.
 		 */
 		for (i = 0; i < commonEntriesCount; i++)
 		{
 			box = DatumGetBoxP(entryvec->vector[commonEntries[i].index].key);
-			commonEntries[i].delta = Abs(box_penalty(leftBox, box) -
-										 box_penalty(rightBox, box));
+			commonEntries[i].delta = Abs(float8_mi(box_penalty(leftBox, box),
+												   box_penalty(rightBox, box)));
 		}
 
 		/*
 		 * Sort "common entries" by calculated deltas in order to distribute
 		 * the most ambiguous entries first.
 		 */
 		qsort(commonEntries, commonEntriesCount, sizeof(CommonEntry), common_entry_cmp);
 
 		/*
 		 * Distribute "common entries" between groups.
@@ -1100,24 +1100,24 @@ gist_circle_compress(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	GISTENTRY  *retval;
 
 	if (entry->leafkey)
 	{
 		CIRCLE	   *in = DatumGetCircleP(entry->key);
 		BOX		   *r;
 
 		r = (BOX *) palloc(sizeof(BOX));
-		r->high.x = in->center.x + in->radius;
-		r->low.x = in->center.x - in->radius;
-		r->high.y = in->center.y + in->radius;
-		r->low.y = in->center.y - in->radius;
+		r->high.x = float8_pl(in->center.x, in->radius);
+		r->low.x = float8_mi(in->center.x, in->radius);
+		r->high.y = float8_pl(in->center.y, in->radius);
+		r->low.y = float8_mi(in->center.y, in->radius);
 
 		retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
 		gistentryinit(*retval, PointerGetDatum(r),
 					  entry->rel, entry->page,
 					  entry->offset, false);
 	}
 	else
 		retval = entry;
 	PG_RETURN_POINTER(retval);
 }
@@ -1141,24 +1141,24 @@ gist_circle_consistent(PG_FUNCTION_ARGS)
 	*recheck = true;
 
 	if (DatumGetBoxP(entry->key) == NULL || query == NULL)
 		PG_RETURN_BOOL(false);
 
 	/*
 	 * Since the operators require recheck anyway, we can just use
 	 * rtree_internal_consistent even at leaf nodes.  (This works in part
 	 * because the index entries are bounding boxes not circles.)
 	 */
-	bbox.high.x = query->center.x + query->radius;
-	bbox.low.x = query->center.x - query->radius;
-	bbox.high.y = query->center.y + query->radius;
-	bbox.low.y = query->center.y - query->radius;
+	bbox.high.x = float8_pl(query->center.x, query->radius);
+	bbox.low.x = float8_mi(query->center.x, query->radius);
+	bbox.high.y = float8_pl(query->center.y, query->radius);
+	bbox.low.y = float8_mi(query->center.y, query->radius);
 
 	result = rtree_internal_consistent(DatumGetBoxP(entry->key),
 									   &bbox, strategy);
 
 	PG_RETURN_BOOL(result);
 }
 
 /**************************************************
  * Point ops
  **************************************************/
@@ -1209,63 +1209,63 @@ gist_point_fetch(PG_FUNCTION_ARGS)
 				  entry->offset, false);
 
 	PG_RETURN_POINTER(retval);
 }
 
 
 #define point_point_distance(p1,p2) \
 	DatumGetFloat8(DirectFunctionCall2(point_distance, \
 									   PointPGetDatum(p1), PointPGetDatum(p2)))
 
-static double
+static float8
 computeDistance(bool isLeaf, BOX *box, Point *point)
 {
-	double		result = 0.0;
+	float8		result = 0.0;
 
 	if (isLeaf)
 	{
 		/* simple point to point distance */
 		result = point_point_distance(point, &box->low);
 	}
 	else if (point->x <= box->high.x && point->x >= box->low.x &&
 			 point->y <= box->high.y && point->y >= box->low.y)
 	{
 		/* point inside the box */
 		result = 0.0;
 	}
 	else if (point->x <= box->high.x && point->x >= box->low.x)
 	{
 		/* point is over or below box */
 		Assert(box->low.y <= box->high.y);
 		if (point->y > box->high.y)
-			result = point->y - box->high.y;
+			result = float8_mi(point->y, box->high.y);
 		else if (point->y < box->low.y)
-			result = box->low.y - point->y;
+			result = float8_mi(box->low.y, point->y);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
 	else if (point->y <= box->high.y && point->y >= box->low.y)
 	{
 		/* point is to left or right of box */
 		Assert(box->low.x <= box->high.x);
 		if (point->x > box->high.x)
-			result = point->x - box->high.x;
+			result = float8_mi(point->x, box->high.x);
 		else if (point->x < box->low.x)
-			result = box->low.x - point->x;
+			result = float8_mi(box->low.x, point->x);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
 	else
 	{
 		/* closest point will be a vertex */
 		Point		p;
-		double		subresult;
+		float8		subresult;
 
 		result = point_point_distance(point, &box->low);
 
 		subresult = point_point_distance(point, &box->high);
 		if (result > subresult)
 			result = subresult;
 
 		p.x = box->low.x;
 		p.y = box->high.y;
 		subresult = point_point_distance(point, &p);
@@ -1442,21 +1442,21 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 	}
 
 	PG_RETURN_BOOL(result);
 }
 
 Datum
 gist_point_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(GIST_LEAF(entry),
 									   DatumGetBoxP(entry->key),
 									   PG_GETARG_POINT_P(1));
 			break;
 		default:
@@ -1471,25 +1471,25 @@ gist_point_distance(PG_FUNCTION_ARGS)
 /*
  * The inexact GiST distance method for geometric types that store bounding
  * boxes.
  *
  * Compute lossy distance from point to index entries.  The result is inexact
  * because index entries are bounding boxes, not the exact shapes of the
  * indexed geometric types.  We use distance from point to MBR of index entry.
  * This is a lower bound estimate of distance from point to indexed geometric
  * type.
  */
-static double
+static float8
 gist_bbox_distance(GISTENTRY *entry, Datum query,
 				   StrategyNumber strategy, bool *recheck)
 {
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	/* Bounding box distance is always inexact. */
 	*recheck = true;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(false,
 									   DatumGetBoxP(entry->key),
@@ -1505,32 +1505,32 @@ gist_bbox_distance(GISTENTRY *entry, Datum query,
 
 Datum
 gist_circle_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
 
 Datum
 gist_poly_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 7e43b8fc87..6f314a2602 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -6,23 +6,20 @@
  *
  * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
  *			src/backend/access/gist/gistutil.c
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
-#include <float.h>
-#include <math.h>
-
 #include "access/gist_private.h"
 #include "access/htup_details.h"
 #include "access/reloptions.h"
 #include "catalog/pg_opclass.h"
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
 #include "utils/float.h"
 #include "utils/syscache.h"
 
 
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index df35557b73..898a5490df 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -8,22 +8,20 @@
  *
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/float.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include <ctype.h>
-#include <float.h>
-#include <math.h>
 #include <limits.h>
 
 #include "catalog/pg_type.h"
 #include "common/int.h"
 #include "libpq/pqformat.h"
 #include "utils/array.h"
 #include "utils/float.h"
 #include "utils/fmgrprotos.h"
 #include "utils/sortsupport.h"
 
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c
index 30696e3575..996f8e336b 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -61,21 +61,20 @@
 
 #ifdef DEBUG_TO_FROM_CHAR
 #define DEBUG_elog_output	DEBUG3
 #endif
 
 #include "postgres.h"
 
 #include <ctype.h>
 #include <unistd.h>
 #include <math.h>
-#include <float.h>
 #include <limits.h>
 
 /*
  * towlower() and friends should be in <wctype.h>, but some pre-C99 systems
  * declare them in <wchar.h>.
  */
 #ifdef HAVE_WCHAR_H
 #include <wchar.h>
 #endif
 #ifdef HAVE_WCTYPE_H
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 0f12684478..df185affcb 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -51,56 +51,56 @@ static inline float8 line_invsl(LINE *line);
 static bool	line_interpt_line(Point *result, LINE *l1, LINE *l2);
 static bool line_contain_point(LINE *line, Point *point);
 static float8 line_closept_point(Point *result, LINE *line, Point *pt);
 
 /* Routines for line segments */
 static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
 static inline float8 lseg_sl(LSEG *lseg);
 static inline float8 lseg_invsl(LSEG *lseg);
 static bool	lseg_interpt_line(Point *result, LSEG *lseg, LINE *line);
 static bool	lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2);
-static int	lseg_crossing(double x, double y, double px, double py);
+static int	lseg_crossing(float8 x, float8 y, float8 px, float8 py);
 static bool	lseg_contain_point(LSEG *lseg, Point *point);
 static float8 lseg_closept_point(Point *result, LSEG *lseg, Point *pt);
 static float8 lseg_closept_line(Point *result, LSEG *lseg, LINE *line);
 static float8 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2);
 
 /* Routines for boxes */
 static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
 static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
-static double box_ar(BOX *box);
-static double box_ht(BOX *box);
-static double box_wd(BOX *box);
+static float8 box_ar(BOX *box);
+static float8 box_ht(BOX *box);
+static float8 box_wd(BOX *box);
 static bool box_contain_point(BOX *box, Point *point);
 static bool box_contain_box(BOX *box1, BOX *box2);
 static bool box_contain_lseg(BOX *box, LSEG *lseg);
 static bool box_interpt_lseg(Point *result, BOX *box, LSEG *lseg);
 static float8 box_closept_point(Point *result, BOX *box, Point *point);
 static float8 box_closept_lseg(Point *result, BOX *box, LSEG *lseg);
 
 /* Routines for circles */
-static double circle_ar(CIRCLE *circle);
+static float8 circle_ar(CIRCLE *circle);
 
 /* Routines for polygons */
 static void make_bound_box(POLYGON *poly);
 static void poly_to_circle(CIRCLE *result, POLYGON *poly);
 static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
 static bool poly_contain_poly(POLYGON *polya, POLYGON *polyb);
 static bool plist_same(int npts, Point *p1, Point *p2);
 static float8 dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 /* Routines for encoding and decoding */
-static double single_decode(char *num, char **endptr_p,
+static float8 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
-static void pair_decode(char *str, double *x, double *y, char **endptr_p,
+static void pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
 static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
 
 
 /*
@@ -138,38 +138,38 @@ static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
  *
  * For boxes, the points are opposite corners with the first point at the top right.
  * For closed paths and polygons, the points should be reordered to allow
  *	fast and correct equality comparisons.
  *
  * XXX perhaps points in complex shapes should be reordered internally
  *	to allow faster internal operations, but should keep track of input order
  *	and restore that order for text output - tgl 97/01/16
  */
 
-static double
+static float8
 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string)
 {
 	return float8in_internal(num, endptr_p, type_name, orig_string);
 }								/* single_decode() */
 
 static void
 single_encode(float8 x, StringInfo str)
 {
 	char	   *xstr = float8out_internal(x);
 
 	appendStringInfoString(str, xstr);
 	pfree(xstr);
 }								/* single_encode() */
 
 static void
-pair_decode(char *str, double *x, double *y, char **endptr_p,
+pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string)
 {
 	bool		has_delim;
 
 	while (isspace((unsigned char) *str))
 		str++;
 	if ((has_delim = (*str == LDELIM)))
 		str++;
 
 	*x = float8in_internal(str, &str, type_name, orig_string);
@@ -368,33 +368,33 @@ pair_count(char *s, char delim)
  *		External format: (two corners of box)
  *				"(f8, f8), (f8, f8)"
  *				also supports the older style "(f8, f8, f8, f8)"
  */
 Datum
 box_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	BOX		   *box = (BOX *) palloc(sizeof(BOX));
 	bool		isopen;
-	double		x,
+	float8		x,
 				y;
 
 	path_decode(str, false, 2, &(box->high), &isopen, NULL, "box", str);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*		box_out -		convert a box to external form.
@@ -408,38 +408,38 @@ box_out(PG_FUNCTION_ARGS)
 }
 
 /*
  *		box_recv			- converts external binary format to box
  */
 Datum
 box_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	BOX		   *box;
-	double		x,
+	float8		x,
 				y;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
 	box->high.x = pq_getmsgfloat8(buf);
 	box->high.y = pq_getmsgfloat8(buf);
 	box->low.x = pq_getmsgfloat8(buf);
 	box->low.y = pq_getmsgfloat8(buf);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*
@@ -458,31 +458,31 @@ box_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, box->low.y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*		box_construct	-		fill in a new box.
  */
 static inline void
 box_construct(BOX *result, Point *pt1, Point *pt2)
 {
-	if (pt1->x > pt2->x)
+	if (float8_gt(pt1->x, pt2->x))
 	{
 		result->high.x = pt1->x;
 		result->low.x = pt2->x;
 	}
 	else
 	{
 		result->high.x = pt2->x;
 		result->low.x = pt1->x;
 	}
-	if (pt1->y > pt2->y)
+	if (float8_gt(pt1->y, pt2->y))
 	{
 		result->high.y = pt1->y;
 		result->low.y = pt2->y;
 	}
 	else
 	{
 		result->high.y = pt2->y;
 		result->low.y = pt1->y;
 	}
 }
@@ -800,54 +800,54 @@ box_center(PG_FUNCTION_ARGS)
 	Point	   *result = (Point *) palloc(sizeof(Point));
 
 	box_cn(result, box);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		box_ar	-		returns the area of the box.
  */
-static double
+static float8
 box_ar(BOX *box)
 {
-	return box_wd(box) * box_ht(box);
+	return float8_mul(box_wd(box), box_ht(box));
 }
 
 
 /*		box_cn	-		stores the centerpoint of the box into *center.
  */
 static void
 box_cn(Point *center, BOX *box)
 {
-	center->x = (box->high.x + box->low.x) / 2.0;
-	center->y = (box->high.y + box->low.y) / 2.0;
+	center->x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	center->y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 }
 
 
 /*		box_wd	-		returns the width (length) of the box
  *								  (horizontal magnitude).
  */
-static double
+static float8
 box_wd(BOX *box)
 {
-	return box->high.x - box->low.x;
+	return float8_mi(box->high.x, box->low.x);
 }
 
 
 /*		box_ht	-		returns the height of the box
  *								  (vertical magnitude).
  */
-static double
+static float8
 box_ht(BOX *box)
 {
-	return box->high.y - box->low.y;
+	return float8_mi(box->high.y, box->low.y);
 }
 
 
 /*----------------------------------------------------------
  *	Funky operations.
  *---------------------------------------------------------*/
 
 /*		box_intersect	-
  *				returns the overlapping portion of two boxes,
  *				  or NULL if they do not intersect.
@@ -857,24 +857,24 @@ box_intersect(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 	BOX		   *result;
 
 	if (!box_ov(box1, box2))
 		PG_RETURN_NULL();
 
 	result = (BOX *) palloc(sizeof(BOX));
 
-	result->high.x = Min(box1->high.x, box2->high.x);
-	result->low.x = Max(box1->low.x, box2->low.x);
-	result->high.y = Min(box1->high.y, box2->high.y);
-	result->low.y = Max(box1->low.y, box2->low.y);
+	result->high.x = float8_min(box1->high.x, box2->high.x);
+	result->low.x = float8_max(box1->low.x, box2->low.x);
+	result->high.y = float8_min(box1->high.y, box2->high.y);
+	result->low.y = float8_max(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(result);
 }
 
 
 /*		box_diagonal	-
  *				returns a line segment which happens to be the
  *				  positive-slope diagonal of "box".
  */
 Datum
@@ -1006,30 +1006,30 @@ line_send(PG_FUNCTION_ARGS)
 
 /*
  * Fill already-allocated LINE struct from the point and the slope
  */
 static inline void
 line_construct(LINE *result, Point *pt, float8 m)
 {
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
-		result->A = -1;
-		result->B = 0;
+		result->A = -1.0;
+		result->B = 0.0;
 		result->C = pt->x;
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
-		result->C = pt->y - m * pt->x;
+		result->C = float8_mi(pt->y, float8_mul(m, pt->x));
 	}
 }
 
 /* line_construct_pp()
  * two points
  */
 Datum
 line_construct_pp(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
@@ -1068,94 +1068,105 @@ Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
 	else if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
 
-	PG_RETURN_BOOL(FPeq(((l1->A * l2->B) / (l1->B * l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
+								   float8_mul(l1->B, l2->A)), -1.0));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
 Datum
 line_horizontal(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->A));
 }
 
+
+/*
+ * Check whether the two lines are the same
+ *
+ * We consider NaNs values to be equal to each other to let those lines
+ * to be found.
+ */
 Datum
 line_eq(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	double		k;
+	float8		ratio;
 
-	if (!FPzero(l2->A))
-		k = l1->A / l2->A;
-	else if (!FPzero(l2->B))
-		k = l1->B / l2->B;
-	else if (!FPzero(l2->C))
-		k = l1->C / l2->C;
+	if (!FPzero(l2->A) && !isnan(l2->A))
+		ratio = float8_div(l1->A, l2->A);
+	else if (!FPzero(l2->B) && !isnan(l2->B))
+		ratio = float8_div(l1->B, l2->B);
+	else if (!FPzero(l2->C) && !isnan(l2->C))
+		ratio = float8_div(l1->C, l2->C);
 	else
-		k = 1.0;
+		ratio = 1.0;
 
-	PG_RETURN_BOOL(FPeq(l1->A, k * l2->A) &&
-				   FPeq(l1->B, k * l2->B) &&
-				   FPeq(l1->C, k * l2->C));
+	PG_RETURN_BOOL((FPeq(l1->A, float8_mul(ratio, l2->A)) &&
+					FPeq(l1->B, float8_mul(ratio, l2->B)) &&
+					FPeq(l1->C, float8_mul(ratio, l2->C))) ||
+				   (float8_eq(l1->A, l2->A) &&
+					float8_eq(l1->B, l2->B) &&
+					float8_eq(l1->C, l2->C)));
 }
 
 
 /*----------------------------------------------------------
  *	Line arithmetic routines.
  *---------------------------------------------------------*/
 
 /*
  * Return inverse slope of the line
  */
 static inline float8
 line_invsl(LINE *line)
 {
 	if (FPzero(line->A))
 		return DBL_MAX;
 	if (FPzero(line->B))
 		return 0.0;
-	return line->B / line->A;
+	return float8_div(line->B, line->A);
 }
 
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
 	Point		tmp;
 
 	if (line_interpt_line(NULL, l1, l2))	/* intersecting? */
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
+		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
 	point_construct(&tmp, 0.0, l1->C);
 	result = line_closept_point(NULL, l2, &tmp);
 	PG_RETURN_FLOAT8(result);
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
@@ -1174,47 +1185,51 @@ line_interpt(PG_FUNCTION_ARGS)
 /*
  * Internal version of line_interpt
  *
  * This returns true if two lines intersect (they do, if they are not
  * parallel), false if they do not.  This also sets the intersection point
  * to *result, if it is not NULL.
  *
  * NOTE: If the lines are identical then we will find they are parallel
  * and report "no intersection".  This is a little weird, but since
  * there's no *unique* intersection, maybe it's appropriate behavior.
+ *
+ * If the lines have NaN constants, we will return true, and the intersection
+ * point would have NaN coordinates.  We shouldn't return false in this case
+ * because that would mean the lines are parallel.
  */
 static bool
 line_interpt_line(Point *result, LINE *l1, LINE *l2)
 {
-	double		x,
+	float8		x,
 				y;
 
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
 		if (FPzero(l2->B))		/* l2 vertical? */
 			return false;
 
 		x = l1->C;
-		y = (l2->A * x + l2->C);
+		y = float8_pl(float8_mul(l2->A, x), l2->C);
 	}
 	else if (FPzero(l2->B))		/* l2 vertical? */
 	{
 		x = l2->C;
-		y = (l1->A * x + l1->C);
+		y = float8_pl(float8_mul(l1->A, x), l1->C);
 	}
 	else
 	{
-		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
 			return false;
 
-		x = (l1->C - l2->C) / (l2->A - l1->A);
-		y = (l1->A * x + l1->C);
+		x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
+		y = float8_pl(float8_mul(l1->A, x), l1->C);
 	}
 
 	if (result != NULL)
 		point_construct(result, x, y);
 
 	return true;
 }
 
 
 /***********************************************************************
@@ -1236,36 +1251,35 @@ line_interpt_line(Point *result, LINE *l1, LINE *l2)
  *				"(xcoord, ycoord),... "
  *				"[xcoord, ycoord,... ]"
  *		Also support older format:
  *				"(closed, npts, xcoord, ycoord,... )"
  *---------------------------------------------------------*/
 
 Datum
 path_area(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P(0);
-	double		area = 0.0;
+	float8		area = 0.0;
 	int			i,
 				j;
 
 	if (!path->closed)
 		PG_RETURN_NULL();
 
 	for (i = 0; i < path->npts; i++)
 	{
 		j = (i + 1) % path->npts;
-		area += path->p[i].x * path->p[j].y;
-		area -= path->p[i].y * path->p[j].x;
+		area = float8_pl(area, float8_mul(path->p[i].x, path->p[j].y));
+		area = float8_mi(area, float8_mul(path->p[i].y, path->p[j].x));
 	}
 
-	area *= 0.5;
-	PG_RETURN_FLOAT8(area < 0.0 ? -area : area);
+	PG_RETURN_FLOAT8(float8_div(fabs(area), 2.0));
 }
 
 
 Datum
 path_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	PATH	   *path;
 	bool		isopen;
 	char	   *s;
@@ -1521,33 +1535,33 @@ path_inter(PG_FUNCTION_ARGS)
 				j;
 	LSEG		seg1,
 				seg2;
 
 	Assert(p1->npts > 0 && p2->npts > 0);
 
 	b1.high.x = b1.low.x = p1->p[0].x;
 	b1.high.y = b1.low.y = p1->p[0].y;
 	for (i = 1; i < p1->npts; i++)
 	{
-		b1.high.x = Max(p1->p[i].x, b1.high.x);
-		b1.high.y = Max(p1->p[i].y, b1.high.y);
-		b1.low.x = Min(p1->p[i].x, b1.low.x);
-		b1.low.y = Min(p1->p[i].y, b1.low.y);
+		b1.high.x = float8_max(p1->p[i].x, b1.high.x);
+		b1.high.y = float8_max(p1->p[i].y, b1.high.y);
+		b1.low.x = float8_min(p1->p[i].x, b1.low.x);
+		b1.low.y = float8_min(p1->p[i].y, b1.low.y);
 	}
 	b2.high.x = b2.low.x = p2->p[0].x;
 	b2.high.y = b2.low.y = p2->p[0].y;
 	for (i = 1; i < p2->npts; i++)
 	{
-		b2.high.x = Max(p2->p[i].x, b2.high.x);
-		b2.high.y = Max(p2->p[i].y, b2.high.y);
-		b2.low.x = Min(p2->p[i].x, b2.low.x);
-		b2.low.y = Min(p2->p[i].y, b2.low.y);
+		b2.high.x = float8_max(p2->p[i].x, b2.high.x);
+		b2.high.y = float8_max(p2->p[i].y, b2.high.y);
+		b2.low.x = float8_min(p2->p[i].x, b2.low.x);
+		b2.low.y = float8_min(p2->p[i].y, b2.low.y);
 	}
 	if (!box_ov(&b1, &b2))
 		PG_RETURN_BOOL(false);
 
 	/* pairwise check lseg intersections */
 	for (i = 0; i < p1->npts; i++)
 	{
 		int			iprev;
 
 		if (i > 0)
@@ -1623,21 +1637,21 @@ path_distance(PG_FUNCTION_ARGS)
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
 			tmp = lseg_closept_lseg(NULL, &seg1, &seg2);
-			if (!have_min || tmp < min)
+			if (!have_min || float8_lt(tmp, min))
 			{
 				min = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	if (!have_min)
 		PG_RETURN_NULL();
 
@@ -1662,21 +1676,21 @@ path_length(PG_FUNCTION_ARGS)
 
 		if (i > 0)
 			iprev = i - 1;
 		else
 		{
 			if (!path->closed)
 				continue;
 			iprev = path->npts - 1; /* include the closure segment */
 		}
 
-		result += point_dt(&path->p[iprev], &path->p[i]);
+		result = float8_pl(result, point_dt(&path->p[iprev], &path->p[i]));
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /***********************************************************************
  **
  **		Routines for 2D points.
  **
  ***********************************************************************/
@@ -1822,44 +1836,52 @@ point_eq(PG_FUNCTION_ARGS)
 
 Datum
 point_ne(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_BOOL(!point_eq_point(pt1, pt2));
 }
 
+
+/*
+ * Check whether the two points are the same
+ *
+ * We consider NaNs coordinates to be equal to each other to let those points
+ * to be found.
+ */
 static inline bool
 point_eq_point(Point *pt1, Point *pt2)
 {
-	return FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y);
+	return ((FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y)) ||
+			(float8_eq(pt1->x, pt2->x) && float8_eq(pt1->y, pt2->y)));
 }
 
 
 /*----------------------------------------------------------
  *	"Arithmetic" operators on points.
  *---------------------------------------------------------*/
 
 Datum
 point_distance(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
 static inline float8
 point_dt(Point *pt1, Point *pt2)
 {
-	return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
+	return HYPOT(float8_mi(pt1->x, pt2->x), float8_mi(pt1->y, pt2->y));
 }
 
 Datum
 point_slope(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_sl(pt1, pt2));
 }
@@ -1870,37 +1892,37 @@ point_slope(PG_FUNCTION_ARGS)
  *
  * Note that this function returns DBL_MAX when the points are the same.
  */
 static inline float8
 point_sl(Point *pt1, Point *pt2)
 {
 	if (FPeq(pt1->x, pt2->x))
 		return DBL_MAX;
 	if (FPeq(pt1->y, pt2->y))
 		return 0.0;
-	return (pt1->y - pt2->y) / (pt1->x - pt2->x);
+	return float8_div(float8_mi(pt1->y, pt2->y), float8_mi(pt1->x, pt2->x));
 }
 
 
 /*
  * Return inverse slope of two points
  *
  * Note that this function returns 0.0 when the points are the same.
  */
 static inline float8
 point_invsl(Point *pt1, Point *pt2)
 {
 	if (FPeq(pt1->x, pt2->x))
 		return 0.0;
 	if (FPeq(pt1->y, pt2->y))
 		return DBL_MAX;
-	return (pt1->x - pt2->x) / (pt2->y - pt1->y);
+	return float8_div(float8_mi(pt1->x, pt2->x), float8_mi(pt2->y, pt1->y));
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D line segments.
  **
  ***********************************************************************/
 
 /*----------------------------------------------------------
@@ -2160,22 +2182,22 @@ lseg_distance(PG_FUNCTION_ARGS)
 
 
 Datum
 lseg_center(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
-	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
+	result->x = float8_div(float8_pl(lseg->p[0].x, lseg->p[1].x), 2.0);
+	result->y = float8_div(float8_pl(lseg->p[0].y, lseg->p[1].y), 2.0);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  *		Find the intersection point of two segments (if any).
  *
  * This returns true if two line segments intersect, false if they do not.
  * This also sets the intersection point to *result, if it is not NULL.
@@ -2284,21 +2306,21 @@ dist_ppath(PG_FUNCTION_ARGS)
 			iprev = i - 1;
 		else
 		{
 			if (!path->closed)
 				continue;
 			iprev = path->npts - 1; /* Include the closure segment */
 		}
 
 		statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
 		tmp = lseg_closept_point(NULL, &lseg, pt);
-		if (!have_min || tmp < result)
+		if (!have_min || float8_lt(tmp, result))
 		{
 			result = tmp;
 			have_min = true;
 		}
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
@@ -2314,33 +2336,28 @@ dist_pb(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
-	float8		result,
-				d2;
+	float8		result;
 
 	if (lseg_interpt_line(NULL, lseg, line))
 		result = 0.0;
 	else
-	{
-		result = line_closept_point(NULL, line, &lseg->p[0]);
-		d2 = line_closept_point(NULL, line, &lseg->p[1]);
 		/* XXX shouldn't we take the min not max? */
-		if (d2 > result)
-			result = d2;
-	}
+		result = float8_max(line_closept_point(NULL, line, &lseg->p[0]),
+							line_closept_point(NULL, line, &lseg->p[1]));
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
@@ -2373,25 +2390,24 @@ dist_lb(PG_FUNCTION_ARGS)
  * Distance from a circle to a polygon
  */
 Datum
 dist_cpoly(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	POLYGON    *poly = PG_GETARG_POLYGON_P(1);
 	float8		result;
 
 	/* calculate distance to center, and subtract radius */
-	result = dist_ppoly_internal(&circle->center, poly);
-
-	result -= circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(dist_ppoly_internal(&circle->center, poly),
+					   circle->radius);
+	if (result < 0.0)
+		result = 0.0;
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a point to a polygon
  */
 Datum
 dist_ppoly(PG_FUNCTION_ARGS)
 {
@@ -2403,21 +2419,21 @@ dist_ppoly(PG_FUNCTION_ARGS)
 
 Datum
 dist_polyp(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(dist_ppoly_internal(point, poly));
 }
 
-static double
+static float8
 dist_ppoly_internal(Point *pt, POLYGON *poly)
 {
 	float8		result;
 	float8		d;
 	int			i;
 	LSEG		seg;
 
 	if (point_inside(pt, poly->npts, poly->p) != 0)
 	{
 #ifdef GEODEBUG
@@ -2440,21 +2456,21 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
 	for (i = 0; i < poly->npts - 1; i++)
 	{
 		seg.p[0].x = poly->p[i].x;
 		seg.p[0].y = poly->p[i].y;
 		seg.p[1].x = poly->p[i + 1].x;
 		seg.p[1].y = poly->p[i + 1].y;
 		d = lseg_closept_point(NULL, &seg, pt);
 #ifdef GEODEBUG
 		printf("dist_ppoly_internal- segment %d distance is %f\n", (i + 1), d);
 #endif
-		if (d < result)
+		if (float8_lt(d, result))
 			result = d;
 	}
 
 	return result;
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
  *				Intersection point of objects.
@@ -2542,21 +2558,22 @@ line_closept_point(Point *result, LINE *line, Point *point)
 
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	line_closept_point(result, line, pt);
+	if (isnan(line_closept_point(result, line, pt)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point on line segment to specified point.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
@@ -2599,134 +2616,136 @@ close_ps(PG_FUNCTION_ARGS)
 /*
  * Closest point on line segment to line segment
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
 {
 	Point		point;
-	double		dist;
-	double		d;
+	float8		dist,
+				d;
 
 	d = lseg_closept_point(NULL, l1, &l2->p[0]);
 	dist = d;
 	if (result != NULL)
 		*result = l2->p[0];
 
 	d = lseg_closept_point(NULL, l1, &l2->p[1]);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = l2->p[1];
 	}
 
-	if (lseg_closept_point(&point, l2, &l1->p[0]) < dist)
+	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[0]), dist))
 		d = lseg_closept_point(result, l1, &point);
 
-	if (lseg_closept_point(&point, l2, &l1->p[1]) < dist)
+	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[1]), dist))
 		d = lseg_closept_point(result, l1, &point);
 
-	if (d < dist)
+	if (float8_lt(d, dist))
 		dist = d;
 
 	return dist;
 }
 
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	lseg_closept_lseg(result, l2, l1);
+	if (isnan(lseg_closept_lseg(result, l2, l1)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point on or in box to specified point.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 box_closept_point(Point *result, BOX *box, Point *pt)
 {
-	LSEG		lseg;
+	float8		dist,
+				d;
 	Point		point,
 				closept;
-	double		dist,
-				d;
+	LSEG		lseg;
 
 	if (box_contain_point(box, pt))
 	{
 		if (result != NULL)
 			*result = *pt;
 
 		return 0.0;
 	}
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&lseg, &box->low, &point);
 	dist = lseg_closept_point(result, &lseg, pt);
 
 	statlseg_construct(&lseg, &box->high, &point);
 	d = lseg_closept_point(&closept, &lseg, pt);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&lseg, &box->low, &point);
 	d = lseg_closept_point(&closept, &lseg, pt);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	statlseg_construct(&lseg, &box->high, &point);
 	d = lseg_closept_point(&closept, &lseg, pt);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	return dist;
 }
 
 Datum
 close_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	box_closept_point(result, box, pt);
+	if (isnan(box_closept_point(result, box, pt)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_sl()
  * Closest point on line to line segment.
  *
  * XXX THIS CODE IS WRONG
  * The code is actually calculating the point on the line segment
@@ -2744,21 +2763,21 @@ close_sl(PG_FUNCTION_ARGS)
 	float8		d1,
 				d2;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (lseg_interpt_line(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = line_closept_point(NULL, line, &lseg->p[0]);
 	d2 = line_closept_point(NULL, line, &lseg->p[1]);
-	if (d1 < d2)
+	if (float8_lt(d1, d2))
 		*result = lseg->p[0];
 	else
 		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
 
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_sl\" not implemented")));
@@ -2808,92 +2827,94 @@ lseg_closept_line(Point *result, LSEG *lseg, LINE *line)
 
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	lseg_closept_line(result, lseg, line);
+	if (isnan(lseg_closept_line(result, lseg, line)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point on or in box to line segment.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 box_closept_lseg(Point *result, BOX *box, LSEG *lseg)
 {
+	float8		dist,
+				d;
 	Point		point,
 				closept;
 	LSEG		bseg;
-	double		dist,
-				d;
 
 	if (box_interpt_lseg(result, box, lseg))
 		return 0.0;
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
 	dist = lseg_closept_lseg(result, &bseg, lseg);
 
 	statlseg_construct(&bseg, &box->high, &point);
 	d = lseg_closept_lseg(&closept, &bseg, lseg);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&bseg, &box->low, &point);
 	d = lseg_closept_lseg(&closept, &bseg, lseg);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	statlseg_construct(&bseg, &box->high, &point);
 	d = lseg_closept_lseg(&closept, &bseg, lseg);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	return dist;
 }
 
 Datum
 close_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	box_closept_lseg(result, box, lseg);
+	if (isnan(box_closept_lseg(result, box, lseg)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 Datum
 close_lb(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -2912,21 +2933,23 @@ close_lb(PG_FUNCTION_ARGS)
  *		on_
  *				Whether one object lies completely within another.
  *-------------------------------------------------------------------*/
 
 /*
  *		Does the point satisfy the equation?
  */
 static bool
 line_contain_point(LINE *line, Point *point)
 {
-	return FPzero(line->A * point->x + line->B * point->y + line->C);
+	return FPzero(float8_pl(float8_pl(float8_mul(line->A, point->x),
+									  float8_mul(line->B, point->y)),
+							line->C));
 }
 
 Datum
 on_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
 	PG_RETURN_BOOL(line_contain_point(line, pt));
 }
@@ -2993,33 +3016,32 @@ box_contain_pt(PG_FUNCTION_ARGS)
  *				but not cross.
  *				(we can do p-in-p in lg(n), but it takes preprocessing)
  */
 Datum
 on_ppath(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	PATH	   *path = PG_GETARG_PATH_P(1);
 	int			i,
 				n;
-	double		a,
+	float8		a,
 				b;
 
 	/*-- OPEN --*/
 	if (!path->closed)
 	{
 		n = path->npts - 1;
 		a = point_dt(pt, &path->p[0]);
 		for (i = 0; i < n; i++)
 		{
 			b = point_dt(pt, &path->p[i + 1]);
-			if (FPeq(a + b,
-					 point_dt(&path->p[i], &path->p[i + 1])))
+			if (FPeq(float8_pl(a, b), point_dt(&path->p[i], &path->p[i + 1])))
 				PG_RETURN_BOOL(true);
 			a = b;
 		}
 		PG_RETURN_BOOL(false);
 	}
 
 	/*-- CLOSED --*/
 	PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
 }
 
@@ -3091,24 +3113,24 @@ inter_sl(PG_FUNCTION_ARGS)
  * Optimize for non-intersection by checking for box intersection first.
  * - thomas 1998-01-30
  */
 static bool
 box_interpt_lseg(Point *result, BOX *box, LSEG *lseg)
 {
 	BOX			lbox;
 	LSEG		bseg;
 	Point		point;
 
-	lbox.low.x = Min(lseg->p[0].x, lseg->p[1].x);
-	lbox.low.y = Min(lseg->p[0].y, lseg->p[1].y);
-	lbox.high.x = Max(lseg->p[0].x, lseg->p[1].x);
-	lbox.high.y = Max(lseg->p[0].y, lseg->p[1].y);
+	lbox.low.x = float8_min(lseg->p[0].x, lseg->p[1].x);
+	lbox.low.y = float8_min(lseg->p[0].y, lseg->p[1].y);
+	lbox.high.x = float8_max(lseg->p[0].x, lseg->p[1].x);
+	lbox.high.y = float8_max(lseg->p[0].y, lseg->p[1].y);
 
 	/* nothing close to overlap? then not going to intersect */
 	if (!box_ov(&lbox, box))
 		return false;
 
 	if (result != NULL)
 	{
 		box_cn(&point, box);
 		lseg_closept_point(result, lseg, &point);
 	}
@@ -3201,38 +3223,38 @@ inter_lb(PG_FUNCTION_ARGS)
  * make_bound_box - create the bounding box for the input polygon
  *------------------------------------------------------------------*/
 
 /*---------------------------------------------------------------------
  * Make the smallest bounding box for the given polygon.
  *---------------------------------------------------------------------*/
 static void
 make_bound_box(POLYGON *poly)
 {
 	int			i;
-	double		x1,
+	float8		x1,
 				y1,
 				x2,
 				y2;
 
 	Assert(poly->npts > 0);
 
 	x1 = x2 = poly->p[0].x;
 	y2 = y1 = poly->p[0].y;
 	for (i = 1; i < poly->npts; i++)
 	{
-		if (poly->p[i].x < x1)
+		if (float8_lt(poly->p[i].x, x1))
 			x1 = poly->p[i].x;
-		if (poly->p[i].x > x2)
+		if (float8_gt(poly->p[i].x, x2))
 			x2 = poly->p[i].x;
-		if (poly->p[i].y < y1)
+		if (float8_lt(poly->p[i].y, y1))
 			y1 = poly->p[i].y;
-		if (poly->p[i].y > y2)
+		if (float8_gt(poly->p[i].y, y2))
 			y2 = poly->p[i].y;
 	}
 
 	poly->boundbox.low.x = x1;
 	poly->boundbox.high.x = x2;
 	poly->boundbox.low.y = y1;
 	poly->boundbox.high.y = y2;
 }
 
 /*------------------------------------------------------------------
@@ -3731,22 +3753,22 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 	}
 
 	if (res && !intersection)
 	{
 		Point		p;
 
 		/*
 		 * if X-intersection wasn't found  then check central point of tested
 		 * segment. In opposite case we already check all subsegments
 		 */
-		p.x = (t.p[0].x + t.p[1].x) / 2.0;
-		p.y = (t.p[0].y + t.p[1].y) / 2.0;
+		p.x = float8_div(float8_pl(t.p[0].x, t.p[1].x), 2.0);
+		p.y = float8_div(float8_pl(t.p[0].y, t.p[1].y), 2.0);
 
 		res = point_inside(&p, poly->npts, poly->p);
 	}
 
 	return res;
 }
 
 /*-----------------------------------------------------------------
  * Determine if polygon A contains polygon B.
  *-----------------------------------------------------------------*/
@@ -3872,22 +3894,22 @@ construct_point(PG_FUNCTION_ARGS)
 	point_construct(result, x, y);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_add_point(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x + pt2->x,
-					pt1->y + pt2->y);
+					float8_pl(pt1->x, pt2->x),
+					float8_pl(pt1->y, pt2->y));
 }
 
 Datum
 point_add(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -3895,22 +3917,22 @@ point_add(PG_FUNCTION_ARGS)
 	point_add_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_sub_point(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x - pt2->x,
-					pt1->y - pt2->y);
+					float8_mi(pt1->x, pt2->x),
+					float8_mi(pt1->y, pt2->y));
 }
 
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -3918,54 +3940,53 @@ point_sub(PG_FUNCTION_ARGS)
 	point_sub_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_mul_point(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					(pt1->x * pt2->x) - (pt1->y * pt2->y),
-					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+					float8_mi(float8_mul(pt1->x, pt2->x),
+							  float8_mul(pt1->y, pt2->y)),
+					float8_pl(float8_mul(pt1->x, pt2->y),
+							  float8_mul(pt1->y, pt2->x)));
 }
 
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	point_mul_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_div_point(Point *result, Point *pt1, Point *pt2)
 {
-	double		div;
+	float8		div;
 
-	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
-
-	if (div == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
+	div = float8_pl(float8_mul(pt2->x, pt2->x), float8_mul(pt2->y, pt2->y));
 
 	point_construct(result,
-					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
-					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+					float8_div(float8_pl(float8_mul(pt1->x, pt2->x),
+										 float8_mul(pt1->y, pt2->y)), div),
+					float8_div(float8_mi(float8_mul(pt1->y, pt2->x),
+										 float8_mul(pt1->x, pt2->y)), div));
 }
 
 Datum
 point_div(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -4088,24 +4109,24 @@ point_box(PG_FUNCTION_ARGS)
  */
 Datum
 boxes_bound_box(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0),
 			   *box2 = PG_GETARG_BOX_P(1),
 			   *container;
 
 	container = (BOX *) palloc(sizeof(BOX));
 
-	container->high.x = Max(box1->high.x, box2->high.x);
-	container->low.x = Min(box1->low.x, box2->low.x);
-	container->high.y = Max(box1->high.y, box2->high.y);
-	container->low.y = Min(box1->low.y, box2->low.y);
+	container->high.x = float8_max(box1->high.x, box2->high.x);
+	container->low.x = float8_min(box1->low.x, box2->low.x);
+	container->high.y = float8_max(box1->high.y, box2->high.y);
+	container->low.y = float8_min(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(container);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D paths.
  **
  ***********************************************************************/
@@ -4411,21 +4432,22 @@ circle_in(PG_FUNCTION_ARGS)
 		if (*cp == LDELIM)
 			s = cp;
 	}
 
 	pair_decode(s, &circle->center.x, &circle->center.y, &s, "circle", str);
 
 	if (*s == DELIM)
 		s++;
 
 	circle->radius = single_decode(s, &s, "circle", str);
-	if (circle->radius < 0)
+	/* We have to accept NaN. */
+	if (circle->radius < 0.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
 
 	while (depth > 0)
 	{
 		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
@@ -4478,21 +4500,22 @@ circle_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	circle->center.x = pq_getmsgfloat8(buf);
 	circle->center.y = pq_getmsgfloat8(buf);
 	circle->radius = pq_getmsgfloat8(buf);
 
-	if (circle->radius < 0)
+	/* We have to accept NaN. */
+	if (circle->radius < 0.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
 				 errmsg("invalid radius in external \"circle\" value")));
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 /*
  *		circle_send			- converts circle to binary format
  */
@@ -4509,166 +4532,170 @@ circle_send(PG_FUNCTION_ARGS)
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for CIRCLEs.
  *		<, >, <=, >=, and == are based on circle area.
  *---------------------------------------------------------*/
 
 /*		circles identical?
+ *
+ * We consider NaNs values to be equal to each other to let those circles
+ * to be found.
  */
 Datum
 circle_same(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPeq(circle1->radius, circle2->radius) &&
+	PG_RETURN_BOOL(((isnan(circle1->radius) && isnan(circle1->radius)) ||
+					FPeq(circle1->radius, circle2->radius)) &&
 				   point_eq_point(&circle1->center, &circle2->center));
 }
 
 /*		circle_overlap	-		does circle1 overlap circle2?
  */
 Datum
 circle_overlap(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle1->radius + circle2->radius));
+						float8_pl(circle1->radius, circle2->radius)));
 }
 
 /*		circle_overleft -		is the right edge of circle1 at or left of
  *								the right edge of circle2?
  */
 Datum
 circle_overleft(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.x + circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_left		-		is circle1 strictly left of circle2?
  */
 Datum
 circle_left(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.x + circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_right	-		is circle1 strictly right of circle2?
  */
 Datum
 circle_right(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.x - circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_overright	-	is the left edge of circle1 at or right of
  *								the left edge of circle2?
  */
 Datum
 circle_overright(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.x - circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_contained		-		is circle1 contained by circle2?
  */
 Datum
 circle_contained(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle2->radius - circle1->radius));
+						float8_mi(circle2->radius, circle1->radius)));
 }
 
 /*		circle_contain	-		does circle1 contain circle2?
  */
 Datum
 circle_contain(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle1->radius - circle2->radius));
+						float8_mi(circle1->radius, circle2->radius)));
 }
 
 
 /*		circle_below		-		is circle1 strictly below circle2?
  */
 Datum
 circle_below(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.y + circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_above	-		is circle1 strictly above circle2?
  */
 Datum
 circle_above(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.y - circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overbelow -		is the upper edge of circle1 at or below
  *								the upper edge of circle2?
  */
 Datum
 circle_overbelow(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.y + circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overabove	-	is the lower edge of circle1 at or above
  *								the lower edge of circle2?
  */
 Datum
 circle_overabove(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.y - circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 
 /*		circle_relop	-		is area(circle1) relop area(circle2), within
  *								our accuracy constraint?
  */
 Datum
 circle_eq(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
@@ -4767,36 +4794,36 @@ circle_sub_pt(PG_FUNCTION_ARGS)
 Datum
 circle_mul_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_mul_point(&result->center, &circle->center, point);
-	result->radius = circle->radius * HYPOT(point->x, point->y);
+	result->radius = float8_mul(circle->radius, HYPOT(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_div_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_div_point(&result->center, &circle->center, point);
-	result->radius = circle->radius / HYPOT(point->x, point->y);
+	result->radius = float8_div(circle->radius, HYPOT(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /*		circle_area		-		returns the area of the circle.
  */
 Datum
 circle_area(PG_FUNCTION_ARGS)
 {
@@ -4806,21 +4833,21 @@ circle_area(PG_FUNCTION_ARGS)
 }
 
 
 /*		circle_diameter -		returns the diameter of the circle.
  */
 Datum
 circle_diameter(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
-	PG_RETURN_FLOAT8(2 * circle->radius);
+	PG_RETURN_FLOAT8(float8_mul(circle->radius, 2.0));
 }
 
 
 /*		circle_radius	-		returns the radius of the circle.
  */
 Datum
 circle_radius(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
@@ -4831,81 +4858,85 @@ circle_radius(PG_FUNCTION_ARGS)
 /*		circle_distance -		returns the distance between
  *								  two circles.
  */
 Datum
 circle_distance(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(&circle1->center, &circle2->center) -
-		(circle1->radius + circle2->radius);
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(&circle1->center, &circle2->center),
+					   float8_pl(circle1->radius, circle2->radius));
+	if (result < 0.0)
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 
 Datum
 circle_contain_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
 	PG_RETURN_BOOL(d <= circle->radius);
 }
 
 
 Datum
 pt_contained_circle(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
 	PG_RETURN_BOOL(d <= circle->radius);
 }
 
 
 /*		dist_pc -		returns the distance between
  *						  a point and a circle.
  */
 Datum
 dist_pc(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center),
+					   circle->radius);
+	if (result < 0.0)
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a circle to a point
  */
 Datum
 dist_cpoint(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center), circle->radius);
+	if (result < 0.0)
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*		circle_center	-		returns the center point of the circle.
  */
 Datum
 circle_center(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *result;
@@ -4913,24 +4944,24 @@ circle_center(PG_FUNCTION_ARGS)
 	result = (Point *) palloc(sizeof(Point));
 	result->x = circle->center.x;
 	result->y = circle->center.y;
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		circle_ar		-		returns the area of the circle.
  */
-static double
+static float8
 circle_ar(CIRCLE *circle)
 {
-	return M_PI * (circle->radius * circle->radius);
+	return float8_mul(float8_mul(circle->radius, circle->radius), M_PI);
 }
 
 
 /*----------------------------------------------------------
  *	Conversion operators.
  *---------------------------------------------------------*/
 
 Datum
 cr_circle(PG_FUNCTION_ARGS)
 {
@@ -4945,65 +4976,65 @@ cr_circle(PG_FUNCTION_ARGS)
 	result->radius = radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_box(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	BOX		   *box;
-	double		delta;
+	float8		delta;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
-	delta = circle->radius / sqrt(2.0);
+	delta = float8_div(circle->radius, sqrt(2.0));
 
-	box->high.x = circle->center.x + delta;
-	box->low.x = circle->center.x - delta;
-	box->high.y = circle->center.y + delta;
-	box->low.y = circle->center.y - delta;
+	box->high.x = float8_pl(circle->center.x, delta);
+	box->low.x = float8_mi(circle->center.x, delta);
+	box->high.y = float8_pl(circle->center.y, delta);
+	box->low.y = float8_mi(circle->center.y, delta);
 
 	PG_RETURN_BOX_P(box);
 }
 
 /* box_circle()
  * Convert a box to a circle.
  */
 Datum
 box_circle(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	circle->center.x = (box->high.x + box->low.x) / 2;
-	circle->center.y = (box->high.y + box->low.y) / 2;
+	circle->center.x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	circle->center.y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 
 	circle->radius = point_dt(&circle->center, &box->high);
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 
 Datum
 circle_poly(PG_FUNCTION_ARGS)
 {
 	int32		npts = PG_GETARG_INT32(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	POLYGON    *poly;
 	int			base_size,
 				size;
 	int			i;
-	double		angle;
-	double		anglestep;
+	float8		angle;
+	float8		anglestep;
 
 	if (FPzero(circle->radius))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("cannot convert circle with radius zero to polygon")));
 
 	if (npts < 2)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("must request at least 2 points")));
@@ -5014,27 +5045,30 @@ circle_poly(PG_FUNCTION_ARGS)
 	/* Check for integer overflow */
 	if (base_size / npts != sizeof(poly->p[0]) || size <= base_size)
 		ereport(ERROR,
 				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 				 errmsg("too many points requested")));
 
 	poly = (POLYGON *) palloc0(size);	/* zero any holes */
 	SET_VARSIZE(poly, size);
 	poly->npts = npts;
 
-	anglestep = (2.0 * M_PI) / npts;
+	anglestep = float8_div(2.0 * M_PI, npts);
 
 	for (i = 0; i < npts; i++)
 	{
-		angle = i * anglestep;
-		poly->p[i].x = circle->center.x - (circle->radius * cos(angle));
-		poly->p[i].y = circle->center.y + (circle->radius * sin(angle));
+		angle = float8_mul(anglestep, i);
+
+		poly->p[i].x = float8_mi(circle->center.x,
+								 float8_mul(circle->radius, cos(angle)));
+		poly->p[i].y = float8_pl(circle->center.y,
+								 float8_mul(circle->radius, sin(angle)));
 	}
 
 	make_bound_box(poly);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
 /*
  * Convert polygon to circle
  *
@@ -5049,26 +5083,27 @@ poly_to_circle(CIRCLE *result, POLYGON *poly)
 	int			i;
 
 	Assert(poly->npts > 0);
 
 	result->center.x = 0;
 	result->center.y = 0;
 	result->radius = 0;
 
 	for (i = 0; i < poly->npts; i++)
 		point_add_point(&result->center, &result->center, &poly->p[i]);
-	result->center.x /= poly->npts;
-	result->center.y /= poly->npts;
+	result->center.x = float8_div(result->center.x, poly->npts);
+	result->center.y = float8_div(result->center.y, poly->npts);
 
 	for (i = 0; i < poly->npts; i++)
-		result->radius += point_dt(&poly->p[i], &result->center);
-	result->radius /= poly->npts;
+		result->radius = float8_pl(result->radius,
+								   point_dt(&poly->p[i], &result->center));
+	result->radius = float8_div(result->radius, poly->npts);
 }
 
 Datum
 poly_circle(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
@@ -5093,44 +5128,44 @@ poly_circle(PG_FUNCTION_ARGS)
  *	http://hopf.math.northwestern.edu/index.html
  *	Description of algorithm:  http://www.linuxjournal.com/article/2197
  *							   http://www.linuxjournal.com/article/2029
  */
 
 #define POINT_ON_POLYGON INT_MAX
 
 static int
 point_inside(Point *p, int npts, Point *plist)
 {
-	double		x0,
+	float8		x0,
 				y0;
-	double		prev_x,
+	float8		prev_x,
 				prev_y;
 	int			i = 0;
-	double		x,
+	float8		x,
 				y;
 	int			cross,
 				total_cross = 0;
 
 	Assert(npts > 0);
 
 	/* compute first polygon point relative to single point */
-	x0 = plist[0].x - p->x;
-	y0 = plist[0].y - p->y;
+	x0 = float8_mi(plist[0].x, p->x);
+	y0 = float8_mi(plist[0].y, p->y);
 
 	prev_x = x0;
 	prev_y = y0;
 	/* loop over polygon points and aggregate total_cross */
 	for (i = 1; i < npts; i++)
 	{
 		/* compute next polygon point relative to single point */
-		x = plist[i].x - p->x;
-		y = plist[i].y - p->y;
+		x = float8_mi(plist[i].x, p->x);
+		y = float8_mi(plist[i].y, p->y);
 
 		/* compute previous to current point crossing */
 		if ((cross = lseg_crossing(x, y, prev_x, prev_y)) == POINT_ON_POLYGON)
 			return 2;
 		total_cross += cross;
 
 		prev_x = x;
 		prev_y = y;
 	}
 
@@ -5148,69 +5183,74 @@ point_inside(Point *p, int npts, Point *plist)
 /* lseg_crossing()
  * Returns +/-2 if line segment crosses the positive X-axis in a +/- direction.
  * Returns +/-1 if one point is on the positive X-axis.
  * Returns 0 if both points are on the positive X-axis, or there is no crossing.
  * Returns POINT_ON_POLYGON if the segment contains (0,0).
  * Wow, that is one confusing API, but it is used above, and when summed,
  * can tell is if a point is in a polygon.
  */
 
 static int
-lseg_crossing(double x, double y, double prev_x, double prev_y)
+lseg_crossing(float8 x, float8 y, float8 prev_x, float8 prev_y)
 {
-	double		z;
+	float8		z;
 	int			y_sign;
 
 	if (FPzero(y))
 	{							/* y == 0, on X axis */
 		if (FPzero(x))			/* (x,y) is (0,0)? */
 			return POINT_ON_POLYGON;
 		else if (FPgt(x, 0))
 		{						/* x > 0 */
 			if (FPzero(prev_y)) /* y and prev_y are zero */
 				/* prev_x > 0? */
-				return FPgt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
-			return FPlt(prev_y, 0) ? 1 : -1;
+				return FPgt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
+			return FPlt(prev_y, 0.0) ? 1 : -1;
 		}
 		else
 		{						/* x < 0, x not on positive X axis */
 			if (FPzero(prev_y))
 				/* prev_x < 0? */
-				return FPlt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
+				return FPlt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
 			return 0;
 		}
 	}
 	else
 	{							/* y != 0 */
 		/* compute y crossing direction from previous point */
-		y_sign = FPgt(y, 0) ? 1 : -1;
+		y_sign = FPgt(y, 0.0) ? 1 : -1;
 
 		if (FPzero(prev_y))
 			/* previous point was on X axis, so new point is either off or on */
-			return FPlt(prev_x, 0) ? 0 : y_sign;
-		else if (FPgt(y_sign * prev_y, 0))
+			return FPlt(prev_x, 0.0) ? 0 : y_sign;
+		else if ((y_sign < 0 && FPlt(prev_y, 0.0)) ||
+				 (y_sign > 0 && FPgt(prev_y, 0.0)))
 			/* both above or below X axis */
 			return 0;			/* same sign */
 		else
 		{						/* y and prev_y cross X-axis */
-			if (FPge(x, 0) && FPgt(prev_x, 0))
+			if (FPge(x, 0.0) && FPgt(prev_x, 0.0))
 				/* both non-negative so cross positive X-axis */
 				return 2 * y_sign;
-			if (FPlt(x, 0) && FPle(prev_x, 0))
+			if (FPlt(x, 0.0) && FPle(prev_x, 0.0))
 				/* both non-positive so do not cross positive X-axis */
 				return 0;
 
 			/* x and y cross axises, see URL above point_inside() */
-			z = (x - prev_x) * y - (y - prev_y) * x;
+			z = float8_mi(float8_mul(float8_mi(x, prev_x), y),
+						  float8_mul(float8_mi(y, prev_y), x));
 			if (FPzero(z))
 				return POINT_ON_POLYGON;
-			return FPgt((y_sign * z), 0) ? 0 : 2 * y_sign;
+			if ((y_sign < 0 && FPlt(z, 0.0)) ||
+				(y_sign > 0 && FPgt(z, 0.0)))
+				return 0;
+			return 2 * y_sign;
 		}
 	}
 }
 
 
 static bool
 plist_same(int npts, Point *p1, Point *p2)
 {
 	int			i,
 				ii,
@@ -5280,47 +5320,52 @@ plist_same(int npts, Point *p1, Point *p2)
  *					 = x * sqrt( 1 + y^2/x^2 )
  *					 = x * sqrt( 1 + y/x * y/x )
  *
  * It is expected that this routine will eventually be replaced with the
  * C99 hypot() function.
  *
  * This implementation conforms to IEEE Std 1003.1 and GLIBC, in that the
  * case of hypot(inf,nan) results in INF, and not NAN.
  *-----------------------------------------------------------------------
  */
-double
-pg_hypot(double x, double y)
+float8
+pg_hypot(float8 x, float8 y)
 {
-	double		yx;
+	float8		yx,
+				result;
 
 	/* Handle INF and NaN properly */
 	if (isinf(x) || isinf(y))
 		return get_float8_infinity();
 
 	if (isnan(x) || isnan(y))
 		return get_float8_nan();
 
 	/* Else, drop any minus signs */
 	x = fabs(x);
 	y = fabs(y);
 
 	/* Swap x and y if needed to make x the larger one */
 	if (x < y)
 	{
-		double		temp = x;
+		float8		temp = x;
 
 		x = y;
 		y = temp;
 	}
 
 	/*
 	 * If y is zero, the hypotenuse is x.  This test saves a few cycles in
 	 * such cases, but more importantly it also protects against
 	 * divide-by-zero errors, since now x >= y.
 	 */
 	if (y == 0.0)
 		return x;
 
 	/* Determine the hypotenuse */
 	yx = y / x;
-	return x * sqrt(1.0 + (yx * yx));
+	result = x * sqrt(1.0 + (yx * yx));
+
+	check_float8_val(result, false, false);
+
+	return result;
 }
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index 5489ed9585..17e24b9628 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -76,38 +76,38 @@
 #include "access/spgist.h"
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
 #include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
- * is going only going to be used in a place to effect the performance
+ * is only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
 compareDoubles(const void *a, const void *b)
 {
-	double		x = *(double *) a;
-	double		y = *(double *) b;
+	float8		x = *(float8 *) a;
+	float8		y = *(float8 *) b;
 
 	if (x == y)
 		return 0;
 	return (x > y) ? 1 : -1;
 }
 
 typedef struct
 {
-	double		low;
-	double		high;
+	float8		low;
+	float8		high;
 } Range;
 
 typedef struct
 {
 	Range		left;
 	Range		right;
 } RangeBox;
 
 typedef struct
 {
@@ -167,21 +167,21 @@ getRangeBox(BOX *box)
 /*
  * Initialize the traversal value
  *
  * In the beginning, we don't have any restrictions.  We have to
  * initialize the struct to cover the whole 4D space.
  */
 static RectBox *
 initRectBox(void)
 {
 	RectBox    *rect_box = (RectBox *) palloc(sizeof(RectBox));
-	double		infinity = get_float8_infinity();
+	float8		infinity = get_float8_infinity();
 
 	rect_box->range_box_x.left.low = -infinity;
 	rect_box->range_box_x.left.high = infinity;
 
 	rect_box->range_box_x.right.low = -infinity;
 	rect_box->range_box_x.right.high = infinity;
 
 	rect_box->range_box_y.left.low = -infinity;
 	rect_box->range_box_y.left.high = infinity;
 
@@ -410,40 +410,40 @@ spg_box_quad_choose(PG_FUNCTION_ARGS)
  * point as the median of the coordinates of the boxes.
  */
 Datum
 spg_box_quad_picksplit(PG_FUNCTION_ARGS)
 {
 	spgPickSplitIn *in = (spgPickSplitIn *) PG_GETARG_POINTER(0);
 	spgPickSplitOut *out = (spgPickSplitOut *) PG_GETARG_POINTER(1);
 	BOX		   *centroid;
 	int			median,
 				i;
-	double	   *lowXs = palloc(sizeof(double) * in->nTuples);
-	double	   *highXs = palloc(sizeof(double) * in->nTuples);
-	double	   *lowYs = palloc(sizeof(double) * in->nTuples);
-	double	   *highYs = palloc(sizeof(double) * in->nTuples);
+	float8	   *lowXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *lowYs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highYs = palloc(sizeof(float8) * in->nTuples);
 
 	/* Calculate median of all 4D coordinates */
 	for (i = 0; i < in->nTuples; i++)
 	{
 		BOX		   *box = DatumGetBoxP(in->datums[i]);
 
 		lowXs[i] = box->low.x;
 		highXs[i] = box->high.x;
 		lowYs[i] = box->low.y;
 		highYs[i] = box->high.y;
 	}
 
-	qsort(lowXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(lowYs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highYs, in->nTuples, sizeof(double), compareDoubles);
+	qsort(lowXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(lowYs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highYs, in->nTuples, sizeof(float8), compareDoubles);
 
 	median = in->nTuples / 2;
 
 	centroid = palloc(sizeof(BOX));
 
 	centroid->low.x = lowXs[median];
 	centroid->high.x = highXs[median];
 	centroid->low.y = lowYs[median];
 	centroid->high.y = highYs[median];
 
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 5a21160eb0..c74029f870 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -15,23 +15,21 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/numeric.c
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
 
 #include <ctype.h>
-#include <float.h>
 #include <limits.h>
-#include <math.h>
 
 #include "access/hash.h"
 #include "catalog/pg_type.h"
 #include "common/int.h"
 #include "funcapi.h"
 #include "lib/hyperloglog.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
 #include "utils/array.h"
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index e7a4ee5ac7..72c60b0385 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -9,22 +9,20 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/timestamp.c
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
 
 #include <ctype.h>
-#include <math.h>
-#include <float.h>
 #include <limits.h>
 #include <sys/time.h>
 
 #include "access/hash.h"
 #include "access/xact.h"
 #include "catalog/pg_type.h"
 #include "common/int128.h"
 #include "funcapi.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 9484657030..dc892f34cb 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -10,22 +10,20 @@
  * Written by Peter Eisentraut <peter_e@gmx.net>.
  *
  * IDENTIFICATION
  *	  src/backend/utils/misc/guc.c
  *
  *--------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include <ctype.h>
-#include <float.h>
-#include <math.h>
 #include <limits.h>
 #include <unistd.h>
 #include <sys/stat.h>
 #ifdef HAVE_SYSLOG
 #include <syslog.h>
 #endif
 
 #include "access/commit_ts.h"
 #include "access/gin.h"
 #include "access/rmgr.h"
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index aeb31515e4..e650901a4e 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -1,42 +1,39 @@
 /*-------------------------------------------------------------------------
  *
  * geo_decls.h - Declarations for various 2D constructs.
  *
  *
  * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * src/include/utils/geo_decls.h
  *
- * NOTE
- *	  These routines do *not* use the float types from adt/.
- *
  *	  XXX These routines were not written by a numerical analyst.
  *
  *	  XXX I have made some attempt to flesh out the operators
  *		and data types. There are still some more to do. - tgl 97/04/19
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEO_DECLS_H
 #define GEO_DECLS_H
 
-#include <math.h>
-
 #include "fmgr.h"
 #include "utils/float.h"
 
 /*--------------------------------------------------------------------
  * Useful floating point utilities and constants.
- *-------------------------------------------------------------------*/
-
+ *-------------------------------------------------------------------
+ *
+ * XXX They are not NaN-aware.
+ */
 
 #define EPSILON					1.0E-06
 
 #ifdef EPSILON
 #define FPzero(A)				(fabs(A) <= EPSILON)
 #define FPeq(A,B)				(fabs((A) - (B)) <= EPSILON)
 #define FPne(A,B)				(fabs((A) - (B)) > EPSILON)
 #define FPlt(A,B)				((B) - (A) > EPSILON)
 #define FPle(A,B)				((A) - (B) <= EPSILON)
 #define FPgt(A,B)				((A) - (B) > EPSILON)
@@ -51,21 +48,21 @@
 #define FPge(A,B)				((A) >= (B))
 #endif
 
 #define HYPOT(A, B)				pg_hypot(A, B)
 
 /*---------------------------------------------------------------------
  * Point - (x,y)
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		x,
+	float8		x,
 				y;
 } Point;
 
 
 /*---------------------------------------------------------------------
  * LSEG - A straight line, specified by endpoints.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		p[2];
@@ -83,21 +80,21 @@ typedef struct
 	int32		dummy;			/* padding to make it double align */
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } PATH;
 
 
 /*---------------------------------------------------------------------
  * LINE - Specified by its general equation (Ax+By+C=0).
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		A,
+	float8		A,
 				B,
 				C;
 } LINE;
 
 
 /*---------------------------------------------------------------------
  * BOX	- Specified by two corner points, which are
  *		 sorted to save calculation time later.
  *-------------------------------------------------------------------*/
 typedef struct
@@ -118,21 +115,21 @@ typedef struct
 	BOX			boundbox;
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } POLYGON;
 
 /*---------------------------------------------------------------------
  * CIRCLE - Specified by a center point and radius.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		center;
-	double		radius;
+	float8		radius;
 } CIRCLE;
 
 /*
  * fmgr interface macros
  *
  * Path and Polygon are toastable varlena types, the others are just
  * fixed-size pass-by-reference types.
  */
 
 #define DatumGetPointP(X)	 ((Point *) DatumGetPointer(X))
@@ -172,13 +169,13 @@ typedef struct
 #define DatumGetCircleP(X)	  ((CIRCLE *) DatumGetPointer(X))
 #define CirclePGetDatum(X)	  PointerGetDatum(X)
 #define PG_GETARG_CIRCLE_P(n) DatumGetCircleP(PG_GETARG_DATUM(n))
 #define PG_RETURN_CIRCLE_P(x) return CirclePGetDatum(x)
 
 
 /*
  * in geo_ops.c
  */
 
-extern double pg_hypot(double x, double y);
+extern float8 pg_hypot(float8 x, float8 y);
 
 #endif							/* GEO_DECLS_H */
-- 
2.14.3 (Apple Git-98)

0004-line-fixes-v10.patchapplication/octet-stream; name=0004-line-fixes-v10.patchDownload
From 0f8e84f7576a6ff0e4b3c9abd6edba9a79490039 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sun, 28 May 2017 11:35:17 +0200
Subject: [PATCH 4/6] line-fixes-v10

Fix obvious problems around the line datatype

I have noticed some line operators retuning wrong results, and Tom Lane
spotted similar problems on more places.  Source history reveals that
during 1990s, the internal format of the line datatype is changed, but
most functions haven't got the hint.  The fixes include:

* Reject invalid specification A=B=0 on receive
* Reject same points on line_construct_pp()
* Fix perpendicular operator when negative values are involved
* Avoid division by zero on perpendicular operator
* Fix intersection and distance operators when neither A nor B are 1
* Return NULL for closest point when objects are parallel
* Check whether closest point of line segments is the intersection point
* Fix closest point of line segments being on the wrong segment

The changes are also aiming make line operators more symmetric and less
sensitive to floating point precision loss.  The EPSILON interferes with
every minor change in different ways.  It is hard to guess which
behaviour is more expected, but we can assume threating both sides of
the operators more equally is more expected.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com

Parallel discussions:

* https://www.postgresql.org/message-id/CAE2gYzw_-z%3DV2kh8QqFjenu%3D8MJXzOP44wRW%3DAzzeamrmTT1%3DQ%40mail.gmail.com
* https://www.postgresql.org/message-id/20180201.205138.34583581.horiguchi.kyotaro@lab.ntt.co.jp
---
 src/backend/utils/adt/geo_ops.c | 159 ++++++++++++++++++++++++++--------------
 1 file changed, 106 insertions(+), 53 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index df185affcb..d5d4797b3f 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -40,20 +40,21 @@ static inline void point_add_point(Point *result, Point *pt1, Point *pt2);
 static inline void point_sub_point(Point *result, Point *pt1, Point *pt2);
 static inline void point_mul_point(Point *result, Point *pt1, Point *pt2);
 static inline void point_div_point(Point *result, Point *pt1, Point *pt2);
 static inline bool point_eq_point(Point *pt1, Point *pt2);
 static inline float8 point_dt(Point *pt1, Point *pt2);
 static inline float8 point_sl(Point *pt1, Point *pt2);
 static int	point_inside(Point *p, int npts, Point *plist);
 
 /* Routines for lines */
 static inline void line_construct(LINE *result, Point *pt, float8 m);
+static inline float8 line_sl(LINE *line);
 static inline float8 line_invsl(LINE *line);
 static bool	line_interpt_line(Point *result, LINE *l1, LINE *l2);
 static bool line_contain_point(LINE *line, Point *point);
 static float8 line_closept_point(Point *result, LINE *line, Point *pt);
 
 /* Routines for line segments */
 static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
 static inline float8 lseg_sl(LSEG *lseg);
 static inline float8 lseg_invsl(LSEG *lseg);
 static bool	lseg_interpt_line(Point *result, LSEG *lseg, LINE *line);
@@ -972,20 +973,25 @@ line_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LINE	   *line;
 
 	line = (LINE *) palloc(sizeof(LINE));
 
 	line->A = pq_getmsgfloat8(buf);
 	line->B = pq_getmsgfloat8(buf);
 	line->C = pq_getmsgfloat8(buf);
 
+	if (FPzero(line->A) && FPzero(line->B))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("invalid line specification: A and B cannot both be zero")));
+
 	PG_RETURN_LINE_P(line);
 }
 
 /*
  *		line_send			- converts line to binary format
  */
 Datum
 line_send(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -1029,20 +1035,25 @@ line_construct(LINE *result, Point *pt, float8 m)
 /* line_construct_pp()
  * two points
  */
 Datum
 line_construct_pp(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 	LINE	   *result = (LINE *) palloc(sizeof(LINE));
 
+	if (point_eq_point(pt1, pt2))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("invalid line specification: must be two distinct points")));
+
 	line_construct(result, pt1, point_sl(pt1, pt2));
 
 	PG_RETURN_LINE_P(result);
 }
 
 
 /*----------------------------------------------------------
  *	Relative position routines.
  *---------------------------------------------------------*/
 
@@ -1065,25 +1076,29 @@ line_parallel(PG_FUNCTION_ARGS)
 }
 
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
-	else if (FPzero(l1->B))
+	if (FPzero(l2->A))
+		PG_RETURN_BOOL(FPzero(l1->B));
+	if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
+	if (FPzero(l2->B))
+		PG_RETURN_BOOL(FPzero(l1->A));
 
-	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
-								   float8_mul(l1->B, l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->A),
+								   float8_mul(l1->B, l2->B)), -1.0));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
@@ -1124,20 +1139,34 @@ line_eq(PG_FUNCTION_ARGS)
 				   (float8_eq(l1->A, l2->A) &&
 					float8_eq(l1->B, l2->B) &&
 					float8_eq(l1->C, l2->C)));
 }
 
 
 /*----------------------------------------------------------
  *	Line arithmetic routines.
  *---------------------------------------------------------*/
 
+/*
+ * Return slope of the line
+ */
+static inline float8
+line_sl(LINE *line)
+{
+	if (FPzero(line->A))
+		return 0.0;
+	if (FPzero(line->B))
+		return DBL_MAX;
+	return float8_div(line->A, -line->B);
+}
+
+
 /*
  * Return inverse slope of the line
  */
 static inline float8
 line_invsl(LINE *line)
 {
 	if (FPzero(line->A))
 		return DBL_MAX;
 	if (FPzero(line->B))
 		return 0.0;
@@ -1146,30 +1175,35 @@ line_invsl(LINE *line)
 
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	float8		result;
-	Point		tmp;
+	float8		ratio;
 
 	if (line_interpt_line(NULL, l1, l2))	/* intersecting? */
 		PG_RETURN_FLOAT8(0.0);
-	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
-	point_construct(&tmp, 0.0, l1->C);
-	result = line_closept_point(NULL, l2, &tmp);
-	PG_RETURN_FLOAT8(result);
+
+	if (!FPzero(l1->A) && !isnan(l1->A) && !FPzero(l2->A) && !isnan(l2->A))
+		ratio = float8_div(l1->A, l2->A);
+	else if (!FPzero(l1->B) && !isnan(l1->B) && !FPzero(l2->B) && !isnan(l2->B))
+		ratio = float8_div(l1->B, l2->B);
+	else
+		ratio = 1.0;
+
+	PG_RETURN_FLOAT8(float8_div(fabs(float8_mi(l1->C,
+											   float8_mul(ratio, l2->C))),
+								HYPOT(l1->A, l1->B)));
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
@@ -1196,41 +1230,44 @@ line_interpt(PG_FUNCTION_ARGS)
  * If the lines have NaN constants, we will return true, and the intersection
  * point would have NaN coordinates.  We shouldn't return false in this case
  * because that would mean the lines are parallel.
  */
 static bool
 line_interpt_line(Point *result, LINE *l1, LINE *l2)
 {
 	float8		x,
 				y;
 
-	if (FPzero(l1->B))			/* l1 vertical? */
-	{
-		if (FPzero(l2->B))		/* l2 vertical? */
-			return false;
-
-		x = l1->C;
-		y = float8_pl(float8_mul(l2->A, x), l2->C);
-	}
-	else if (FPzero(l2->B))		/* l2 vertical? */
-	{
-		x = l2->C;
-		y = float8_pl(float8_mul(l1->A, x), l1->C);
-	}
-	else
+	if (!FPzero(l1->B))
 	{
 		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
 			return false;
 
-		x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
-		y = float8_pl(float8_mul(l1->A, x), l1->C);
+		x = float8_div(float8_mi(float8_mul(l1->B, l2->C),
+								 float8_mul(l2->B, l1->C)),
+					   float8_mi(float8_mul(l1->A, l2->B),
+								 float8_mul(l2->A, l1->B)));
+		y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
 	}
+	else if (!FPzero(l2->B))
+	{
+		if (FPeq(l1->A, float8_mul(l2->A, float8_div(l1->B, l2->B))))
+			return false;
+
+		x = float8_div(float8_mi(float8_mul(l2->B, l1->C),
+								 float8_mul(l1->B, l2->C)),
+					   float8_mi(float8_mul(l2->A, l1->B),
+								 float8_mul(l1->A, l2->B)));
+		y = float8_div(-float8_pl(float8_mul(l2->A, x), l2->C), l2->B);
+	}
+	else
+		return false;
 
 	if (result != NULL)
 		point_construct(result, x, y);
 
 	return true;
 }
 
 
 /***********************************************************************
  **
@@ -2336,30 +2373,22 @@ dist_pb(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
-	float8		result;
 
-	if (lseg_interpt_line(NULL, lseg, line))
-		result = 0.0;
-	else
-		/* XXX shouldn't we take the min not max? */
-		result = float8_max(line_closept_point(NULL, line, &lseg->p[0]),
-							line_closept_point(NULL, line, &lseg->p[1]));
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(lseg_closept_line(NULL, lseg, line));
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
@@ -2533,33 +2562,40 @@ lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
 /*
  *		The intersection point of a perpendicular of the line
  *		through the point.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 line_closept_point(Point *result, LINE *line, Point *point)
 {
-	bool		retval;
-	Point       closept;
+	Point		closept;
 	LINE		tmp;
 
-	/* We drop a perpendicular to find the intersection point. */
+	/*
+	 * We drop a perpendicular to find the intersection point.  Ordinarily
+	 * we should always find it, but that can fail in the presence of NaN
+	 * coordinates, and perhaps even from simple roundoff issues.
+	 */
 	line_construct(&tmp, point, line_invsl(line));
-	retval = line_interpt_line(&closept, line, &tmp);
-	Assert(retval);		/* XXX: We need something better. */
+	if (!line_interpt_line(&closept, &tmp, line))
+	{
+		if (result != NULL)
+			*result = *point;
+
+		return get_float8_nan();
+	}
 
 	if (result != NULL)
 		*result = closept;
 
-	/* Then we calculate the distance between the points. */
 	return point_dt(&closept, point);
 }
 
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
@@ -2619,52 +2655,66 @@ close_ps(PG_FUNCTION_ARGS)
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
 {
 	Point		point;
 	float8		dist,
 				d;
 
-	d = lseg_closept_point(NULL, l1, &l2->p[0]);
-	dist = d;
-	if (result != NULL)
-		*result = l2->p[0];
+	/* First, we handle the case when the line segments are intersecting. */
+	if (lseg_interpt_lseg(result, l1, l2))
+		return 0.0;
 
-	d = lseg_closept_point(NULL, l1, &l2->p[1]);
+	/*
+	 * Then, we find the closest points from the endpoints of the second
+	 * line segment, and keep the closest one.
+	 */
+	dist = lseg_closept_point(result, l1, &l2->p[0]);
+	d = lseg_closept_point(&point, l1, &l2->p[1]);
 	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
-			*result = l2->p[1];
+			*result = point;
 	}
 
-	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[0]), dist))
-		d = lseg_closept_point(result, l1, &point);
-
-	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[1]), dist))
-		d = lseg_closept_point(result, l1, &point);
-
+	/* The closest point can still be one of the endpoints, so we test them. */
+	d = lseg_closept_point(NULL, l2, &l1->p[0]);
 	if (float8_lt(d, dist))
+	{
 		dist = d;
+		if (result != NULL)
+			*result = l1->p[0];
+	}
+	d = lseg_closept_point(NULL, l2, &l1->p[1]);
+	if (float8_lt(d, dist))
+	{
+		dist = d;
+		if (result != NULL)
+			*result = l1->p[1];
+	}
 
 	return dist;
 }
 
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
+	if (lseg_sl(l1) == lseg_sl(l2))
+		PG_RETURN_NULL();
+
 	result = (Point *) palloc(sizeof(Point));
 
 	if (isnan(lseg_closept_lseg(result, l2, l1)))
 		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
@@ -2825,20 +2875,23 @@ lseg_closept_line(Point *result, LSEG *lseg, LINE *line)
 	}
 }
 
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
+	if (lseg_sl(lseg) == line_sl(line))
+		PG_RETURN_NULL();
+
 	result = (Point *) palloc(sizeof(Point));
 
 	if (isnan(lseg_closept_line(result, lseg, line)))
 		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
-- 
2.14.3 (Apple Git-98)

0005-float-zero-v06.patchapplication/octet-stream; name=0005-float-zero-v06.patchDownload
From 7a02dad9c234e824a2a8916cf043d3ac22908f79 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Thu, 2 Nov 2017 12:21:19 +0100
Subject: [PATCH 5/6] float-zero-v06

Check for float -0 after multiplications and divisions

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com
---
 src/include/utils/float.h | 26 ++++++++++++++++++++------
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/src/include/utils/float.h b/src/include/utils/float.h
index 48a16f491c..0ce37f4a17 100644
--- a/src/include/utils/float.h
+++ b/src/include/utils/float.h
@@ -210,69 +210,83 @@ float8_mi(const float8 val1, const float8 val2)
 
 	result = val1 - val2;
 	check_float8_val(result, isinf(val1) || isinf(val2), true);
 
 	return result;
 }
 
 static inline float4
 float4_mul(const float4 val1, const float4 val2)
 {
+	const bool	zero_is_valid = val1 == 0.0f || val2 == 0.0f;
 	float4		result;
 
 	result = val1 * val2;
-	check_float4_val(result, isinf(val1) || isinf(val2),
-					 val1 == 0.0f || val2 == 0.0f);
+	check_float4_val(result, isinf(val1) || isinf(val2), zero_is_valid);
+
+	if (zero_is_valid && unlikely(result == -0.0f))
+		result = 0.0f;
 
 	return result;
 }
 
 static inline float8
 float8_mul(const float8 val1, const float8 val2)
 {
+	const bool	zero_is_valid = val1 == 0.0 || val2 == 0.0;
 	float8		result;
 
 	result = val1 * val2;
-	check_float8_val(result, isinf(val1) || isinf(val2),
-					 val1 == 0.0 || val2 == 0.0);
+	check_float8_val(result, isinf(val1) || isinf(val2), zero_is_valid);
+
+	if (zero_is_valid && unlikely(result == -0.0))
+		result = 0.0;
 
 	return result;
 }
 
 static inline float4
 float4_div(const float4 val1, const float4 val2)
 {
+	const bool	zero_is_valid = val1 == 0.0f;
 	float4		result;
 
 	if (val2 == 0.0f)
 		ereport(ERROR,
 				(errcode(ERRCODE_DIVISION_BY_ZERO),
 				 errmsg("division by zero")));
 
 	result = val1 / val2;
-	check_float4_val(result, isinf(val1) || isinf(val2), val1 == 0.0f);
+	check_float4_val(result, isinf(val1) || isinf(val2), zero_is_valid);
+
+	if (zero_is_valid && unlikely(result == -0.0f))
+		result = 0.0f;
 
 	return result;
 }
 
 static inline float8
 float8_div(const float8 val1, const float8 val2)
 {
+	const bool	zero_is_valid = val1 == 0.0;
 	float8		result;
 
 	if (val2 == 0.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_DIVISION_BY_ZERO),
 				 errmsg("division by zero")));
 
 	result = val1 / val2;
-	check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
+	check_float8_val(result, isinf(val1) || isinf(val2), zero_is_valid);
+
+	if (zero_is_valid && unlikely(result == -0.0))
+		result = 0.0;
 
 	return result;
 }
 
 /*
  * Routines for NaN-aware comparisons
  *
  * We consider all NaNs to be equal and larger than any non-NaN. This is
  * somewhat arbitrary; the important thing is to have a consistent sort
  * order.
-- 
2.14.3 (Apple Git-98)

0006-geo-tests-v06.patchapplication/octet-stream; name=0006-geo-tests-v06.patchDownload
From 8607af5b0acc6eb9550ee2feecdd54e23155208e Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Tue, 24 Oct 2017 11:28:21 +0200
Subject: [PATCH 6/6] geo-tests-v06

Improve test coverage of geometric types

The tests for the geometric functions and operators were in sad state.
This commit increases test coverage of geo_ops.c significantly.  It
removes the alternative results to expect -0 on some platforms.  We
better try to return the same results on different platforms, but if we
can't we can add them back using the results from build farm.

The tests are added to geometric.sql file.  It is not clear where to
put them as there are many cross datatype operators.  Organising them
on a single file sorted by the left hand side of the operators appear
to be a simple solution.  We may take this further and remove the other
tests later.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com
---
 src/test/regress/expected/box.out          |   44 +-
 src/test/regress/expected/circle.out       |   39 +-
 src/test/regress/expected/create_index.out |   73 +-
 src/test/regress/expected/geometry.out     | 4879 ++++++++++++++++++++++++++--
 src/test/regress/expected/geometry_1.out   |  563 ----
 src/test/regress/expected/geometry_2.out   |  563 ----
 src/test/regress/expected/line.out         |  272 +-
 src/test/regress/expected/lseg.out         |   24 +-
 src/test/regress/expected/path.out         |   49 +-
 src/test/regress/expected/point.out        |  358 +-
 src/test/regress/expected/polygon.out      |  200 +-
 src/test/regress/sql/box.sql               |    9 +
 src/test/regress/sql/circle.sql            |   10 +-
 src/test/regress/sql/geometry.sql          |  400 ++-
 src/test/regress/sql/line.sql              |   79 +-
 src/test/regress/sql/lseg.sql              |    9 +-
 src/test/regress/sql/path.sql              |   22 +-
 src/test/regress/sql/point.sql             |   10 +
 src/test/regress/sql/polygon.sql           |   91 +-
 19 files changed, 5483 insertions(+), 2211 deletions(-)
 delete mode 100644 src/test/regress/expected/geometry_1.out
 delete mode 100644 src/test/regress/expected/geometry_2.out

diff --git a/src/test/regress/expected/box.out b/src/test/regress/expected/box.out
index 49af242c8c..998b52223c 100644
--- a/src/test/regress/expected/box.out
+++ b/src/test/regress/expected/box.out
@@ -11,92 +11,109 @@
 -- 1	| o-+-o
 --	|   |
 -- 0	+---+
 --
 --	0 1 2 3
 --
 -- boxes are specified by two points, given by four floats x1,y1,x2,y2
 CREATE TABLE BOX_TBL (f1 box);
 INSERT INTO BOX_TBL (f1) VALUES ('(2.0,2.0,0.0,0.0)');
 INSERT INTO BOX_TBL (f1) VALUES ('(1.0,1.0,3.0,3.0)');
+INSERT INTO BOX_TBL (f1) VALUES ('((-8, 2), (-2, -10))');
 -- degenerate cases where the box is a line or a point
 -- note that lines and points boxes all have zero area
 INSERT INTO BOX_TBL (f1) VALUES ('(2.5, 2.5, 2.5,3.5)');
 INSERT INTO BOX_TBL (f1) VALUES ('(3.0, 3.0,3.0,3.0)');
 -- badly formatted box inputs
 INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
 ERROR:  invalid input syntax for type box: "(2.3, 4.5)"
 LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
                                          ^
+INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+ERROR:  invalid input syntax for type box: "[1, 2, 3, 4)"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+                                         ^
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+ERROR:  invalid input syntax for type box: "(1, 2, 3, 4]"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+                                         ^
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+ERROR:  invalid input syntax for type box: "(1, 2, 3, 4) x"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+                                         ^
 INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
 ERROR:  invalid input syntax for type box: "asdfasdf(ad"
 LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
                                          ^
 SELECT '' AS four, * FROM BOX_TBL;
  four |         f1          
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
+      | (-2,2),(-8,-10)
       | (2.5,3.5),(2.5,2.5)
       | (3,3),(3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, b.*, area(b.f1) as barea
    FROM BOX_TBL b;
  four |         f1          | barea 
 ------+---------------------+-------
       | (2,2),(0,0)         |     4
       | (3,3),(1,1)         |     4
+      | (-2,2),(-8,-10)     |    72
       | (2.5,3.5),(2.5,2.5) |     0
       | (3,3),(3,3)         |     0
-(4 rows)
+(5 rows)
 
 -- overlap
 SELECT '' AS three, b.f1
    FROM BOX_TBL b
    WHERE b.f1 && box '(2.5,2.5,1.0,1.0)';
  three |         f1          
 -------+---------------------
        | (2,2),(0,0)
        | (3,3),(1,1)
        | (2.5,3.5),(2.5,2.5)
 (3 rows)
 
 -- left-or-overlap (x only)
 SELECT '' AS two, b1.*
    FROM BOX_TBL b1
    WHERE b1.f1 &< box '(2.0,2.0,2.5,2.5)';
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- right-or-overlap (x only)
 SELECT '' AS two, b1.*
    FROM BOX_TBL b1
    WHERE b1.f1 &> box '(2.0,2.0,2.5,2.5)';
  two |         f1          
 -----+---------------------
      | (2.5,3.5),(2.5,2.5)
      | (3,3),(3,3)
 (2 rows)
 
 -- left of
 SELECT '' AS two, b.f1
    FROM BOX_TBL b
    WHERE b.f1 << box '(3.0,3.0,5.0,5.0)';
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- area <=
 SELECT '' AS four, b.f1
    FROM BOX_TBL b
    WHERE b.f1 <= box '(3.0,3.0,5.0,5.0)';
  four |         f1          
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
       | (2.5,3.5),(2.5,2.5)
@@ -120,47 +137,50 @@ SELECT '' AS two, b.f1
  two |     f1      
 -----+-------------
      | (2,2),(0,0)
      | (3,3),(1,1)
 (2 rows)
 
 -- area >
 SELECT '' AS two, b.f1
    FROM BOX_TBL b				-- zero area
    WHERE b.f1 > box '(3.5,3.0,4.5,3.0)';
- two |     f1      
------+-------------
+ two |       f1        
+-----+-----------------
      | (2,2),(0,0)
      | (3,3),(1,1)
-(2 rows)
+     | (-2,2),(-8,-10)
+(3 rows)
 
 -- area >=
 SELECT '' AS four, b.f1
    FROM BOX_TBL b				-- zero area
    WHERE b.f1 >= box '(3.5,3.0,4.5,3.0)';
  four |         f1          
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
+      | (-2,2),(-8,-10)
       | (2.5,3.5),(2.5,2.5)
       | (3,3),(3,3)
-(4 rows)
+(5 rows)
 
 -- right of
 SELECT '' AS two, b.f1
    FROM BOX_TBL b
    WHERE box '(3.0,3.0,5.0,5.0)' >> b.f1;
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- contained in
 SELECT '' AS three, b.f1
    FROM BOX_TBL b
    WHERE b.f1 <@ box '(0,0,3,3)';
  three |     f1      
 -------+-------------
        | (2,2),(0,0)
        | (3,3),(1,1)
        | (3,3),(3,3)
@@ -186,41 +206,43 @@ SELECT '' AS one, b.f1
      | (3,3),(1,1)
 (1 row)
 
 -- center of box, left unary operator
 SELECT '' AS four, @@(b1.f1) AS p
    FROM BOX_TBL b1;
  four |    p    
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 -- wholly-contained
 SELECT '' AS one, b1.*, b2.*
    FROM BOX_TBL b1, BOX_TBL b2
    WHERE b1.f1 @> b2.f1 and not b1.f1 ~= b2.f1;
  one |     f1      |     f1      
 -----+-------------+-------------
      | (3,3),(1,1) | (3,3),(3,3)
 (1 row)
 
 SELECT '' AS four, height(f1), width(f1) FROM BOX_TBL;
  four | height | width 
 ------+--------+-------
       |      2 |     2
       |      2 |     2
+      |     12 |     6
       |      1 |     0
       |      0 |     0
-(4 rows)
+(5 rows)
 
 --
 -- Test the SP-GiST index
 --
 CREATE TEMPORARY TABLE box_temp (f1 box);
 INSERT INTO box_temp
 	SELECT box(point(i, i), point(i * 2, i * 2))
 	FROM generate_series(1, 50) AS i;
 CREATE INDEX box_spgist ON box_temp USING spgist (f1);
 INSERT INTO box_temp
diff --git a/src/test/regress/expected/circle.out b/src/test/regress/expected/circle.out
index 9ba4a0495d..2ed74cc6aa 100644
--- a/src/test/regress/expected/circle.out
+++ b/src/test/regress/expected/circle.out
@@ -1,99 +1,122 @@
 --
 -- CIRCLE
 --
 CREATE TABLE CIRCLE_TBL (f1 circle);
 INSERT INTO CIRCLE_TBL VALUES ('<(5,1),3>');
 INSERT INTO CIRCLE_TBL VALUES ('<(1,2),100>');
 INSERT INTO CIRCLE_TBL VALUES ('1,3,5');
 INSERT INTO CIRCLE_TBL VALUES ('((1,2),3)');
 INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10>');
-INSERT INTO CIRCLE_TBL VALUES ('<(100,1),115>');
+INSERT INTO CIRCLE_TBL VALUES (' < ( 100 , 1 ) , 115 > ');
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),0>');	-- Zero radius
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),NaN>');	-- NaN radius
 -- bad values
 INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
 ERROR:  invalid input syntax for type circle: "<(-100,0),-100>"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
                                        ^
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+ERROR:  invalid input syntax for type circle: "<(100,200),10"
+LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+                                       ^
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+ERROR:  invalid input syntax for type circle: "<(100,200),10> x"
+LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+                                       ^
 INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
 ERROR:  invalid input syntax for type circle: "1abc,3,5"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
                                        ^
 INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
 ERROR:  invalid input syntax for type circle: "(3,(1,2),3)"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
                                        ^
 SELECT * FROM CIRCLE_TBL;
        f1       
 ----------------
  <(5,1),3>
  <(1,2),100>
  <(1,3),5>
  <(1,2),3>
  <(100,200),10>
  <(100,1),115>
-(6 rows)
+ <(3,5),0>
+ <(3,5),NaN>
+(8 rows)
 
 SELECT '' AS six, center(f1) AS center
   FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS six, radius(f1) AS radius
   FROM CIRCLE_TBL;
  six | radius 
 -----+--------
      |      3
      |    100
      |      5
      |      3
      |     10
      |    115
-(6 rows)
+     |      0
+     |    NaN
+(8 rows)
 
 SELECT '' AS six, diameter(f1) AS diameter
   FROM CIRCLE_TBL;
  six | diameter 
 -----+----------
      |        6
      |      200
      |       10
      |        6
      |       20
      |      230
-(6 rows)
+     |        0
+     |      NaN
+(8 rows)
 
 SELECT '' AS two, f1 FROM CIRCLE_TBL WHERE radius(f1) < 5;
  two |    f1     
 -----+-----------
      | <(5,1),3>
      | <(1,2),3>
-(2 rows)
+     | <(3,5),0>
+(3 rows)
 
 SELECT '' AS four, f1 FROM CIRCLE_TBL WHERE diameter(f1) >= 10;
  four |       f1       
 ------+----------------
       | <(1,2),100>
       | <(1,3),5>
       | <(100,200),10>
       | <(100,1),115>
-(4 rows)
+      | <(3,5),NaN>
+(5 rows)
 
 SELECT '' as five, c1.f1 AS one, c2.f1 AS two, (c1.f1 <-> c2.f1) AS distance
   FROM CIRCLE_TBL c1, CIRCLE_TBL c2
   WHERE (c1.f1 < c2.f1) AND ((c1.f1 <-> c2.f1) > 0)
   ORDER BY distance, area(c1.f1), area(c2.f1);
  five |      one       |      two       |     distance     
 ------+----------------+----------------+------------------
+      | <(3,5),0>      | <(1,2),3>      | 0.60555127546399
+      | <(3,5),0>      | <(5,1),3>      | 1.47213595499958
       | <(100,200),10> | <(100,1),115>  |               74
       | <(100,200),10> | <(1,2),100>    | 111.370729772479
       | <(1,3),5>      | <(100,200),10> | 205.476756144497
       | <(5,1),3>      | <(100,200),10> |  207.51303816328
+      | <(3,5),0>      | <(100,200),10> | 207.793480159531
       | <(1,2),3>      | <(100,200),10> | 208.370729772479
-(5 rows)
+(8 rows)
 
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc81088d4b..4e5f573349 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -150,96 +150,103 @@ SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)';
 
 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
+     5
 (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
+     3
 (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
+     4
 (1 row)
 
 SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
  count 
 -------
      1
 (1 row)
 
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
  (-5,-12)
  (5.1,34.5)
+ (1e+300,Infinity)
+ (NaN,NaN)
  
-(7 rows)
+(10 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NULL;
  f1 
 ----
  
 (1 row)
 
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (1e-300,-1e-300)
  (0,0)
  (-3,4)
  (-10,0)
  (10,10)
  (-5,-12)
  (5.1,34.5)
-(6 rows)
+ (1e+300,Infinity)
+ (NaN,NaN)
+(9 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
  count 
 -------
      3
 (1 row)
 
 SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
  count 
 -------
@@ -567,21 +574,21 @@ SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,
                                        QUERY PLAN                                       
 ----------------------------------------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     4
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>';
                      QUERY PLAN                     
 ----------------------------------------------------
  Aggregate
    ->  Index Only Scan using gpointind on point_tbl
          Index Cond: (f1 <@ '<(50,50),50>'::circle)
 (3 rows)
@@ -612,21 +619,21 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     3
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl p WHERE p.f1 <^ '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only Scan using gpointind on point_tbl p
          Index Cond: (f1 <^ '(0,0)'::point)
 (3 rows)
@@ -642,21 +649,21 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 >^ '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     4
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only Scan using gpointind on point_tbl p
          Index Cond: (f1 ~= '(-5,-12)'::point)
 (3 rows)
@@ -669,30 +676,33 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
                   QUERY PLAN                  
 ----------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Order By: (f1 <-> '(0,1)'::point)
 (2 rows)
 
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (10,10)
+ (NaN,NaN)
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
- (10,10)
  (-5,-12)
  (5.1,34.5)
  
-(7 rows)
+ (1e+300,Infinity)
+(10 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 IS NULL;
                   QUERY PLAN                  
 ----------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Index Cond: (f1 IS NULL)
 (2 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NULL;
@@ -704,47 +714,51 @@ SELECT * FROM point_tbl WHERE f1 IS NULL;
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
                   QUERY PLAN                  
 ----------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Index Cond: (f1 IS NOT NULL)
    Order By: (f1 <-> '(0,1)'::point)
 (3 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (10,10)
+ (NaN,NaN)
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
- (10,10)
  (-5,-12)
  (5.1,34.5)
-(6 rows)
+ (1e+300,Infinity)
+(9 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
                    QUERY PLAN                   
 ------------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Index Cond: (f1 <@ '(10,10),(-10,-10)'::box)
    Order By: (f1 <-> '(0,1)'::point)
 (3 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
                         QUERY PLAN                         
 -----------------------------------------------------------
  Aggregate
    ->  Index Only Scan using sp_quad_ind on quad_point_tbl
          Index Cond: (p IS NULL)
 (3 rows)
 
@@ -1261,27 +1275,28 @@ SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0
 ------------------------------------------------------------
  Sort
    Sort Key: ((f1 <-> '(0,1)'::point))
    ->  Bitmap Heap Scan on point_tbl
          Recheck Cond: (f1 <@ '(10,10),(-10,-10)'::box)
          ->  Bitmap Index Scan on gpointind
                Index Cond: (f1 <@ '(10,10),(-10,-10)'::box)
 (6 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
                   QUERY PLAN                  
 ----------------------------------------------
  Aggregate
    ->  Bitmap Heap Scan on quad_point_tbl
          Recheck Cond: (p IS NULL)
          ->  Bitmap Index Scan on sp_quad_ind
                Index Cond: (p IS NULL)
diff --git a/src/test/regress/expected/geometry.out b/src/test/regress/expected/geometry.out
index e4c0039040..b4da3baa37 100644
--- a/src/test/regress/expected/geometry.out
+++ b/src/test/regress/expected/geometry.out
@@ -6,558 +6,4885 @@
 SET extra_float_digits TO -3;
 --
 -- Points
 --
 SELECT '' AS four, center(f1) AS center
    FROM BOX_TBL;
  four | center  
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, (@@ f1) AS center
    FROM BOX_TBL;
  four | center  
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS six, point(f1) AS center
    FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS six, (@@ f1) AS center
    FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS two, (@@ f1) AS center
    FROM POLYGON_TBL
    WHERE (# f1) > 2;
  two |            center             
 -----+-------------------------------
      | (1.33333333333,1.33333333333)
      | (2.33333333333,1.33333333333)
-(2 rows)
+     | (4,5)
+     | (4,5)
+     | (4,3)
+(5 rows)
 
 -- "is horizontal" function
 SELECT '' AS two, p1.f1
    FROM POINT_TBL p1
    WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 -- "is horizontal" operator
 SELECT '' AS two, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 -- "is vertical" function
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE isvertical(p1.f1, point '(5.1,34.5)');
  one |     f1     
 -----+------------
      | (5.1,34.5)
 (1 row)
 
 -- "is vertical" operator
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?| point '(5.1,34.5)';
  one |     f1     
 -----+------------
      | (5.1,34.5)
 (1 row)
 
+-- Slope
+SELECT p1.f1, p2.f1, slope(p1.f1, p2.f1) FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |       slope        
+-------------------+-------------------+--------------------
+ (0,0)             | (0,0)             | 1.79769313486e+308
+ (0,0)             | (-10,0)           |                  0
+ (0,0)             | (-3,4)            |     -1.33333333333
+ (0,0)             | (5.1,34.5)        |      6.76470588235
+ (0,0)             | (-5,-12)          |                2.4
+ (0,0)             | (1e-300,-1e-300)  | 1.79769313486e+308
+ (0,0)             | (1e+300,Infinity) |           Infinity
+ (0,0)             | (NaN,NaN)         |                NaN
+ (0,0)             | (10,10)           |                  1
+ (-10,0)           | (0,0)             |                  0
+ (-10,0)           | (-10,0)           | 1.79769313486e+308
+ (-10,0)           | (-3,4)            |     0.571428571429
+ (-10,0)           | (5.1,34.5)        |      2.28476821192
+ (-10,0)           | (-5,-12)          |               -2.4
+ (-10,0)           | (1e-300,-1e-300)  |                  0
+ (-10,0)           | (1e+300,Infinity) |           Infinity
+ (-10,0)           | (NaN,NaN)         |                NaN
+ (-10,0)           | (10,10)           |                0.5
+ (-3,4)            | (0,0)             |     -1.33333333333
+ (-3,4)            | (-10,0)           |     0.571428571429
+ (-3,4)            | (-3,4)            | 1.79769313486e+308
+ (-3,4)            | (5.1,34.5)        |      3.76543209877
+ (-3,4)            | (-5,-12)          |                  8
+ (-3,4)            | (1e-300,-1e-300)  |     -1.33333333333
+ (-3,4)            | (1e+300,Infinity) |           Infinity
+ (-3,4)            | (NaN,NaN)         |                NaN
+ (-3,4)            | (10,10)           |     0.461538461538
+ (5.1,34.5)        | (0,0)             |      6.76470588235
+ (5.1,34.5)        | (-10,0)           |      2.28476821192
+ (5.1,34.5)        | (-3,4)            |      3.76543209877
+ (5.1,34.5)        | (5.1,34.5)        | 1.79769313486e+308
+ (5.1,34.5)        | (-5,-12)          |      4.60396039604
+ (5.1,34.5)        | (1e-300,-1e-300)  |      6.76470588235
+ (5.1,34.5)        | (1e+300,Infinity) |           Infinity
+ (5.1,34.5)        | (NaN,NaN)         |                NaN
+ (5.1,34.5)        | (10,10)           |                 -5
+ (-5,-12)          | (0,0)             |                2.4
+ (-5,-12)          | (-10,0)           |               -2.4
+ (-5,-12)          | (-3,4)            |                  8
+ (-5,-12)          | (5.1,34.5)        |      4.60396039604
+ (-5,-12)          | (-5,-12)          | 1.79769313486e+308
+ (-5,-12)          | (1e-300,-1e-300)  |                2.4
+ (-5,-12)          | (1e+300,Infinity) |           Infinity
+ (-5,-12)          | (NaN,NaN)         |                NaN
+ (-5,-12)          | (10,10)           |      1.46666666667
+ (1e-300,-1e-300)  | (0,0)             | 1.79769313486e+308
+ (1e-300,-1e-300)  | (-10,0)           |                  0
+ (1e-300,-1e-300)  | (-3,4)            |     -1.33333333333
+ (1e-300,-1e-300)  | (5.1,34.5)        |      6.76470588235
+ (1e-300,-1e-300)  | (-5,-12)          |                2.4
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | 1.79769313486e+308
+ (1e-300,-1e-300)  | (1e+300,Infinity) |           Infinity
+ (1e-300,-1e-300)  | (NaN,NaN)         |                NaN
+ (1e-300,-1e-300)  | (10,10)           |                  1
+ (1e+300,Infinity) | (0,0)             |           Infinity
+ (1e+300,Infinity) | (-10,0)           |           Infinity
+ (1e+300,Infinity) | (-3,4)            |           Infinity
+ (1e+300,Infinity) | (5.1,34.5)        |           Infinity
+ (1e+300,Infinity) | (-5,-12)          |           Infinity
+ (1e+300,Infinity) | (1e-300,-1e-300)  |           Infinity
+ (1e+300,Infinity) | (1e+300,Infinity) | 1.79769313486e+308
+ (1e+300,Infinity) | (NaN,NaN)         |                NaN
+ (1e+300,Infinity) | (10,10)           |           Infinity
+ (NaN,NaN)         | (0,0)             |                NaN
+ (NaN,NaN)         | (-10,0)           |                NaN
+ (NaN,NaN)         | (-3,4)            |                NaN
+ (NaN,NaN)         | (5.1,34.5)        |                NaN
+ (NaN,NaN)         | (-5,-12)          |                NaN
+ (NaN,NaN)         | (1e-300,-1e-300)  |                NaN
+ (NaN,NaN)         | (1e+300,Infinity) |                NaN
+ (NaN,NaN)         | (NaN,NaN)         |                NaN
+ (NaN,NaN)         | (10,10)           |                NaN
+ (10,10)           | (0,0)             |                  1
+ (10,10)           | (-10,0)           |                0.5
+ (10,10)           | (-3,4)            |     0.461538461538
+ (10,10)           | (5.1,34.5)        |                 -5
+ (10,10)           | (-5,-12)          |      1.46666666667
+ (10,10)           | (1e-300,-1e-300)  |                  1
+ (10,10)           | (1e+300,Infinity) |           Infinity
+ (10,10)           | (NaN,NaN)         |                NaN
+ (10,10)           | (10,10)           | 1.79769313486e+308
+(81 rows)
+
+-- Add point
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |     ?column?      
+-------------------+-------------------+-------------------
+ (0,0)             | (0,0)             | (0,0)
+ (0,0)             | (-10,0)           | (-10,0)
+ (0,0)             | (-3,4)            | (-3,4)
+ (0,0)             | (5.1,34.5)        | (5.1,34.5)
+ (0,0)             | (-5,-12)          | (-5,-12)
+ (0,0)             | (1e-300,-1e-300)  | (1e-300,-1e-300)
+ (0,0)             | (1e+300,Infinity) | (1e+300,Infinity)
+ (0,0)             | (NaN,NaN)         | (NaN,NaN)
+ (0,0)             | (10,10)           | (10,10)
+ (-10,0)           | (0,0)             | (-10,0)
+ (-10,0)           | (-10,0)           | (-20,0)
+ (-10,0)           | (-3,4)            | (-13,4)
+ (-10,0)           | (5.1,34.5)        | (-4.9,34.5)
+ (-10,0)           | (-5,-12)          | (-15,-12)
+ (-10,0)           | (1e-300,-1e-300)  | (-10,-1e-300)
+ (-10,0)           | (1e+300,Infinity) | (1e+300,Infinity)
+ (-10,0)           | (NaN,NaN)         | (NaN,NaN)
+ (-10,0)           | (10,10)           | (0,10)
+ (-3,4)            | (0,0)             | (-3,4)
+ (-3,4)            | (-10,0)           | (-13,4)
+ (-3,4)            | (-3,4)            | (-6,8)
+ (-3,4)            | (5.1,34.5)        | (2.1,38.5)
+ (-3,4)            | (-5,-12)          | (-8,-8)
+ (-3,4)            | (1e-300,-1e-300)  | (-3,4)
+ (-3,4)            | (1e+300,Infinity) | (1e+300,Infinity)
+ (-3,4)            | (NaN,NaN)         | (NaN,NaN)
+ (-3,4)            | (10,10)           | (7,14)
+ (5.1,34.5)        | (0,0)             | (5.1,34.5)
+ (5.1,34.5)        | (-10,0)           | (-4.9,34.5)
+ (5.1,34.5)        | (-3,4)            | (2.1,38.5)
+ (5.1,34.5)        | (5.1,34.5)        | (10.2,69)
+ (5.1,34.5)        | (-5,-12)          | (0.1,22.5)
+ (5.1,34.5)        | (1e-300,-1e-300)  | (5.1,34.5)
+ (5.1,34.5)        | (1e+300,Infinity) | (1e+300,Infinity)
+ (5.1,34.5)        | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5)        | (10,10)           | (15.1,44.5)
+ (-5,-12)          | (0,0)             | (-5,-12)
+ (-5,-12)          | (-10,0)           | (-15,-12)
+ (-5,-12)          | (-3,4)            | (-8,-8)
+ (-5,-12)          | (5.1,34.5)        | (0.1,22.5)
+ (-5,-12)          | (-5,-12)          | (-10,-24)
+ (-5,-12)          | (1e-300,-1e-300)  | (-5,-12)
+ (-5,-12)          | (1e+300,Infinity) | (1e+300,Infinity)
+ (-5,-12)          | (NaN,NaN)         | (NaN,NaN)
+ (-5,-12)          | (10,10)           | (5,-2)
+ (1e-300,-1e-300)  | (0,0)             | (1e-300,-1e-300)
+ (1e-300,-1e-300)  | (-10,0)           | (-10,-1e-300)
+ (1e-300,-1e-300)  | (-3,4)            | (-3,4)
+ (1e-300,-1e-300)  | (5.1,34.5)        | (5.1,34.5)
+ (1e-300,-1e-300)  | (-5,-12)          | (-5,-12)
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | (2e-300,-2e-300)
+ (1e-300,-1e-300)  | (1e+300,Infinity) | (1e+300,Infinity)
+ (1e-300,-1e-300)  | (NaN,NaN)         | (NaN,NaN)
+ (1e-300,-1e-300)  | (10,10)           | (10,10)
+ (1e+300,Infinity) | (0,0)             | (1e+300,Infinity)
+ (1e+300,Infinity) | (-10,0)           | (1e+300,Infinity)
+ (1e+300,Infinity) | (-3,4)            | (1e+300,Infinity)
+ (1e+300,Infinity) | (5.1,34.5)        | (1e+300,Infinity)
+ (1e+300,Infinity) | (-5,-12)          | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e-300,-1e-300)  | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e+300,Infinity) | (2e+300,Infinity)
+ (1e+300,Infinity) | (NaN,NaN)         | (NaN,NaN)
+ (1e+300,Infinity) | (10,10)           | (1e+300,Infinity)
+ (NaN,NaN)         | (0,0)             | (NaN,NaN)
+ (NaN,NaN)         | (-10,0)           | (NaN,NaN)
+ (NaN,NaN)         | (-3,4)            | (NaN,NaN)
+ (NaN,NaN)         | (5.1,34.5)        | (NaN,NaN)
+ (NaN,NaN)         | (-5,-12)          | (NaN,NaN)
+ (NaN,NaN)         | (1e-300,-1e-300)  | (NaN,NaN)
+ (NaN,NaN)         | (1e+300,Infinity) | (NaN,NaN)
+ (NaN,NaN)         | (NaN,NaN)         | (NaN,NaN)
+ (NaN,NaN)         | (10,10)           | (NaN,NaN)
+ (10,10)           | (0,0)             | (10,10)
+ (10,10)           | (-10,0)           | (0,10)
+ (10,10)           | (-3,4)            | (7,14)
+ (10,10)           | (5.1,34.5)        | (15.1,44.5)
+ (10,10)           | (-5,-12)          | (5,-2)
+ (10,10)           | (1e-300,-1e-300)  | (10,10)
+ (10,10)           | (1e+300,Infinity) | (1e+300,Infinity)
+ (10,10)           | (NaN,NaN)         | (NaN,NaN)
+ (10,10)           | (10,10)           | (20,20)
+(81 rows)
+
+-- Subtract point
+SELECT p1.f1, p2.f1, p1.f1 - p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |      ?column?       
+-------------------+-------------------+---------------------
+ (0,0)             | (0,0)             | (0,0)
+ (0,0)             | (-10,0)           | (10,0)
+ (0,0)             | (-3,4)            | (3,-4)
+ (0,0)             | (5.1,34.5)        | (-5.1,-34.5)
+ (0,0)             | (-5,-12)          | (5,12)
+ (0,0)             | (1e-300,-1e-300)  | (-1e-300,1e-300)
+ (0,0)             | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (0,0)             | (NaN,NaN)         | (NaN,NaN)
+ (0,0)             | (10,10)           | (-10,-10)
+ (-10,0)           | (0,0)             | (-10,0)
+ (-10,0)           | (-10,0)           | (0,0)
+ (-10,0)           | (-3,4)            | (-7,-4)
+ (-10,0)           | (5.1,34.5)        | (-15.1,-34.5)
+ (-10,0)           | (-5,-12)          | (-5,12)
+ (-10,0)           | (1e-300,-1e-300)  | (-10,1e-300)
+ (-10,0)           | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-10,0)           | (NaN,NaN)         | (NaN,NaN)
+ (-10,0)           | (10,10)           | (-20,-10)
+ (-3,4)            | (0,0)             | (-3,4)
+ (-3,4)            | (-10,0)           | (7,4)
+ (-3,4)            | (-3,4)            | (0,0)
+ (-3,4)            | (5.1,34.5)        | (-8.1,-30.5)
+ (-3,4)            | (-5,-12)          | (2,16)
+ (-3,4)            | (1e-300,-1e-300)  | (-3,4)
+ (-3,4)            | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-3,4)            | (NaN,NaN)         | (NaN,NaN)
+ (-3,4)            | (10,10)           | (-13,-6)
+ (5.1,34.5)        | (0,0)             | (5.1,34.5)
+ (5.1,34.5)        | (-10,0)           | (15.1,34.5)
+ (5.1,34.5)        | (-3,4)            | (8.1,30.5)
+ (5.1,34.5)        | (5.1,34.5)        | (0,0)
+ (5.1,34.5)        | (-5,-12)          | (10.1,46.5)
+ (5.1,34.5)        | (1e-300,-1e-300)  | (5.1,34.5)
+ (5.1,34.5)        | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (5.1,34.5)        | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5)        | (10,10)           | (-4.9,24.5)
+ (-5,-12)          | (0,0)             | (-5,-12)
+ (-5,-12)          | (-10,0)           | (5,-12)
+ (-5,-12)          | (-3,4)            | (-2,-16)
+ (-5,-12)          | (5.1,34.5)        | (-10.1,-46.5)
+ (-5,-12)          | (-5,-12)          | (0,0)
+ (-5,-12)          | (1e-300,-1e-300)  | (-5,-12)
+ (-5,-12)          | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-5,-12)          | (NaN,NaN)         | (NaN,NaN)
+ (-5,-12)          | (10,10)           | (-15,-22)
+ (1e-300,-1e-300)  | (0,0)             | (1e-300,-1e-300)
+ (1e-300,-1e-300)  | (-10,0)           | (10,-1e-300)
+ (1e-300,-1e-300)  | (-3,4)            | (3,-4)
+ (1e-300,-1e-300)  | (5.1,34.5)        | (-5.1,-34.5)
+ (1e-300,-1e-300)  | (-5,-12)          | (5,12)
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | (0,0)
+ (1e-300,-1e-300)  | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (1e-300,-1e-300)  | (NaN,NaN)         | (NaN,NaN)
+ (1e-300,-1e-300)  | (10,10)           | (-10,-10)
+ (1e+300,Infinity) | (0,0)             | (1e+300,Infinity)
+ (1e+300,Infinity) | (-10,0)           | (1e+300,Infinity)
+ (1e+300,Infinity) | (-3,4)            | (1e+300,Infinity)
+ (1e+300,Infinity) | (5.1,34.5)        | (1e+300,Infinity)
+ (1e+300,Infinity) | (-5,-12)          | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e-300,-1e-300)  | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e+300,Infinity) | (0,NaN)
+ (1e+300,Infinity) | (NaN,NaN)         | (NaN,NaN)
+ (1e+300,Infinity) | (10,10)           | (1e+300,Infinity)
+ (NaN,NaN)         | (0,0)             | (NaN,NaN)
+ (NaN,NaN)         | (-10,0)           | (NaN,NaN)
+ (NaN,NaN)         | (-3,4)            | (NaN,NaN)
+ (NaN,NaN)         | (5.1,34.5)        | (NaN,NaN)
+ (NaN,NaN)         | (-5,-12)          | (NaN,NaN)
+ (NaN,NaN)         | (1e-300,-1e-300)  | (NaN,NaN)
+ (NaN,NaN)         | (1e+300,Infinity) | (NaN,NaN)
+ (NaN,NaN)         | (NaN,NaN)         | (NaN,NaN)
+ (NaN,NaN)         | (10,10)           | (NaN,NaN)
+ (10,10)           | (0,0)             | (10,10)
+ (10,10)           | (-10,0)           | (20,10)
+ (10,10)           | (-3,4)            | (13,6)
+ (10,10)           | (5.1,34.5)        | (4.9,-24.5)
+ (10,10)           | (-5,-12)          | (15,22)
+ (10,10)           | (1e-300,-1e-300)  | (10,10)
+ (10,10)           | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (10,10)           | (NaN,NaN)         | (NaN,NaN)
+ (10,10)           | (10,10)           | (0,0)
+(81 rows)
+
+-- Multiply with point
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+     f1     |        f1         |       ?column?        
+------------+-------------------+-----------------------
+ (5.1,34.5) | (0,0)             | (0,0)
+ (10,10)    | (0,0)             | (0,0)
+ (5.1,34.5) | (-10,0)           | (-51,-345)
+ (10,10)    | (-10,0)           | (-100,-100)
+ (5.1,34.5) | (-3,4)            | (-153.3,-83.1)
+ (10,10)    | (-3,4)            | (-70,10)
+ (5.1,34.5) | (5.1,34.5)        | (-1164.24,351.9)
+ (10,10)    | (5.1,34.5)        | (-294,396)
+ (5.1,34.5) | (-5,-12)          | (388.5,-233.7)
+ (10,10)    | (-5,-12)          | (70,-170)
+ (5.1,34.5) | (1e-300,-1e-300)  | (3.96e-299,2.94e-299)
+ (10,10)    | (1e-300,-1e-300)  | (2e-299,0)
+ (5.1,34.5) | (1e+300,Infinity) | (-Infinity,Infinity)
+ (10,10)    | (1e+300,Infinity) | (-Infinity,Infinity)
+ (5.1,34.5) | (NaN,NaN)         | (NaN,NaN)
+ (10,10)    | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5) | (10,10)           | (-294,396)
+ (10,10)    | (10,10)           | (0,200)
+(18 rows)
+
+-- Underflow error
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] < 1;
+ERROR:  value out of range: underflow
+-- Divide by point
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] BETWEEN 1 AND 1000;
+        f1         |     f1     |                 ?column?                  
+-------------------+------------+-------------------------------------------
+ (0,0)             | (5.1,34.5) | (0,0)
+ (0,0)             | (10,10)    | (0,0)
+ (-10,0)           | (5.1,34.5) | (-0.0419318237877,0.283656455034)
+ (-10,0)           | (10,10)    | (-0.5,0.5)
+ (-3,4)            | (5.1,34.5) | (0.100883034877,0.101869666025)
+ (-3,4)            | (10,10)    | (0.05,0.35)
+ (5.1,34.5)        | (5.1,34.5) | (1,0)
+ (5.1,34.5)        | (10,10)    | (1.98,1.47)
+ (-5,-12)          | (5.1,34.5) | (-0.361353657935,0.0915100389719)
+ (-5,-12)          | (10,10)    | (-0.85,-0.35)
+ (1e-300,-1e-300)  | (5.1,34.5) | (-2.41724631247e-302,-3.25588278822e-302)
+ (1e-300,-1e-300)  | (10,10)    | (0,-1e-301)
+ (1e+300,Infinity) | (5.1,34.5) | (Infinity,Infinity)
+ (1e+300,Infinity) | (10,10)    | (Infinity,Infinity)
+ (NaN,NaN)         | (5.1,34.5) | (NaN,NaN)
+ (NaN,NaN)         | (10,10)    | (NaN,NaN)
+ (10,10)           | (5.1,34.5) | (0.325588278822,-0.241724631247)
+ (10,10)           | (10,10)    | (1,0)
+(18 rows)
+
+-- Overflow error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] > 1000;
+ERROR:  value out of range: overflow
+-- Division by 0 error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to line
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LINE_TBL l;
+        f1         |                   s                   |      ?column?      
+-------------------+---------------------------------------+--------------------
+ (0,0)             | {0,-1,5}                              |                  5
+ (0,0)             | {1,0,5}                               |                  5
+ (0,0)             | {0,3,0}                               |                  0
+ (0,0)             | {1,-1,0}                              |                  0
+ (0,0)             | {-0.4,-1,-6}                          |      5.57086014531
+ (0,0)             | {-0.000184615384615,-1,15.3846153846} |      15.3846151224
+ (0,0)             | {3,NaN,5}                             |                NaN
+ (0,0)             | {NaN,NaN,NaN}                         |                NaN
+ (0,0)             | {0,-1,3}                              |                  3
+ (0,0)             | {-1,0,3}                              |                  3
+ (-10,0)           | {0,-1,5}                              |                  5
+ (-10,0)           | {1,0,5}                               |                  5
+ (-10,0)           | {0,3,0}                               |                  0
+ (-10,0)           | {1,-1,0}                              |      7.07106781187
+ (-10,0)           | {-0.4,-1,-6}                          |      1.85695338177
+ (-10,0)           | {-0.000184615384615,-1,15.3846153846} |      15.3864612763
+ (-10,0)           | {3,NaN,5}                             |                NaN
+ (-10,0)           | {NaN,NaN,NaN}                         |                NaN
+ (-10,0)           | {0,-1,3}                              |                  3
+ (-10,0)           | {-1,0,3}                              |                 13
+ (-3,4)            | {0,-1,5}                              |                  1
+ (-3,4)            | {1,0,5}                               |                  2
+ (-3,4)            | {0,3,0}                               |                  4
+ (-3,4)            | {1,-1,0}                              |      4.94974746831
+ (-3,4)            | {-0.4,-1,-6}                          |      8.17059487979
+ (-3,4)            | {-0.000184615384615,-1,15.3846153846} |      11.3851690368
+ (-3,4)            | {3,NaN,5}                             |                NaN
+ (-3,4)            | {NaN,NaN,NaN}                         |                NaN
+ (-3,4)            | {0,-1,3}                              |                  1
+ (-3,4)            | {-1,0,3}                              |                  6
+ (5.1,34.5)        | {0,-1,5}                              |               29.5
+ (5.1,34.5)        | {1,0,5}                               |               10.1
+ (5.1,34.5)        | {0,3,0}                               |               34.5
+ (5.1,34.5)        | {1,-1,0}                              |      20.7889393669
+ (5.1,34.5)        | {-0.4,-1,-6}                          |      39.4973984303
+ (5.1,34.5)        | {-0.000184615384615,-1,15.3846153846} |      19.1163258281
+ (5.1,34.5)        | {3,NaN,5}                             |                NaN
+ (5.1,34.5)        | {NaN,NaN,NaN}                         |                NaN
+ (5.1,34.5)        | {0,-1,3}                              |               31.5
+ (5.1,34.5)        | {-1,0,3}                              |                2.1
+ (-5,-12)          | {0,-1,5}                              |                 17
+ (-5,-12)          | {1,0,5}                               |                  0
+ (-5,-12)          | {0,3,0}                               |                 12
+ (-5,-12)          | {1,-1,0}                              |      4.94974746831
+ (-5,-12)          | {-0.4,-1,-6}                          |      7.42781352708
+ (-5,-12)          | {-0.000184615384615,-1,15.3846153846} |      27.3855379948
+ (-5,-12)          | {3,NaN,5}                             |                NaN
+ (-5,-12)          | {NaN,NaN,NaN}                         |                NaN
+ (-5,-12)          | {0,-1,3}                              |                 15
+ (-5,-12)          | {-1,0,3}                              |                  8
+ (1e-300,-1e-300)  | {0,-1,5}                              |                  5
+ (1e-300,-1e-300)  | {1,0,5}                               |                  5
+ (1e-300,-1e-300)  | {0,3,0}                               |             1e-300
+ (1e-300,-1e-300)  | {1,-1,0}                              | 1.41421356237e-300
+ (1e-300,-1e-300)  | {-0.4,-1,-6}                          |      5.57086014531
+ (1e-300,-1e-300)  | {-0.000184615384615,-1,15.3846153846} |      15.3846151224
+ (1e-300,-1e-300)  | {3,NaN,5}                             |                NaN
+ (1e-300,-1e-300)  | {NaN,NaN,NaN}                         |                NaN
+ (1e-300,-1e-300)  | {0,-1,3}                              |                  3
+ (1e-300,-1e-300)  | {-1,0,3}                              |                  3
+ (1e+300,Infinity) | {0,-1,5}                              |           Infinity
+ (1e+300,Infinity) | {1,0,5}                               |                NaN
+ (1e+300,Infinity) | {0,3,0}                               |           Infinity
+ (1e+300,Infinity) | {1,-1,0}                              |           Infinity
+ (1e+300,Infinity) | {-0.4,-1,-6}                          |           Infinity
+ (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} |           Infinity
+ (1e+300,Infinity) | {3,NaN,5}                             |                NaN
+ (1e+300,Infinity) | {NaN,NaN,NaN}                         |                NaN
+ (1e+300,Infinity) | {0,-1,3}                              |           Infinity
+ (1e+300,Infinity) | {-1,0,3}                              |                NaN
+ (NaN,NaN)         | {0,-1,5}                              |                NaN
+ (NaN,NaN)         | {1,0,5}                               |                NaN
+ (NaN,NaN)         | {0,3,0}                               |                NaN
+ (NaN,NaN)         | {1,-1,0}                              |                NaN
+ (NaN,NaN)         | {-0.4,-1,-6}                          |                NaN
+ (NaN,NaN)         | {-0.000184615384615,-1,15.3846153846} |                NaN
+ (NaN,NaN)         | {3,NaN,5}                             |                NaN
+ (NaN,NaN)         | {NaN,NaN,NaN}                         |                NaN
+ (NaN,NaN)         | {0,-1,3}                              |                NaN
+ (NaN,NaN)         | {-1,0,3}                              |                NaN
+ (10,10)           | {0,-1,5}                              |                  5
+ (10,10)           | {1,0,5}                               |                 15
+ (10,10)           | {0,3,0}                               |                 10
+ (10,10)           | {1,-1,0}                              |                  0
+ (10,10)           | {-0.4,-1,-6}                          |      18.5695338177
+ (10,10)           | {-0.000184615384615,-1,15.3846153846} |      5.38276913903
+ (10,10)           | {3,NaN,5}                             |                NaN
+ (10,10)           | {NaN,NaN,NaN}                         |                NaN
+ (10,10)           | {0,-1,3}                              |                  7
+ (10,10)           | {-1,0,3}                              |                  7
+(90 rows)
+
+-- Distance to line segment
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LSEG_TBL l;
+        f1         |               s               |      ?column?      
+-------------------+-------------------------------+--------------------
+ (0,0)             | [(1,2),(3,4)]                 |       2.2360679775
+ (0,0)             | [(0,0),(6,6)]                 |                  0
+ (0,0)             | [(10,-10),(-3,-4)]            |      4.88901207039
+ (0,0)             | [(-1000000,200),(300000,-40)] |      15.3846151224
+ (0,0)             | [(11,22),(33,44)]             |      24.5967477525
+ (0,0)             | [(-10,2),(-10,3)]             |      10.1980390272
+ (0,0)             | [(0,-20),(30,-20)]            |                 20
+ (0,0)             | [(NaN,1),(NaN,90)]            |                NaN
+ (-10,0)           | [(1,2),(3,4)]                 |      11.1803398875
+ (-10,0)           | [(0,0),(6,6)]                 |                 10
+ (-10,0)           | [(10,-10),(-3,-4)]            |       8.0622577483
+ (-10,0)           | [(-1000000,200),(300000,-40)] |      15.3864612763
+ (-10,0)           | [(11,22),(33,44)]             |      30.4138126515
+ (-10,0)           | [(-10,2),(-10,3)]             |                  2
+ (-10,0)           | [(0,-20),(30,-20)]            |       22.360679775
+ (-10,0)           | [(NaN,1),(NaN,90)]            |                NaN
+ (-3,4)            | [(1,2),(3,4)]                 |        4.472135955
+ (-3,4)            | [(0,0),(6,6)]                 |      4.94974746831
+ (-3,4)            | [(10,-10),(-3,-4)]            |                  8
+ (-3,4)            | [(-1000000,200),(300000,-40)] |      11.3851690367
+ (-3,4)            | [(11,22),(33,44)]             |       22.803508502
+ (-3,4)            | [(-10,2),(-10,3)]             |      7.07106781187
+ (-3,4)            | [(0,-20),(30,-20)]            |      24.1867732449
+ (-3,4)            | [(NaN,1),(NaN,90)]            |                NaN
+ (5.1,34.5)        | [(1,2),(3,4)]                 |      30.5722096028
+ (5.1,34.5)        | [(0,0),(6,6)]                 |      28.5142069853
+ (5.1,34.5)        | [(10,-10),(-3,-4)]            |      39.3428519556
+ (5.1,34.5)        | [(-1000000,200),(300000,-40)] |      19.1163258281
+ (5.1,34.5)        | [(11,22),(33,44)]             |      13.0107647738
+ (5.1,34.5)        | [(-10,2),(-10,3)]             |       34.932220084
+ (5.1,34.5)        | [(0,-20),(30,-20)]            |               54.5
+ (5.1,34.5)        | [(NaN,1),(NaN,90)]            |                NaN
+ (-5,-12)          | [(1,2),(3,4)]                 |      15.2315462117
+ (-5,-12)          | [(0,0),(6,6)]                 |                 13
+ (-5,-12)          | [(10,-10),(-3,-4)]            |      8.10179143093
+ (-5,-12)          | [(-1000000,200),(300000,-40)] |      27.3855379949
+ (-5,-12)          | [(11,22),(33,44)]             |      37.5765884561
+ (-5,-12)          | [(-10,2),(-10,3)]             |      14.8660687473
+ (-5,-12)          | [(0,-20),(30,-20)]            |      9.43398113206
+ (-5,-12)          | [(NaN,1),(NaN,90)]            |                NaN
+ (1e-300,-1e-300)  | [(1,2),(3,4)]                 |       2.2360679775
+ (1e-300,-1e-300)  | [(0,0),(6,6)]                 | 1.41421356237e-300
+ (1e-300,-1e-300)  | [(10,-10),(-3,-4)]            |      4.88901207039
+ (1e-300,-1e-300)  | [(-1000000,200),(300000,-40)] |      15.3846151224
+ (1e-300,-1e-300)  | [(11,22),(33,44)]             |      24.5967477525
+ (1e-300,-1e-300)  | [(-10,2),(-10,3)]             |      10.1980390272
+ (1e-300,-1e-300)  | [(0,-20),(30,-20)]            |                 20
+ (1e-300,-1e-300)  | [(NaN,1),(NaN,90)]            |                NaN
+ (1e+300,Infinity) | [(1,2),(3,4)]                 |           Infinity
+ (1e+300,Infinity) | [(0,0),(6,6)]                 |           Infinity
+ (1e+300,Infinity) | [(10,-10),(-3,-4)]            |           Infinity
+ (1e+300,Infinity) | [(-1000000,200),(300000,-40)] |           Infinity
+ (1e+300,Infinity) | [(11,22),(33,44)]             |           Infinity
+ (1e+300,Infinity) | [(-10,2),(-10,3)]             |           Infinity
+ (1e+300,Infinity) | [(0,-20),(30,-20)]            |           Infinity
+ (1e+300,Infinity) | [(NaN,1),(NaN,90)]            |           Infinity
+ (NaN,NaN)         | [(1,2),(3,4)]                 |                NaN
+ (NaN,NaN)         | [(0,0),(6,6)]                 |                NaN
+ (NaN,NaN)         | [(10,-10),(-3,-4)]            |                NaN
+ (NaN,NaN)         | [(-1000000,200),(300000,-40)] |                NaN
+ (NaN,NaN)         | [(11,22),(33,44)]             |                NaN
+ (NaN,NaN)         | [(-10,2),(-10,3)]             |                NaN
+ (NaN,NaN)         | [(0,-20),(30,-20)]            |                NaN
+ (NaN,NaN)         | [(NaN,1),(NaN,90)]            |                NaN
+ (10,10)           | [(1,2),(3,4)]                 |      9.21954445729
+ (10,10)           | [(0,0),(6,6)]                 |      5.65685424949
+ (10,10)           | [(10,-10),(-3,-4)]            |        18.15918769
+ (10,10)           | [(-1000000,200),(300000,-40)] |      5.38276913904
+ (10,10)           | [(11,22),(33,44)]             |      12.0415945788
+ (10,10)           | [(-10,2),(-10,3)]             |      21.1896201004
+ (10,10)           | [(0,-20),(30,-20)]            |                 30
+ (10,10)           | [(NaN,1),(NaN,90)]            |                NaN
+(72 rows)
+
+-- Distance to box
+SELECT p.f1, b.f1, p.f1 <-> b.f1 FROM POINT_TBL p, BOX_TBL b;
+        f1         |         f1          |      ?column?      
+-------------------+---------------------+--------------------
+ (0,0)             | (2,2),(0,0)         |                  0
+ (0,0)             | (3,3),(1,1)         |      1.41421356237
+ (0,0)             | (-2,2),(-8,-10)     |                  2
+ (0,0)             | (2.5,3.5),(2.5,2.5) |      3.53553390593
+ (0,0)             | (3,3),(3,3)         |      4.24264068712
+ (-10,0)           | (2,2),(0,0)         |                 10
+ (-10,0)           | (3,3),(1,1)         |      11.0453610172
+ (-10,0)           | (-2,2),(-8,-10)     |                  2
+ (-10,0)           | (2.5,3.5),(2.5,2.5) |       12.747548784
+ (-10,0)           | (3,3),(3,3)         |      13.3416640641
+ (-3,4)            | (2,2),(0,0)         |      3.60555127546
+ (-3,4)            | (3,3),(1,1)         |      4.12310562562
+ (-3,4)            | (-2,2),(-8,-10)     |                  2
+ (-3,4)            | (2.5,3.5),(2.5,2.5) |      5.52268050859
+ (-3,4)            | (3,3),(3,3)         |       6.0827625303
+ (5.1,34.5)        | (2,2),(0,0)         |      32.6475113906
+ (5.1,34.5)        | (3,3),(1,1)         |      31.5699223946
+ (5.1,34.5)        | (-2,2),(-8,-10)     |      33.2664996656
+ (5.1,34.5)        | (2.5,3.5),(2.5,2.5) |       31.108841187
+ (5.1,34.5)        | (3,3),(3,3)         |      31.5699223946
+ (-5,-12)          | (2,2),(0,0)         |                 13
+ (-5,-12)          | (3,3),(1,1)         |      14.3178210633
+ (-5,-12)          | (-2,2),(-8,-10)     |                  2
+ (-5,-12)          | (2.5,3.5),(2.5,2.5) |      16.3248277173
+ (-5,-12)          | (3,3),(3,3)         |                 17
+ (1e-300,-1e-300)  | (2,2),(0,0)         | 1.41421356237e-300
+ (1e-300,-1e-300)  | (3,3),(1,1)         |      1.41421356237
+ (1e-300,-1e-300)  | (-2,2),(-8,-10)     |                  2
+ (1e-300,-1e-300)  | (2.5,3.5),(2.5,2.5) |      3.53553390593
+ (1e-300,-1e-300)  | (3,3),(3,3)         |      4.24264068712
+ (1e+300,Infinity) | (2,2),(0,0)         |           Infinity
+ (1e+300,Infinity) | (3,3),(1,1)         |           Infinity
+ (1e+300,Infinity) | (-2,2),(-8,-10)     |           Infinity
+ (1e+300,Infinity) | (2.5,3.5),(2.5,2.5) |           Infinity
+ (1e+300,Infinity) | (3,3),(3,3)         |           Infinity
+ (NaN,NaN)         | (2,2),(0,0)         |                NaN
+ (NaN,NaN)         | (3,3),(1,1)         |                NaN
+ (NaN,NaN)         | (-2,2),(-8,-10)     |                NaN
+ (NaN,NaN)         | (2.5,3.5),(2.5,2.5) |                NaN
+ (NaN,NaN)         | (3,3),(3,3)         |                NaN
+ (10,10)           | (2,2),(0,0)         |       11.313708499
+ (10,10)           | (3,3),(1,1)         |      9.89949493661
+ (10,10)           | (-2,2),(-8,-10)     |      14.4222051019
+ (10,10)           | (2.5,3.5),(2.5,2.5) |      9.92471662064
+ (10,10)           | (3,3),(3,3)         |      9.89949493661
+(45 rows)
+
+-- Distance to path
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, PATH_TBL p1;
+        f1         |            f1             |      ?column?      
+-------------------+---------------------------+--------------------
+ (0,0)             | [(1,2),(3,4)]             |       2.2360679775
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | [(0,0),(3,0),(4,5),(1,6)] |                  0
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | [(1,2),(3,4)]             |       2.2360679775
+ (0,0)             | ((10,20))                 |       22.360679775
+ (0,0)             | [(11,12),(13,14)]         |      16.2788205961
+ (0,0)             | ((11,12),(13,14))         |      16.2788205961
+ (-10,0)           | [(1,2),(3,4)]             |      11.1803398875
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | [(0,0),(3,0),(4,5),(1,6)] |                 10
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | [(1,2),(3,4)]             |      11.1803398875
+ (-10,0)           | ((10,20))                 |      28.2842712475
+ (-10,0)           | [(11,12),(13,14)]         |      24.1867732449
+ (-10,0)           | ((11,12),(13,14))         |      24.1867732449
+ (-3,4)            | [(1,2),(3,4)]             |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | [(0,0),(3,0),(4,5),(1,6)] |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | [(1,2),(3,4)]             |        4.472135955
+ (-3,4)            | ((10,20))                 |      20.6155281281
+ (-3,4)            | [(11,12),(13,14)]         |      16.1245154966
+ (-3,4)            | ((11,12),(13,14))         |      16.1245154966
+ (5.1,34.5)        | [(1,2),(3,4)]             |      30.5722096028
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | [(0,0),(3,0),(4,5),(1,6)] |       28.793402022
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | [(1,2),(3,4)]             |      30.5722096028
+ (5.1,34.5)        | ((10,20))                 |      15.3055545473
+ (5.1,34.5)        | [(11,12),(13,14)]         |      21.9695243462
+ (5.1,34.5)        | ((11,12),(13,14))         |      21.9695243462
+ (-5,-12)          | [(1,2),(3,4)]             |      15.2315462117
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | [(0,0),(3,0),(4,5),(1,6)] |                 13
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | [(1,2),(3,4)]             |      15.2315462117
+ (-5,-12)          | ((10,20))                 |      35.3411940941
+ (-5,-12)          | [(11,12),(13,14)]         |      28.8444102037
+ (-5,-12)          | ((11,12),(13,14))         |      28.8444102037
+ (1e-300,-1e-300)  | [(1,2),(3,4)]             |       2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | [(0,0),(3,0),(4,5),(1,6)] | 1.41421356237e-300
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | [(1,2),(3,4)]             |       2.2360679775
+ (1e-300,-1e-300)  | ((10,20))                 |       22.360679775
+ (1e-300,-1e-300)  | [(11,12),(13,14)]         |      16.2788205961
+ (1e-300,-1e-300)  | ((11,12),(13,14))         |      16.2788205961
+ (1e+300,Infinity) | [(1,2),(3,4)]             |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | [(0,0),(3,0),(4,5),(1,6)] |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | [(1,2),(3,4)]             |           Infinity
+ (1e+300,Infinity) | ((10,20))                 |           Infinity
+ (1e+300,Infinity) | [(11,12),(13,14)]         |           Infinity
+ (1e+300,Infinity) | ((11,12),(13,14))         |           Infinity
+ (NaN,NaN)         | [(1,2),(3,4)]             |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | [(0,0),(3,0),(4,5),(1,6)] |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | [(1,2),(3,4)]             |                NaN
+ (NaN,NaN)         | ((10,20))                 |                NaN
+ (NaN,NaN)         | [(11,12),(13,14)]         |                NaN
+ (NaN,NaN)         | ((11,12),(13,14))         |                NaN
+ (10,10)           | [(1,2),(3,4)]             |      9.21954445729
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | [(0,0),(3,0),(4,5),(1,6)] |      7.81024967591
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | [(1,2),(3,4)]             |      9.21954445729
+ (10,10)           | ((10,20))                 |                 10
+ (10,10)           | [(11,12),(13,14)]         |       2.2360679775
+ (10,10)           | ((11,12),(13,14))         |       2.2360679775
+(81 rows)
+
+-- Distance to polygon
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, POLYGON_TBL p1;
+        f1         |             f1             |   ?column?    
+-------------------+----------------------------+---------------
+ (0,0)             | ((2,0),(2,4),(0,0))        |             0
+ (0,0)             | ((3,1),(3,3),(1,0))        |             1
+ (0,0)             | ((1,2),(3,4),(5,6),(7,8))  |  2.2360679775
+ (0,0)             | ((7,8),(5,6),(3,4),(1,2))  |  2.2360679775
+ (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | 1.58113883008
+ (0,0)             | ((0,0))                    |             0
+ (0,0)             | ((0,1),(0,1))              |             1
+ (-10,0)           | ((2,0),(2,4),(0,0))        |            10
+ (-10,0)           | ((3,1),(3,3),(1,0))        |            11
+ (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | 11.1803398875
+ (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | 11.1803398875
+ (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | 11.1803398875
+ (-10,0)           | ((0,0))                    |            10
+ (-10,0)           | ((0,1),(0,1))              | 10.0498756211
+ (-3,4)            | ((2,0),(2,4),(0,0))        |   4.472135955
+ (-3,4)            | ((3,1),(3,3),(1,0))        | 5.54700196225
+ (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  |   4.472135955
+ (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  |   4.472135955
+ (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) |   4.472135955
+ (-3,4)            | ((0,0))                    |             5
+ (-3,4)            | ((0,1),(0,1))              | 4.24264068712
+ (5.1,34.5)        | ((2,0),(2,4),(0,0))        | 30.6571362002
+ (5.1,34.5)        | ((3,1),(3,3),(1,0))        | 31.5699223946
+ (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | 26.5680258958
+ (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | 26.5680258958
+ (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | 26.5680258958
+ (5.1,34.5)        | ((0,0))                    | 34.8749193547
+ (5.1,34.5)        | ((0,1),(0,1))              | 33.8859853037
+ (-5,-12)          | ((2,0),(2,4),(0,0))        |            13
+ (-5,-12)          | ((3,1),(3,3),(1,0))        |  13.416407865
+ (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | 15.2315462117
+ (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | 15.2315462117
+ (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) |  11.313708499
+ (-5,-12)          | ((0,0))                    |            13
+ (-5,-12)          | ((0,1),(0,1))              | 13.9283882772
+ (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        |             0
+ (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        |             1
+ (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  |  2.2360679775
+ (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  |  2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | 1.58113883008
+ (1e-300,-1e-300)  | ((0,0))                    |             0
+ (1e-300,-1e-300)  | ((0,1),(0,1))              |             1
+ (1e+300,Infinity) | ((2,0),(2,4),(0,0))        |      Infinity
+ (1e+300,Infinity) | ((3,1),(3,3),(1,0))        |      Infinity
+ (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  |      Infinity
+ (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  |      Infinity
+ (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) |      Infinity
+ (1e+300,Infinity) | ((0,0))                    |      Infinity
+ (1e+300,Infinity) | ((0,1),(0,1))              |      Infinity
+ (NaN,NaN)         | ((2,0),(2,4),(0,0))        |             0
+ (NaN,NaN)         | ((3,1),(3,3),(1,0))        |             0
+ (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  |             0
+ (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  |             0
+ (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) |             0
+ (NaN,NaN)         | ((0,0))                    |             0
+ (NaN,NaN)         | ((0,1),(0,1))              |             0
+ (10,10)           | ((2,0),(2,4),(0,0))        |            10
+ (10,10)           | ((3,1),(3,3),(1,0))        | 9.89949493661
+ (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | 3.60555127546
+ (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | 3.60555127546
+ (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | 3.60555127546
+ (10,10)           | ((0,0))                    | 14.1421356237
+ (10,10)           | ((0,1),(0,1))              | 13.4536240471
+(63 rows)
+
+-- Closest point to line
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LINE_TBL l;
+        f1         |                   s                   |             ?column?             
+-------------------+---------------------------------------+----------------------------------
+ (0,0)             | {0,-1,5}                              | (0,5)
+ (0,0)             | {1,0,5}                               | (-5,0)
+ (0,0)             | {0,3,0}                               | (0,0)
+ (0,0)             | {1,-1,0}                              | (0,0)
+ (0,0)             | {-0.4,-1,-6}                          | (-2.06896551724,-5.1724137931)
+ (0,0)             | {-0.000184615384615,-1,15.3846153846} | (0.00284023658959,15.3846148603)
+ (0,0)             | {3,NaN,5}                             | 
+ (0,0)             | {NaN,NaN,NaN}                         | 
+ (0,0)             | {0,-1,3}                              | (0,3)
+ (0,0)             | {-1,0,3}                              | (3,0)
+ (-10,0)           | {0,-1,5}                              | (-10,5)
+ (-10,0)           | {1,0,5}                               | (-5,0)
+ (-10,0)           | {0,3,0}                               | (-10,0)
+ (-10,0)           | {1,-1,0}                              | (-5,-5)
+ (-10,0)           | {-0.4,-1,-6}                          | (-10.6896551724,-1.72413793103)
+ (-10,0)           | {-0.000184615384615,-1,15.3846153846} | (-9.99715942258,15.386461014)
+ (-10,0)           | {3,NaN,5}                             | 
+ (-10,0)           | {NaN,NaN,NaN}                         | 
+ (-10,0)           | {0,-1,3}                              | (-10,3)
+ (-10,0)           | {-1,0,3}                              | (3,0)
+ (-3,4)            | {0,-1,5}                              | (-3,5)
+ (-3,4)            | {1,0,5}                               | (-5,4)
+ (-3,4)            | {0,3,0}                               | (-3,0)
+ (-3,4)            | {1,-1,0}                              | (0.5,0.5)
+ (-3,4)            | {-0.4,-1,-6}                          | (-6.03448275862,-3.58620689655)
+ (-3,4)            | {-0.000184615384615,-1,15.3846153846} | (-2.99789812268,15.3851688427)
+ (-3,4)            | {3,NaN,5}                             | 
+ (-3,4)            | {NaN,NaN,NaN}                         | 
+ (-3,4)            | {0,-1,3}                              | (-3,3)
+ (-3,4)            | {-1,0,3}                              | (3,4)
+ (5.1,34.5)        | {0,-1,5}                              | (5.1,5)
+ (5.1,34.5)        | {1,0,5}                               | (-5,34.5)
+ (5.1,34.5)        | {0,3,0}                               | (5.1,0)
+ (5.1,34.5)        | {1,-1,0}                              | (19.8,19.8)
+ (5.1,34.5)        | {-0.4,-1,-6}                          | (-9.56896551724,-2.1724137931)
+ (5.1,34.5)        | {-0.000184615384615,-1,15.3846153846} | (5.09647083221,15.3836744977)
+ (5.1,34.5)        | {3,NaN,5}                             | 
+ (5.1,34.5)        | {NaN,NaN,NaN}                         | 
+ (5.1,34.5)        | {0,-1,3}                              | (5.1,3)
+ (5.1,34.5)        | {-1,0,3}                              | (3,34.5)
+ (-5,-12)          | {0,-1,5}                              | (-5,5)
+ (-5,-12)          | {1,0,5}                               | (-5,-12)
+ (-5,-12)          | {0,3,0}                               | (-5,0)
+ (-5,-12)          | {1,-1,0}                              | (-8.5,-8.5)
+ (-5,-12)          | {-0.4,-1,-6}                          | (-2.24137931034,-5.10344827586)
+ (-5,-12)          | {-0.000184615384615,-1,15.3846153846} | (-4.99494420846,15.3855375282)
+ (-5,-12)          | {3,NaN,5}                             | 
+ (-5,-12)          | {NaN,NaN,NaN}                         | 
+ (-5,-12)          | {0,-1,3}                              | (-5,3)
+ (-5,-12)          | {-1,0,3}                              | (3,-12)
+ (1e-300,-1e-300)  | {0,-1,5}                              | (1e-300,5)
+ (1e-300,-1e-300)  | {1,0,5}                               | (-5,-1e-300)
+ (1e-300,-1e-300)  | {0,3,0}                               | (1e-300,0)
+ (1e-300,-1e-300)  | {1,-1,0}                              | (0,0)
+ (1e-300,-1e-300)  | {-0.4,-1,-6}                          | (-2.06896551724,-5.1724137931)
+ (1e-300,-1e-300)  | {-0.000184615384615,-1,15.3846153846} | (0.00284023658959,15.3846148603)
+ (1e-300,-1e-300)  | {3,NaN,5}                             | 
+ (1e-300,-1e-300)  | {NaN,NaN,NaN}                         | 
+ (1e-300,-1e-300)  | {0,-1,3}                              | (1e-300,3)
+ (1e-300,-1e-300)  | {-1,0,3}                              | (3,-1e-300)
+ (1e+300,Infinity) | {0,-1,5}                              | (1e+300,5)
+ (1e+300,Infinity) | {1,0,5}                               | 
+ (1e+300,Infinity) | {0,3,0}                               | (1e+300,0)
+ (1e+300,Infinity) | {1,-1,0}                              | (Infinity,NaN)
+ (1e+300,Infinity) | {-0.4,-1,-6}                          | (-Infinity,NaN)
+ (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} | (-Infinity,NaN)
+ (1e+300,Infinity) | {3,NaN,5}                             | 
+ (1e+300,Infinity) | {NaN,NaN,NaN}                         | 
+ (1e+300,Infinity) | {0,-1,3}                              | (1e+300,3)
+ (1e+300,Infinity) | {-1,0,3}                              | 
+ (NaN,NaN)         | {0,-1,5}                              | 
+ (NaN,NaN)         | {1,0,5}                               | 
+ (NaN,NaN)         | {0,3,0}                               | 
+ (NaN,NaN)         | {1,-1,0}                              | 
+ (NaN,NaN)         | {-0.4,-1,-6}                          | 
+ (NaN,NaN)         | {-0.000184615384615,-1,15.3846153846} | 
+ (NaN,NaN)         | {3,NaN,5}                             | 
+ (NaN,NaN)         | {NaN,NaN,NaN}                         | 
+ (NaN,NaN)         | {0,-1,3}                              | 
+ (NaN,NaN)         | {-1,0,3}                              | 
+ (10,10)           | {0,-1,5}                              | (10,5)
+ (10,10)           | {1,0,5}                               | (-5,10)
+ (10,10)           | {0,3,0}                               | (10,0)
+ (10,10)           | {1,-1,0}                              | (10,10)
+ (10,10)           | {-0.4,-1,-6}                          | (3.10344827586,-7.24137931034)
+ (10,10)           | {-0.000184615384615,-1,15.3846153846} | (10.000993742,15.3827690473)
+ (10,10)           | {3,NaN,5}                             | 
+ (10,10)           | {NaN,NaN,NaN}                         | 
+ (10,10)           | {0,-1,3}                              | (10,3)
+ (10,10)           | {-1,0,3}                              | (3,10)
+(90 rows)
+
+-- Closest point to line segment
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LSEG_TBL l;
+        f1         |               s               |             ?column?             
+-------------------+-------------------------------+----------------------------------
+ (0,0)             | [(1,2),(3,4)]                 | (1,2)
+ (0,0)             | [(0,0),(6,6)]                 | (0,0)
+ (0,0)             | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ (0,0)             | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
+ (0,0)             | [(11,22),(33,44)]             | (11,22)
+ (0,0)             | [(-10,2),(-10,3)]             | (-10,2)
+ (0,0)             | [(0,-20),(30,-20)]            | (0,-20)
+ (0,0)             | [(NaN,1),(NaN,90)]            | 
+ (-10,0)           | [(1,2),(3,4)]                 | (1,2)
+ (-10,0)           | [(0,0),(6,6)]                 | (0,0)
+ (-10,0)           | [(10,-10),(-3,-4)]            | (-3,-4)
+ (-10,0)           | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
+ (-10,0)           | [(11,22),(33,44)]             | (11,22)
+ (-10,0)           | [(-10,2),(-10,3)]             | (-10,2)
+ (-10,0)           | [(0,-20),(30,-20)]            | (0,-20)
+ (-10,0)           | [(NaN,1),(NaN,90)]            | 
+ (-3,4)            | [(1,2),(3,4)]                 | (1,2)
+ (-3,4)            | [(0,0),(6,6)]                 | (0.5,0.5)
+ (-3,4)            | [(10,-10),(-3,-4)]            | (-3,-4)
+ (-3,4)            | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
+ (-3,4)            | [(11,22),(33,44)]             | (11,22)
+ (-3,4)            | [(-10,2),(-10,3)]             | (-10,3)
+ (-3,4)            | [(0,-20),(30,-20)]            | (0,-20)
+ (-3,4)            | [(NaN,1),(NaN,90)]            | 
+ (5.1,34.5)        | [(1,2),(3,4)]                 | (3,4)
+ (5.1,34.5)        | [(0,0),(6,6)]                 | (6,6)
+ (5.1,34.5)        | [(10,-10),(-3,-4)]            | (-3,-4)
+ (5.1,34.5)        | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
+ (5.1,34.5)        | [(11,22),(33,44)]             | (14.3,25.3)
+ (5.1,34.5)        | [(-10,2),(-10,3)]             | (-10,3)
+ (5.1,34.5)        | [(0,-20),(30,-20)]            | (5.1,-20)
+ (5.1,34.5)        | [(NaN,1),(NaN,90)]            | 
+ (-5,-12)          | [(1,2),(3,4)]                 | (1,2)
+ (-5,-12)          | [(0,0),(6,6)]                 | (0,0)
+ (-5,-12)          | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
+ (-5,-12)          | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
+ (-5,-12)          | [(11,22),(33,44)]             | (11,22)
+ (-5,-12)          | [(-10,2),(-10,3)]             | (-10,2)
+ (-5,-12)          | [(0,-20),(30,-20)]            | (0,-20)
+ (-5,-12)          | [(NaN,1),(NaN,90)]            | 
+ (1e-300,-1e-300)  | [(1,2),(3,4)]                 | (1,2)
+ (1e-300,-1e-300)  | [(0,0),(6,6)]                 | (0,0)
+ (1e-300,-1e-300)  | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ (1e-300,-1e-300)  | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
+ (1e-300,-1e-300)  | [(11,22),(33,44)]             | (11,22)
+ (1e-300,-1e-300)  | [(-10,2),(-10,3)]             | (-10,2)
+ (1e-300,-1e-300)  | [(0,-20),(30,-20)]            | (0,-20)
+ (1e-300,-1e-300)  | [(NaN,1),(NaN,90)]            | 
+ (1e+300,Infinity) | [(1,2),(3,4)]                 | (3,4)
+ (1e+300,Infinity) | [(0,0),(6,6)]                 | (6,6)
+ (1e+300,Infinity) | [(10,-10),(-3,-4)]            | (-3,-4)
+ (1e+300,Infinity) | [(-1000000,200),(300000,-40)] | (300000,-40)
+ (1e+300,Infinity) | [(11,22),(33,44)]             | (33,44)
+ (1e+300,Infinity) | [(-10,2),(-10,3)]             | (-10,3)
+ (1e+300,Infinity) | [(0,-20),(30,-20)]            | (30,-20)
+ (1e+300,Infinity) | [(NaN,1),(NaN,90)]            | (NaN,90)
+ (NaN,NaN)         | [(1,2),(3,4)]                 | 
+ (NaN,NaN)         | [(0,0),(6,6)]                 | 
+ (NaN,NaN)         | [(10,-10),(-3,-4)]            | 
+ (NaN,NaN)         | [(-1000000,200),(300000,-40)] | 
+ (NaN,NaN)         | [(11,22),(33,44)]             | 
+ (NaN,NaN)         | [(-10,2),(-10,3)]             | 
+ (NaN,NaN)         | [(0,-20),(30,-20)]            | 
+ (NaN,NaN)         | [(NaN,1),(NaN,90)]            | 
+ (10,10)           | [(1,2),(3,4)]                 | (3,4)
+ (10,10)           | [(0,0),(6,6)]                 | (6,6)
+ (10,10)           | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
+ (10,10)           | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
+ (10,10)           | [(11,22),(33,44)]             | (11,22)
+ (10,10)           | [(-10,2),(-10,3)]             | (-10,3)
+ (10,10)           | [(0,-20),(30,-20)]            | (10,-20)
+ (10,10)           | [(NaN,1),(NaN,90)]            | 
+(72 rows)
+
+-- Closest point to box
+SELECT p.f1, b.f1, p.f1 ## b.f1 FROM POINT_TBL p, BOX_TBL b;
+        f1         |         f1          |   ?column?   
+-------------------+---------------------+--------------
+ (0,0)             | (2,2),(0,0)         | (0,0)
+ (0,0)             | (3,3),(1,1)         | (1,1)
+ (0,0)             | (-2,2),(-8,-10)     | (-2,0)
+ (0,0)             | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (0,0)             | (3,3),(3,3)         | (3,3)
+ (-10,0)           | (2,2),(0,0)         | (0,0)
+ (-10,0)           | (3,3),(1,1)         | (1,1)
+ (-10,0)           | (-2,2),(-8,-10)     | (-8,0)
+ (-10,0)           | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (-10,0)           | (3,3),(3,3)         | (3,3)
+ (-3,4)            | (2,2),(0,0)         | (0,2)
+ (-3,4)            | (3,3),(1,1)         | (1,3)
+ (-3,4)            | (-2,2),(-8,-10)     | (-3,2)
+ (-3,4)            | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (-3,4)            | (3,3),(3,3)         | (3,3)
+ (5.1,34.5)        | (2,2),(0,0)         | (2,2)
+ (5.1,34.5)        | (3,3),(1,1)         | (3,3)
+ (5.1,34.5)        | (-2,2),(-8,-10)     | (-2,2)
+ (5.1,34.5)        | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (5.1,34.5)        | (3,3),(3,3)         | (3,3)
+ (-5,-12)          | (2,2),(0,0)         | (0,0)
+ (-5,-12)          | (3,3),(1,1)         | (1,1)
+ (-5,-12)          | (-2,2),(-8,-10)     | (-5,-10)
+ (-5,-12)          | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (-5,-12)          | (3,3),(3,3)         | (3,3)
+ (1e-300,-1e-300)  | (2,2),(0,0)         | (0,0)
+ (1e-300,-1e-300)  | (3,3),(1,1)         | (1,1)
+ (1e-300,-1e-300)  | (-2,2),(-8,-10)     | (-2,-1e-300)
+ (1e-300,-1e-300)  | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (1e-300,-1e-300)  | (3,3),(3,3)         | (3,3)
+ (1e+300,Infinity) | (2,2),(0,0)         | (0,2)
+ (1e+300,Infinity) | (3,3),(1,1)         | (1,3)
+ (1e+300,Infinity) | (-2,2),(-8,-10)     | (-8,2)
+ (1e+300,Infinity) | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (1e+300,Infinity) | (3,3),(3,3)         | (3,3)
+ (NaN,NaN)         | (2,2),(0,0)         | 
+ (NaN,NaN)         | (3,3),(1,1)         | 
+ (NaN,NaN)         | (-2,2),(-8,-10)     | 
+ (NaN,NaN)         | (2.5,3.5),(2.5,2.5) | 
+ (NaN,NaN)         | (3,3),(3,3)         | 
+ (10,10)           | (2,2),(0,0)         | (2,2)
+ (10,10)           | (3,3),(1,1)         | (3,3)
+ (10,10)           | (-2,2),(-8,-10)     | (-2,2)
+ (10,10)           | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (10,10)           | (3,3),(3,3)         | (3,3)
+(45 rows)
+
+-- On line
+SELECT p.f1, l.s FROM POINT_TBL p, LINE_TBL l WHERE p.f1 <@ l.s;
+        f1        |    s     
+------------------+----------
+ (0,0)            | {0,3,0}
+ (0,0)            | {1,-1,0}
+ (-10,0)          | {0,3,0}
+ (-5,-12)         | {1,0,5}
+ (1e-300,-1e-300) | {0,3,0}
+ (1e-300,-1e-300) | {1,-1,0}
+ (10,10)          | {1,-1,0}
+(7 rows)
+
+-- On line segment
+SELECT p.f1, l.s FROM POINT_TBL p, LSEG_TBL l WHERE p.f1 <@ l.s;
+        f1        |       s       
+------------------+---------------
+ (0,0)            | [(0,0),(6,6)]
+ (1e-300,-1e-300) | [(0,0),(6,6)]
+(2 rows)
+
+-- On path
+SELECT p.f1, p1.f1 FROM POINT_TBL p, PATH_TBL p1 WHERE p.f1 <@ p1.f1;
+        f1        |            f1             
+------------------+---------------------------
+ (0,0)            | [(0,0),(3,0),(4,5),(1,6)]
+ (1e-300,-1e-300) | [(0,0),(3,0),(4,5),(1,6)]
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((10,20))
+ (NaN,NaN)        | ((11,12),(13,14))
+(7 rows)
+
+--
+-- Lines
+--
+-- Vertical
+SELECT s FROM LINE_TBL WHERE ?| s;
+    s     
+----------
+ {1,0,5}
+ {-1,0,3}
+(2 rows)
+
+-- Horizontal
+SELECT s FROM LINE_TBL WHERE ?- s;
+    s     
+----------
+ {0,-1,5}
+ {0,3,0}
+ {0,-1,3}
+(3 rows)
+
+-- Same as line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s = l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {0,-1,5}
+ {1,0,5}                               | {1,0,5}
+ {0,3,0}                               | {0,3,0}
+ {1,-1,0}                              | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846}
+ {3,NaN,5}                             | {3,NaN,5}
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}
+ {0,-1,3}                              | {0,-1,3}
+ {-1,0,3}                              | {-1,0,3}
+(10 rows)
+
+-- Parallel to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?|| l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {0,-1,5}
+ {0,-1,5}                              | {0,3,0}
+ {0,-1,5}                              | {0,-1,3}
+ {1,0,5}                               | {1,0,5}
+ {1,0,5}                               | {-1,0,3}
+ {0,3,0}                               | {0,-1,5}
+ {0,3,0}                               | {0,3,0}
+ {0,3,0}                               | {0,-1,3}
+ {1,-1,0}                              | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,3}                              | {0,-1,5}
+ {0,-1,3}                              | {0,3,0}
+ {0,-1,3}                              | {0,-1,3}
+ {-1,0,3}                              | {1,0,5}
+ {-1,0,3}                              | {-1,0,3}
+(16 rows)
+
+-- Perpendicular to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?-| l2.s;
+    s     |    s     
+----------+----------
+ {0,-1,5} | {1,0,5}
+ {0,-1,5} | {-1,0,3}
+ {1,0,5}  | {0,-1,5}
+ {1,0,5}  | {0,3,0}
+ {1,0,5}  | {0,-1,3}
+ {0,3,0}  | {1,0,5}
+ {0,3,0}  | {-1,0,3}
+ {0,-1,3} | {1,0,5}
+ {0,-1,3} | {-1,0,3}
+ {-1,0,3} | {0,-1,5}
+ {-1,0,3} | {0,3,0}
+ {-1,0,3} | {0,-1,3}
+(12 rows)
+
+-- Distance to line
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2;
+                   s                   |                   s                   | ?column? 
+---------------------------------------+---------------------------------------+----------
+ {0,-1,5}                              | {0,-1,5}                              |        0
+ {0,-1,5}                              | {1,0,5}                               |        0
+ {0,-1,5}                              | {0,3,0}                               |        5
+ {0,-1,5}                              | {1,-1,0}                              |        0
+ {0,-1,5}                              | {-0.4,-1,-6}                          |        0
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,-1,5}                              | {3,NaN,5}                             |        0
+ {0,-1,5}                              | {NaN,NaN,NaN}                         |        0
+ {0,-1,5}                              | {0,-1,3}                              |        2
+ {0,-1,5}                              | {-1,0,3}                              |        0
+ {1,0,5}                               | {0,-1,5}                              |        0
+ {1,0,5}                               | {1,0,5}                               |        0
+ {1,0,5}                               | {0,3,0}                               |        0
+ {1,0,5}                               | {1,-1,0}                              |        0
+ {1,0,5}                               | {-0.4,-1,-6}                          |        0
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846} |        0
+ {1,0,5}                               | {3,NaN,5}                             |        0
+ {1,0,5}                               | {NaN,NaN,NaN}                         |        0
+ {1,0,5}                               | {0,-1,3}                              |        0
+ {1,0,5}                               | {-1,0,3}                              |        8
+ {0,3,0}                               | {0,-1,5}                              |        5
+ {0,3,0}                               | {1,0,5}                               |        0
+ {0,3,0}                               | {0,3,0}                               |        0
+ {0,3,0}                               | {1,-1,0}                              |        0
+ {0,3,0}                               | {-0.4,-1,-6}                          |        0
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,3,0}                               | {3,NaN,5}                             |        0
+ {0,3,0}                               | {NaN,NaN,NaN}                         |        0
+ {0,3,0}                               | {0,-1,3}                              |        3
+ {0,3,0}                               | {-1,0,3}                              |        0
+ {1,-1,0}                              | {0,-1,5}                              |        0
+ {1,-1,0}                              | {1,0,5}                               |        0
+ {1,-1,0}                              | {0,3,0}                               |        0
+ {1,-1,0}                              | {1,-1,0}                              |        0
+ {1,-1,0}                              | {-0.4,-1,-6}                          |        0
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {1,-1,0}                              | {3,NaN,5}                             |        0
+ {1,-1,0}                              | {NaN,NaN,NaN}                         |        0
+ {1,-1,0}                              | {0,-1,3}                              |        0
+ {1,-1,0}                              | {-1,0,3}                              |        0
+ {-0.4,-1,-6}                          | {0,-1,5}                              |        0
+ {-0.4,-1,-6}                          | {1,0,5}                               |        0
+ {-0.4,-1,-6}                          | {0,3,0}                               |        0
+ {-0.4,-1,-6}                          | {1,-1,0}                              |        0
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}                          |        0
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846} |        0
+ {-0.4,-1,-6}                          | {3,NaN,5}                             |        0
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}                         |        0
+ {-0.4,-1,-6}                          | {0,-1,3}                              |        0
+ {-0.4,-1,-6}                          | {-1,0,3}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}                               |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}                               |        0
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}                          |        0
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} |        0
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}                             |        0
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}                         |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}                              |        0
+ {3,NaN,5}                             | {0,-1,5}                              |        0
+ {3,NaN,5}                             | {1,0,5}                               |        0
+ {3,NaN,5}                             | {0,3,0}                               |        0
+ {3,NaN,5}                             | {1,-1,0}                              |        0
+ {3,NaN,5}                             | {-0.4,-1,-6}                          |        0
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846} |        0
+ {3,NaN,5}                             | {3,NaN,5}                             |        0
+ {3,NaN,5}                             | {NaN,NaN,NaN}                         |        0
+ {3,NaN,5}                             | {0,-1,3}                              |        0
+ {3,NaN,5}                             | {-1,0,3}                              |        0
+ {NaN,NaN,NaN}                         | {0,-1,5}                              |        0
+ {NaN,NaN,NaN}                         | {1,0,5}                               |        0
+ {NaN,NaN,NaN}                         | {0,3,0}                               |        0
+ {NaN,NaN,NaN}                         | {1,-1,0}                              |        0
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}                          |        0
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846} |        0
+ {NaN,NaN,NaN}                         | {3,NaN,5}                             |        0
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}                         |        0
+ {NaN,NaN,NaN}                         | {0,-1,3}                              |        0
+ {NaN,NaN,NaN}                         | {-1,0,3}                              |        0
+ {0,-1,3}                              | {0,-1,5}                              |        2
+ {0,-1,3}                              | {1,0,5}                               |        0
+ {0,-1,3}                              | {0,3,0}                               |        3
+ {0,-1,3}                              | {1,-1,0}                              |        0
+ {0,-1,3}                              | {-0.4,-1,-6}                          |        0
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,-1,3}                              | {3,NaN,5}                             |        0
+ {0,-1,3}                              | {NaN,NaN,NaN}                         |        0
+ {0,-1,3}                              | {0,-1,3}                              |        0
+ {0,-1,3}                              | {-1,0,3}                              |        0
+ {-1,0,3}                              | {0,-1,5}                              |        0
+ {-1,0,3}                              | {1,0,5}                               |        8
+ {-1,0,3}                              | {0,3,0}                               |        0
+ {-1,0,3}                              | {1,-1,0}                              |        0
+ {-1,0,3}                              | {-0.4,-1,-6}                          |        0
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {-1,0,3}                              | {3,NaN,5}                             |        0
+ {-1,0,3}                              | {NaN,NaN,NaN}                         |        0
+ {-1,0,3}                              | {0,-1,3}                              |        0
+ {-1,0,3}                              | {-1,0,3}                              |        0
+(100 rows)
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LINE_TBL l, BOX_TBL b;
+ERROR:  function "dist_lb" not implemented
+-- Intersect with line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?# l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {1,0,5}
+ {0,-1,5}                              | {1,-1,0}
+ {0,-1,5}                              | {-0.4,-1,-6}
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,5}                              | {3,NaN,5}
+ {0,-1,5}                              | {NaN,NaN,NaN}
+ {0,-1,5}                              | {-1,0,3}
+ {1,0,5}                               | {0,-1,5}
+ {1,0,5}                               | {0,3,0}
+ {1,0,5}                               | {1,-1,0}
+ {1,0,5}                               | {-0.4,-1,-6}
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846}
+ {1,0,5}                               | {3,NaN,5}
+ {1,0,5}                               | {NaN,NaN,NaN}
+ {1,0,5}                               | {0,-1,3}
+ {0,3,0}                               | {1,0,5}
+ {0,3,0}                               | {1,-1,0}
+ {0,3,0}                               | {-0.4,-1,-6}
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846}
+ {0,3,0}                               | {3,NaN,5}
+ {0,3,0}                               | {NaN,NaN,NaN}
+ {0,3,0}                               | {-1,0,3}
+ {1,-1,0}                              | {0,-1,5}
+ {1,-1,0}                              | {1,0,5}
+ {1,-1,0}                              | {0,3,0}
+ {1,-1,0}                              | {-0.4,-1,-6}
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846}
+ {1,-1,0}                              | {3,NaN,5}
+ {1,-1,0}                              | {NaN,NaN,NaN}
+ {1,-1,0}                              | {0,-1,3}
+ {1,-1,0}                              | {-1,0,3}
+ {-0.4,-1,-6}                          | {0,-1,5}
+ {-0.4,-1,-6}                          | {1,0,5}
+ {-0.4,-1,-6}                          | {0,3,0}
+ {-0.4,-1,-6}                          | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846}
+ {-0.4,-1,-6}                          | {3,NaN,5}
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}
+ {-0.4,-1,-6}                          | {0,-1,3}
+ {-0.4,-1,-6}                          | {-1,0,3}
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}
+ {3,NaN,5}                             | {0,-1,5}
+ {3,NaN,5}                             | {1,0,5}
+ {3,NaN,5}                             | {0,3,0}
+ {3,NaN,5}                             | {1,-1,0}
+ {3,NaN,5}                             | {-0.4,-1,-6}
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846}
+ {3,NaN,5}                             | {3,NaN,5}
+ {3,NaN,5}                             | {NaN,NaN,NaN}
+ {3,NaN,5}                             | {0,-1,3}
+ {3,NaN,5}                             | {-1,0,3}
+ {NaN,NaN,NaN}                         | {0,-1,5}
+ {NaN,NaN,NaN}                         | {1,0,5}
+ {NaN,NaN,NaN}                         | {0,3,0}
+ {NaN,NaN,NaN}                         | {1,-1,0}
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846}
+ {NaN,NaN,NaN}                         | {3,NaN,5}
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}
+ {NaN,NaN,NaN}                         | {0,-1,3}
+ {NaN,NaN,NaN}                         | {-1,0,3}
+ {0,-1,3}                              | {1,0,5}
+ {0,-1,3}                              | {1,-1,0}
+ {0,-1,3}                              | {-0.4,-1,-6}
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,3}                              | {3,NaN,5}
+ {0,-1,3}                              | {NaN,NaN,NaN}
+ {0,-1,3}                              | {-1,0,3}
+ {-1,0,3}                              | {0,-1,5}
+ {-1,0,3}                              | {0,3,0}
+ {-1,0,3}                              | {1,-1,0}
+ {-1,0,3}                              | {-0.4,-1,-6}
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846}
+ {-1,0,3}                              | {3,NaN,5}
+ {-1,0,3}                              | {NaN,NaN,NaN}
+ {-1,0,3}                              | {0,-1,3}
+(84 rows)
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LINE_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+      s       |         f1          
+--------------+---------------------
+ {1,0,5}      | (-2,2),(-8,-10)
+ {0,3,0}      | (2,2),(0,0)
+ {0,3,0}      | (-2,2),(-8,-10)
+ {1,-1,0}     | (2,2),(0,0)
+ {1,-1,0}     | (3,3),(1,1)
+ {1,-1,0}     | (-2,2),(-8,-10)
+ {1,-1,0}     | (2.5,3.5),(2.5,2.5)
+ {1,-1,0}     | (3,3),(3,3)
+ {-0.4,-1,-6} | (-2,2),(-8,-10)
+ {0,-1,3}     | (3,3),(1,1)
+ {0,-1,3}     | (2.5,3.5),(2.5,2.5)
+ {0,-1,3}     | (3,3),(3,3)
+ {-1,0,3}     | (3,3),(1,1)
+(13 rows)
+
+-- Intersection point with line
+SELECT l1.s, l2.s, l1.s # l2.s FROM LINE_TBL l1, LINE_TBL l2;
+                   s                   |                   s                   |             ?column?              
+---------------------------------------+---------------------------------------+-----------------------------------
+ {0,-1,5}                              | {0,-1,5}                              | 
+ {0,-1,5}                              | {1,0,5}                               | (-5,5)
+ {0,-1,5}                              | {0,3,0}                               | 
+ {0,-1,5}                              | {1,-1,0}                              | (5,5)
+ {0,-1,5}                              | {-0.4,-1,-6}                          | (-27.5,5)
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846} | (56250,5)
+ {0,-1,5}                              | {3,NaN,5}                             | (NaN,NaN)
+ {0,-1,5}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,-1,5}                              | {0,-1,3}                              | 
+ {0,-1,5}                              | {-1,0,3}                              | (3,5)
+ {1,0,5}                               | {0,-1,5}                              | (-5,5)
+ {1,0,5}                               | {1,0,5}                               | 
+ {1,0,5}                               | {0,3,0}                               | (-5,0)
+ {1,0,5}                               | {1,-1,0}                              | (-5,-5)
+ {1,0,5}                               | {-0.4,-1,-6}                          | (-5,-4)
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846} | (-5,15.3855384615)
+ {1,0,5}                               | {3,NaN,5}                             | (NaN,NaN)
+ {1,0,5}                               | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {1,0,5}                               | {0,-1,3}                              | (-5,3)
+ {1,0,5}                               | {-1,0,3}                              | 
+ {0,3,0}                               | {0,-1,5}                              | 
+ {0,3,0}                               | {1,0,5}                               | (-5,0)
+ {0,3,0}                               | {0,3,0}                               | 
+ {0,3,0}                               | {1,-1,0}                              | (0,0)
+ {0,3,0}                               | {-0.4,-1,-6}                          | (-15,0)
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846} | (83333.3333333,0)
+ {0,3,0}                               | {3,NaN,5}                             | (NaN,NaN)
+ {0,3,0}                               | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,3,0}                               | {0,-1,3}                              | 
+ {0,3,0}                               | {-1,0,3}                              | (3,0)
+ {1,-1,0}                              | {0,-1,5}                              | (5,5)
+ {1,-1,0}                              | {1,0,5}                               | (-5,-5)
+ {1,-1,0}                              | {0,3,0}                               | (0,0)
+ {1,-1,0}                              | {1,-1,0}                              | 
+ {1,-1,0}                              | {-0.4,-1,-6}                          | (-4.28571428571,-4.28571428571)
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846} | (15.3817756722,15.3817756722)
+ {1,-1,0}                              | {3,NaN,5}                             | (NaN,NaN)
+ {1,-1,0}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {1,-1,0}                              | {0,-1,3}                              | (3,3)
+ {1,-1,0}                              | {-1,0,3}                              | (3,3)
+ {-0.4,-1,-6}                          | {0,-1,5}                              | (-27.5,5)
+ {-0.4,-1,-6}                          | {1,0,5}                               | (-5,-4)
+ {-0.4,-1,-6}                          | {0,3,0}                               | (-15,0)
+ {-0.4,-1,-6}                          | {1,-1,0}                              | (-4.28571428571,-4.28571428571)
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}                          | 
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846} | (-53.4862244113,15.3944897645)
+ {-0.4,-1,-6}                          | {3,NaN,5}                             | (NaN,NaN)
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-0.4,-1,-6}                          | {0,-1,3}                              | (-22.5,3)
+ {-0.4,-1,-6}                          | {-1,0,3}                              | (3,-7.2)
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}                              | (56250,5)
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}                               | (-5,15.3855384615)
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}                               | (83333.3333333,-1.7763568394e-15)
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}                              | (15.3817756722,15.3817756722)
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}                          | (-53.4862244113,15.3944897645)
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} | 
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}                             | (NaN,NaN)
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}                              | (67083.3333333,3)
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}                              | (3,15.3840615385)
+ {3,NaN,5}                             | {0,-1,5}                              | (NaN,NaN)
+ {3,NaN,5}                             | {1,0,5}                               | (NaN,NaN)
+ {3,NaN,5}                             | {0,3,0}                               | (NaN,NaN)
+ {3,NaN,5}                             | {1,-1,0}                              | (NaN,NaN)
+ {3,NaN,5}                             | {-0.4,-1,-6}                          | (NaN,NaN)
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ {3,NaN,5}                             | {3,NaN,5}                             | (NaN,NaN)
+ {3,NaN,5}                             | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {3,NaN,5}                             | {0,-1,3}                              | (NaN,NaN)
+ {3,NaN,5}                             | {-1,0,3}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,-1,5}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {1,0,5}                               | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,3,0}                               | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {1,-1,0}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}                          | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {3,NaN,5}                             | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,-1,3}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-1,0,3}                              | (NaN,NaN)
+ {0,-1,3}                              | {0,-1,5}                              | 
+ {0,-1,3}                              | {1,0,5}                               | (-5,3)
+ {0,-1,3}                              | {0,3,0}                               | 
+ {0,-1,3}                              | {1,-1,0}                              | (3,3)
+ {0,-1,3}                              | {-0.4,-1,-6}                          | (-22.5,3)
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846} | (67083.3333333,3)
+ {0,-1,3}                              | {3,NaN,5}                             | (NaN,NaN)
+ {0,-1,3}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,-1,3}                              | {0,-1,3}                              | 
+ {0,-1,3}                              | {-1,0,3}                              | (3,3)
+ {-1,0,3}                              | {0,-1,5}                              | (3,5)
+ {-1,0,3}                              | {1,0,5}                               | 
+ {-1,0,3}                              | {0,3,0}                               | (3,0)
+ {-1,0,3}                              | {1,-1,0}                              | (3,3)
+ {-1,0,3}                              | {-0.4,-1,-6}                          | (3,-7.2)
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846} | (3,15.3840615385)
+ {-1,0,3}                              | {3,NaN,5}                             | (NaN,NaN)
+ {-1,0,3}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-1,0,3}                              | {0,-1,3}                              | (3,3)
+ {-1,0,3}                              | {-1,0,3}                              | 
+(100 rows)
+
+-- Closest point to line segment
+SELECT l.s, l1.s, l.s ## l1.s FROM LINE_TBL l, LSEG_TBL l1;
+                   s                   |               s               |             ?column?              
+---------------------------------------+-------------------------------+-----------------------------------
+ {0,-1,5}                              | [(1,2),(3,4)]                 | (3,4)
+ {0,-1,5}                              | [(0,0),(6,6)]                 | (5,5)
+ {0,-1,5}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,-1,5}                              | [(-1000000,200),(300000,-40)] | (56250,5)
+ {0,-1,5}                              | [(11,22),(33,44)]             | (11,22)
+ {0,-1,5}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {0,-1,5}                              | [(0,-20),(30,-20)]            | 
+ {0,-1,5}                              | [(NaN,1),(NaN,90)]            | 
+ {1,0,5}                               | [(1,2),(3,4)]                 | (1,2)
+ {1,0,5}                               | [(0,0),(6,6)]                 | (0,0)
+ {1,0,5}                               | [(10,-10),(-3,-4)]            | (-3,-4)
+ {1,0,5}                               | [(-1000000,200),(300000,-40)] | (-5,15.3855384615)
+ {1,0,5}                               | [(11,22),(33,44)]             | (11,22)
+ {1,0,5}                               | [(-10,2),(-10,3)]             | 
+ {1,0,5}                               | [(0,-20),(30,-20)]            | (0,-20)
+ {1,0,5}                               | [(NaN,1),(NaN,90)]            | 
+ {0,3,0}                               | [(1,2),(3,4)]                 | (1,2)
+ {0,3,0}                               | [(0,0),(6,6)]                 | (0,0)
+ {0,3,0}                               | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,3,0}                               | [(-1000000,200),(300000,-40)] | (83333.3333333,-1.7763568394e-15)
+ {0,3,0}                               | [(11,22),(33,44)]             | (11,22)
+ {0,3,0}                               | [(-10,2),(-10,3)]             | (-10,2)
+ {0,3,0}                               | [(0,-20),(30,-20)]            | 
+ {0,3,0}                               | [(NaN,1),(NaN,90)]            | 
+ {1,-1,0}                              | [(1,2),(3,4)]                 | 
+ {1,-1,0}                              | [(0,0),(6,6)]                 | 
+ {1,-1,0}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {1,-1,0}                              | [(-1000000,200),(300000,-40)] | (15.3817756722,15.3817756722)
+ {1,-1,0}                              | [(11,22),(33,44)]             | 
+ {1,-1,0}                              | [(-10,2),(-10,3)]             | (-10,2)
+ {1,-1,0}                              | [(0,-20),(30,-20)]            | (0,-20)
+ {1,-1,0}                              | [(NaN,1),(NaN,90)]            | 
+ {-0.4,-1,-6}                          | [(1,2),(3,4)]                 | (1,2)
+ {-0.4,-1,-6}                          | [(0,0),(6,6)]                 | (0,0)
+ {-0.4,-1,-6}                          | [(10,-10),(-3,-4)]            | (10,-10)
+ {-0.4,-1,-6}                          | [(-1000000,200),(300000,-40)] | (-53.4862244113,15.3944897645)
+ {-0.4,-1,-6}                          | [(11,22),(33,44)]             | (11,22)
+ {-0.4,-1,-6}                          | [(-10,2),(-10,3)]             | (-10,2)
+ {-0.4,-1,-6}                          | [(0,-20),(30,-20)]            | (30,-20)
+ {-0.4,-1,-6}                          | [(NaN,1),(NaN,90)]            | 
+ {-0.000184615384615,-1,15.3846153846} | [(1,2),(3,4)]                 | (3,4)
+ {-0.000184615384615,-1,15.3846153846} | [(0,0),(6,6)]                 | (6,6)
+ {-0.000184615384615,-1,15.3846153846} | [(10,-10),(-3,-4)]            | (-3,-4)
+ {-0.000184615384615,-1,15.3846153846} | [(-1000000,200),(300000,-40)] | 
+ {-0.000184615384615,-1,15.3846153846} | [(11,22),(33,44)]             | (11,22)
+ {-0.000184615384615,-1,15.3846153846} | [(-10,2),(-10,3)]             | (-10,3)
+ {-0.000184615384615,-1,15.3846153846} | [(0,-20),(30,-20)]            | (30,-20)
+ {-0.000184615384615,-1,15.3846153846} | [(NaN,1),(NaN,90)]            | 
+ {3,NaN,5}                             | [(1,2),(3,4)]                 | 
+ {3,NaN,5}                             | [(0,0),(6,6)]                 | 
+ {3,NaN,5}                             | [(10,-10),(-3,-4)]            | 
+ {3,NaN,5}                             | [(-1000000,200),(300000,-40)] | 
+ {3,NaN,5}                             | [(11,22),(33,44)]             | 
+ {3,NaN,5}                             | [(-10,2),(-10,3)]             | 
+ {3,NaN,5}                             | [(0,-20),(30,-20)]            | 
+ {3,NaN,5}                             | [(NaN,1),(NaN,90)]            | 
+ {NaN,NaN,NaN}                         | [(1,2),(3,4)]                 | 
+ {NaN,NaN,NaN}                         | [(0,0),(6,6)]                 | 
+ {NaN,NaN,NaN}                         | [(10,-10),(-3,-4)]            | 
+ {NaN,NaN,NaN}                         | [(-1000000,200),(300000,-40)] | 
+ {NaN,NaN,NaN}                         | [(11,22),(33,44)]             | 
+ {NaN,NaN,NaN}                         | [(-10,2),(-10,3)]             | 
+ {NaN,NaN,NaN}                         | [(0,-20),(30,-20)]            | 
+ {NaN,NaN,NaN}                         | [(NaN,1),(NaN,90)]            | 
+ {0,-1,3}                              | [(1,2),(3,4)]                 | (2,3)
+ {0,-1,3}                              | [(0,0),(6,6)]                 | (3,3)
+ {0,-1,3}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,-1,3}                              | [(-1000000,200),(300000,-40)] | (67083.3333333,3)
+ {0,-1,3}                              | [(11,22),(33,44)]             | (11,22)
+ {0,-1,3}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {0,-1,3}                              | [(0,-20),(30,-20)]            | 
+ {0,-1,3}                              | [(NaN,1),(NaN,90)]            | 
+ {-1,0,3}                              | [(1,2),(3,4)]                 | (3,4)
+ {-1,0,3}                              | [(0,0),(6,6)]                 | (3,3)
+ {-1,0,3}                              | [(10,-10),(-3,-4)]            | (3,-6.76923076923)
+ {-1,0,3}                              | [(-1000000,200),(300000,-40)] | (3,15.3840615385)
+ {-1,0,3}                              | [(11,22),(33,44)]             | (11,22)
+ {-1,0,3}                              | [(-10,2),(-10,3)]             | 
+ {-1,0,3}                              | [(0,-20),(30,-20)]            | (3,-20)
+ {-1,0,3}                              | [(NaN,1),(NaN,90)]            | 
+(80 rows)
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LINE_TBL l, BOX_TBL b;
+ERROR:  function "close_lb" not implemented
 --
 -- Line segments
 --
 -- intersection
 SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
    FROM LSEG_TBL l, POINT_TBL p;
 ERROR:  operator does not exist: lseg # point
 LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
                                            ^
 HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (-0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
+-- Length
+SELECT s, @-@ s FROM LSEG_TBL;
+               s               |   ?column?    
+-------------------------------+---------------
+ [(1,2),(3,4)]                 | 2.82842712475
+ [(0,0),(6,6)]                 | 8.48528137424
+ [(10,-10),(-3,-4)]            | 14.3178210633
+ [(-1000000,200),(300000,-40)] | 1300000.02215
+ [(11,22),(33,44)]             | 31.1126983722
+ [(-10,2),(-10,3)]             |             1
+ [(0,-20),(30,-20)]            |            30
+ [(NaN,1),(NaN,90)]            |           NaN
+(8 rows)
+
+-- Vertical
+SELECT s FROM LSEG_TBL WHERE ?| s;
+         s         
+-------------------
+ [(-10,2),(-10,3)]
+(1 row)
+
+-- Horizontal
+SELECT s FROM LSEG_TBL WHERE ?- s;
+         s          
+--------------------
+ [(0,-20),(30,-20)]
+(1 row)
+
+-- Center
+SELECT s, @@ s FROM LSEG_TBL;
+               s               |   ?column?   
+-------------------------------+--------------
+ [(1,2),(3,4)]                 | (2,3)
+ [(0,0),(6,6)]                 | (3,3)
+ [(10,-10),(-3,-4)]            | (3.5,-7)
+ [(-1000000,200),(300000,-40)] | (-350000,80)
+ [(11,22),(33,44)]             | (22,33)
+ [(-10,2),(-10,3)]             | (-10,2.5)
+ [(0,-20),(30,-20)]            | (15,-20)
+ [(NaN,1),(NaN,90)]            | (NaN,45.5)
+(8 rows)
+
+-- To point
+SELECT s, s::point FROM LSEG_TBL;
+               s               |      s       
+-------------------------------+--------------
+ [(1,2),(3,4)]                 | (2,3)
+ [(0,0),(6,6)]                 | (3,3)
+ [(10,-10),(-3,-4)]            | (3.5,-7)
+ [(-1000000,200),(300000,-40)] | (-350000,80)
+ [(11,22),(33,44)]             | (22,33)
+ [(-10,2),(-10,3)]             | (-10,2.5)
+ [(0,-20),(30,-20)]            | (15,-20)
+ [(NaN,1),(NaN,90)]            | (NaN,45.5)
+(8 rows)
+
+-- Has points less than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s < l2.s;
+         s          |               s               
+--------------------+-------------------------------
+ [(1,2),(3,4)]      | [(0,0),(6,6)]
+ [(1,2),(3,4)]      | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]      | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]      | [(11,22),(33,44)]
+ [(1,2),(3,4)]      | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]      | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]      | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]      | [(11,22),(33,44)]
+ [(0,0),(6,6)]      | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)] | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)] | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]  | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]  | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]  | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]  | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]  | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]  | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]  | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)] | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)] | [(11,22),(33,44)]
+(21 rows)
+
+-- Has points less than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s <= l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(28 rows)
+
+-- Has points equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s = l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]
+(8 rows)
+
+-- Has points greater than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s >= l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(28 rows)
+
+-- Has points greater than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s > l2.s;
+               s               |         s          
+-------------------------------+--------------------
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+(21 rows)
+
+-- Has points not equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s != l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)]
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]
+(56 rows)
+
+-- Parallel with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?|| l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(13 rows)
+
+-- Perpendicular with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?-| l2.s;
+         s          |         s          
+--------------------+--------------------
+ [(-10,2),(-10,3)]  | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)] | [(-10,2),(-10,3)]
+(2 rows)
+
+-- Distance to line
+SELECT l.s, l1.s, l.s <-> l1.s FROM LSEG_TBL l, LINE_TBL l1;
+               s               |                   s                   |    ?column?    
+-------------------------------+---------------------------------------+----------------
+ [(1,2),(3,4)]                 | {0,-1,5}                              |              1
+ [(0,0),(6,6)]                 | {0,-1,5}                              |              0
+ [(10,-10),(-3,-4)]            | {0,-1,5}                              |              9
+ [(-1000000,200),(300000,-40)] | {0,-1,5}                              |              0
+ [(11,22),(33,44)]             | {0,-1,5}                              |             17
+ [(-10,2),(-10,3)]             | {0,-1,5}                              |              2
+ [(0,-20),(30,-20)]            | {0,-1,5}                              |             25
+ [(NaN,1),(NaN,90)]            | {0,-1,5}                              |            NaN
+ [(1,2),(3,4)]                 | {1,0,5}                               |              6
+ [(0,0),(6,6)]                 | {1,0,5}                               |              5
+ [(10,-10),(-3,-4)]            | {1,0,5}                               |              2
+ [(-1000000,200),(300000,-40)] | {1,0,5}                               |              0
+ [(11,22),(33,44)]             | {1,0,5}                               |             16
+ [(-10,2),(-10,3)]             | {1,0,5}                               |              5
+ [(0,-20),(30,-20)]            | {1,0,5}                               |              5
+ [(NaN,1),(NaN,90)]            | {1,0,5}                               |            NaN
+ [(1,2),(3,4)]                 | {0,3,0}                               |              2
+ [(0,0),(6,6)]                 | {0,3,0}                               |              0
+ [(10,-10),(-3,-4)]            | {0,3,0}                               |              4
+ [(-1000000,200),(300000,-40)] | {0,3,0}                               |              0
+ [(11,22),(33,44)]             | {0,3,0}                               |             22
+ [(-10,2),(-10,3)]             | {0,3,0}                               |              2
+ [(0,-20),(30,-20)]            | {0,3,0}                               |             20
+ [(NaN,1),(NaN,90)]            | {0,3,0}                               |            NaN
+ [(1,2),(3,4)]                 | {1,-1,0}                              | 0.707106781187
+ [(0,0),(6,6)]                 | {1,-1,0}                              |              0
+ [(10,-10),(-3,-4)]            | {1,-1,0}                              | 0.707106781187
+ [(-1000000,200),(300000,-40)] | {1,-1,0}                              |              0
+ [(11,22),(33,44)]             | {1,-1,0}                              |  7.77817459305
+ [(-10,2),(-10,3)]             | {1,-1,0}                              |  8.48528137424
+ [(0,-20),(30,-20)]            | {1,-1,0}                              |  14.1421356237
+ [(NaN,1),(NaN,90)]            | {1,-1,0}                              |            NaN
+ [(1,2),(3,4)]                 | {-0.4,-1,-6}                          |  7.79920420344
+ [(0,0),(6,6)]                 | {-0.4,-1,-6}                          |  5.57086014531
+ [(10,-10),(-3,-4)]            | {-0.4,-1,-6}                          |              0
+ [(-1000000,200),(300000,-40)] | {-0.4,-1,-6}                          |              0
+ [(11,22),(33,44)]             | {-0.4,-1,-6}                          |  30.0826447847
+ [(-10,2),(-10,3)]             | {-0.4,-1,-6}                          |  3.71390676354
+ [(0,-20),(30,-20)]            | {-0.4,-1,-6}                          |  1.85695338177
+ [(NaN,1),(NaN,90)]            | {-0.4,-1,-6}                          |            NaN
+ [(1,2),(3,4)]                 | {-0.000184615384615,-1,15.3846153846} |  11.3840613445
+ [(0,0),(6,6)]                 | {-0.000184615384615,-1,15.3846153846} |   9.3835075324
+ [(10,-10),(-3,-4)]            | {-0.000184615384615,-1,15.3846153846} |  19.3851689004
+ [(-1000000,200),(300000,-40)] | {-0.000184615384615,-1,15.3846153846} |              0
+ [(11,22),(33,44)]             | {-0.000184615384615,-1,15.3846153846} |  6.61741527185
+ [(-10,2),(-10,3)]             | {-0.000184615384615,-1,15.3846153846} |  12.3864613274
+ [(0,-20),(30,-20)]            | {-0.000184615384615,-1,15.3846153846} |  35.3790763202
+ [(NaN,1),(NaN,90)]            | {-0.000184615384615,-1,15.3846153846} |            NaN
+ [(1,2),(3,4)]                 | {3,NaN,5}                             |            NaN
+ [(0,0),(6,6)]                 | {3,NaN,5}                             |            NaN
+ [(10,-10),(-3,-4)]            | {3,NaN,5}                             |            NaN
+ [(-1000000,200),(300000,-40)] | {3,NaN,5}                             |            NaN
+ [(11,22),(33,44)]             | {3,NaN,5}                             |            NaN
+ [(-10,2),(-10,3)]             | {3,NaN,5}                             |            NaN
+ [(0,-20),(30,-20)]            | {3,NaN,5}                             |            NaN
+ [(NaN,1),(NaN,90)]            | {3,NaN,5}                             |            NaN
+ [(1,2),(3,4)]                 | {NaN,NaN,NaN}                         |            NaN
+ [(0,0),(6,6)]                 | {NaN,NaN,NaN}                         |            NaN
+ [(10,-10),(-3,-4)]            | {NaN,NaN,NaN}                         |            NaN
+ [(-1000000,200),(300000,-40)] | {NaN,NaN,NaN}                         |            NaN
+ [(11,22),(33,44)]             | {NaN,NaN,NaN}                         |            NaN
+ [(-10,2),(-10,3)]             | {NaN,NaN,NaN}                         |            NaN
+ [(0,-20),(30,-20)]            | {NaN,NaN,NaN}                         |            NaN
+ [(NaN,1),(NaN,90)]            | {NaN,NaN,NaN}                         |            NaN
+ [(1,2),(3,4)]                 | {0,-1,3}                              |              0
+ [(0,0),(6,6)]                 | {0,-1,3}                              |              0
+ [(10,-10),(-3,-4)]            | {0,-1,3}                              |              7
+ [(-1000000,200),(300000,-40)] | {0,-1,3}                              |              0
+ [(11,22),(33,44)]             | {0,-1,3}                              |             19
+ [(-10,2),(-10,3)]             | {0,-1,3}                              |              0
+ [(0,-20),(30,-20)]            | {0,-1,3}                              |             23
+ [(NaN,1),(NaN,90)]            | {0,-1,3}                              |            NaN
+ [(1,2),(3,4)]                 | {-1,0,3}                              |              0
+ [(0,0),(6,6)]                 | {-1,0,3}                              |              0
+ [(10,-10),(-3,-4)]            | {-1,0,3}                              |              0
+ [(-1000000,200),(300000,-40)] | {-1,0,3}                              |              0
+ [(11,22),(33,44)]             | {-1,0,3}                              |              8
+ [(-10,2),(-10,3)]             | {-1,0,3}                              |             13
+ [(0,-20),(30,-20)]            | {-1,0,3}                              |              0
+ [(NaN,1),(NaN,90)]            | {-1,0,3}                              |            NaN
+(80 rows)
+
+-- Distance to line segment
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               |    ?column?    
+-------------------------------+-------------------------------+----------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 |              0
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 0.707106781187
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            |  7.12398901685
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] |  11.3840613445
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             |  19.6977156036
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             |             11
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            |             22
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            |            NaN
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 0.707106781187
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 |              0
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            |  4.88901207039
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] |   9.3835075324
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             |  16.7630546142
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             |  10.1980390272
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            |             20
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            |            NaN
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 |  7.12398901685
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 |  4.88901207039
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            |              0
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] |  19.3851689004
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             |  29.4737584815
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             |  9.21954445729
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            |             10
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            |            NaN
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 |  11.3840613445
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 |   9.3835075324
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            |  19.3851689004
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] |              0
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             |  6.61741527185
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             |  12.3864613274
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            |  35.3790763202
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            |            NaN
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 |  19.6977156036
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 |  16.7630546142
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            |  29.4737584815
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] |  6.61741527185
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             |              0
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             |   28.319604517
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            |             42
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            |            NaN
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 |             11
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 |  10.1980390272
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            |  9.21954445729
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] |  12.3864613274
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             |   28.319604517
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             |              0
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            |  24.1660919472
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            |            NaN
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 |             22
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 |             20
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            |             10
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] |  35.3790763202
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             |             42
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             |  24.1660919472
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            |              0
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 |            NaN
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 |            NaN
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] |            NaN
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             |            NaN
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             |            NaN
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            |            NaN
+(64 rows)
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LSEG_TBL l, BOX_TBL b;
+               s               |         f1          |    ?column?    
+-------------------------------+---------------------+----------------
+ [(1,2),(3,4)]                 | (2,2),(0,0)         |              0
+ [(1,2),(3,4)]                 | (3,3),(1,1)         |              0
+ [(1,2),(3,4)]                 | (-2,2),(-8,-10)     |              3
+ [(1,2),(3,4)]                 | (2.5,3.5),(2.5,2.5) |              0
+ [(1,2),(3,4)]                 | (3,3),(3,3)         | 0.707106781187
+ [(0,0),(6,6)]                 | (2,2),(0,0)         |              0
+ [(0,0),(6,6)]                 | (3,3),(1,1)         |              0
+ [(0,0),(6,6)]                 | (-2,2),(-8,-10)     |              2
+ [(0,0),(6,6)]                 | (2.5,3.5),(2.5,2.5) |              0
+ [(0,0),(6,6)]                 | (3,3),(3,3)         |              0
+ [(10,-10),(-3,-4)]            | (2,2),(0,0)         |  4.88901207039
+ [(10,-10),(-3,-4)]            | (3,3),(1,1)         |  6.21602963235
+ [(10,-10),(-3,-4)]            | (-2,2),(-8,-10)     |              0
+ [(10,-10),(-3,-4)]            | (2.5,3.5),(2.5,2.5) |  8.20655597529
+ [(10,-10),(-3,-4)]            | (3,3),(3,3)         |  8.87006475627
+ [(-1000000,200),(300000,-40)] | (2,2),(0,0)         |  13.3842459258
+ [(-1000000,200),(300000,-40)] | (3,3),(1,1)         |  12.3840613274
+ [(-1000000,200),(300000,-40)] | (-2,2),(-8,-10)     |  13.3849843873
+ [(-1000000,200),(300000,-40)] | (2.5,3.5),(2.5,2.5) |  11.8841536436
+ [(-1000000,200),(300000,-40)] | (3,3),(3,3)         |  12.3840613274
+ [(11,22),(33,44)]             | (2,2),(0,0)         |  21.9317121995
+ [(11,22),(33,44)]             | (3,3),(1,1)         |  20.6155281281
+ [(11,22),(33,44)]             | (-2,2),(-8,-10)     |  23.8537208838
+ [(11,22),(33,44)]             | (2.5,3.5),(2.5,2.5) |  20.3592730715
+ [(11,22),(33,44)]             | (3,3),(3,3)         |  20.6155281281
+ [(-10,2),(-10,3)]             | (2,2),(0,0)         |             10
+ [(-10,2),(-10,3)]             | (3,3),(1,1)         |             11
+ [(-10,2),(-10,3)]             | (-2,2),(-8,-10)     |              2
+ [(-10,2),(-10,3)]             | (2.5,3.5),(2.5,2.5) |           12.5
+ [(-10,2),(-10,3)]             | (3,3),(3,3)         |             13
+ [(0,-20),(30,-20)]            | (2,2),(0,0)         |             20
+ [(0,-20),(30,-20)]            | (3,3),(1,1)         |             21
+ [(0,-20),(30,-20)]            | (-2,2),(-8,-10)     |  10.1980390272
+ [(0,-20),(30,-20)]            | (2.5,3.5),(2.5,2.5) |           22.5
+ [(0,-20),(30,-20)]            | (3,3),(3,3)         |             23
+ [(NaN,1),(NaN,90)]            | (2,2),(0,0)         |            NaN
+ [(NaN,1),(NaN,90)]            | (3,3),(1,1)         |            NaN
+ [(NaN,1),(NaN,90)]            | (-2,2),(-8,-10)     |            NaN
+ [(NaN,1),(NaN,90)]            | (2.5,3.5),(2.5,2.5) |            NaN
+ [(NaN,1),(NaN,90)]            | (3,3),(3,3)         |            NaN
+(40 rows)
+
+-- Intersect with line segment
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s ?# l1.s;
+               s               |      s       
+-------------------------------+--------------
+ [(0,0),(6,6)]                 | {0,-1,5}
+ [(-1000000,200),(300000,-40)] | {0,-1,5}
+ [(-1000000,200),(300000,-40)] | {1,0,5}
+ [(0,0),(6,6)]                 | {0,3,0}
+ [(-1000000,200),(300000,-40)] | {0,3,0}
+ [(-1000000,200),(300000,-40)] | {1,-1,0}
+ [(10,-10),(-3,-4)]            | {-0.4,-1,-6}
+ [(-1000000,200),(300000,-40)] | {-0.4,-1,-6}
+ [(1,2),(3,4)]                 | {0,-1,3}
+ [(0,0),(6,6)]                 | {0,-1,3}
+ [(-1000000,200),(300000,-40)] | {0,-1,3}
+ [(-10,2),(-10,3)]             | {0,-1,3}
+ [(1,2),(3,4)]                 | {-1,0,3}
+ [(0,0),(6,6)]                 | {-1,0,3}
+ [(10,-10),(-3,-4)]            | {-1,0,3}
+ [(-1000000,200),(300000,-40)] | {-1,0,3}
+ [(0,-20),(30,-20)]            | {-1,0,3}
+(17 rows)
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+         s          |         f1          
+--------------------+---------------------
+ [(1,2),(3,4)]      | (2,2),(0,0)
+ [(1,2),(3,4)]      | (3,3),(1,1)
+ [(1,2),(3,4)]      | (2.5,3.5),(2.5,2.5)
+ [(0,0),(6,6)]      | (2,2),(0,0)
+ [(0,0),(6,6)]      | (3,3),(1,1)
+ [(0,0),(6,6)]      | (2.5,3.5),(2.5,2.5)
+ [(0,0),(6,6)]      | (3,3),(3,3)
+ [(10,-10),(-3,-4)] | (-2,2),(-8,-10)
+(8 rows)
+
+-- Intersection point with line segment
+SELECT l1.s, l2.s, l1.s # l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               | ?column? 
+-------------------------------+-------------------------------+----------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 | 
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            | 
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] | 
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             | 
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             | 
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            | 
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            | 
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 | 
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            | 
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] | 
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             | 
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             | 
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            | 
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            | 
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 | 
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 | 
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            | 
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] | 
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             | 
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             | 
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            | 
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            | 
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 | 
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 | 
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            | 
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] | 
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             | 
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             | 
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            | 
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            | 
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 | 
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 | 
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            | 
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] | 
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             | 
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             | 
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            | 
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            | 
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 | 
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 | 
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            | 
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] | 
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             | 
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             | 
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            | 
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            | 
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 | 
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 | 
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            | 
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] | 
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             | 
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             | 
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            | 
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            | 
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 | 
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 | 
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            | 
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] | 
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             | 
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             | 
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            | 
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            | 
+(64 rows)
+
+-- Closest point to line
+SELECT l.s, l1.s, l.s ## l1.s FROM LSEG_TBL l, LINE_TBL l1;
+ERROR:  function "close_sl" not implemented
+-- Closest point to line segment
+SELECT l1.s, l2.s, l1.s ## l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               |            ?column?             
+-------------------------------+-------------------------------+---------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 | 
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            | (-1.98536585366,-4.46829268293)
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] | (3.00210167283,15.3840611505)
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             | 
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             | (-10,2)
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            | (1,-20)
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            | 
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 | 
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] | (6.00173233982,15.3835073725)
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             | 
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             | (-10,2)
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            | (0,-20)
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            | 
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 | (1,2)
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 | (0,0)
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            | 
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] | (-2.99642119965,15.3851685701)
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             | (11,22)
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             | (-10,2)
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            | (10,-20)
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            | 
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 | (3,4)
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 | (6,6)
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            | (-3,-4)
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] | 
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             | (11,22)
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             | (-10,3)
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            | (30,-20)
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            | 
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 | 
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 | 
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            | (-1.3512195122,-4.76097560976)
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] | (10.9987783234,15.3825848409)
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             | 
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             | (-10,3)
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            | (11,-20)
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            | 
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 | (1,2)
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 | (0,0)
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            | (-3,-4)
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] | (-9.99771326872,15.3864611163)
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             | (11,22)
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             | 
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            | (0,-20)
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            | 
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 | (1,2)
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 | (0,0)
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            | (10,-10)
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] | (30.0065315217,15.3790757173)
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             | (11,22)
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             | (-10,2)
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            | 
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            | 
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 | 
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 | 
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            | 
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] | 
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             | 
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             | 
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            | 
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            | 
+(64 rows)
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LSEG_TBL l, BOX_TBL b;
+               s               |         f1          |  ?column?   
+-------------------------------+---------------------+-------------
+ [(1,2),(3,4)]                 | (2,2),(0,0)         | (1,2)
+ [(1,2),(3,4)]                 | (3,3),(1,1)         | (1.5,2.5)
+ [(1,2),(3,4)]                 | (-2,2),(-8,-10)     | (-2,2)
+ [(1,2),(3,4)]                 | (2.5,3.5),(2.5,2.5) | (2.25,3.25)
+ [(1,2),(3,4)]                 | (3,3),(3,3)         | (3,3)
+ [(0,0),(6,6)]                 | (2,2),(0,0)         | (1,1)
+ [(0,0),(6,6)]                 | (3,3),(1,1)         | (2,2)
+ [(0,0),(6,6)]                 | (-2,2),(-8,-10)     | (-2,0)
+ [(0,0),(6,6)]                 | (2.5,3.5),(2.5,2.5) | (2.75,2.75)
+ [(0,0),(6,6)]                 | (3,3),(3,3)         | (3,3)
+ [(10,-10),(-3,-4)]            | (2,2),(0,0)         | (0,0)
+ [(10,-10),(-3,-4)]            | (3,3),(1,1)         | (1,1)
+ [(10,-10),(-3,-4)]            | (-2,2),(-8,-10)     | (-3,-4)
+ [(10,-10),(-3,-4)]            | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ [(10,-10),(-3,-4)]            | (3,3),(3,3)         | (3,3)
+ [(-1000000,200),(300000,-40)] | (2,2),(0,0)         | (2,2)
+ [(-1000000,200),(300000,-40)] | (3,3),(1,1)         | (3,3)
+ [(-1000000,200),(300000,-40)] | (-2,2),(-8,-10)     | (-2,2)
+ [(-1000000,200),(300000,-40)] | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ [(-1000000,200),(300000,-40)] | (3,3),(3,3)         | (3,3)
+ [(11,22),(33,44)]             | (2,2),(0,0)         | (2,2)
+ [(11,22),(33,44)]             | (3,3),(1,1)         | (3,3)
+ [(11,22),(33,44)]             | (-2,2),(-8,-10)     | (-2,2)
+ [(11,22),(33,44)]             | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ [(11,22),(33,44)]             | (3,3),(3,3)         | (3,3)
+ [(-10,2),(-10,3)]             | (2,2),(0,0)         | (0,2)
+ [(-10,2),(-10,3)]             | (3,3),(1,1)         | (1,2)
+ [(-10,2),(-10,3)]             | (-2,2),(-8,-10)     | (-8,2)
+ [(-10,2),(-10,3)]             | (2.5,3.5),(2.5,2.5) | (2.5,3)
+ [(-10,2),(-10,3)]             | (3,3),(3,3)         | (3,3)
+ [(0,-20),(30,-20)]            | (2,2),(0,0)         | (0,0)
+ [(0,-20),(30,-20)]            | (3,3),(1,1)         | (1,1)
+ [(0,-20),(30,-20)]            | (-2,2),(-8,-10)     | (-2,-10)
+ [(0,-20),(30,-20)]            | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ [(0,-20),(30,-20)]            | (3,3),(3,3)         | (3,3)
+ [(NaN,1),(NaN,90)]            | (2,2),(0,0)         | 
+ [(NaN,1),(NaN,90)]            | (3,3),(1,1)         | 
+ [(NaN,1),(NaN,90)]            | (-2,2),(-8,-10)     | 
+ [(NaN,1),(NaN,90)]            | (2.5,3.5),(2.5,2.5) | 
+ [(NaN,1),(NaN,90)]            | (3,3),(3,3)         | 
+(40 rows)
+
+-- On line
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s <@ l1.s;
+               s               |                   s                   
+-------------------------------+---------------------------------------
+ [(0,0),(6,6)]                 | {1,-1,0}
+ [(-1000000,200),(300000,-40)] | {-0.000184615384615,-1,15.3846153846}
+(2 rows)
+
+-- On box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s <@ b.f1;
+ s | f1 
+---+----
+(0 rows)
 
 --
 -- Boxes
 --
 SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
  six |                              box                               
 -----+----------------------------------------------------------------
      | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
      | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
      | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
      | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
      | (107.071067812,207.071067812),(92.9289321881,192.928932188)
      | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
+     | (3,5),(3,5)
+     | (NaN,NaN),(NaN,NaN)
+(8 rows)
 
 -- translation
 SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
+ twentyfour |             translation             
+------------+-------------------------------------
             | (2,2),(0,0)
             | (3,3),(1,1)
+            | (-2,2),(-8,-10)
             | (2.5,3.5),(2.5,2.5)
             | (3,3),(3,3)
             | (-8,2),(-10,0)
             | (-7,3),(-9,1)
+            | (-12,2),(-18,-10)
             | (-7.5,3.5),(-7.5,2.5)
             | (-7,3),(-7,3)
             | (-1,6),(-3,4)
             | (0,7),(-2,5)
+            | (-5,6),(-11,-6)
             | (-0.5,7.5),(-0.5,6.5)
             | (0,7),(0,7)
             | (7.1,36.5),(5.1,34.5)
             | (8.1,37.5),(6.1,35.5)
+            | (3.1,36.5),(-2.9,24.5)
             | (7.6,38),(7.6,37)
             | (8.1,37.5),(8.1,37.5)
             | (-3,-10),(-5,-12)
             | (-2,-9),(-4,-11)
+            | (-7,-10),(-13,-22)
             | (-2.5,-8.5),(-2.5,-9.5)
             | (-2,-9),(-2,-9)
+            | (2,2),(1e-300,-1e-300)
+            | (3,3),(1,1)
+            | (-2,2),(-8,-10)
+            | (2.5,3.5),(2.5,2.5)
+            | (3,3),(3,3)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
             | (12,12),(10,10)
             | (13,13),(11,11)
+            | (8,12),(2,0)
             | (12.5,13.5),(12.5,12.5)
             | (13,13),(13,13)
-(24 rows)
+(45 rows)
 
 SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
+ twentyfour |               translation               
+------------+-----------------------------------------
             | (2,2),(0,0)
             | (3,3),(1,1)
+            | (-2,2),(-8,-10)
             | (2.5,3.5),(2.5,2.5)
             | (3,3),(3,3)
             | (12,2),(10,0)
             | (13,3),(11,1)
+            | (8,2),(2,-10)
             | (12.5,3.5),(12.5,2.5)
             | (13,3),(13,3)
             | (5,-2),(3,-4)
             | (6,-1),(4,-3)
+            | (1,-2),(-5,-14)
             | (5.5,-0.5),(5.5,-1.5)
             | (6,-1),(6,-1)
             | (-3.1,-32.5),(-5.1,-34.5)
             | (-2.1,-31.5),(-4.1,-33.5)
+            | (-7.1,-32.5),(-13.1,-44.5)
             | (-2.6,-31),(-2.6,-32)
             | (-2.1,-31.5),(-2.1,-31.5)
             | (7,14),(5,12)
             | (8,15),(6,13)
+            | (3,14),(-3,2)
             | (7.5,15.5),(7.5,14.5)
             | (8,15),(8,15)
+            | (2,2),(-1e-300,1e-300)
+            | (3,3),(1,1)
+            | (-2,2),(-8,-10)
+            | (2.5,3.5),(2.5,2.5)
+            | (3,3),(3,3)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
             | (-8,-8),(-10,-10)
             | (-7,-7),(-9,-9)
+            | (-12,-8),(-18,-20)
             | (-7.5,-6.5),(-7.5,-7.5)
             | (-7,-7),(-7,-7)
-(24 rows)
+(45 rows)
 
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (-0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (-0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,-0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
+-- Multiply with point
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+         f1          |     f1     |          ?column?           
+---------------------+------------+-----------------------------
+ (2,2),(0,0)         | (5.1,34.5) | (0,79.2),(-58.8,0)
+ (2,2),(0,0)         | (10,10)    | (0,40),(0,0)
+ (3,3),(1,1)         | (5.1,34.5) | (-29.4,118.8),(-88.2,39.6)
+ (3,3),(1,1)         | (10,10)    | (0,60),(0,20)
+ (-2,2),(-8,-10)     | (5.1,34.5) | (304.2,-58.8),(-79.2,-327)
+ (-2,2),(-8,-10)     | (10,10)    | (20,0),(-40,-180)
+ (2.5,3.5),(2.5,2.5) | (5.1,34.5) | (-73.5,104.1),(-108,99)
+ (2.5,3.5),(2.5,2.5) | (10,10)    | (0,60),(-10,50)
+ (3,3),(3,3)         | (5.1,34.5) | (-88.2,118.8),(-88.2,118.8)
+ (3,3),(3,3)         | (10,10)    | (0,60),(0,60)
+(10 rows)
 
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,-0),(-0.2,-0.2)
-        | (0.08,-0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (-0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
+-- Overflow error
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] > 1000;
+         f1          |        f1         |                  ?column?                  
+---------------------+-------------------+--------------------------------------------
+ (2,2),(0,0)         | (1e+300,Infinity) | (NaN,NaN),(-Infinity,Infinity)
+ (2,2),(0,0)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (3,3),(1,1)         | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (3,3),(1,1)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (-2,2),(-8,-10)     | (1e+300,Infinity) | (Infinity,-Infinity),(-Infinity,-Infinity)
+ (-2,2),(-8,-10)     | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (2.5,3.5),(2.5,2.5) | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (2.5,3.5),(2.5,2.5) | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (3,3),(3,3)         | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (3,3),(3,3)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+(10 rows)
 
+-- Divide by point
+SELECT b.f1, p.f1, b.f1 / p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+         f1          |     f1     |                               ?column?                               
+---------------------+------------+----------------------------------------------------------------------
+ (2,2),(0,0)         | (5.1,34.5) | (0.0651176557644,0),(0,-0.0483449262493)
+ (2,2),(0,0)         | (10,10)    | (0.2,0),(0,0)
+ (3,3),(1,1)         | (5.1,34.5) | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
+ (3,3),(1,1)         | (10,10)    | (0.3,0),(0.1,0)
+ (-2,2),(-8,-10)     | (5.1,34.5) | (0.0483449262493,0.18499334024),(-0.317201914064,0.0651176557644)
+ (-2,2),(-8,-10)     | (10,10)    | (0,0.2),(-0.9,-0.1)
+ (2.5,3.5),(2.5,2.5) | (5.1,34.5) | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
+ (2.5,3.5),(2.5,2.5) | (10,10)    | (0.3,0.05),(0.25,0)
+ (3,3),(3,3)         | (5.1,34.5) | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
+ (3,3),(3,3)         | (10,10)    | (0.3,0),(0.3,0)
+(10 rows)
+
+-- To box
 SELECT f1::box
 	FROM POINT_TBL;
-          f1           
------------------------
+                 f1                  
+-------------------------------------
  (0,0),(0,0)
  (-10,0),(-10,0)
  (-3,4),(-3,4)
  (5.1,34.5),(5.1,34.5)
  (-5,-12),(-5,-12)
+ (1e-300,-1e-300),(1e-300,-1e-300)
+ (1e+300,Infinity),(1e+300,Infinity)
+ (NaN,NaN),(NaN,NaN)
  (10,10),(10,10)
-(6 rows)
+(9 rows)
 
 SELECT bound_box(a.f1, b.f1)
 	FROM BOX_TBL a, BOX_TBL b;
       bound_box      
 ---------------------
  (2,2),(0,0)
  (3,3),(0,0)
+ (2,2),(-8,-10)
  (2.5,3.5),(0,0)
  (3,3),(0,0)
  (3,3),(0,0)
  (3,3),(1,1)
+ (3,3),(-8,-10)
  (3,3.5),(1,1)
  (3,3),(1,1)
+ (2,2),(-8,-10)
+ (3,3),(-8,-10)
+ (-2,2),(-8,-10)
+ (2.5,3.5),(-8,-10)
+ (3,3),(-8,-10)
  (2.5,3.5),(0,0)
  (3,3.5),(1,1)
+ (2.5,3.5),(-8,-10)
  (2.5,3.5),(2.5,2.5)
  (3,3.5),(2.5,2.5)
  (3,3),(0,0)
  (3,3),(1,1)
+ (3,3),(-8,-10)
  (3,3.5),(2.5,2.5)
  (3,3),(3,3)
-(16 rows)
+(25 rows)
+
+-- Below box
+SELECT b1.f1, b2.f1, b1.f1 <^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          | ?column? 
+---------------------+---------------------+----------
+ (2,2),(0,0)         | (2,2),(0,0)         | f
+ (2,2),(0,0)         | (3,3),(1,1)         | f
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | f
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | t
+ (2,2),(0,0)         | (3,3),(3,3)         | t
+ (3,3),(1,1)         | (2,2),(0,0)         | f
+ (3,3),(1,1)         | (3,3),(1,1)         | f
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | f
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(1,1)         | (3,3),(3,3)         | t
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | f
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | f
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | f
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | t
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | t
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | f
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | f
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | f
+ (3,3),(3,3)         | (2,2),(0,0)         | f
+ (3,3),(3,3)         | (3,3),(1,1)         | f
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | f
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(3,3)         | (3,3),(3,3)         | t
+(25 rows)
+
+-- Above box
+SELECT b1.f1, b2.f1, b1.f1 >^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          | ?column? 
+---------------------+---------------------+----------
+ (2,2),(0,0)         | (2,2),(0,0)         | f
+ (2,2),(0,0)         | (3,3),(1,1)         | f
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | f
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | f
+ (2,2),(0,0)         | (3,3),(3,3)         | f
+ (3,3),(1,1)         | (2,2),(0,0)         | f
+ (3,3),(1,1)         | (3,3),(1,1)         | f
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | f
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(1,1)         | (3,3),(3,3)         | f
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | f
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | f
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | f
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | f
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | f
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | t
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | f
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | t
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | f
+ (3,3),(3,3)         | (2,2),(0,0)         | t
+ (3,3),(3,3)         | (3,3),(1,1)         | t
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | t
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(3,3)         | (3,3),(3,3)         | t
+(25 rows)
+
+-- Intersection point with box
+SELECT b1.f1, b2.f1, b1.f1 # b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          |      ?column?       
+---------------------+---------------------+---------------------
+ (2,2),(0,0)         | (2,2),(0,0)         | (2,2),(0,0)
+ (2,2),(0,0)         | (3,3),(1,1)         | (2,2),(1,1)
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | 
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | 
+ (2,2),(0,0)         | (3,3),(3,3)         | 
+ (3,3),(1,1)         | (2,2),(0,0)         | (2,2),(1,1)
+ (3,3),(1,1)         | (3,3),(1,1)         | (3,3),(1,1)
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | 
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | (2.5,3),(2.5,2.5)
+ (3,3),(1,1)         | (3,3),(3,3)         | (3,3),(3,3)
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | 
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | 
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | (-2,2),(-8,-10)
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | 
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | 
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | 
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | (2.5,3),(2.5,2.5)
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | 
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5)
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | 
+ (3,3),(3,3)         | (2,2),(0,0)         | 
+ (3,3),(3,3)         | (3,3),(1,1)         | (3,3),(3,3)
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | 
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | 
+ (3,3),(3,3)         | (3,3),(3,3)         | (3,3),(3,3)
+(25 rows)
+
+-- Diagonal
+SELECT f1, diagonal(f1) FROM BOX_TBL;
+         f1          |       diagonal        
+---------------------+-----------------------
+ (2,2),(0,0)         | [(2,2),(0,0)]
+ (3,3),(1,1)         | [(3,3),(1,1)]
+ (-2,2),(-8,-10)     | [(-2,2),(-8,-10)]
+ (2.5,3.5),(2.5,2.5) | [(2.5,3.5),(2.5,2.5)]
+ (3,3),(3,3)         | [(3,3),(3,3)]
+(5 rows)
+
+-- Distance to box
+SELECT b1.f1, b2.f1, b1.f1 <-> b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          |   ?column?    
+---------------------+---------------------+---------------
+ (2,2),(0,0)         | (2,2),(0,0)         |             0
+ (2,2),(0,0)         | (3,3),(1,1)         | 1.41421356237
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | 7.81024967591
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) |           2.5
+ (2,2),(0,0)         | (3,3),(3,3)         | 2.82842712475
+ (3,3),(1,1)         | (2,2),(0,0)         | 1.41421356237
+ (3,3),(1,1)         | (3,3),(1,1)         |             0
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | 9.21954445729
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | 1.11803398875
+ (3,3),(1,1)         | (3,3),(3,3)         | 1.41421356237
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | 7.81024967591
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | 9.21954445729
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     |             0
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | 10.2591422643
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | 10.6301458127
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         |           2.5
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | 1.11803398875
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | 10.2591422643
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) |             0
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         |           0.5
+ (3,3),(3,3)         | (2,2),(0,0)         | 2.82842712475
+ (3,3),(3,3)         | (3,3),(1,1)         | 1.41421356237
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | 10.6301458127
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) |           0.5
+ (3,3),(3,3)         | (3,3),(3,3)         |             0
+(25 rows)
 
 --
 -- Paths
 --
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
+-- Points
+SELECT f1, npoints(f1) FROM PATH_TBL;
+            f1             | npoints 
+---------------------------+---------
+ [(1,2),(3,4)]             |       2
+ ((1,2),(3,4))             |       2
+ [(0,0),(3,0),(4,5),(1,6)] |       4
+ ((1,2),(3,4))             |       2
+ ((1,2),(3,4))             |       2
+ [(1,2),(3,4)]             |       2
+ ((10,20))                 |       1
+ [(11,12),(13,14)]         |       2
+ ((11,12),(13,14))         |       2
+(9 rows)
 
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
+-- Area
+SELECT f1, area(f1) FROM PATH_TBL;
+            f1             | area 
+---------------------------+------
+ [(1,2),(3,4)]             |     
+ ((1,2),(3,4))             |    0
+ [(0,0),(3,0),(4,5),(1,6)] |     
+ ((1,2),(3,4))             |    0
+ ((1,2),(3,4))             |    0
+ [(1,2),(3,4)]             |     
+ ((10,20))                 |    0
+ [(11,12),(13,14)]         |     
+ ((11,12),(13,14))         |    0
+(9 rows)
 
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
+-- Length
+SELECT f1, @-@ f1 FROM PATH_TBL;
+            f1             |   ?column?    
+---------------------------+---------------
+ [(1,2),(3,4)]             | 2.82842712475
+ ((1,2),(3,4))             | 5.65685424949
+ [(0,0),(3,0),(4,5),(1,6)] | 11.2612971738
+ ((1,2),(3,4))             | 5.65685424949
+ ((1,2),(3,4))             | 5.65685424949
+ [(1,2),(3,4)]             | 2.82842712475
+ ((10,20))                 |             0
+ [(11,12),(13,14)]         | 2.82842712475
+ ((11,12),(13,14))         | 5.65685424949
+(9 rows)
 
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
+-- Center
+SELECT f1, @@ f1 FROM PATH_TBL;
+ERROR:  function "path_center" not implemented
+-- To polygon
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isclosed(f1);
+        f1         |        f1         
+-------------------+-------------------
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((10,20))         | ((10,20))
+ ((11,12),(13,14)) | ((11,12),(13,14))
+(5 rows)
+
+-- Open path cannot be converted to polygon error
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isopen(f1);
+ERROR:  open path cannot be converted to polygon
+-- Has points less than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 < p2.f1;
+        f1         |            f1             
+-------------------+---------------------------
+ [(1,2),(3,4)]     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]     | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))         | [(1,2),(3,4)]
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | [(1,2),(3,4)]
+ ((10,20))         | [(11,12),(13,14)]
+ ((10,20))         | ((11,12),(13,14))
+ [(11,12),(13,14)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((11,12),(13,14)) | [(0,0),(3,0),(4,5),(1,6)]
+(15 rows)
+
+-- Has points less than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 <= p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | [(1,2),(3,4)]
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | [(1,2),(3,4)]
+ ((10,20))                 | ((10,20))
+ ((10,20))                 | [(11,12),(13,14)]
+ ((10,20))                 | ((11,12),(13,14))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(66 rows)
+
+-- Has points equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 = p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | ((10,20))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(51 rows)
+
+-- Has points greater than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 >= p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | ((10,20))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((10,20))
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((10,20))
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(66 rows)
+
+-- Has points greater than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 > p2.f1;
+            f1             |        f1         
+---------------------------+-------------------
+ [(1,2),(3,4)]             | ((10,20))
+ ((1,2),(3,4))             | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | ((10,20))
+ [(1,2),(3,4)]             | ((10,20))
+ [(11,12),(13,14)]         | ((10,20))
+ ((11,12),(13,14))         | ((10,20))
+(15 rows)
+
+-- Add path
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+            f1             |            f1             |                     ?column?                      
+---------------------------+---------------------------+---------------------------------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4),(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))                 | 
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         | [(1,2),(3,4),(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6),(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6),(0,0),(3,0),(4,5),(1,6)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6),(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))                 | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6),(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4),(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))                 | 
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         | [(1,2),(3,4),(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))         | 
+ ((10,20))                 | [(1,2),(3,4)]             | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | [(1,2),(3,4)]             | 
+ ((10,20))                 | ((10,20))                 | 
+ ((10,20))                 | [(11,12),(13,14)]         | 
+ ((10,20))                 | ((11,12),(13,14))         | 
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             | [(11,12),(13,14),(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14),(0,0),(3,0),(4,5),(1,6)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             | [(11,12),(13,14),(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((10,20))                 | 
+ [(11,12),(13,14)]         | [(11,12),(13,14)]         | [(11,12),(13,14),(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))         | 
+ ((11,12),(13,14))         | [(1,2),(3,4)]             | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | [(1,2),(3,4)]             | 
+ ((11,12),(13,14))         | ((10,20))                 | 
+ ((11,12),(13,14))         | [(11,12),(13,14)]         | 
+ ((11,12),(13,14))         | ((11,12),(13,14))         | 
+(81 rows)
+
+-- Add point
+SELECT p.f1, p1.f1, p.f1 + p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                                 ?column?                                  
+---------------------------+-------------------+---------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((10,20))                 | (0,0)             | ((10,20))
+ [(11,12),(13,14)]         | (0,0)             | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (0,0)             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (-10,0)           | [(-9,2),(-7,4)]
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(-10,0),(-7,0),(-6,5),(-9,6)]
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ [(1,2),(3,4)]             | (-10,0)           | [(-9,2),(-7,4)]
+ ((10,20))                 | (-10,0)           | ((0,20))
+ [(11,12),(13,14)]         | (-10,0)           | [(1,12),(3,14)]
+ ((11,12),(13,14))         | (-10,0)           | ((1,12),(3,14))
+ [(1,2),(3,4)]             | (-3,4)            | [(-2,6),(0,8)]
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(-3,4),(0,4),(1,9),(-2,10)]
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ [(1,2),(3,4)]             | (-3,4)            | [(-2,6),(0,8)]
+ ((10,20))                 | (-3,4)            | ((7,24))
+ [(11,12),(13,14)]         | (-3,4)            | [(8,16),(10,18)]
+ ((11,12),(13,14))         | (-3,4)            | ((8,16),(10,18))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(6.1,36.5),(8.1,38.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(5.1,34.5),(8.1,34.5),(9.1,39.5),(6.1,40.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(6.1,36.5),(8.1,38.5)]
+ ((10,20))                 | (5.1,34.5)        | ((15.1,54.5))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(16.1,46.5),(18.1,48.5)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((16.1,46.5),(18.1,48.5))
+ [(1,2),(3,4)]             | (-5,-12)          | [(-4,-10),(-2,-8)]
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(-5,-12),(-2,-12),(-1,-7),(-4,-6)]
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ [(1,2),(3,4)]             | (-5,-12)          | [(-4,-10),(-2,-8)]
+ ((10,20))                 | (-5,-12)          | ((5,8))
+ [(11,12),(13,14)]         | (-5,-12)          | [(6,0),(8,2)]
+ ((11,12),(13,14))         | (-5,-12)          | ((6,0),(8,2))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(1e-300,-1e-300),(3,-1e-300),(4,5),(1,6)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((10,20))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity),(1e+300,Infinity),(1e+300,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((1e+300,Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(11,12),(13,14)]
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(10,10),(13,10),(14,15),(11,16)]
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (10,10)           | [(11,12),(13,14)]
+ ((10,20))                 | (10,10)           | ((20,30))
+ [(11,12),(13,14)]         | (10,10)           | [(21,22),(23,24)]
+ ((11,12),(13,14))         | (10,10)           | ((21,22),(23,24))
+(81 rows)
+
+-- Subtract point
+SELECT p.f1, p1.f1, p.f1 - p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                                     ?column?                                      
+---------------------------+-------------------+-----------------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((10,20))                 | (0,0)             | ((10,20))
+ [(11,12),(13,14)]         | (0,0)             | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (0,0)             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (-10,0)           | [(11,2),(13,4)]
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(10,0),(13,0),(14,5),(11,6)]
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ [(1,2),(3,4)]             | (-10,0)           | [(11,2),(13,4)]
+ ((10,20))                 | (-10,0)           | ((20,20))
+ [(11,12),(13,14)]         | (-10,0)           | [(21,12),(23,14)]
+ ((11,12),(13,14))         | (-10,0)           | ((21,12),(23,14))
+ [(1,2),(3,4)]             | (-3,4)            | [(4,-2),(6,0)]
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(3,-4),(6,-4),(7,1),(4,2)]
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ [(1,2),(3,4)]             | (-3,4)            | [(4,-2),(6,0)]
+ ((10,20))                 | (-3,4)            | ((13,16))
+ [(11,12),(13,14)]         | (-3,4)            | [(14,8),(16,10)]
+ ((11,12),(13,14))         | (-3,4)            | ((14,8),(16,10))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-4.1,-32.5),(-2.1,-30.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(-5.1,-34.5),(-2.1,-34.5),(-1.1,-29.5),(-4.1,-28.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-4.1,-32.5),(-2.1,-30.5)]
+ ((10,20))                 | (5.1,34.5)        | ((4.9,-14.5))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(5.9,-22.5),(7.9,-20.5)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((5.9,-22.5),(7.9,-20.5))
+ [(1,2),(3,4)]             | (-5,-12)          | [(6,14),(8,16)]
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(5,12),(8,12),(9,17),(6,18)]
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ [(1,2),(3,4)]             | (-5,-12)          | [(6,14),(8,16)]
+ ((10,20))                 | (-5,-12)          | ((15,32))
+ [(11,12),(13,14)]         | (-5,-12)          | [(16,24),(18,26)]
+ ((11,12),(13,14))         | (-5,-12)          | ((16,24),(18,26))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(-1e-300,1e-300),(3,1e-300),(4,5),(1,6)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((10,20))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity),(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((-1e+300,-Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(-9,-8),(-7,-6)]
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(-10,-10),(-7,-10),(-6,-5),(-9,-4)]
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ [(1,2),(3,4)]             | (10,10)           | [(-9,-8),(-7,-6)]
+ ((10,20))                 | (10,10)           | ((0,10))
+ [(11,12),(13,14)]         | (10,10)           | [(1,2),(3,4)]
+ ((11,12),(13,14))         | (10,10)           | ((1,2),(3,4))
+(81 rows)
+
+-- Multiply with point
+SELECT p.f1, p1.f1, p.f1 * p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                               ?column?                               
+---------------------------+-------------------+----------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(0,0),(0,0)]
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(0,0),(0,0),(0,0)]
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ [(1,2),(3,4)]             | (0,0)             | [(0,0),(0,0)]
+ ((10,20))                 | (0,0)             | ((0,0))
+ [(11,12),(13,14)]         | (0,0)             | [(0,0),(0,0)]
+ ((11,12),(13,14))         | (0,0)             | ((0,0),(0,0))
+ [(1,2),(3,4)]             | (-10,0)           | [(-10,-20),(-30,-40)]
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(0,0),(-30,0),(-40,-50),(-10,-60)]
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ [(1,2),(3,4)]             | (-10,0)           | [(-10,-20),(-30,-40)]
+ ((10,20))                 | (-10,0)           | ((-100,-200))
+ [(11,12),(13,14)]         | (-10,0)           | [(-110,-120),(-130,-140)]
+ ((11,12),(13,14))         | (-10,0)           | ((-110,-120),(-130,-140))
+ [(1,2),(3,4)]             | (-3,4)            | [(-11,-2),(-25,0)]
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(0,0),(-9,12),(-32,1),(-27,-14)]
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ [(1,2),(3,4)]             | (-3,4)            | [(-11,-2),(-25,0)]
+ ((10,20))                 | (-3,4)            | ((-110,-20))
+ [(11,12),(13,14)]         | (-3,4)            | [(-81,8),(-95,10)]
+ ((11,12),(13,14))         | (-3,4)            | ((-81,8),(-95,10))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-63.9,44.7),(-122.7,123.9)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(0,0),(15.3,103.5),(-152.1,163.5),(-201.9,65.1)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-63.9,44.7),(-122.7,123.9)]
+ ((10,20))                 | (5.1,34.5)        | ((-639,447))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(-357.9,440.7),(-416.7,519.9)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((-357.9,440.7),(-416.7,519.9))
+ [(1,2),(3,4)]             | (-5,-12)          | [(19,-22),(33,-56)]
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(0,0),(-15,-36),(40,-73),(67,-42)]
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ [(1,2),(3,4)]             | (-5,-12)          | [(19,-22),(33,-56)]
+ ((10,20))                 | (-5,-12)          | ((190,-220))
+ [(11,12),(13,14)]         | (-5,-12)          | [(89,-192),(103,-226)]
+ ((11,12),(13,14))         | (-5,-12)          | ((89,-192),(103,-226))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(3e-300,1e-300),(7e-300,1e-300)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(0,0),(3e-300,-3e-300),(9e-300,1e-300),(7e-300,5e-300)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(3e-300,1e-300),(7e-300,1e-300)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((3e-299,1e-299))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(2.3e-299,1e-300),(2.7e-299,1e-300)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((2.3e-299,1e-300),(2.7e-299,1e-300))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(NaN,NaN),(NaN,Infinity),(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((-Infinity,Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(-10,30),(-10,70)]
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(0,0),(30,30),(-10,90),(-50,70)]
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ [(1,2),(3,4)]             | (10,10)           | [(-10,30),(-10,70)]
+ ((10,20))                 | (10,10)           | ((-100,300))
+ [(11,12),(13,14)]         | (10,10)           | [(-10,230),(-10,270)]
+ ((11,12),(13,14))         | (10,10)           | ((-10,230),(-10,270))
+(81 rows)
+
+-- Divide by point
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+            f1             |     f1     |                                                    ?column?                                                     
+---------------------------+------------+-----------------------------------------------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (5.1,34.5) | [(0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952)]
+ [(1,2),(3,4)]             | (10,10)    | [(0.15,0.05),(0.35,0.05)]
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5) | [(0,0),(0.0125795471363,-0.0850969365103),(0.158600957032,-0.0924966701199),(0.174387055399,-0.00320655123082)]
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)    | [(0,0),(0.15,-0.15),(0.45,0.05),(0.35,0.25)]
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ [(1,2),(3,4)]             | (5.1,34.5) | [(0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952)]
+ [(1,2),(3,4)]             | (10,10)    | [(0.15,0.05),(0.35,0.05)]
+ ((10,20))                 | (5.1,34.5) | ((0.609244733856,-0.199792807459))
+ ((10,20))                 | (10,10)    | ((1.5,0.5))
+ [(11,12),(13,14)]         | (5.1,34.5) | [(0.386512752208,-0.261703911993),(0.451630407972,-0.310048838242)]
+ [(11,12),(13,14)]         | (10,10)    | [(1.15,0.05),(1.35,0.05)]
+ ((11,12),(13,14))         | (5.1,34.5) | ((0.386512752208,-0.261703911993),(0.451630407972,-0.310048838242))
+ ((11,12),(13,14))         | (10,10)    | ((1.15,0.05),(1.35,0.05))
+(18 rows)
+
+-- Division by 0 error
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to path
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+            f1             |            f1             |    ?column?    
+---------------------------+---------------------------+----------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((10,20))                 |  17.4642491966
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         |   11.313708499
+ [(1,2),(3,4)]             | ((11,12),(13,14))         |   11.313708499
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)] |              0
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))                 |  16.1554944214
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]         |  9.89949493661
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))         |  9.89949493661
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((10,20))                 |  17.4642491966
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         |   11.313708499
+ [(1,2),(3,4)]             | ((11,12),(13,14))         |   11.313708499
+ ((10,20))                 | [(1,2),(3,4)]             |  17.4642491966
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)] |  16.1554944214
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | [(1,2),(3,4)]             |  17.4642491966
+ ((10,20))                 | ((10,20))                 |              0
+ ((10,20))                 | [(11,12),(13,14)]         |   6.7082039325
+ ((10,20))                 | ((11,12),(13,14))         |   6.7082039325
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             |   11.313708499
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)] |  9.89949493661
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             |   11.313708499
+ [(11,12),(13,14)]         | ((10,20))                 |   6.7082039325
+ [(11,12),(13,14)]         | [(11,12),(13,14)]         |              0
+ [(11,12),(13,14)]         | ((11,12),(13,14))         |              0
+ ((11,12),(13,14))         | [(1,2),(3,4)]             |   11.313708499
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)] |  9.89949493661
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | [(1,2),(3,4)]             |   11.313708499
+ ((11,12),(13,14))         | ((10,20))                 |   6.7082039325
+ ((11,12),(13,14))         | [(11,12),(13,14)]         |              0
+ ((11,12),(13,14))         | ((11,12),(13,14))         |              0
+(81 rows)
 
 --
 -- Polygons
 --
 -- containment
 SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
    FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
+ twentyfour |        f1         |             f1             | contains 
+------------+-------------------+----------------------------+----------
+            | (0,0)             | ((2,0),(2,4),(0,0))        | t
+            | (0,0)             | ((3,1),(3,3),(1,0))        | f
+            | (0,0)             | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (0,0)             | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (0,0)             | ((0,0))                    | t
+            | (0,0)             | ((0,1),(0,1))              | f
+            | (-10,0)           | ((2,0),(2,4),(0,0))        | f
+            | (-10,0)           | ((3,1),(3,3),(1,0))        | f
+            | (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-10,0)           | ((0,0))                    | f
+            | (-10,0)           | ((0,1),(0,1))              | f
+            | (-3,4)            | ((2,0),(2,4),(0,0))        | f
+            | (-3,4)            | ((3,1),(3,3),(1,0))        | f
+            | (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-3,4)            | ((0,0))                    | f
+            | (-3,4)            | ((0,1),(0,1))              | f
+            | (5.1,34.5)        | ((2,0),(2,4),(0,0))        | f
+            | (5.1,34.5)        | ((3,1),(3,3),(1,0))        | f
+            | (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (5.1,34.5)        | ((0,0))                    | f
+            | (5.1,34.5)        | ((0,1),(0,1))              | f
+            | (-5,-12)          | ((2,0),(2,4),(0,0))        | f
+            | (-5,-12)          | ((3,1),(3,3),(1,0))        | f
+            | (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-5,-12)          | ((0,0))                    | f
+            | (-5,-12)          | ((0,1),(0,1))              | f
+            | (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        | t
+            | (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        | f
+            | (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e-300,-1e-300)  | ((0,0))                    | t
+            | (1e-300,-1e-300)  | ((0,1),(0,1))              | f
+            | (1e+300,Infinity) | ((2,0),(2,4),(0,0))        | f
+            | (1e+300,Infinity) | ((3,1),(3,3),(1,0))        | f
+            | (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e+300,Infinity) | ((0,0))                    | f
+            | (1e+300,Infinity) | ((0,1),(0,1))              | f
+            | (NaN,NaN)         | ((2,0),(2,4),(0,0))        | t
+            | (NaN,NaN)         | ((3,1),(3,3),(1,0))        | t
+            | (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  | t
+            | (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  | t
+            | (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) | t
+            | (NaN,NaN)         | ((0,0))                    | t
+            | (NaN,NaN)         | ((0,1),(0,1))              | t
+            | (10,10)           | ((2,0),(2,4),(0,0))        | f
+            | (10,10)           | ((3,1),(3,3),(1,0))        | f
+            | (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (10,10)           | ((0,0))                    | f
+            | (10,10)           | ((0,1),(0,1))              | f
+(63 rows)
 
 SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
    FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
+ twentyfour |        f1         |             f1             | contained 
+------------+-------------------+----------------------------+-----------
+            | (0,0)             | ((2,0),(2,4),(0,0))        | t
+            | (0,0)             | ((3,1),(3,3),(1,0))        | f
+            | (0,0)             | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (0,0)             | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (0,0)             | ((0,0))                    | t
+            | (0,0)             | ((0,1),(0,1))              | f
+            | (-10,0)           | ((2,0),(2,4),(0,0))        | f
+            | (-10,0)           | ((3,1),(3,3),(1,0))        | f
+            | (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-10,0)           | ((0,0))                    | f
+            | (-10,0)           | ((0,1),(0,1))              | f
+            | (-3,4)            | ((2,0),(2,4),(0,0))        | f
+            | (-3,4)            | ((3,1),(3,3),(1,0))        | f
+            | (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-3,4)            | ((0,0))                    | f
+            | (-3,4)            | ((0,1),(0,1))              | f
+            | (5.1,34.5)        | ((2,0),(2,4),(0,0))        | f
+            | (5.1,34.5)        | ((3,1),(3,3),(1,0))        | f
+            | (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (5.1,34.5)        | ((0,0))                    | f
+            | (5.1,34.5)        | ((0,1),(0,1))              | f
+            | (-5,-12)          | ((2,0),(2,4),(0,0))        | f
+            | (-5,-12)          | ((3,1),(3,3),(1,0))        | f
+            | (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-5,-12)          | ((0,0))                    | f
+            | (-5,-12)          | ((0,1),(0,1))              | f
+            | (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        | t
+            | (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        | f
+            | (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e-300,-1e-300)  | ((0,0))                    | t
+            | (1e-300,-1e-300)  | ((0,1),(0,1))              | f
+            | (1e+300,Infinity) | ((2,0),(2,4),(0,0))        | f
+            | (1e+300,Infinity) | ((3,1),(3,3),(1,0))        | f
+            | (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e+300,Infinity) | ((0,0))                    | f
+            | (1e+300,Infinity) | ((0,1),(0,1))              | f
+            | (NaN,NaN)         | ((2,0),(2,4),(0,0))        | t
+            | (NaN,NaN)         | ((3,1),(3,3),(1,0))        | t
+            | (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  | t
+            | (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  | t
+            | (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) | t
+            | (NaN,NaN)         | ((0,0))                    | t
+            | (NaN,NaN)         | ((0,1),(0,1))              | t
+            | (10,10)           | ((2,0),(2,4),(0,0))        | f
+            | (10,10)           | ((3,1),(3,3),(1,0))        | f
+            | (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (10,10)           | ((0,0))                    | f
+            | (10,10)           | ((0,1),(0,1))              | f
+(63 rows)
 
 SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
    FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
+ four | npoints |          polygon           
+------+---------+----------------------------
       |       3 | ((2,0),(2,4),(0,0))
       |       3 | ((3,1),(3,3),(1,0))
+      |       4 | ((1,2),(3,4),(5,6),(7,8))
+      |       4 | ((7,8),(5,6),(3,4),(1,2))
+      |       4 | ((1,2),(7,8),(5,6),(3,-4))
       |       1 | ((0,0))
       |       2 | ((0,1),(0,1))
-(4 rows)
+(7 rows)
 
 SELECT '' AS four, polygon(f1)
    FROM BOX_TBL;
  four |                  polygon                  
 ------+-------------------------------------------
       | ((0,0),(0,2),(2,2),(2,0))
       | ((1,1),(1,3),(3,3),(3,1))
+      | ((-8,-10),(-8,2),(-2,2),(-2,-10))
       | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
       | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, polygon(f1)
    FROM PATH_TBL WHERE isclosed(f1);
  four |      polygon      
 ------+-------------------
       | ((1,2),(3,4))
       | ((1,2),(3,4))
       | ((1,2),(3,4))
+      | ((10,20))
       | ((11,12),(13,14))
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
    FROM PATH_TBL
    WHERE isopen(f1);
  four |         open_path         |          polygon          
 ------+---------------------------+---------------------------
       | [(1,2),(3,4)]             | ((1,2),(3,4))
       | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
       | [(1,2),(3,4)]             | ((1,2),(3,4))
       | [(11,12),(13,14)]         | ((11,12),(13,14))
 (4 rows)
 
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
+-- To box
+SELECT f1, f1::box FROM POLYGON_TBL;
+             f1             |      f1      
+----------------------------+--------------
+ ((2,0),(2,4),(0,0))        | (2,4),(0,0)
+ ((3,1),(3,3),(1,0))        | (3,3),(1,0)
+ ((1,2),(3,4),(5,6),(7,8))  | (7,8),(1,2)
+ ((7,8),(5,6),(3,4),(1,2))  | (7,8),(1,2)
+ ((1,2),(7,8),(5,6),(3,-4)) | (7,8),(1,-4)
+ ((0,0))                    | (0,0),(0,0)
+ ((0,1),(0,1))              | (0,1),(0,1)
+(7 rows)
 
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
+-- To path
+SELECT f1, f1::path FROM POLYGON_TBL;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(7 rows)
 
+-- Same as polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 ~= p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(9 rows)
+
+-- Contained by polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <@ p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(12 rows)
+
+-- Contains polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 @> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(12 rows)
+
+-- Overlap with polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 && p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(25 rows)
+
+-- Left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 << p2.f1;
+      f1       |             f1             
+---------------+----------------------------
+ ((0,0))       | ((3,1),(3,3),(1,0))
+ ((0,0))       | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))       | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))       | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1)) | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1)) | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1)) | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1)) | ((1,2),(7,8),(5,6),(3,-4))
+(8 rows)
+
+-- Overlap of left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &< p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))                    | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1))              | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(32 rows)
+
+-- Right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 >> p2.f1;
+             f1             |      f1       
+----------------------------+---------------
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((0,1),(0,1))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1))
+(8 rows)
+
+-- Overlap of right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((2,0),(2,4),(0,0))        | ((0,1),(0,1))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((0,1),(0,1))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((3,1),(3,3),(1,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(37 rows)
+
+-- Below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <<| p2.f1;
+      f1       |            f1             
+---------------+---------------------------
+ ((0,0))       | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))       | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))       | ((0,1),(0,1))
+ ((0,1),(0,1)) | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1)) | ((7,8),(5,6),(3,4),(1,2))
+(5 rows)
+
+-- Overlap or below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &<| p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))                    | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1))              | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(31 rows)
+
+-- Above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |>> p2.f1;
+            f1             |      f1       
+---------------------------+---------------
+ ((1,2),(3,4),(5,6),(7,8)) | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8)) | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2)) | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2)) | ((0,1),(0,1))
+ ((0,1),(0,1))             | ((0,0))
+(5 rows)
+
+-- Overlap or above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |&> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((3,1),(3,3),(1,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(32 rows)
+
+-- Distance to polygon
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2;
+ERROR:  function "poly_distance" not implemented
 --
 -- Circles
 --
 SELECT '' AS six, circle(f1, 50.0)
    FROM POINT_TBL;
- six |     circle      
------+-----------------
+ six |         circle         
+-----+------------------------
      | <(0,0),50>
      | <(-10,0),50>
      | <(-3,4),50>
      | <(5.1,34.5),50>
      | <(-5,-12),50>
+     | <(1e-300,-1e-300),50>
+     | <(1e+300,Infinity),50>
+     | <(NaN,NaN),50>
      | <(10,10),50>
-(6 rows)
+(9 rows)
 
 SELECT '' AS four, circle(f1)
    FROM BOX_TBL;
- four |        circle         
-------+-----------------------
+ four |         circle         
+------+------------------------
       | <(1,1),1.41421356237>
       | <(2,2),1.41421356237>
+      | <(-5,-4),6.7082039325>
       | <(2.5,3),0.5>
       | <(3,3),0>
-(4 rows)
+(5 rows)
 
 SELECT '' AS two, circle(f1)
    FROM POLYGON_TBL
    WHERE (# f1) >= 3;
  two |                    circle                     
 -----+-----------------------------------------------
      | <(1.33333333333,1.33333333333),2.04168905064>
      | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
+     | <(4,5),2.82842712475>
+     | <(4,5),2.82842712475>
+     | <(4,3),4.80664375676>
+(5 rows)
 
 SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
    FROM CIRCLE_TBL c1, POINT_TBL p1
    WHERE (p1.f1 <-> c1.f1) > 0
    ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
+ twentyfour |     circle     |       point       |   distance    
+------------+----------------+-------------------+---------------
+            | <(1,2),3>      | (-3,4)            |   1.472135955
+            | <(5,1),3>      | (0,0)             | 2.09901951359
+            | <(5,1),3>      | (1e-300,-1e-300)  | 2.09901951359
+            | <(5,1),3>      | (-3,4)            | 5.54400374532
+            | <(3,5),0>      | (0,0)             | 5.83095189485
+            | <(3,5),0>      | (1e-300,-1e-300)  | 5.83095189485
+            | <(3,5),0>      | (-3,4)            |  6.0827625303
+            | <(1,3),5>      | (-10,0)           | 6.40175425099
+            | <(1,3),5>      | (10,10)           | 6.40175425099
+            | <(5,1),3>      | (10,10)           | 7.29563014099
+            | <(1,2),3>      | (-10,0)           |  8.1803398875
+            | <(3,5),0>      | (10,10)           | 8.60232526704
+            | <(1,2),3>      | (10,10)           | 9.04159457879
+            | <(1,3),5>      | (-5,-12)          | 11.1554944214
+            | <(5,1),3>      | (-10,0)           | 12.0332963784
+            | <(1,2),3>      | (-5,-12)          | 12.2315462117
+            | <(5,1),3>      | (-5,-12)          | 13.4012194669
+            | <(3,5),0>      | (-10,0)           | 13.9283882772
+            | <(3,5),0>      | (-5,-12)          | 18.7882942281
+            | <(1,3),5>      | (5.1,34.5)        | 26.7657047773
+            | <(3,5),0>      | (5.1,34.5)        | 29.5746513082
+            | <(1,2),3>      | (5.1,34.5)        | 29.7575945393
+            | <(5,1),3>      | (5.1,34.5)        | 30.5001492534
+            | <(100,200),10> | (5.1,34.5)        | 180.778038568
+            | <(100,200),10> | (10,10)           | 200.237960416
+            | <(100,200),10> | (-3,4)            | 211.415898255
+            | <(100,200),10> | (0,0)             |  213.60679775
+            | <(100,200),10> | (1e-300,-1e-300)  |  213.60679775
+            | <(100,200),10> | (-10,0)           |  218.25424421
+            | <(100,200),10> | (-5,-12)          | 226.577682802
+            | <(3,5),0>      | (1e+300,Infinity) |      Infinity
+            | <(1,2),3>      | (1e+300,Infinity) |      Infinity
+            | <(5,1),3>      | (1e+300,Infinity) |      Infinity
+            | <(1,3),5>      | (1e+300,Infinity) |      Infinity
+            | <(100,200),10> | (1e+300,Infinity) |      Infinity
+            | <(1,2),100>    | (1e+300,Infinity) |      Infinity
+            | <(100,1),115>  | (1e+300,Infinity) |      Infinity
+            | <(3,5),0>      | (NaN,NaN)         |           NaN
+            | <(1,2),3>      | (NaN,NaN)         |           NaN
+            | <(5,1),3>      | (NaN,NaN)         |           NaN
+            | <(1,3),5>      | (NaN,NaN)         |           NaN
+            | <(100,200),10> | (NaN,NaN)         |           NaN
+            | <(1,2),100>    | (NaN,NaN)         |           NaN
+            | <(100,1),115>  | (NaN,NaN)         |           NaN
+            | <(3,5),NaN>    | (-10,0)           |           NaN
+            | <(3,5),NaN>    | (-5,-12)          |           NaN
+            | <(3,5),NaN>    | (-3,4)            |           NaN
+            | <(3,5),NaN>    | (0,0)             |           NaN
+            | <(3,5),NaN>    | (1e-300,-1e-300)  |           NaN
+            | <(3,5),NaN>    | (5.1,34.5)        |           NaN
+            | <(3,5),NaN>    | (10,10)           |           NaN
+            | <(3,5),NaN>    | (1e+300,Infinity) |           NaN
+            | <(3,5),NaN>    | (NaN,NaN)         |           NaN
+(53 rows)
+
+-- To polygon
+SELECT f1, f1::polygon FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+       f1       |                                                                                                          f1                                                                                                          
+----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ <(5,1),3>      | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
+ <(1,2),100>    | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
+ <(1,3),5>      | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
+ <(1,2),3>      | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
+ <(100,200),10> | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
+ <(100,1),115>  | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
+(6 rows)
+
+-- To polygon with less points
+SELECT f1, polygon(8, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+       f1       |                                                                             polygon                                                                              
+----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ <(5,1),3>      | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
+ <(1,2),100>    | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
+ <(1,3),5>      | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
+ <(1,2),3>      | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
+ <(100,200),10> | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
+ <(100,1),115>  | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
+(6 rows)
+
+-- Too less points error
+SELECT f1, polygon(1, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+ERROR:  must request at least 2 points
+-- Zero radius error
+SELECT f1, polygon(10, f1) FROM CIRCLE_TBL WHERE f1 < '<(0,0),1>';
+ERROR:  cannot convert circle with radius zero to polygon
+-- Same as circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 ~= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+ <(3,5),NaN>    | <(3,5),0>
+ <(3,5),NaN>    | <(3,5),NaN>
+(9 rows)
+
+-- Overlap with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 && c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,1),115>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(100,1),115>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(33 rows)
+
+-- Overlap or left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &< c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(28 rows)
+
+-- Left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 << c2.f1;
+    f1     |       f1       
+-----------+----------------
+ <(5,1),3> | <(100,200),10>
+ <(1,3),5> | <(100,200),10>
+ <(1,2),3> | <(100,200),10>
+ <(3,5),0> | <(100,200),10>
+(4 rows)
+
+-- Right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >> c2.f1;
+       f1       |    f1     
+----------------+-----------
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(3,5),0>
+(4 rows)
+
+-- Overlap or right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(28 rows)
+
+-- Contained by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <@ c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(17 rows)
+
+-- Contain by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 @> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(3,5),0>
+(17 rows)
+
+-- Below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <<| c2.f1;
+      f1       |       f1       
+---------------+----------------
+ <(5,1),3>     | <(100,200),10>
+ <(5,1),3>     | <(3,5),0>
+ <(1,2),100>   | <(100,200),10>
+ <(1,3),5>     | <(100,200),10>
+ <(1,2),3>     | <(100,200),10>
+ <(100,1),115> | <(100,200),10>
+ <(3,5),0>     | <(100,200),10>
+(7 rows)
+
+-- Above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |>> c2.f1;
+       f1       |      f1       
+----------------+---------------
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(3,5),0>      | <(5,1),3>
+(7 rows)
+
+-- Overlap or below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &<| c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Overlap or above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |&> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 = c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(9 rows)
+
+-- Area not equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 != c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(40 rows)
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 > c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(3,5),0>
+(20 rows)
+
+-- Area less than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area greater than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Add point
+SELECT c.f1, p.f1, c.f1 + p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |        ?column?         
+----------------+-------------------+-------------------------
+ <(5,1),3>      | (0,0)             | <(5,1),3>
+ <(1,2),100>    | (0,0)             | <(1,2),100>
+ <(1,3),5>      | (0,0)             | <(1,3),5>
+ <(1,2),3>      | (0,0)             | <(1,2),3>
+ <(100,200),10> | (0,0)             | <(100,200),10>
+ <(100,1),115>  | (0,0)             | <(100,1),115>
+ <(3,5),0>      | (0,0)             | <(3,5),0>
+ <(3,5),NaN>    | (0,0)             | <(3,5),NaN>
+ <(5,1),3>      | (-10,0)           | <(-5,1),3>
+ <(1,2),100>    | (-10,0)           | <(-9,2),100>
+ <(1,3),5>      | (-10,0)           | <(-9,3),5>
+ <(1,2),3>      | (-10,0)           | <(-9,2),3>
+ <(100,200),10> | (-10,0)           | <(90,200),10>
+ <(100,1),115>  | (-10,0)           | <(90,1),115>
+ <(3,5),0>      | (-10,0)           | <(-7,5),0>
+ <(3,5),NaN>    | (-10,0)           | <(-7,5),NaN>
+ <(5,1),3>      | (-3,4)            | <(2,5),3>
+ <(1,2),100>    | (-3,4)            | <(-2,6),100>
+ <(1,3),5>      | (-3,4)            | <(-2,7),5>
+ <(1,2),3>      | (-3,4)            | <(-2,6),3>
+ <(100,200),10> | (-3,4)            | <(97,204),10>
+ <(100,1),115>  | (-3,4)            | <(97,5),115>
+ <(3,5),0>      | (-3,4)            | <(0,9),0>
+ <(3,5),NaN>    | (-3,4)            | <(0,9),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(10.1,35.5),3>
+ <(1,2),100>    | (5.1,34.5)        | <(6.1,36.5),100>
+ <(1,3),5>      | (5.1,34.5)        | <(6.1,37.5),5>
+ <(1,2),3>      | (5.1,34.5)        | <(6.1,36.5),3>
+ <(100,200),10> | (5.1,34.5)        | <(105.1,234.5),10>
+ <(100,1),115>  | (5.1,34.5)        | <(105.1,35.5),115>
+ <(3,5),0>      | (5.1,34.5)        | <(8.1,39.5),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(8.1,39.5),NaN>
+ <(5,1),3>      | (-5,-12)          | <(0,-11),3>
+ <(1,2),100>    | (-5,-12)          | <(-4,-10),100>
+ <(1,3),5>      | (-5,-12)          | <(-4,-9),5>
+ <(1,2),3>      | (-5,-12)          | <(-4,-10),3>
+ <(100,200),10> | (-5,-12)          | <(95,188),10>
+ <(100,1),115>  | (-5,-12)          | <(95,-11),115>
+ <(3,5),0>      | (-5,-12)          | <(-2,-7),0>
+ <(3,5),NaN>    | (-5,-12)          | <(-2,-7),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(5,1),3>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(1,2),100>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(1,3),5>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(1,2),3>
+ <(100,200),10> | (1e-300,-1e-300)  | <(100,200),10>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(100,1),115>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(3,5),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(3,5),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(1e+300,Infinity),3>
+ <(1,2),100>    | (1e+300,Infinity) | <(1e+300,Infinity),100>
+ <(1,3),5>      | (1e+300,Infinity) | <(1e+300,Infinity),5>
+ <(1,2),3>      | (1e+300,Infinity) | <(1e+300,Infinity),3>
+ <(100,200),10> | (1e+300,Infinity) | <(1e+300,Infinity),10>
+ <(100,1),115>  | (1e+300,Infinity) | <(1e+300,Infinity),115>
+ <(3,5),0>      | (1e+300,Infinity) | <(1e+300,Infinity),0>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(1e+300,Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),100>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),5>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),10>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),115>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),0>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(15,11),3>
+ <(1,2),100>    | (10,10)           | <(11,12),100>
+ <(1,3),5>      | (10,10)           | <(11,13),5>
+ <(1,2),3>      | (10,10)           | <(11,12),3>
+ <(100,200),10> | (10,10)           | <(110,210),10>
+ <(100,1),115>  | (10,10)           | <(110,11),115>
+ <(3,5),0>      | (10,10)           | <(13,15),0>
+ <(3,5),NaN>    | (10,10)           | <(13,15),NaN>
+(72 rows)
+
+-- Subtract point
+SELECT c.f1, p.f1, c.f1 - p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |         ?column?          
+----------------+-------------------+---------------------------
+ <(5,1),3>      | (0,0)             | <(5,1),3>
+ <(1,2),100>    | (0,0)             | <(1,2),100>
+ <(1,3),5>      | (0,0)             | <(1,3),5>
+ <(1,2),3>      | (0,0)             | <(1,2),3>
+ <(100,200),10> | (0,0)             | <(100,200),10>
+ <(100,1),115>  | (0,0)             | <(100,1),115>
+ <(3,5),0>      | (0,0)             | <(3,5),0>
+ <(3,5),NaN>    | (0,0)             | <(3,5),NaN>
+ <(5,1),3>      | (-10,0)           | <(15,1),3>
+ <(1,2),100>    | (-10,0)           | <(11,2),100>
+ <(1,3),5>      | (-10,0)           | <(11,3),5>
+ <(1,2),3>      | (-10,0)           | <(11,2),3>
+ <(100,200),10> | (-10,0)           | <(110,200),10>
+ <(100,1),115>  | (-10,0)           | <(110,1),115>
+ <(3,5),0>      | (-10,0)           | <(13,5),0>
+ <(3,5),NaN>    | (-10,0)           | <(13,5),NaN>
+ <(5,1),3>      | (-3,4)            | <(8,-3),3>
+ <(1,2),100>    | (-3,4)            | <(4,-2),100>
+ <(1,3),5>      | (-3,4)            | <(4,-1),5>
+ <(1,2),3>      | (-3,4)            | <(4,-2),3>
+ <(100,200),10> | (-3,4)            | <(103,196),10>
+ <(100,1),115>  | (-3,4)            | <(103,-3),115>
+ <(3,5),0>      | (-3,4)            | <(6,1),0>
+ <(3,5),NaN>    | (-3,4)            | <(6,1),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(-0.1,-33.5),3>
+ <(1,2),100>    | (5.1,34.5)        | <(-4.1,-32.5),100>
+ <(1,3),5>      | (5.1,34.5)        | <(-4.1,-31.5),5>
+ <(1,2),3>      | (5.1,34.5)        | <(-4.1,-32.5),3>
+ <(100,200),10> | (5.1,34.5)        | <(94.9,165.5),10>
+ <(100,1),115>  | (5.1,34.5)        | <(94.9,-33.5),115>
+ <(3,5),0>      | (5.1,34.5)        | <(-2.1,-29.5),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(-2.1,-29.5),NaN>
+ <(5,1),3>      | (-5,-12)          | <(10,13),3>
+ <(1,2),100>    | (-5,-12)          | <(6,14),100>
+ <(1,3),5>      | (-5,-12)          | <(6,15),5>
+ <(1,2),3>      | (-5,-12)          | <(6,14),3>
+ <(100,200),10> | (-5,-12)          | <(105,212),10>
+ <(100,1),115>  | (-5,-12)          | <(105,13),115>
+ <(3,5),0>      | (-5,-12)          | <(8,17),0>
+ <(3,5),NaN>    | (-5,-12)          | <(8,17),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(5,1),3>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(1,2),100>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(1,3),5>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(1,2),3>
+ <(100,200),10> | (1e-300,-1e-300)  | <(100,200),10>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(100,1),115>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(3,5),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(3,5),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(-1e+300,-Infinity),3>
+ <(1,2),100>    | (1e+300,Infinity) | <(-1e+300,-Infinity),100>
+ <(1,3),5>      | (1e+300,Infinity) | <(-1e+300,-Infinity),5>
+ <(1,2),3>      | (1e+300,Infinity) | <(-1e+300,-Infinity),3>
+ <(100,200),10> | (1e+300,Infinity) | <(-1e+300,-Infinity),10>
+ <(100,1),115>  | (1e+300,Infinity) | <(-1e+300,-Infinity),115>
+ <(3,5),0>      | (1e+300,Infinity) | <(-1e+300,-Infinity),0>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(-1e+300,-Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),100>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),5>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),10>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),115>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),0>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(-5,-9),3>
+ <(1,2),100>    | (10,10)           | <(-9,-8),100>
+ <(1,3),5>      | (10,10)           | <(-9,-7),5>
+ <(1,2),3>      | (10,10)           | <(-9,-8),3>
+ <(100,200),10> | (10,10)           | <(90,190),10>
+ <(100,1),115>  | (10,10)           | <(90,-9),115>
+ <(3,5),0>      | (10,10)           | <(-7,-5),0>
+ <(3,5),NaN>    | (10,10)           | <(-7,-5),NaN>
+(72 rows)
+
+-- Multiply with point
+SELECT c.f1, p.f1, c.f1 * p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |                  ?column?                  
+----------------+-------------------+--------------------------------------------
+ <(5,1),3>      | (0,0)             | <(0,0),0>
+ <(1,2),100>    | (0,0)             | <(0,0),0>
+ <(1,3),5>      | (0,0)             | <(0,0),0>
+ <(1,2),3>      | (0,0)             | <(0,0),0>
+ <(100,200),10> | (0,0)             | <(0,0),0>
+ <(100,1),115>  | (0,0)             | <(0,0),0>
+ <(3,5),0>      | (0,0)             | <(0,0),0>
+ <(3,5),NaN>    | (0,0)             | <(0,0),NaN>
+ <(5,1),3>      | (-10,0)           | <(-50,-10),30>
+ <(1,2),100>    | (-10,0)           | <(-10,-20),1000>
+ <(1,3),5>      | (-10,0)           | <(-10,-30),50>
+ <(1,2),3>      | (-10,0)           | <(-10,-20),30>
+ <(100,200),10> | (-10,0)           | <(-1000,-2000),100>
+ <(100,1),115>  | (-10,0)           | <(-1000,-10),1150>
+ <(3,5),0>      | (-10,0)           | <(-30,-50),0>
+ <(3,5),NaN>    | (-10,0)           | <(-30,-50),NaN>
+ <(5,1),3>      | (-3,4)            | <(-19,17),15>
+ <(1,2),100>    | (-3,4)            | <(-11,-2),500>
+ <(1,3),5>      | (-3,4)            | <(-15,-5),25>
+ <(1,2),3>      | (-3,4)            | <(-11,-2),15>
+ <(100,200),10> | (-3,4)            | <(-1100,-200),50>
+ <(100,1),115>  | (-3,4)            | <(-304,397),575>
+ <(3,5),0>      | (-3,4)            | <(-29,-3),0>
+ <(3,5),NaN>    | (-3,4)            | <(-29,-3),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(-9,177.6),104.624758064>
+ <(1,2),100>    | (5.1,34.5)        | <(-63.9,44.7),3487.49193547>
+ <(1,3),5>      | (5.1,34.5)        | <(-98.4,49.8),174.374596774>
+ <(1,2),3>      | (5.1,34.5)        | <(-63.9,44.7),104.624758064>
+ <(100,200),10> | (5.1,34.5)        | <(-6390,4470),348.749193547>
+ <(100,1),115>  | (5.1,34.5)        | <(475.5,3455.1),4010.6157258>
+ <(3,5),0>      | (5.1,34.5)        | <(-157.2,129),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(-157.2,129),NaN>
+ <(5,1),3>      | (-5,-12)          | <(-13,-65),39>
+ <(1,2),100>    | (-5,-12)          | <(19,-22),1300>
+ <(1,3),5>      | (-5,-12)          | <(31,-27),65>
+ <(1,2),3>      | (-5,-12)          | <(19,-22),39>
+ <(100,200),10> | (-5,-12)          | <(1900,-2200),130>
+ <(100,1),115>  | (-5,-12)          | <(-488,-1205),1495>
+ <(3,5),0>      | (-5,-12)          | <(45,-61),0>
+ <(3,5),NaN>    | (-5,-12)          | <(45,-61),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(6e-300,-4e-300),4.24264068712e-300>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(3e-300,1e-300),1.41421356237e-298>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(4e-300,2e-300),7.07106781187e-300>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(3e-300,1e-300),4.24264068712e-300>
+ <(100,200),10> | (1e-300,-1e-300)  | <(3e-298,1e-298),1.41421356237e-299>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(1.01e-298,-9.9e-299),1.62634559673e-298>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(8e-300,2e-300),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(8e-300,2e-300),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,2),100>    | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,3),5>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,2),3>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(100,200),10> | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(100,1),115>  | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(3,5),0>      | (1e+300,Infinity) | <(-Infinity,Infinity),NaN>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(-Infinity,Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(40,60),42.4264068712>
+ <(1,2),100>    | (10,10)           | <(-10,30),1414.21356237>
+ <(1,3),5>      | (10,10)           | <(-20,40),70.7106781187>
+ <(1,2),3>      | (10,10)           | <(-10,30),42.4264068712>
+ <(100,200),10> | (10,10)           | <(-1000,3000),141.421356237>
+ <(100,1),115>  | (10,10)           | <(990,1010),1626.34559673>
+ <(3,5),0>      | (10,10)           | <(-20,80),0>
+ <(3,5),NaN>    | (10,10)           | <(-20,80),NaN>
+(72 rows)
+
+-- Divide by point
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+       f1       |     f1     |                       ?column?                       
+----------------+------------+------------------------------------------------------
+ <(5,1),3>      | (5.1,34.5) | <(0.0493315573973,-0.137635045138),0.0860217042937>
+ <(5,1),3>      | (10,10)    | <(0.3,-0.2),0.212132034356>
+ <(1,2),100>    | (5.1,34.5) | <(0.0609244733856,-0.0199792807459),2.86739014312>
+ <(1,2),100>    | (10,10)    | <(0.15,0.05),7.07106781187>
+ <(1,3),5>      | (5.1,34.5) | <(0.0892901188891,-0.0157860983671),0.143369507156>
+ <(1,3),5>      | (10,10)    | <(0.2,0.1),0.353553390593>
+ <(1,2),3>      | (5.1,34.5) | <(0.0609244733856,-0.0199792807459),0.0860217042937>
+ <(1,2),3>      | (10,10)    | <(0.15,0.05),0.212132034356>
+ <(100,200),10> | (5.1,34.5) | <(6.09244733856,-1.99792807459),0.286739014312>
+ <(100,200),10> | (10,10)    | <(15,5),0.707106781187>
+ <(100,1),115>  | (5.1,34.5) | <(0.44768388338,-2.83237136796),3.29749866459>
+ <(100,1),115>  | (10,10)    | <(5.05,-4.95),8.13172798365>
+ <(3,5),0>      | (5.1,34.5) | <(0.154407774653,-0.0641310246164),0>
+ <(3,5),0>      | (10,10)    | <(0.4,0.1),0>
+ <(3,5),NaN>    | (5.1,34.5) | <(0.154407774653,-0.0641310246164),NaN>
+ <(3,5),NaN>    | (10,10)    | <(0.4,0.1),NaN>
+(16 rows)
+
+-- Overflow error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] > 1000;
+ERROR:  value out of range: overflow
+-- Division by 0 error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to polygon
+SELECT c.f1, p.f1, c.f1 <-> p.f1 FROM CIRCLE_TBL c, POLYGON_TBL p;
+       f1       |             f1             |    ?column?    
+----------------+----------------------------+----------------
+ <(5,1),3>      | ((2,0),(2,4),(0,0))        |              0
+ <(5,1),3>      | ((3,1),(3,3),(1,0))        |              0
+ <(5,1),3>      | ((1,2),(3,4),(5,6),(7,8))  | 0.535533905933
+ <(5,1),3>      | ((7,8),(5,6),(3,4),(1,2))  | 0.535533905933
+ <(5,1),3>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(5,1),3>      | ((0,0))                    |  2.09901951359
+ <(5,1),3>      | ((0,1),(0,1))              |              2
+ <(1,2),100>    | ((2,0),(2,4),(0,0))        |              0
+ <(1,2),100>    | ((3,1),(3,3),(1,0))        |              0
+ <(1,2),100>    | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,2),100>    | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,2),100>    | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,2),100>    | ((0,0))                    |              0
+ <(1,2),100>    | ((0,1),(0,1))              |              0
+ <(1,3),5>      | ((2,0),(2,4),(0,0))        |              0
+ <(1,3),5>      | ((3,1),(3,3),(1,0))        |              0
+ <(1,3),5>      | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,3),5>      | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,3),5>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,3),5>      | ((0,0))                    |              0
+ <(1,3),5>      | ((0,1),(0,1))              |              0
+ <(1,2),3>      | ((2,0),(2,4),(0,0))        |              0
+ <(1,2),3>      | ((3,1),(3,3),(1,0))        |              0
+ <(1,2),3>      | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,2),3>      | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,2),3>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,2),3>      | ((0,0))                    |              0
+ <(1,2),3>      | ((0,1),(0,1))              |              0
+ <(100,200),10> | ((2,0),(2,4),(0,0))        |  209.134661795
+ <(100,200),10> | ((3,1),(3,3),(1,0))        |  209.585974051
+ <(100,200),10> | ((1,2),(3,4),(5,6),(7,8))  |  203.337760371
+ <(100,200),10> | ((7,8),(5,6),(3,4),(1,2))  |  203.337760371
+ <(100,200),10> | ((1,2),(7,8),(5,6),(3,-4)) |  203.337760371
+ <(100,200),10> | ((0,0))                    |   213.60679775
+ <(100,200),10> | ((0,1),(0,1))              |  212.712819568
+ <(100,1),115>  | ((2,0),(2,4),(0,0))        |              0
+ <(100,1),115>  | ((3,1),(3,3),(1,0))        |              0
+ <(100,1),115>  | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(100,1),115>  | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(100,1),115>  | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(100,1),115>  | ((0,0))                    |              0
+ <(100,1),115>  | ((0,1),(0,1))              |              0
+ <(3,5),0>      | ((2,0),(2,4),(0,0))        |  1.41421356237
+ <(3,5),0>      | ((3,1),(3,3),(1,0))        |              2
+ <(3,5),0>      | ((1,2),(3,4),(5,6),(7,8))  | 0.707106781187
+ <(3,5),0>      | ((7,8),(5,6),(3,4),(1,2))  | 0.707106781187
+ <(3,5),0>      | ((1,2),(7,8),(5,6),(3,-4)) | 0.707106781187
+ <(3,5),0>      | ((0,0))                    |  5.83095189485
+ <(3,5),0>      | ((0,1),(0,1))              |              5
+ <(3,5),NaN>    | ((2,0),(2,4),(0,0))        |            NaN
+ <(3,5),NaN>    | ((3,1),(3,3),(1,0))        |            NaN
+ <(3,5),NaN>    | ((1,2),(3,4),(5,6),(7,8))  |            NaN
+ <(3,5),NaN>    | ((7,8),(5,6),(3,4),(1,2))  |            NaN
+ <(3,5),NaN>    | ((1,2),(7,8),(5,6),(3,-4)) |            NaN
+ <(3,5),NaN>    | ((0,0))                    |            NaN
+ <(3,5),NaN>    | ((0,1),(0,1))              |            NaN
+(56 rows)
 
diff --git a/src/test/regress/expected/geometry_1.out b/src/test/regress/expected/geometry_1.out
deleted file mode 100644
index 3b92e23059..0000000000
--- a/src/test/regress/expected/geometry_1.out
+++ /dev/null
@@ -1,563 +0,0 @@
---
--- GEOMETRY
---
--- Back off displayed precision a little bit to reduce platform-to-platform
--- variation in results.
-SET extra_float_digits TO -3;
---
--- Points
---
-SELECT '' AS four, center(f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS four, (@@ f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS six, point(f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS six, (@@ f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS two, (@@ f1) AS center
-   FROM POLYGON_TBL
-   WHERE (# f1) > 2;
- two |            center             
------+-------------------------------
-     | (1.33333333333,1.33333333333)
-     | (2.33333333333,1.33333333333)
-(2 rows)
-
--- "is horizontal" function
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is horizontal" operator
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is vertical" function
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE isvertical(p1.f1, point '(5.1,34.5)');
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
--- "is vertical" operator
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?| point '(5.1,34.5)';
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
---
--- Line segments
---
--- intersection
-SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-   FROM LSEG_TBL l, POINT_TBL p;
-ERROR:  operator does not exist: lseg # point
-LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-                                           ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
-
---
--- Boxes
---
-SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
- six |                              box                               
------+----------------------------------------------------------------
-     | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
-     | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
-     | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
-     | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
-     | (107.071067812,207.071067812),(92.9289321881,192.928932188)
-     | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
-
--- translation
-SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (-8,2),(-10,0)
-            | (-7,3),(-9,1)
-            | (-7.5,3.5),(-7.5,2.5)
-            | (-7,3),(-7,3)
-            | (-1,6),(-3,4)
-            | (0,7),(-2,5)
-            | (-0.5,7.5),(-0.5,6.5)
-            | (0,7),(0,7)
-            | (7.1,36.5),(5.1,34.5)
-            | (8.1,37.5),(6.1,35.5)
-            | (7.6,38),(7.6,37)
-            | (8.1,37.5),(8.1,37.5)
-            | (-3,-10),(-5,-12)
-            | (-2,-9),(-4,-11)
-            | (-2.5,-8.5),(-2.5,-9.5)
-            | (-2,-9),(-2,-9)
-            | (12,12),(10,10)
-            | (13,13),(11,11)
-            | (12.5,13.5),(12.5,12.5)
-            | (13,13),(13,13)
-(24 rows)
-
-SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (12,2),(10,0)
-            | (13,3),(11,1)
-            | (12.5,3.5),(12.5,2.5)
-            | (13,3),(13,3)
-            | (5,-2),(3,-4)
-            | (6,-1),(4,-3)
-            | (5.5,-0.5),(5.5,-1.5)
-            | (6,-1),(6,-1)
-            | (-3.1,-32.5),(-5.1,-34.5)
-            | (-2.1,-31.5),(-4.1,-33.5)
-            | (-2.6,-31),(-2.6,-32)
-            | (-2.1,-31.5),(-2.1,-31.5)
-            | (7,14),(5,12)
-            | (8,15),(6,13)
-            | (7.5,15.5),(7.5,14.5)
-            | (8,15),(8,15)
-            | (-8,-8),(-10,-10)
-            | (-7,-7),(-9,-9)
-            | (-7.5,-6.5),(-7.5,-7.5)
-            | (-7,-7),(-7,-7)
-(24 rows)
-
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
-
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,0),(-0.2,-0.2)
-        | (0.08,0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
-
-SELECT f1::box
-	FROM POINT_TBL;
-          f1           
------------------------
- (0,0),(0,0)
- (-10,0),(-10,0)
- (-3,4),(-3,4)
- (5.1,34.5),(5.1,34.5)
- (-5,-12),(-5,-12)
- (10,10),(10,10)
-(6 rows)
-
-SELECT bound_box(a.f1, b.f1)
-	FROM BOX_TBL a, BOX_TBL b;
-      bound_box      
----------------------
- (2,2),(0,0)
- (3,3),(0,0)
- (2.5,3.5),(0,0)
- (3,3),(0,0)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(1,1)
- (3,3),(1,1)
- (2.5,3.5),(0,0)
- (3,3.5),(1,1)
- (2.5,3.5),(2.5,2.5)
- (3,3.5),(2.5,2.5)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(2.5,2.5)
- (3,3),(3,3)
-(16 rows)
-
---
--- Paths
---
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
-
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
-
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
-
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
-
---
--- Polygons
---
--- containment
-SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
-   FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
-      |       3 | ((2,0),(2,4),(0,0))
-      |       3 | ((3,1),(3,3),(1,0))
-      |       1 | ((0,0))
-      |       2 | ((0,1),(0,1))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM BOX_TBL;
- four |                  polygon                  
-------+-------------------------------------------
-      | ((0,0),(0,2),(2,2),(2,0))
-      | ((1,1),(1,3),(3,3),(3,1))
-      | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
-      | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM PATH_TBL WHERE isclosed(f1);
- four |      polygon      
-------+-------------------
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((11,12),(13,14))
-(4 rows)
-
-SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
-   FROM PATH_TBL
-   WHERE isopen(f1);
- four |         open_path         |          polygon          
-------+---------------------------+---------------------------
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(11,12),(13,14)]         | ((11,12),(13,14))
-(4 rows)
-
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
-
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
-
---
--- Circles
---
-SELECT '' AS six, circle(f1, 50.0)
-   FROM POINT_TBL;
- six |     circle      
------+-----------------
-     | <(0,0),50>
-     | <(-10,0),50>
-     | <(-3,4),50>
-     | <(5.1,34.5),50>
-     | <(-5,-12),50>
-     | <(10,10),50>
-(6 rows)
-
-SELECT '' AS four, circle(f1)
-   FROM BOX_TBL;
- four |        circle         
-------+-----------------------
-      | <(1,1),1.41421356237>
-      | <(2,2),1.41421356237>
-      | <(2.5,3),0.5>
-      | <(3,3),0>
-(4 rows)
-
-SELECT '' AS two, circle(f1)
-   FROM POLYGON_TBL
-   WHERE (# f1) >= 3;
- two |                    circle                     
------+-----------------------------------------------
-     | <(1.33333333333,1.33333333333),2.04168905064>
-     | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
-
-SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
-   FROM CIRCLE_TBL c1, POINT_TBL p1
-   WHERE (p1.f1 <-> c1.f1) > 0
-   ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
-
diff --git a/src/test/regress/expected/geometry_2.out b/src/test/regress/expected/geometry_2.out
deleted file mode 100644
index 5a922bcd3f..0000000000
--- a/src/test/regress/expected/geometry_2.out
+++ /dev/null
@@ -1,563 +0,0 @@
---
--- GEOMETRY
---
--- Back off displayed precision a little bit to reduce platform-to-platform
--- variation in results.
-SET extra_float_digits TO -3;
---
--- Points
---
-SELECT '' AS four, center(f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS four, (@@ f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS six, point(f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS six, (@@ f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS two, (@@ f1) AS center
-   FROM POLYGON_TBL
-   WHERE (# f1) > 2;
- two |            center             
------+-------------------------------
-     | (1.33333333333,1.33333333333)
-     | (2.33333333333,1.33333333333)
-(2 rows)
-
--- "is horizontal" function
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is horizontal" operator
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is vertical" function
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE isvertical(p1.f1, point '(5.1,34.5)');
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
--- "is vertical" operator
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?| point '(5.1,34.5)';
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
---
--- Line segments
---
--- intersection
-SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-   FROM LSEG_TBL l, POINT_TBL p;
-ERROR:  operator does not exist: lseg # point
-LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-                                           ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
-
---
--- Boxes
---
-SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
- six |                              box                               
------+----------------------------------------------------------------
-     | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
-     | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
-     | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
-     | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
-     | (107.071067812,207.071067812),(92.9289321881,192.928932188)
-     | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
-
--- translation
-SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (-8,2),(-10,0)
-            | (-7,3),(-9,1)
-            | (-7.5,3.5),(-7.5,2.5)
-            | (-7,3),(-7,3)
-            | (-1,6),(-3,4)
-            | (0,7),(-2,5)
-            | (-0.5,7.5),(-0.5,6.5)
-            | (0,7),(0,7)
-            | (7.1,36.5),(5.1,34.5)
-            | (8.1,37.5),(6.1,35.5)
-            | (7.6,38),(7.6,37)
-            | (8.1,37.5),(8.1,37.5)
-            | (-3,-10),(-5,-12)
-            | (-2,-9),(-4,-11)
-            | (-2.5,-8.5),(-2.5,-9.5)
-            | (-2,-9),(-2,-9)
-            | (12,12),(10,10)
-            | (13,13),(11,11)
-            | (12.5,13.5),(12.5,12.5)
-            | (13,13),(13,13)
-(24 rows)
-
-SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (12,2),(10,0)
-            | (13,3),(11,1)
-            | (12.5,3.5),(12.5,2.5)
-            | (13,3),(13,3)
-            | (5,-2),(3,-4)
-            | (6,-1),(4,-3)
-            | (5.5,-0.5),(5.5,-1.5)
-            | (6,-1),(6,-1)
-            | (-3.1,-32.5),(-5.1,-34.5)
-            | (-2.1,-31.5),(-4.1,-33.5)
-            | (-2.6,-31),(-2.6,-32)
-            | (-2.1,-31.5),(-2.1,-31.5)
-            | (7,14),(5,12)
-            | (8,15),(6,13)
-            | (7.5,15.5),(7.5,14.5)
-            | (8,15),(8,15)
-            | (-8,-8),(-10,-10)
-            | (-7,-7),(-9,-9)
-            | (-7.5,-6.5),(-7.5,-7.5)
-            | (-7,-7),(-7,-7)
-(24 rows)
-
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (-0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (-0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,-0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
-
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,-0),(-0.2,-0.2)
-        | (0.08,-0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (-0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
-
-SELECT f1::box
-	FROM POINT_TBL;
-          f1           
------------------------
- (0,0),(0,0)
- (-10,0),(-10,0)
- (-3,4),(-3,4)
- (5.1,34.5),(5.1,34.5)
- (-5,-12),(-5,-12)
- (10,10),(10,10)
-(6 rows)
-
-SELECT bound_box(a.f1, b.f1)
-	FROM BOX_TBL a, BOX_TBL b;
-      bound_box      
----------------------
- (2,2),(0,0)
- (3,3),(0,0)
- (2.5,3.5),(0,0)
- (3,3),(0,0)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(1,1)
- (3,3),(1,1)
- (2.5,3.5),(0,0)
- (3,3.5),(1,1)
- (2.5,3.5),(2.5,2.5)
- (3,3.5),(2.5,2.5)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(2.5,2.5)
- (3,3),(3,3)
-(16 rows)
-
---
--- Paths
---
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
-
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
-
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
-
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
-
---
--- Polygons
---
--- containment
-SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
-   FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
-      |       3 | ((2,0),(2,4),(0,0))
-      |       3 | ((3,1),(3,3),(1,0))
-      |       1 | ((0,0))
-      |       2 | ((0,1),(0,1))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM BOX_TBL;
- four |                  polygon                  
-------+-------------------------------------------
-      | ((0,0),(0,2),(2,2),(2,0))
-      | ((1,1),(1,3),(3,3),(3,1))
-      | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
-      | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM PATH_TBL WHERE isclosed(f1);
- four |      polygon      
-------+-------------------
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((11,12),(13,14))
-(4 rows)
-
-SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
-   FROM PATH_TBL
-   WHERE isopen(f1);
- four |         open_path         |          polygon          
-------+---------------------------+---------------------------
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(11,12),(13,14)]         | ((11,12),(13,14))
-(4 rows)
-
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
-
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
-
---
--- Circles
---
-SELECT '' AS six, circle(f1, 50.0)
-   FROM POINT_TBL;
- six |     circle      
------+-----------------
-     | <(0,0),50>
-     | <(-10,0),50>
-     | <(-3,4),50>
-     | <(5.1,34.5),50>
-     | <(-5,-12),50>
-     | <(10,10),50>
-(6 rows)
-
-SELECT '' AS four, circle(f1)
-   FROM BOX_TBL;
- four |        circle         
-------+-----------------------
-      | <(1,1),1.41421356237>
-      | <(2,2),1.41421356237>
-      | <(2.5,3),0.5>
-      | <(3,3),0>
-(4 rows)
-
-SELECT '' AS two, circle(f1)
-   FROM POLYGON_TBL
-   WHERE (# f1) >= 3;
- two |                    circle                     
------+-----------------------------------------------
-     | <(1.33333333333,1.33333333333),2.04168905064>
-     | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
-
-SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
-   FROM CIRCLE_TBL c1, POINT_TBL p1
-   WHERE (p1.f1 <-> c1.f1) > 0
-   ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
-
diff --git a/src/test/regress/expected/line.out b/src/test/regress/expected/line.out
index f20abdc430..bf780daa2c 100644
--- a/src/test/regress/expected/line.out
+++ b/src/test/regress/expected/line.out
@@ -1,271 +1,87 @@
 --
 -- LINE
 -- Infinite lines
 --
 --DROP TABLE LINE_TBL;
 CREATE TABLE LINE_TBL (s line);
-INSERT INTO LINE_TBL VALUES ('{1,-1,1}');
-INSERT INTO LINE_TBL VALUES ('(0,0),(6,6)');
+INSERT INTO LINE_TBL VALUES ('{0,-1,5}');	-- A == 0
+INSERT INTO LINE_TBL VALUES ('{1,0,5}');	-- B == 0
+INSERT INTO LINE_TBL VALUES ('{0,3,0}');	-- A == C == 0
+INSERT INTO LINE_TBL VALUES (' (0,0), (6,6)');
 INSERT INTO LINE_TBL VALUES ('10,-10 ,-5,-4');
 INSERT INTO LINE_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LINE_TBL VALUES ('(11,22,33,44)');
-INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
-ERROR:  invalid line specification: must be two distinct points
-LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
-                                     ^
+INSERT INTO LINE_TBL VALUES ('{3,NaN,5}');
+INSERT INTO LINE_TBL VALUES ('{NaN,NaN,NaN}');
 -- horizontal
 INSERT INTO LINE_TBL VALUES ('[(1,3),(2,3)]');
 -- vertical
-INSERT INTO LINE_TBL VALUES ('[(3,1),(3,2)]');
+INSERT INTO LINE_TBL VALUES (line(point '(3,1)', point '(3,2)'));
 -- bad values for parser testing
+INSERT INTO LINE_TBL VALUES ('{}');
+ERROR:  invalid input syntax for type line: "{}"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{}');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0');
+ERROR:  invalid input syntax for type line: "{0"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0,0}');
+ERROR:  invalid input syntax for type line: "{0,0}"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0}');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0,0,1');
+ERROR:  invalid input syntax for type line: "{0,0,1"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1');
+                                     ^
 INSERT INTO LINE_TBL VALUES ('{0,0,1}');
 ERROR:  invalid line specification: A and B cannot both be zero
 LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1}');
                                      ^
+INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
+ERROR:  invalid input syntax for type line: "{0,0,1} x"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
+                                     ^
 INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
 ERROR:  invalid input syntax for type line: "(3asdf,2 ,3,4r2)"
 LINE 1: INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
                                      ^
 INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
 ERROR:  invalid input syntax for type line: "[1,2,3, 4"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
                                      ^
 INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
 ERROR:  invalid input syntax for type line: "[(,2),(3,4)]"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
                                      ^
 INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
 ERROR:  invalid input syntax for type line: "[(1,2),(3,4)"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
                                      ^
+INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
+ERROR:  invalid line specification: must be two distinct points
+LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
+                                     ^
+INSERT INTO LINE_TBL VALUES (line(point '(1,0)', point '(1,0)'));
+ERROR:  invalid line specification: must be two distinct points
 select * from LINE_TBL;
                       s                      
 ---------------------------------------------
- {1,-1,1}
+ {0,-1,5}
+ {1,0,5}
+ {0,3,0}
  {1,-1,0}
  {-0.4,-1,-6}
  {-0.000184615384615385,-1,15.3846153846154}
- {1,-1,11}
+ {3,NaN,5}
+ {NaN,NaN,NaN}
  {0,-1,3}
  {-1,0,3}
-(7 rows)
+(10 rows)
 
--- functions and operators
-SELECT * FROM LINE_TBL WHERE (s <-> line '[(1,2),(3,4)]') < 10;
-                      s                      
----------------------------------------------
- {1,-1,1}
- {1,-1,0}
- {-0.4,-1,-6}
- {-0.000184615384615385,-1,15.3846153846154}
- {1,-1,11}
- {0,-1,3}
- {-1,0,3}
-(7 rows)
-
-SELECT * FROM LINE_TBL WHERE (point '(0.1,0.1)' <-> s) < 1;
-    s     
-----------
- {1,-1,1}
- {1,-1,0}
-(2 rows)
-
-SELECT * FROM LINE_TBL WHERE (lseg '[(0.1,0.1),(0.2,0.2)]' <-> s) < 1;
-    s     
-----------
- {1,-1,1}
- {1,-1,0}
-(2 rows)
-
-SELECT line '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
- ?column? 
-----------
-        2
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
- ?column? 
-----------
-        2
-(1 row)
-
-SELECT point '(-1,1)' <-> line '[(-3,0),(-4,0)]';
- ?column? 
-----------
-        1
-(1 row)
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(2,0),(0,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# box '(0,0,2,2)';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(3,0),(4,1)]' ?# box '(0,0,2,2)';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(1,1)' <@ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT point '(1,1)' <@ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(1,1)' @ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT point '(1,1)' @ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT lseg '[(1,1),(2,2)]' <@ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' <@ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT lseg '[(1,1),(2,2)]' @ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' @ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(0,1)' ## line '[(0,0),(1,1)]';
- ?column?  
------------
- (0.5,0.5)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ## lseg '[(1,0),(2,0)]';
- ?column? 
-----------
- (1,0)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(2,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(1,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(2,1)]';
- ?column? 
-----------
- 
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(1,1)]';
- ?column? 
-----------
- (1,1)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(2,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,0)]' ?-| line '[(0,0),(0,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?-| line '[(1,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT ?- line '[(0,0),(1,0)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT ?- line '[(0,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT ?| line '[(0,0),(0,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT ?| line '[(0,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line(point '(1,2)', point '(3,4)');
-   line   
-----------
- {1,-1,1}
-(1 row)
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,5)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,4)]';  -- false
- ?column? 
-----------
- f
+select '{nan, 1, nan}'::line = '{nan, 1, nan}'::line as true,
+	   '{nan, 1, nan}'::line = '{nan, 2, nan}'::line as false;
+ true | false 
+------+-------
+ t    | f
 (1 row)
 
diff --git a/src/test/regress/expected/lseg.out b/src/test/regress/expected/lseg.out
index bba1f3ee80..7e878b5577 100644
--- a/src/test/regress/expected/lseg.out
+++ b/src/test/regress/expected/lseg.out
@@ -1,21 +1,24 @@
 --
 -- LSEG
 -- Line segments
 --
 --DROP TABLE LSEG_TBL;
 CREATE TABLE LSEG_TBL (s lseg);
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('(0,0),(6,6)');
 INSERT INTO LSEG_TBL VALUES ('10,-10 ,-3,-4');
 INSERT INTO LSEG_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LSEG_TBL VALUES ('(11,22,33,44)');
+INSERT INTO LSEG_TBL VALUES (lseg(point(11, 22), point(33,44)));
+INSERT INTO LSEG_TBL VALUES ('[(-10,2),(-10,3)]');	-- vertical
+INSERT INTO LSEG_TBL VALUES ('[(0,-20),(30,-20)]');	-- horizontal
+INSERT INTO LSEG_TBL VALUES ('[(NaN,1),(NaN,90)]');	-- NaN
 -- bad values for parser testing
 INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
 ERROR:  invalid input syntax for type lseg: "(3asdf,2 ,3,4r2)"
 LINE 1: INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
                                      ^
 INSERT INTO LSEG_TBL VALUES ('[1,2,3, 4');
 ERROR:  invalid input syntax for type lseg: "[1,2,3, 4"
 LINE 1: INSERT INTO LSEG_TBL VALUES ('[1,2,3, 4');
                                      ^
 INSERT INTO LSEG_TBL VALUES ('[(,2),(3,4)]');
@@ -27,26 +30,15 @@ ERROR:  invalid input syntax for type lseg: "[(1,2),(3,4)"
 LINE 1: INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)');
                                      ^
 select * from LSEG_TBL;
                s               
 -------------------------------
  [(1,2),(3,4)]
  [(0,0),(6,6)]
  [(10,-10),(-3,-4)]
  [(-1000000,200),(300000,-40)]
  [(11,22),(33,44)]
-(5 rows)
-
-SELECT * FROM LSEG_TBL WHERE s <= lseg '[(1,2),(3,4)]';
-       s       
----------------
- [(1,2),(3,4)]
-(1 row)
-
-SELECT * FROM LSEG_TBL WHERE (s <-> lseg '[(1,2),(3,4)]') < 10;
-         s          
---------------------
- [(1,2),(3,4)]
- [(0,0),(6,6)]
- [(10,-10),(-3,-4)]
-(3 rows)
+ [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]
+ [(NaN,1),(NaN,90)]
+(8 rows)
 
diff --git a/src/test/regress/expected/path.out b/src/test/regress/expected/path.out
index 08d6d61dda..bd6e467752 100644
--- a/src/test/regress/expected/path.out
+++ b/src/test/regress/expected/path.out
@@ -1,79 +1,82 @@
 --
 -- PATH
 --
 --DROP TABLE PATH_TBL;
 CREATE TABLE PATH_TBL (f1 path);
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)]');
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
-INSERT INTO PATH_TBL VALUES ('[(0,0),(3,0),(4,5),(1,6)]');
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
-INSERT INTO PATH_TBL VALUES ('1,2 ,3,4');
-INSERT INTO PATH_TBL VALUES ('[1,2,3, 4]');
-INSERT INTO PATH_TBL VALUES ('[11,12,13,14]');
-INSERT INTO PATH_TBL VALUES ('(11,12,13,14)');
+INSERT INTO PATH_TBL VALUES (' ( ( 1 , 2 ) , ( 3 , 4 ) ) ');
+INSERT INTO PATH_TBL VALUES ('[ (0,0),(3,0),(4,5),(1,6) ]');
+INSERT INTO PATH_TBL VALUES ('((1,2) ,(3,4 ))');
+INSERT INTO PATH_TBL VALUES ('1,2 ,3,4 ');
+INSERT INTO PATH_TBL VALUES (' [1,2,3, 4] ');
+INSERT INTO PATH_TBL VALUES ('((10,20))');	-- Only one point
+INSERT INTO PATH_TBL VALUES ('[ 11,12,13,14 ]');
+INSERT INTO PATH_TBL VALUES ('( 11,12,13,14) ');
 -- bad values for parser testing
+INSERT INTO PATH_TBL VALUES ('[]');
+ERROR:  invalid input syntax for type path: "[]"
+LINE 1: INSERT INTO PATH_TBL VALUES ('[]');
+                                     ^
 INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
 ERROR:  invalid input syntax for type path: "[(,2),(3,4)]"
 LINE 1: INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
                                      ^
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
 ERROR:  invalid input syntax for type path: "[(1,2),(3,4)"
 LINE 1: INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
                                      ^
-SELECT f1 FROM PATH_TBL;
-            f1             
----------------------------
- [(1,2),(3,4)]
- ((1,2),(3,4))
- [(0,0),(3,0),(4,5),(1,6)]
- ((1,2),(3,4))
- ((1,2),(3,4))
- [(1,2),(3,4)]
- [(11,12),(13,14)]
- ((11,12),(13,14))
-(8 rows)
-
+INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+ERROR:  invalid input syntax for type path: "(1,2,3,4"
+LINE 1: INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+                                     ^
+INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
+ERROR:  invalid input syntax for type path: "(1,2),(3,4)]"
+LINE 1: INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
+                                     ^
 SELECT '' AS count, f1 AS open_path FROM PATH_TBL WHERE isopen(f1);
  count |         open_path         
 -------+---------------------------
        | [(1,2),(3,4)]
        | [(0,0),(3,0),(4,5),(1,6)]
        | [(1,2),(3,4)]
        | [(11,12),(13,14)]
 (4 rows)
 
 SELECT '' AS count, f1 AS closed_path FROM PATH_TBL WHERE isclosed(f1);
  count |    closed_path    
 -------+-------------------
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
+       | ((10,20))
        | ((11,12),(13,14))
-(4 rows)
+(5 rows)
 
 SELECT '' AS count, pclose(f1) AS closed_path FROM PATH_TBL;
  count |        closed_path        
 -------+---------------------------
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((0,0),(3,0),(4,5),(1,6))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
+       | ((10,20))
        | ((11,12),(13,14))
        | ((11,12),(13,14))
-(8 rows)
+(9 rows)
 
 SELECT '' AS count, popen(f1) AS open_path FROM PATH_TBL;
  count |         open_path         
 -------+---------------------------
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
        | [(0,0),(3,0),(4,5),(1,6)]
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
+       | [(10,20)]
        | [(11,12),(13,14)]
        | [(11,12),(13,14)]
-(8 rows)
+(9 rows)
 
diff --git a/src/test/regress/expected/point.out b/src/test/regress/expected/point.out
index bfc0962749..c18e865370 100644
--- a/src/test/regress/expected/point.out
+++ b/src/test/regress/expected/point.out
@@ -1,43 +1,57 @@
 --
 -- POINT
 --
 CREATE TABLE POINT_TBL(f1 point);
 INSERT INTO POINT_TBL(f1) VALUES ('(0.0,0.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-10.0,0.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-3.0,4.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(5.1, 34.5)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-5.0,-12.0)');
+INSERT INTO POINT_TBL(f1) VALUES ('(1e-300,-1e-300)');	-- To underflow
+INSERT INTO POINT_TBL(f1) VALUES ('(1e+300,Inf)');		-- To overflow
+INSERT INTO POINT_TBL(f1) VALUES (' ( Nan , NaN ) ');
 -- bad format points
 INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
 ERROR:  invalid input syntax for type point: "asdfasdf"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
                                           ^
 INSERT INTO POINT_TBL(f1) VALUES ('10.0,10.0');
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
 ERROR:  invalid input syntax for type point: "(10.0 10.0)"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
                                           ^
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+ERROR:  invalid input syntax for type point: "(10.0, 10.0) x"
+LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+                                          ^
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
 ERROR:  invalid input syntax for type point: "(10.0,10.0"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
                                           ^
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');	-- Out of range
+ERROR:  "1e+500" is out of range for type double precision
+LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');
+                                          ^
 SELECT '' AS six, * FROM POINT_TBL;
- six |     f1     
------+------------
+ six |        f1         
+-----+-------------------
      | (0,0)
      | (-10,0)
      | (-3,4)
      | (5.1,34.5)
      | (-5,-12)
+     | (1e-300,-1e-300)
+     | (1e+300,Infinity)
+     | (NaN,NaN)
      | (10,10)
-(6 rows)
+(9 rows)
 
 -- left of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE p.f1 << '(0.0, 0.0)';
  three |    f1    
 -------+----------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
 (3 rows)
 
@@ -85,172 +99,282 @@ 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    
--------+----------
+ three |        f1         
+-------+-------------------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
-(3 rows)
+       | (1e-300,-1e-300)
+       | (1e+300,Infinity)
+       | (NaN,NaN)
+(6 rows)
 
 SELECT '' AS two, p.* FROM POINT_TBL p
    WHERE p.f1 <@ path '[(0,0),(-10,0),(-10,10)]';
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 SELECT '' AS three, p.* FROM POINT_TBL p
    WHERE not box '(0,0,100,100)' @> p.f1;
- three |    f1    
--------+----------
+ three |        f1         
+-------+-------------------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
-(3 rows)
+       | (1e-300,-1e-300)
+       | (1e+300,Infinity)
+       | (NaN,NaN)
+(6 rows)
 
 SELECT '' AS six, p.f1, p.f1 <-> point '(0,0)' AS dist
    FROM POINT_TBL p
    ORDER BY dist;
- six |     f1     |       dist       
------+------------+------------------
-     | (0,0)      |                0
-     | (-3,4)     |                5
-     | (-10,0)    |               10
-     | (-5,-12)   |               13
-     | (10,10)    |  14.142135623731
-     | (5.1,34.5) | 34.8749193547455
-(6 rows)
+ six |        f1         |         dist         
+-----+-------------------+----------------------
+     | (0,0)             |                    0
+     | (1e-300,-1e-300)  | 1.4142135623731e-300
+     | (-3,4)            |                    5
+     | (-10,0)           |                   10
+     | (-5,-12)          |                   13
+     | (10,10)           |      14.142135623731
+     | (5.1,34.5)        |     34.8749193547455
+     | (1e+300,Infinity) |             Infinity
+     | (NaN,NaN)         |                  NaN
+(9 rows)
 
 SELECT '' AS thirtysix, p1.f1 AS point1, p2.f1 AS point2, p1.f1 <-> p2.f1 AS dist
    FROM POINT_TBL p1, POINT_TBL p2
    ORDER BY dist, p1.f1[0], p2.f1[0];
- thirtysix |   point1   |   point2   |       dist       
------------+------------+------------+------------------
-           | (-10,0)    | (-10,0)    |                0
-           | (-5,-12)   | (-5,-12)   |                0
-           | (-3,4)     | (-3,4)     |                0
-           | (0,0)      | (0,0)      |                0
-           | (5.1,34.5) | (5.1,34.5) |                0
-           | (10,10)    | (10,10)    |                0
-           | (-3,4)     | (0,0)      |                5
-           | (0,0)      | (-3,4)     |                5
-           | (-10,0)    | (-3,4)     | 8.06225774829855
-           | (-3,4)     | (-10,0)    | 8.06225774829855
-           | (-10,0)    | (0,0)      |               10
-           | (0,0)      | (-10,0)    |               10
-           | (-10,0)    | (-5,-12)   |               13
-           | (-5,-12)   | (-10,0)    |               13
-           | (-5,-12)   | (0,0)      |               13
-           | (0,0)      | (-5,-12)   |               13
-           | (0,0)      | (10,10)    |  14.142135623731
-           | (10,10)    | (0,0)      |  14.142135623731
-           | (-3,4)     | (10,10)    | 14.3178210632764
-           | (10,10)    | (-3,4)     | 14.3178210632764
-           | (-5,-12)   | (-3,4)     | 16.1245154965971
-           | (-3,4)     | (-5,-12)   | 16.1245154965971
-           | (-10,0)    | (10,10)    | 22.3606797749979
-           | (10,10)    | (-10,0)    | 22.3606797749979
-           | (5.1,34.5) | (10,10)    | 24.9851956166046
-           | (10,10)    | (5.1,34.5) | 24.9851956166046
-           | (-5,-12)   | (10,10)    | 26.6270539113887
-           | (10,10)    | (-5,-12)   | 26.6270539113887
-           | (-3,4)     | (5.1,34.5) | 31.5572495632937
-           | (5.1,34.5) | (-3,4)     | 31.5572495632937
-           | (0,0)      | (5.1,34.5) | 34.8749193547455
-           | (5.1,34.5) | (0,0)      | 34.8749193547455
-           | (-10,0)    | (5.1,34.5) | 37.6597928831267
-           | (5.1,34.5) | (-10,0)    | 37.6597928831267
-           | (-5,-12)   | (5.1,34.5) | 47.5842410888311
-           | (5.1,34.5) | (-5,-12)   | 47.5842410888311
-(36 rows)
+ thirtysix |      point1       |      point2       |         dist         
+-----------+-------------------+-------------------+----------------------
+           | (-10,0)           | (-10,0)           |                    0
+           | (-5,-12)          | (-5,-12)          |                    0
+           | (-3,4)            | (-3,4)            |                    0
+           | (0,0)             | (0,0)             |                    0
+           | (1e-300,-1e-300)  | (1e-300,-1e-300)  |                    0
+           | (5.1,34.5)        | (5.1,34.5)        |                    0
+           | (10,10)           | (10,10)           |                    0
+           | (0,0)             | (1e-300,-1e-300)  | 1.4142135623731e-300
+           | (1e-300,-1e-300)  | (0,0)             | 1.4142135623731e-300
+           | (-3,4)            | (0,0)             |                    5
+           | (-3,4)            | (1e-300,-1e-300)  |                    5
+           | (0,0)             | (-3,4)            |                    5
+           | (1e-300,-1e-300)  | (-3,4)            |                    5
+           | (-10,0)           | (-3,4)            |     8.06225774829855
+           | (-3,4)            | (-10,0)           |     8.06225774829855
+           | (-10,0)           | (0,0)             |                   10
+           | (-10,0)           | (1e-300,-1e-300)  |                   10
+           | (0,0)             | (-10,0)           |                   10
+           | (1e-300,-1e-300)  | (-10,0)           |                   10
+           | (-10,0)           | (-5,-12)          |                   13
+           | (-5,-12)          | (-10,0)           |                   13
+           | (-5,-12)          | (0,0)             |                   13
+           | (-5,-12)          | (1e-300,-1e-300)  |                   13
+           | (0,0)             | (-5,-12)          |                   13
+           | (1e-300,-1e-300)  | (-5,-12)          |                   13
+           | (0,0)             | (10,10)           |      14.142135623731
+           | (1e-300,-1e-300)  | (10,10)           |      14.142135623731
+           | (10,10)           | (0,0)             |      14.142135623731
+           | (10,10)           | (1e-300,-1e-300)  |      14.142135623731
+           | (-3,4)            | (10,10)           |     14.3178210632764
+           | (10,10)           | (-3,4)            |     14.3178210632764
+           | (-5,-12)          | (-3,4)            |     16.1245154965971
+           | (-3,4)            | (-5,-12)          |     16.1245154965971
+           | (-10,0)           | (10,10)           |     22.3606797749979
+           | (10,10)           | (-10,0)           |     22.3606797749979
+           | (5.1,34.5)        | (10,10)           |     24.9851956166046
+           | (10,10)           | (5.1,34.5)        |     24.9851956166046
+           | (-5,-12)          | (10,10)           |     26.6270539113887
+           | (10,10)           | (-5,-12)          |     26.6270539113887
+           | (-3,4)            | (5.1,34.5)        |     31.5572495632937
+           | (5.1,34.5)        | (-3,4)            |     31.5572495632937
+           | (0,0)             | (5.1,34.5)        |     34.8749193547455
+           | (1e-300,-1e-300)  | (5.1,34.5)        |     34.8749193547455
+           | (5.1,34.5)        | (0,0)             |     34.8749193547455
+           | (5.1,34.5)        | (1e-300,-1e-300)  |     34.8749193547455
+           | (-10,0)           | (5.1,34.5)        |     37.6597928831267
+           | (5.1,34.5)        | (-10,0)           |     37.6597928831267
+           | (-5,-12)          | (5.1,34.5)        |     47.5842410888311
+           | (5.1,34.5)        | (-5,-12)          |     47.5842410888311
+           | (-10,0)           | (1e+300,Infinity) |             Infinity
+           | (-5,-12)          | (1e+300,Infinity) |             Infinity
+           | (-3,4)            | (1e+300,Infinity) |             Infinity
+           | (0,0)             | (1e+300,Infinity) |             Infinity
+           | (1e-300,-1e-300)  | (1e+300,Infinity) |             Infinity
+           | (5.1,34.5)        | (1e+300,Infinity) |             Infinity
+           | (10,10)           | (1e+300,Infinity) |             Infinity
+           | (1e+300,Infinity) | (-10,0)           |             Infinity
+           | (1e+300,Infinity) | (-5,-12)          |             Infinity
+           | (1e+300,Infinity) | (-3,4)            |             Infinity
+           | (1e+300,Infinity) | (0,0)             |             Infinity
+           | (1e+300,Infinity) | (1e-300,-1e-300)  |             Infinity
+           | (1e+300,Infinity) | (5.1,34.5)        |             Infinity
+           | (1e+300,Infinity) | (10,10)           |             Infinity
+           | (-10,0)           | (NaN,NaN)         |                  NaN
+           | (-5,-12)          | (NaN,NaN)         |                  NaN
+           | (-3,4)            | (NaN,NaN)         |                  NaN
+           | (0,0)             | (NaN,NaN)         |                  NaN
+           | (1e-300,-1e-300)  | (NaN,NaN)         |                  NaN
+           | (5.1,34.5)        | (NaN,NaN)         |                  NaN
+           | (10,10)           | (NaN,NaN)         |                  NaN
+           | (1e+300,Infinity) | (1e+300,Infinity) |                  NaN
+           | (1e+300,Infinity) | (NaN,NaN)         |                  NaN
+           | (NaN,NaN)         | (-10,0)           |                  NaN
+           | (NaN,NaN)         | (-5,-12)          |                  NaN
+           | (NaN,NaN)         | (-3,4)            |                  NaN
+           | (NaN,NaN)         | (0,0)             |                  NaN
+           | (NaN,NaN)         | (1e-300,-1e-300)  |                  NaN
+           | (NaN,NaN)         | (5.1,34.5)        |                  NaN
+           | (NaN,NaN)         | (10,10)           |                  NaN
+           | (NaN,NaN)         | (1e+300,Infinity) |                  NaN
+           | (NaN,NaN)         | (NaN,NaN)         |                  NaN
+(81 rows)
 
 SELECT '' AS thirty, p1.f1 AS point1, p2.f1 AS point2
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3;
- thirty |   point1   |   point2   
---------+------------+------------
-        | (0,0)      | (-10,0)
-        | (0,0)      | (-3,4)
-        | (0,0)      | (5.1,34.5)
-        | (0,0)      | (-5,-12)
-        | (0,0)      | (10,10)
-        | (-10,0)    | (0,0)
-        | (-10,0)    | (-3,4)
-        | (-10,0)    | (5.1,34.5)
-        | (-10,0)    | (-5,-12)
-        | (-10,0)    | (10,10)
-        | (-3,4)     | (0,0)
-        | (-3,4)     | (-10,0)
-        | (-3,4)     | (5.1,34.5)
-        | (-3,4)     | (-5,-12)
-        | (-3,4)     | (10,10)
-        | (5.1,34.5) | (0,0)
-        | (5.1,34.5) | (-10,0)
-        | (5.1,34.5) | (-3,4)
-        | (5.1,34.5) | (-5,-12)
-        | (5.1,34.5) | (10,10)
-        | (-5,-12)   | (0,0)
-        | (-5,-12)   | (-10,0)
-        | (-5,-12)   | (-3,4)
-        | (-5,-12)   | (5.1,34.5)
-        | (-5,-12)   | (10,10)
-        | (10,10)    | (0,0)
-        | (10,10)    | (-10,0)
-        | (10,10)    | (-3,4)
-        | (10,10)    | (5.1,34.5)
-        | (10,10)    | (-5,-12)
-(30 rows)
+ thirty |      point1       |      point2       
+--------+-------------------+-------------------
+        | (0,0)             | (-10,0)
+        | (0,0)             | (-3,4)
+        | (0,0)             | (5.1,34.5)
+        | (0,0)             | (-5,-12)
+        | (0,0)             | (1e+300,Infinity)
+        | (0,0)             | (NaN,NaN)
+        | (0,0)             | (10,10)
+        | (-10,0)           | (0,0)
+        | (-10,0)           | (-3,4)
+        | (-10,0)           | (5.1,34.5)
+        | (-10,0)           | (-5,-12)
+        | (-10,0)           | (1e-300,-1e-300)
+        | (-10,0)           | (1e+300,Infinity)
+        | (-10,0)           | (NaN,NaN)
+        | (-10,0)           | (10,10)
+        | (-3,4)            | (0,0)
+        | (-3,4)            | (-10,0)
+        | (-3,4)            | (5.1,34.5)
+        | (-3,4)            | (-5,-12)
+        | (-3,4)            | (1e-300,-1e-300)
+        | (-3,4)            | (1e+300,Infinity)
+        | (-3,4)            | (NaN,NaN)
+        | (-3,4)            | (10,10)
+        | (5.1,34.5)        | (0,0)
+        | (5.1,34.5)        | (-10,0)
+        | (5.1,34.5)        | (-3,4)
+        | (5.1,34.5)        | (-5,-12)
+        | (5.1,34.5)        | (1e-300,-1e-300)
+        | (5.1,34.5)        | (1e+300,Infinity)
+        | (5.1,34.5)        | (NaN,NaN)
+        | (5.1,34.5)        | (10,10)
+        | (-5,-12)          | (0,0)
+        | (-5,-12)          | (-10,0)
+        | (-5,-12)          | (-3,4)
+        | (-5,-12)          | (5.1,34.5)
+        | (-5,-12)          | (1e-300,-1e-300)
+        | (-5,-12)          | (1e+300,Infinity)
+        | (-5,-12)          | (NaN,NaN)
+        | (-5,-12)          | (10,10)
+        | (1e-300,-1e-300)  | (-10,0)
+        | (1e-300,-1e-300)  | (-3,4)
+        | (1e-300,-1e-300)  | (5.1,34.5)
+        | (1e-300,-1e-300)  | (-5,-12)
+        | (1e-300,-1e-300)  | (1e+300,Infinity)
+        | (1e-300,-1e-300)  | (NaN,NaN)
+        | (1e-300,-1e-300)  | (10,10)
+        | (1e+300,Infinity) | (0,0)
+        | (1e+300,Infinity) | (-10,0)
+        | (1e+300,Infinity) | (-3,4)
+        | (1e+300,Infinity) | (5.1,34.5)
+        | (1e+300,Infinity) | (-5,-12)
+        | (1e+300,Infinity) | (1e-300,-1e-300)
+        | (1e+300,Infinity) | (1e+300,Infinity)
+        | (1e+300,Infinity) | (NaN,NaN)
+        | (1e+300,Infinity) | (10,10)
+        | (NaN,NaN)         | (0,0)
+        | (NaN,NaN)         | (-10,0)
+        | (NaN,NaN)         | (-3,4)
+        | (NaN,NaN)         | (5.1,34.5)
+        | (NaN,NaN)         | (-5,-12)
+        | (NaN,NaN)         | (1e-300,-1e-300)
+        | (NaN,NaN)         | (1e+300,Infinity)
+        | (NaN,NaN)         | (NaN,NaN)
+        | (NaN,NaN)         | (10,10)
+        | (10,10)           | (0,0)
+        | (10,10)           | (-10,0)
+        | (10,10)           | (-3,4)
+        | (10,10)           | (5.1,34.5)
+        | (10,10)           | (-5,-12)
+        | (10,10)           | (1e-300,-1e-300)
+        | (10,10)           | (1e+300,Infinity)
+        | (10,10)           | (NaN,NaN)
+(72 rows)
 
 -- put distance result into output to allow sorting with GEQ optimizer - tgl 97/05/10
 SELECT '' AS fifteen, p1.f1 AS point1, p2.f1 AS point2, (p1.f1 <-> p2.f1) AS distance
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3 and p1.f1 << p2.f1
    ORDER BY distance, p1.f1[0], p2.f1[0];
- fifteen |   point1   |   point2   |     distance     
----------+------------+------------+------------------
-         | (-3,4)     | (0,0)      |                5
-         | (-10,0)    | (-3,4)     | 8.06225774829855
-         | (-10,0)    | (0,0)      |               10
-         | (-10,0)    | (-5,-12)   |               13
-         | (-5,-12)   | (0,0)      |               13
-         | (0,0)      | (10,10)    |  14.142135623731
-         | (-3,4)     | (10,10)    | 14.3178210632764
-         | (-5,-12)   | (-3,4)     | 16.1245154965971
-         | (-10,0)    | (10,10)    | 22.3606797749979
-         | (5.1,34.5) | (10,10)    | 24.9851956166046
-         | (-5,-12)   | (10,10)    | 26.6270539113887
-         | (-3,4)     | (5.1,34.5) | 31.5572495632937
-         | (0,0)      | (5.1,34.5) | 34.8749193547455
-         | (-10,0)    | (5.1,34.5) | 37.6597928831267
-         | (-5,-12)   | (5.1,34.5) | 47.5842410888311
-(15 rows)
+ fifteen |      point1      |      point2       |     distance     
+---------+------------------+-------------------+------------------
+         | (-3,4)           | (0,0)             |                5
+         | (-3,4)           | (1e-300,-1e-300)  |                5
+         | (-10,0)          | (-3,4)            | 8.06225774829855
+         | (-10,0)          | (0,0)             |               10
+         | (-10,0)          | (1e-300,-1e-300)  |               10
+         | (-10,0)          | (-5,-12)          |               13
+         | (-5,-12)         | (0,0)             |               13
+         | (-5,-12)         | (1e-300,-1e-300)  |               13
+         | (0,0)            | (10,10)           |  14.142135623731
+         | (1e-300,-1e-300) | (10,10)           |  14.142135623731
+         | (-3,4)           | (10,10)           | 14.3178210632764
+         | (-5,-12)         | (-3,4)            | 16.1245154965971
+         | (-10,0)          | (10,10)           | 22.3606797749979
+         | (5.1,34.5)       | (10,10)           | 24.9851956166046
+         | (-5,-12)         | (10,10)           | 26.6270539113887
+         | (-3,4)           | (5.1,34.5)        | 31.5572495632937
+         | (0,0)            | (5.1,34.5)        | 34.8749193547455
+         | (1e-300,-1e-300) | (5.1,34.5)        | 34.8749193547455
+         | (-10,0)          | (5.1,34.5)        | 37.6597928831267
+         | (-5,-12)         | (5.1,34.5)        | 47.5842410888311
+         | (-10,0)          | (1e+300,Infinity) |         Infinity
+         | (-5,-12)         | (1e+300,Infinity) |         Infinity
+         | (-3,4)           | (1e+300,Infinity) |         Infinity
+         | (0,0)            | (1e+300,Infinity) |         Infinity
+         | (1e-300,-1e-300) | (1e+300,Infinity) |         Infinity
+         | (5.1,34.5)       | (1e+300,Infinity) |         Infinity
+         | (10,10)          | (1e+300,Infinity) |         Infinity
+(27 rows)
 
 -- put distance result into output to allow sorting with GEQ optimizer - tgl 97/05/10
 SELECT '' AS three, p1.f1 AS point1, p2.f1 AS point2, (p1.f1 <-> p2.f1) AS distance
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3 and p1.f1 << p2.f1 and p1.f1 >^ p2.f1
    ORDER BY distance;
- three |   point1   |  point2  |     distance     
--------+------------+----------+------------------
-       | (-3,4)     | (0,0)    |                5
-       | (-10,0)    | (-5,-12) |               13
-       | (5.1,34.5) | (10,10)  | 24.9851956166046
-(3 rows)
+ three |   point1   |      point2      |     distance     
+-------+------------+------------------+------------------
+       | (-3,4)     | (0,0)            |                5
+       | (-3,4)     | (1e-300,-1e-300) |                5
+       | (-10,0)    | (-5,-12)         |               13
+       | (5.1,34.5) | (10,10)          | 24.9851956166046
+(4 rows)
 
 -- Test that GiST indexes provide same behavior as sequential scan
 CREATE TEMP TABLE point_gist_tbl(f1 point);
 INSERT INTO point_gist_tbl SELECT '(0,0)' FROM generate_series(0,1000);
 CREATE INDEX point_gist_tbl_index ON point_gist_tbl USING gist (f1);
 INSERT INTO point_gist_tbl VALUES ('(0.0000009,0.0000009)');
 SET enable_seqscan TO true;
 SET enable_indexscan TO false;
 SET enable_bitmapscan TO false;
 SELECT COUNT(*) FROM point_gist_tbl WHERE f1 ~= '(0.0000009,0.0000009)'::point;
diff --git a/src/test/regress/expected/polygon.out b/src/test/regress/expected/polygon.out
index 4a1f60427a..be5f76bf9d 100644
--- a/src/test/regress/expected/polygon.out
+++ b/src/test/regress/expected/polygon.out
@@ -1,18 +1,21 @@
 --
 -- POLYGON
 --
 -- polygon logic
 --
 CREATE TABLE POLYGON_TBL(f1 polygon);
 INSERT INTO POLYGON_TBL(f1) VALUES ('(2.0,0.0),(2.0,4.0),(0.0,0.0)');
 INSERT INTO POLYGON_TBL(f1) VALUES ('(3.0,1.0),(3.0,3.0),(1.0,0.0)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(3,4),(5,6),(7,8)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(7,8),(5,6),(3,4),(1,2)'); -- Reverse
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(7,8),(5,6),(3,-4)');
 -- degenerate polygons
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,0.0)');
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,1.0),(0.0,1.0)');
 -- bad polygon input strings
 INSERT INTO POLYGON_TBL(f1) VALUES ('0.0');
 ERROR:  invalid input syntax for type polygon: "0.0"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('0.0');
                                             ^
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0 0.0');
 ERROR:  invalid input syntax for type polygon: "(0.0 0.0"
@@ -24,215 +27,30 @@ LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2)');
                                             ^
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2,3');
 ERROR:  invalid input syntax for type polygon: "(0,1,2,3"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2,3');
                                             ^
 INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
 ERROR:  invalid input syntax for type polygon: "asdf"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
                                             ^
 SELECT '' AS four, * FROM POLYGON_TBL;
- four |         f1          
-------+---------------------
+ four |             f1             
+------+----------------------------
       | ((2,0),(2,4),(0,0))
       | ((3,1),(3,3),(1,0))
+      | ((1,2),(3,4),(5,6),(7,8))
+      | ((7,8),(5,6),(3,4),(1,2))
+      | ((1,2),(7,8),(5,6),(3,-4))
       | ((0,0))
       | ((0,1),(0,1))
-(4 rows)
-
--- overlap
-SELECT '' AS three, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 && '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- three |         f1          
--------+---------------------
-       | ((2,0),(2,4),(0,0))
-       | ((3,1),(3,3),(1,0))
-(2 rows)
-
--- left overlap
-SELECT '' AS four, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &< '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- four |         f1          
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
-
--- right overlap
-SELECT '' AS two, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- two |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- left of
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 << '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |      f1       
------+---------------
-     | ((0,0))
-     | ((0,1),(0,1))
-(2 rows)
-
--- right of
-SELECT '' AS zero, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 >> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- zero | f1 
-------+----
-(0 rows)
-
--- contained
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- same
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- contains
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
---
--- polygon logic
---
--- left of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- left overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
- true 
-------
- f
-(1 row)
-
--- right overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' &> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- right of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' >> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- contained in
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- contains
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((0,4),(6,4),(3,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
-SELECT '((1,1),(1,4),(5,4),(5,3),(2,3),(2,2),(5,2),(5,1))'::polygon @> '((3,2),(3,3),(4,3),(4,2))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((0,0),(0,3),(3,3),(3,0))'::polygon @> '((2,1),(2,2),(3,2),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
--- same
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' && polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
- true 
-------
- t
-(1 row)
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon && '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
-SELECT '((1,4),(1,1),(4,1),(4,2),(2,2),(2,4),(1,4))'::polygon && '((3,3),(4,3),(4,4),(3,4),(3,3))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((200,800),(800,800),(800,200),(200,200))' &&  '(1000,1000,0,0)'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
--- distance from a point
-SELECT	'(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
-	'(1,1)'::point <-> '((0,0),(2,2),(1,3))'::polygon as on_segment,
-	'(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;
- on_corner | on_segment | inside |   near_corner   | near_segment 
------------+------------+--------+-----------------+--------------
-         0 |          0 |      0 | 1.4142135623731 |          3.2
-(1 row)
+(7 rows)
 
 --
 -- 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
diff --git a/src/test/regress/sql/box.sql b/src/test/regress/sql/box.sql
index 135ac108eb..6710fc90f5 100644
--- a/src/test/regress/sql/box.sql
+++ b/src/test/regress/sql/box.sql
@@ -18,29 +18,38 @@
 
 -- boxes are specified by two points, given by four floats x1,y1,x2,y2
 
 
 CREATE TABLE BOX_TBL (f1 box);
 
 INSERT INTO BOX_TBL (f1) VALUES ('(2.0,2.0,0.0,0.0)');
 
 INSERT INTO BOX_TBL (f1) VALUES ('(1.0,1.0,3.0,3.0)');
 
+INSERT INTO BOX_TBL (f1) VALUES ('((-8, 2), (-2, -10))');
+
+
 -- degenerate cases where the box is a line or a point
 -- note that lines and points boxes all have zero area
 INSERT INTO BOX_TBL (f1) VALUES ('(2.5, 2.5, 2.5,3.5)');
 
 INSERT INTO BOX_TBL (f1) VALUES ('(3.0, 3.0,3.0,3.0)');
 
 -- badly formatted box inputs
 INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
 
+INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+
 INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
 
 
 SELECT '' AS four, * FROM BOX_TBL;
 
 SELECT '' AS four, b.*, area(b.f1) as barea
    FROM BOX_TBL b;
 
 -- overlap
 SELECT '' AS three, b.f1
diff --git a/src/test/regress/sql/circle.sql b/src/test/regress/sql/circle.sql
index c0284b2b59..46c96e1400 100644
--- a/src/test/regress/sql/circle.sql
+++ b/src/test/regress/sql/circle.sql
@@ -7,26 +7,34 @@ CREATE TABLE CIRCLE_TBL (f1 circle);
 INSERT INTO CIRCLE_TBL VALUES ('<(5,1),3>');
 
 INSERT INTO CIRCLE_TBL VALUES ('<(1,2),100>');
 
 INSERT INTO CIRCLE_TBL VALUES ('1,3,5');
 
 INSERT INTO CIRCLE_TBL VALUES ('((1,2),3)');
 
 INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10>');
 
-INSERT INTO CIRCLE_TBL VALUES ('<(100,1),115>');
+INSERT INTO CIRCLE_TBL VALUES (' < ( 100 , 1 ) , 115 > ');
+
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),0>');	-- Zero radius
+
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),NaN>');	-- NaN radius
 
 -- bad values
 
 INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
 
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+
 INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
 
 INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
 
 SELECT * FROM CIRCLE_TBL;
 
 SELECT '' AS six, center(f1) AS center
   FROM CIRCLE_TBL;
 
 SELECT '' AS six, radius(f1) AS radius
diff --git a/src/test/regress/sql/geometry.sql b/src/test/regress/sql/geometry.sql
index 1429ee772a..ce98b3e90c 100644
--- a/src/test/regress/sql/geometry.sql
+++ b/src/test/regress/sql/geometry.sql
@@ -39,74 +39,298 @@ SELECT '' AS two, p1.f1
 -- "is vertical" function
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE isvertical(p1.f1, point '(5.1,34.5)');
 
 -- "is vertical" operator
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?| point '(5.1,34.5)';
 
+-- Slope
+SELECT p1.f1, p2.f1, slope(p1.f1, p2.f1) FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Add point
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Subtract point
+SELECT p1.f1, p2.f1, p1.f1 - p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Multiply with point
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+
+-- Underflow error
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] < 1;
+
+-- Divide by point
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] BETWEEN 1 AND 1000;
+
+-- Overflow error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] > 1000;
+
+-- Division by 0 error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1 ~= '(0,0)'::point;
+
+-- Distance to line
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LINE_TBL l;
+
+-- Distance to line segment
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LSEG_TBL l;
+
+-- Distance to box
+SELECT p.f1, b.f1, p.f1 <-> b.f1 FROM POINT_TBL p, BOX_TBL b;
+
+-- Distance to path
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, PATH_TBL p1;
+
+-- Distance to polygon
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, POLYGON_TBL p1;
+
+-- Closest point to line
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LINE_TBL l;
+
+-- Closest point to line segment
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LSEG_TBL l;
+
+-- Closest point to box
+SELECT p.f1, b.f1, p.f1 ## b.f1 FROM POINT_TBL p, BOX_TBL b;
+
+-- On line
+SELECT p.f1, l.s FROM POINT_TBL p, LINE_TBL l WHERE p.f1 <@ l.s;
+
+-- On line segment
+SELECT p.f1, l.s FROM POINT_TBL p, LSEG_TBL l WHERE p.f1 <@ l.s;
+
+-- On path
+SELECT p.f1, p1.f1 FROM POINT_TBL p, PATH_TBL p1 WHERE p.f1 <@ p1.f1;
+
+--
+-- Lines
+--
+
+-- Vertical
+SELECT s FROM LINE_TBL WHERE ?| s;
+
+-- Horizontal
+SELECT s FROM LINE_TBL WHERE ?- s;
+
+-- Same as line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s = l2.s;
+
+-- Parallel to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?|| l2.s;
+
+-- Perpendicular to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?-| l2.s;
+
+-- Distance to line
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2;
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LINE_TBL l, BOX_TBL b;
+
+-- Intersect with line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?# l2.s;
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LINE_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+
+-- Intersection point with line
+SELECT l1.s, l2.s, l1.s # l2.s FROM LINE_TBL l1, LINE_TBL l2;
+
+-- Closest point to line segment
+SELECT l.s, l1.s, l.s ## l1.s FROM LINE_TBL l, LSEG_TBL l1;
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LINE_TBL l, BOX_TBL b;
+
 --
 -- Line segments
 --
 
 -- intersection
 SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
    FROM LSEG_TBL l, POINT_TBL p;
 
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
+-- Length
+SELECT s, @-@ s FROM LSEG_TBL;
+
+-- Vertical
+SELECT s FROM LSEG_TBL WHERE ?| s;
+
+-- Horizontal
+SELECT s FROM LSEG_TBL WHERE ?- s;
+
+-- Center
+SELECT s, @@ s FROM LSEG_TBL;
+
+-- To point
+SELECT s, s::point FROM LSEG_TBL;
+
+-- Has points less than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s < l2.s;
+
+-- Has points less than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s <= l2.s;
+
+-- Has points equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s = l2.s;
+
+-- Has points greater than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s >= l2.s;
+
+-- Has points greater than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s > l2.s;
+
+-- Has points not equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s != l2.s;
+
+-- Parallel with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?|| l2.s;
+
+-- Perpendicular with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?-| l2.s;
+
+-- Distance to line
+SELECT l.s, l1.s, l.s <-> l1.s FROM LSEG_TBL l, LINE_TBL l1;
+
+-- Distance to line segment
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LSEG_TBL l, BOX_TBL b;
+
+-- Intersect with line segment
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s ?# l1.s;
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+
+-- Intersection point with line segment
+SELECT l1.s, l2.s, l1.s # l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Closest point to line
+SELECT l.s, l1.s, l.s ## l1.s FROM LSEG_TBL l, LINE_TBL l1;
+
+-- Closest point to line segment
+SELECT l1.s, l2.s, l1.s ## l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LSEG_TBL l, BOX_TBL b;
+
+-- On line
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s <@ l1.s;
+
+-- On box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s <@ b.f1;
 
 --
 -- Boxes
 --
 
 SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
 
 -- translation
 SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
 
 SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
 
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
+-- Multiply with point
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
 
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
+-- Overflow error
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] > 1000;
 
+-- Divide by point
+SELECT b.f1, p.f1, b.f1 / p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+
+-- To box
 SELECT f1::box
 	FROM POINT_TBL;
 
 SELECT bound_box(a.f1, b.f1)
 	FROM BOX_TBL a, BOX_TBL b;
 
+-- Below box
+SELECT b1.f1, b2.f1, b1.f1 <^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Above box
+SELECT b1.f1, b2.f1, b1.f1 >^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Intersection point with box
+SELECT b1.f1, b2.f1, b1.f1 # b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Diagonal
+SELECT f1, diagonal(f1) FROM BOX_TBL;
+
+-- Distance to box
+SELECT b1.f1, b2.f1, b1.f1 <-> b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
 --
 -- Paths
 --
 
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
+-- Points
+SELECT f1, npoints(f1) FROM PATH_TBL;
 
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
+-- Area
+SELECT f1, area(f1) FROM PATH_TBL;
 
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
+-- Length
+SELECT f1, @-@ f1 FROM PATH_TBL;
 
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
+-- Center
+SELECT f1, @@ f1 FROM PATH_TBL;
+
+-- To polygon
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isclosed(f1);
+
+-- Open path cannot be converted to polygon error
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isopen(f1);
+
+-- Has points less than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 < p2.f1;
+
+-- Has points less than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 <= p2.f1;
+
+-- Has points equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 = p2.f1;
+
+-- Has points greater than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 >= p2.f1;
+
+-- Has points greater than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 > p2.f1;
+
+-- Add path
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+
+-- Add point
+SELECT p.f1, p1.f1, p.f1 + p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+
+-- Subtract point
+SELECT p.f1, p1.f1, p.f1 - p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+
+-- Multiply with point
+SELECT p.f1, p1.f1, p.f1 * p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+
+-- Divide by point
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+
+-- Division by 0 error
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1 ~= '(0,0)'::point;
+
+-- Distance to path
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
 
 --
 -- Polygons
 --
 
 -- containment
 SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
    FROM POLYGON_TBL poly, POINT_TBL p;
 
 SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
@@ -118,36 +342,166 @@ SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
 SELECT '' AS four, polygon(f1)
    FROM BOX_TBL;
 
 SELECT '' AS four, polygon(f1)
    FROM PATH_TBL WHERE isclosed(f1);
 
 SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
    FROM PATH_TBL
    WHERE isopen(f1);
 
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
+-- To box
+SELECT f1, f1::box FROM POLYGON_TBL;
 
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
+-- To path
+SELECT f1, f1::path FROM POLYGON_TBL;
+
+-- Same as polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 ~= p2.f1;
+
+-- Contained by polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <@ p2.f1;
+
+-- Contains polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 @> p2.f1;
+
+-- Overlap with polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 && p2.f1;
+
+-- Left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 << p2.f1;
+
+-- Overlap of left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &< p2.f1;
+
+-- Right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 >> p2.f1;
+
+-- Overlap of right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &> p2.f1;
+
+-- Below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <<| p2.f1;
+
+-- Overlap or below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &<| p2.f1;
+
+-- Above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |>> p2.f1;
+
+-- Overlap or above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |&> p2.f1;
+
+-- Distance to polygon
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2;
 
 --
 -- Circles
 --
 
 SELECT '' AS six, circle(f1, 50.0)
    FROM POINT_TBL;
 
 SELECT '' AS four, circle(f1)
    FROM BOX_TBL;
 
 SELECT '' AS two, circle(f1)
    FROM POLYGON_TBL
    WHERE (# f1) >= 3;
 
 SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
    FROM CIRCLE_TBL c1, POINT_TBL p1
    WHERE (p1.f1 <-> c1.f1) > 0
    ORDER BY distance, area(c1.f1), p1.f1[0];
+
+-- To polygon
+SELECT f1, f1::polygon FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+
+-- To polygon with less points
+SELECT f1, polygon(8, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+
+-- Too less points error
+SELECT f1, polygon(1, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+
+-- Zero radius error
+SELECT f1, polygon(10, f1) FROM CIRCLE_TBL WHERE f1 < '<(0,0),1>';
+
+-- Same as circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 ~= c2.f1;
+
+-- Overlap with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 && c2.f1;
+
+-- Overlap or left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &< c2.f1;
+
+-- Left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 << c2.f1;
+
+-- Right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >> c2.f1;
+
+-- Overlap or right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &> c2.f1;
+
+-- Contained by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <@ c2.f1;
+
+-- Contain by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 @> c2.f1;
+
+-- Below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <<| c2.f1;
+
+-- Above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |>> c2.f1;
+
+-- Overlap or below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &<| c2.f1;
+
+-- Overlap or above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |&> c2.f1;
+
+-- Area equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 = c2.f1;
+
+-- Area not equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 != c2.f1;
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 > c2.f1;
+
+-- Area less than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <= c2.f1;
+
+-- Area greater than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >= c2.f1;
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+
+-- Add point
+SELECT c.f1, p.f1, c.f1 + p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Subtract point
+SELECT c.f1, p.f1, c.f1 - p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Multiply with point
+SELECT c.f1, p.f1, c.f1 * p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Divide by point
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+
+-- Overflow error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] > 1000;
+
+-- Division by 0 error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1 ~= '(0,0)'::point;
+
+-- Distance to polygon
+SELECT c.f1, p.f1, c.f1 <-> p.f1 FROM CIRCLE_TBL c, POLYGON_TBL p;
diff --git a/src/test/regress/sql/line.sql b/src/test/regress/sql/line.sql
index 94067b0cee..f589ffecc8 100644
--- a/src/test/regress/sql/line.sql
+++ b/src/test/regress/sql/line.sql
@@ -1,87 +1,42 @@
 --
 -- LINE
 -- Infinite lines
 --
 
 --DROP TABLE LINE_TBL;
 CREATE TABLE LINE_TBL (s line);
 
-INSERT INTO LINE_TBL VALUES ('{1,-1,1}');
-INSERT INTO LINE_TBL VALUES ('(0,0),(6,6)');
+INSERT INTO LINE_TBL VALUES ('{0,-1,5}');	-- A == 0
+INSERT INTO LINE_TBL VALUES ('{1,0,5}');	-- B == 0
+INSERT INTO LINE_TBL VALUES ('{0,3,0}');	-- A == C == 0
+INSERT INTO LINE_TBL VALUES (' (0,0), (6,6)');
 INSERT INTO LINE_TBL VALUES ('10,-10 ,-5,-4');
 INSERT INTO LINE_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LINE_TBL VALUES ('(11,22,33,44)');
 
-INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
+INSERT INTO LINE_TBL VALUES ('{3,NaN,5}');
+INSERT INTO LINE_TBL VALUES ('{NaN,NaN,NaN}');
 
 -- horizontal
 INSERT INTO LINE_TBL VALUES ('[(1,3),(2,3)]');
 -- vertical
-INSERT INTO LINE_TBL VALUES ('[(3,1),(3,2)]');
+INSERT INTO LINE_TBL VALUES (line(point '(3,1)', point '(3,2)'));
 
 -- bad values for parser testing
+INSERT INTO LINE_TBL VALUES ('{}');
+INSERT INTO LINE_TBL VALUES ('{0');
+INSERT INTO LINE_TBL VALUES ('{0,0}');
+INSERT INTO LINE_TBL VALUES ('{0,0,1');
 INSERT INTO LINE_TBL VALUES ('{0,0,1}');
+INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
 INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
 INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
 INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
 INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
+INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
+
+INSERT INTO LINE_TBL VALUES (line(point '(1,0)', point '(1,0)'));
 
 select * from LINE_TBL;
 
-
--- functions and operators
-
-SELECT * FROM LINE_TBL WHERE (s <-> line '[(1,2),(3,4)]') < 10;
-
-SELECT * FROM LINE_TBL WHERE (point '(0.1,0.1)' <-> s) < 1;
-
-SELECT * FROM LINE_TBL WHERE (lseg '[(0.1,0.1),(0.2,0.2)]' <-> s) < 1;
-
-SELECT line '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
-SELECT lseg '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
-SELECT point '(-1,1)' <-> line '[(-3,0),(-4,0)]';
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(2,0),(0,2)]';  -- true
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(0,0),(1,0)]';  -- false
-
-SELECT line '[(0,0),(1,1)]' ?# box '(0,0,2,2)';  -- true
-SELECT line '[(3,0),(4,1)]' ?# box '(0,0,2,2)';  -- false
-
-SELECT point '(1,1)' <@ line '[(0,0),(2,2)]';  -- true
-SELECT point '(1,1)' <@ line '[(0,0),(1,0)]';  -- false
-
-SELECT point '(1,1)' @ line '[(0,0),(2,2)]';  -- true
-SELECT point '(1,1)' @ line '[(0,0),(1,0)]';  -- false
-
-SELECT lseg '[(1,1),(2,2)]' <@ line '[(0,0),(2,2)]';  -- true
-SELECT lseg '[(1,1),(2,1)]' <@ line '[(0,0),(1,0)]';  -- false
-
-SELECT lseg '[(1,1),(2,2)]' @ line '[(0,0),(2,2)]';  -- true
-SELECT lseg '[(1,1),(2,1)]' @ line '[(0,0),(1,0)]';  -- false
-
-SELECT point '(0,1)' ## line '[(0,0),(1,1)]';
-
-SELECT line '[(0,0),(1,1)]' ## lseg '[(1,0),(2,0)]';
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(2,1)]';  -- false
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(1,1)]';  -- true
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(2,1)]';
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(1,1)]';
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(2,1)]';  -- true
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(1,1)]';  -- false
-
-SELECT line '[(0,0),(1,0)]' ?-| line '[(0,0),(0,1)]';  -- true
-SELECT line '[(0,0),(1,1)]' ?-| line '[(1,0),(1,1)]';  -- false
-
-SELECT ?- line '[(0,0),(1,0)]';  -- true
-SELECT ?- line '[(0,0),(1,1)]';  -- false
-
-SELECT ?| line '[(0,0),(0,1)]';  -- true
-SELECT ?| line '[(0,0),(1,1)]';  -- false
-
-SELECT line(point '(1,2)', point '(3,4)');
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,5)]';  -- true
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,4)]';  -- false
+select '{nan, 1, nan}'::line = '{nan, 1, nan}'::line as true,
+	   '{nan, 1, nan}'::line = '{nan, 2, nan}'::line as false;
diff --git a/src/test/regress/sql/lseg.sql b/src/test/regress/sql/lseg.sql
index 07c5a29e0a..f266ca3e09 100644
--- a/src/test/regress/sql/lseg.sql
+++ b/src/test/regress/sql/lseg.sql
@@ -3,23 +3,22 @@
 -- Line segments
 --
 
 --DROP TABLE LSEG_TBL;
 CREATE TABLE LSEG_TBL (s lseg);
 
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('(0,0),(6,6)');
 INSERT INTO LSEG_TBL VALUES ('10,-10 ,-3,-4');
 INSERT INTO LSEG_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LSEG_TBL VALUES ('(11,22,33,44)');
+INSERT INTO LSEG_TBL VALUES (lseg(point(11, 22), point(33,44)));
+INSERT INTO LSEG_TBL VALUES ('[(-10,2),(-10,3)]');	-- vertical
+INSERT INTO LSEG_TBL VALUES ('[(0,-20),(30,-20)]');	-- horizontal
+INSERT INTO LSEG_TBL VALUES ('[(NaN,1),(NaN,90)]');	-- NaN
 
 -- bad values for parser testing
 INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
 INSERT INTO LSEG_TBL VALUES ('[1,2,3, 4');
 INSERT INTO LSEG_TBL VALUES ('[(,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)');
 
 select * from LSEG_TBL;
-
-SELECT * FROM LSEG_TBL WHERE s <= lseg '[(1,2),(3,4)]';
-
-SELECT * FROM LSEG_TBL WHERE (s <-> lseg '[(1,2),(3,4)]') < 10;
diff --git a/src/test/regress/sql/path.sql b/src/test/regress/sql/path.sql
index 7e69b539ad..318decf974 100644
--- a/src/test/regress/sql/path.sql
+++ b/src/test/regress/sql/path.sql
@@ -1,38 +1,44 @@
 --
 -- PATH
 --
 
 --DROP TABLE PATH_TBL;
 
 CREATE TABLE PATH_TBL (f1 path);
 
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)]');
 
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
+INSERT INTO PATH_TBL VALUES (' ( ( 1 , 2 ) , ( 3 , 4 ) ) ');
 
-INSERT INTO PATH_TBL VALUES ('[(0,0),(3,0),(4,5),(1,6)]');
+INSERT INTO PATH_TBL VALUES ('[ (0,0),(3,0),(4,5),(1,6) ]');
 
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
+INSERT INTO PATH_TBL VALUES ('((1,2) ,(3,4 ))');
 
-INSERT INTO PATH_TBL VALUES ('1,2 ,3,4');
+INSERT INTO PATH_TBL VALUES ('1,2 ,3,4 ');
 
-INSERT INTO PATH_TBL VALUES ('[1,2,3, 4]');
+INSERT INTO PATH_TBL VALUES (' [1,2,3, 4] ');
 
-INSERT INTO PATH_TBL VALUES ('[11,12,13,14]');
+INSERT INTO PATH_TBL VALUES ('((10,20))');	-- Only one point
 
-INSERT INTO PATH_TBL VALUES ('(11,12,13,14)');
+INSERT INTO PATH_TBL VALUES ('[ 11,12,13,14 ]');
+
+INSERT INTO PATH_TBL VALUES ('( 11,12,13,14) ');
 
 -- bad values for parser testing
+INSERT INTO PATH_TBL VALUES ('[]');
+
 INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
 
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
 
-SELECT f1 FROM PATH_TBL;
+INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+
+INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
 
 SELECT '' AS count, f1 AS open_path FROM PATH_TBL WHERE isopen(f1);
 
 SELECT '' AS count, f1 AS closed_path FROM PATH_TBL WHERE isclosed(f1);
 
 SELECT '' AS count, pclose(f1) AS closed_path FROM PATH_TBL;
 
 SELECT '' AS count, popen(f1) AS open_path FROM PATH_TBL;
diff --git a/src/test/regress/sql/point.sql b/src/test/regress/sql/point.sql
index 63a803a809..a209f3bfeb 100644
--- a/src/test/regress/sql/point.sql
+++ b/src/test/regress/sql/point.sql
@@ -7,29 +7,39 @@ CREATE TABLE POINT_TBL(f1 point);
 INSERT INTO POINT_TBL(f1) VALUES ('(0.0,0.0)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-10.0,0.0)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-3.0,4.0)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(5.1, 34.5)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-5.0,-12.0)');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(1e-300,-1e-300)');	-- To underflow
+
+INSERT INTO POINT_TBL(f1) VALUES ('(1e+300,Inf)');		-- To overflow
+
+INSERT INTO POINT_TBL(f1) VALUES (' ( Nan , NaN ) ');
+
 -- bad format points
 INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
 
 INSERT INTO POINT_TBL(f1) VALUES ('10.0,10.0');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');	-- Out of range
+
 
 SELECT '' AS six, * FROM POINT_TBL;
 
 -- left of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE p.f1 << '(0.0, 0.0)';
 
 -- right of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE '(0.0,0.0)' >> p.f1;
 
 -- above
diff --git a/src/test/regress/sql/polygon.sql b/src/test/regress/sql/polygon.sql
index 7e8cb08cd8..d3d2fe3457 100644
--- a/src/test/regress/sql/polygon.sql
+++ b/src/test/regress/sql/polygon.sql
@@ -4,126 +4,43 @@
 -- polygon logic
 --
 
 CREATE TABLE POLYGON_TBL(f1 polygon);
 
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(2.0,0.0),(2.0,4.0),(0.0,0.0)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(3.0,1.0),(3.0,3.0),(1.0,0.0)');
 
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(3,4),(5,6),(7,8)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(7,8),(5,6),(3,4),(1,2)'); -- Reverse
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(7,8),(5,6),(3,-4)');
+
 -- degenerate polygons
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,0.0)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,1.0),(0.0,1.0)');
 
 -- bad polygon input strings
 INSERT INTO POLYGON_TBL(f1) VALUES ('0.0');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0 0.0');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2,3');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
 
 
 SELECT '' AS four, * FROM POLYGON_TBL;
 
--- overlap
-SELECT '' AS three, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 && '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- left overlap
-SELECT '' AS four, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &< '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- right overlap
-SELECT '' AS two, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- left of
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 << '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- right of
-SELECT '' AS zero, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 >> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- contained
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- same
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- contains
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
---
--- polygon logic
---
--- left of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- left overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
-
--- right overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' &> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- right of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' >> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- contained in
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- contains
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "false";
-
-SELECT '((0,4),(6,4),(3,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
-
-SELECT '((1,1),(1,4),(5,4),(5,3),(2,3),(2,2),(5,2),(5,1))'::polygon @> '((3,2),(3,3),(4,3),(4,2))'::polygon AS "false";
-
-SELECT '((0,0),(0,3),(3,3),(3,0))'::polygon @> '((2,1),(2,2),(3,2),(3,1))'::polygon AS "true";
-
--- same
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' && polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon && '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
-
-SELECT '((1,4),(1,1),(4,1),(4,2),(2,2),(2,4),(1,4))'::polygon && '((3,3),(4,3),(4,4),(3,4),(3,3))'::polygon AS "false";
-SELECT '((200,800),(800,800),(800,200),(200,200))' &&  '(1000,1000,0,0)'::polygon AS "true";
-
--- distance from a point
-SELECT	'(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
-	'(1,1)'::point <-> '((0,0),(2,2),(1,3))'::polygon as on_segment,
-	'(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;
-- 
2.14.3 (Apple Git-98)

#70Emre Hasegeli
emre@hasegeli.com
In reply to: Emre Hasegeli (#69)
6 attachment(s)
Re: [PATCH] Improve geometric types

New versions are attached after the <float.h> patch got in. I noticed
tests failing on Windows [1]https://ci.appveyor.com/project/postgresql-cfbot/postgresql/build/1.0.5235 and added alternative .out file.

[1]: https://ci.appveyor.com/project/postgresql-cfbot/postgresql/build/1.0.5235

Attachments:

0001-geo-funcs-v11.patchapplication/octet-stream; name=0001-geo-funcs-v11.patchDownload
From 013c00a7c8ae183e0f787d50cca98e1d238428c7 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 27 May 2017 11:27:18 -0400
Subject: [PATCH 1/6] geo-funcs-v11

Refactor geometric functions and operators code

Most of the geometric types were not using functions of each other's.
I believe the reason behind this is simpler types line point and line
being developed after more complicated ones.  This patch reduces
duplicate code and makes functions of different datatypes more
compatible.  The changes can be summarised as:

* Eliminate SQL level function calls
* Re-use more functions to implement others
* Unify internal function names and signatures
* Remove private functions from geo_decls.h
* Replace not-possible checks with Assert()
* Add comments to describe some functions
* Remove some unreachable code
* Define delimiter symbols of line datatype like the other ones
* Remove debugging print()s from the refactored functions
* Unify code style of a few oddly formatted lines

This commits aims to not cause any user visible changes, but it is
almost impossible to stay completely bug-compatible with the old code.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com
---
 src/backend/utils/adt/geo_ops.c    | 1908 +++++++++++++++++-------------------
 src/backend/utils/adt/geo_spgist.c |    3 +-
 src/include/utils/geo_decls.h      |    4 -
 src/test/regress/regress.c         |    7 +-
 4 files changed, 883 insertions(+), 1039 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index f57380a4df..3e7519015d 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -31,75 +31,104 @@
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
+/* Routines for points */
+static inline void point_construct(Point *result, float8 x, float8 y);
+static inline void point_add_point(Point *result, Point *pt1, Point *pt2);
+static inline void point_sub_point(Point *result, Point *pt1, Point *pt2);
+static inline void point_mul_point(Point *result, Point *pt1, Point *pt2);
+static inline void point_div_point(Point *result, Point *pt1, Point *pt2);
+static inline bool point_eq_point(Point *pt1, Point *pt2);
+static inline float8 point_dt(Point *pt1, Point *pt2);
+static inline float8 point_sl(Point *pt1, Point *pt2);
 static int	point_inside(Point *p, int npts, Point *plist);
+
+/* Routines for lines */
+static inline void line_construct(LINE *result, Point *pt, float8 m);
+static inline float8 line_invsl(LINE *line);
+static bool	line_interpt_line(Point *result, LINE *l1, LINE *l2);
+static bool line_contain_point(LINE *line, Point *point);
+static float8 line_closept_point(Point *result, LINE *line, Point *pt);
+
+/* Routines for line segments */
+static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
+static inline float8 lseg_sl(LSEG *lseg);
+static inline float8 lseg_invsl(LSEG *lseg);
+static bool	lseg_interpt_line(Point *result, LSEG *lseg, LINE *line);
+static bool	lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2);
 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_fill(BOX *result, double x1, double x2, double y1, double y2);
+static bool	lseg_contain_point(LSEG *lseg, Point *point);
+static float8 lseg_closept_point(Point *result, LSEG *lseg, Point *pt);
+static float8 lseg_closept_line(Point *result, LSEG *lseg, LINE *line);
+static float8 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2);
+
+/* Routines for boxes */
+static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
+static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
+static double box_ar(BOX *box);
 static double box_ht(BOX *box);
 static double box_wd(BOX *box);
+static bool box_contain_point(BOX *box, Point *point);
+static bool box_contain_box(BOX *box1, BOX *box2);
+static bool box_contain_lseg(BOX *box, LSEG *lseg);
+static bool box_interpt_lseg(Point *result, BOX *box, LSEG *lseg);
+static float8 box_closept_point(Point *result, BOX *box, Point *point);
+static float8 box_closept_lseg(Point *result, BOX *box, LSEG *lseg);
+
+/* Routines for circles */
 static double circle_ar(CIRCLE *circle);
-static CIRCLE *circle_copy(CIRCLE *circle);
-static LINE *line_construct_pm(Point *pt, double m);
-static void line_construct_pts(LINE *line, Point *pt1, Point *pt2);
-static bool lseg_intersect_internal(LSEG *l1, LSEG *l2);
-static double lseg_dt(LSEG *l1, LSEG *l2);
-static bool on_ps_internal(Point *pt, LSEG *lseg);
+
+/* Routines for polygons */
 static void make_bound_box(POLYGON *poly);
+static void poly_to_circle(CIRCLE *result, POLYGON *poly);
+static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
+static bool poly_contain_poly(POLYGON *polya, POLYGON *polyb);
 static bool plist_same(int npts, Point *p1, Point *p2);
-static Point *point_construct(double x, double y);
-static Point *point_copy(Point *pt);
+static float8 dist_ppoly_internal(Point *pt, POLYGON *poly);
+
+/* Routines for encoding and decoding */
 static double single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
 static void pair_decode(char *str, double *x, double *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
 static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
-static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
-static double box_ar(BOX *box);
-static void box_cn(Point *center, BOX *box);
-static Point *interpt_sl(LSEG *lseg, LINE *line);
-static bool has_interpt_sl(LSEG *lseg, LINE *line);
-static double dist_pl_internal(Point *pt, LINE *line);
-static double dist_ps_internal(Point *pt, LSEG *lseg);
-static Point *line_interpt_internal(LINE *l1, LINE *l2);
-static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
-static Point *lseg_interpt_internal(LSEG *l1, LSEG *l2);
-static double dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 
 /*
  * Delimiters for input and output strings.
  * LDELIM, RDELIM, and DELIM are left, right, and separator delimiters, respectively.
  * LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints.
  */
 
 #define LDELIM			'('
 #define RDELIM			')'
 #define DELIM			','
 #define LDELIM_EP		'['
 #define RDELIM_EP		']'
 #define LDELIM_C		'<'
 #define RDELIM_C		'>'
+#define LDELIM_L		'{'
+#define RDELIM_L		'}'
 
 
 /*
  * Geometric data types are composed of points.
  * This code tries to support a common format throughout the data types,
  *	to allow for more predictable usage and data type conversion.
  * The fundamental unit is the point. Other units are line segments,
  *	open paths, boxes, closed paths, and polygons (which should be considered
  *	non-intersecting closed paths).
  *
@@ -229,26 +258,23 @@ path_decode(char *str, bool opentype, int npts, Point *p,
 	}
 
 	for (i = 0; i < npts; i++)
 	{
 		pair_decode(str, &(p->x), &(p->y), &str, type_name, orig_string);
 		if (*str == DELIM)
 			str++;
 		p++;
 	}
 
-	while (isspace((unsigned char) *str))
-		str++;
 	while (depth > 0)
 	{
-		if ((*str == RDELIM)
-			|| ((*str == RDELIM_EP) && (*isopen) && (depth == 1)))
+		if (*str == RDELIM || (*str == RDELIM_EP && *isopen && depth == 1))
 		{
 			depth--;
 			str++;
 			while (isspace((unsigned char) *str))
 				str++;
 		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
@@ -433,89 +459,61 @@ box_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, box->high.x);
 	pq_sendfloat8(&buf, box->high.y);
 	pq_sendfloat8(&buf, box->low.x);
 	pq_sendfloat8(&buf, box->low.y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*		box_construct	-		fill in a new box.
  */
-static BOX *
-box_construct(double x1, double x2, double y1, double y2)
+static inline void
+box_construct(BOX *result, Point *pt1, Point *pt2)
 {
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	return box_fill(result, x1, x2, y1, y2);
-}
-
-
-/*		box_fill		-		fill in a given box struct
- */
-static BOX *
-box_fill(BOX *result, double x1, double x2, double y1, double y2)
-{
-	if (x1 > x2)
+	if (pt1->x > pt2->x)
 	{
-		result->high.x = x1;
-		result->low.x = x2;
+		result->high.x = pt1->x;
+		result->low.x = pt2->x;
 	}
 	else
 	{
-		result->high.x = x2;
-		result->low.x = x1;
+		result->high.x = pt2->x;
+		result->low.x = pt1->x;
 	}
-	if (y1 > y2)
+	if (pt1->y > pt2->y)
 	{
-		result->high.y = y1;
-		result->low.y = y2;
+		result->high.y = pt1->y;
+		result->low.y = pt2->y;
 	}
 	else
 	{
-		result->high.y = y2;
-		result->low.y = y1;
+		result->high.y = pt2->y;
+		result->low.y = pt1->y;
 	}
-
-	return result;
-}
-
-
-/*		box_copy		-		copy a box
- */
-BOX *
-box_copy(BOX *box)
-{
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	memcpy((char *) result, (char *) box, sizeof(BOX));
-
-	return result;
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for BOXes.
  *		<, >, <=, >=, and == are based on box area.
  *---------------------------------------------------------*/
 
 /*		box_same		-		are two boxes identical?
  */
 Datum
 box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPeq(box1->high.x, box2->high.x) &&
-				   FPeq(box1->low.x, box2->low.x) &&
-				   FPeq(box1->high.y, box2->high.y) &&
-				   FPeq(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(point_eq_point(&box1->high, &box2->high) &&
+				   point_eq_point(&box1->low, &box2->low));
 }
 
 /*		box_overlap		-		does box1 overlap box2?
  */
 Datum
 box_overlap(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
@@ -630,38 +628,44 @@ box_overabove(PG_FUNCTION_ARGS)
 }
 
 /*		box_contained	-		is box1 contained by box2?
  */
 Datum
 box_contained(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPle(box1->high.x, box2->high.x) &&
-				   FPge(box1->low.x, box2->low.x) &&
-				   FPle(box1->high.y, box2->high.y) &&
-				   FPge(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(box_contain_box(box2, box1));
 }
 
 /*		box_contain		-		does box1 contain box2?
  */
 Datum
 box_contain(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPge(box1->high.x, box2->high.x) &&
-				   FPle(box1->low.x, box2->low.x) &&
-				   FPge(box1->high.y, box2->high.y) &&
-				   FPle(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(box_contain_box(box1, box2));
+}
+
+/*
+ * Check whether the box is in the box or on its border
+ */
+static bool
+box_contain_box(BOX *box1, BOX *box2)
+{
+	return FPge(box1->high.x, box2->high.x) &&
+		   FPle(box1->low.x, box2->low.x) &&
+		   FPge(box1->high.y, box2->high.y) &&
+		   FPle(box1->low.y, box2->low.y);
 }
 
 
 /*		box_positionop	-
  *				is box1 entirely {above,below} box2?
  *
  * box_below_eq and box_above_eq are obsolete versions that (probably
  * erroneously) accept the equal-boundaries case.  Since these are not
  * in sync with the box_left and box_right code, they are deprecated and
  * not supported in the PG 8.1 rtree operator class extension.
@@ -750,51 +754,51 @@ box_area(PG_FUNCTION_ARGS)
 
 
 /*		box_width		-		returns the width of the box
  *								  (horizontal magnitude).
  */
 Datum
 box_width(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.x - box->low.x);
+	PG_RETURN_FLOAT8(box_wd(box));
 }
 
 
 /*		box_height		-		returns the height of the box
  *								  (vertical magnitude).
  */
 Datum
 box_height(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.y - box->low.y);
+	PG_RETURN_FLOAT8(box_ht(box));
 }
 
 
 /*		box_distance	-		returns the distance between the
  *								  center points of two boxes.
  */
 Datum
 box_distance(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 	Point		a,
 				b;
 
 	box_cn(&a, box1);
 	box_cn(&b, box2);
 
-	PG_RETURN_FLOAT8(HYPOT(a.x - b.x, a.y - b.y));
+	PG_RETURN_FLOAT8(point_dt(&a, &b));
 }
 
 
 /*		box_center		-		returns the center point of the box.
  */
 Datum
 box_center(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *result = (Point *) palloc(sizeof(Point));
@@ -898,76 +902,77 @@ static bool
 line_decode(char *s, const char *str, LINE *line)
 {
 	/* s was already advanced over leading '{' */
 	line->A = single_decode(s, &s, "line", str);
 	if (*s++ != DELIM)
 		return false;
 	line->B = single_decode(s, &s, "line", str);
 	if (*s++ != DELIM)
 		return false;
 	line->C = single_decode(s, &s, "line", str);
-	if (*s++ != '}')
+	if (*s++ != RDELIM_L)
 		return false;
 	while (isspace((unsigned char) *s))
 		s++;
 	if (*s != '\0')
 		return false;
 	return true;
 }
 
 Datum
 line_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	LINE	   *line = (LINE *) palloc(sizeof(LINE));
 	LSEG		lseg;
 	bool		isopen;
 	char	   *s;
 
 	s = str;
 	while (isspace((unsigned char) *s))
 		s++;
-	if (*s == '{')
+	if (*s == LDELIM_L)
 	{
 		if (!line_decode(s + 1, str, line))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
 							"line", str)));
 		if (FPzero(line->A) && FPzero(line->B))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: A and B cannot both be zero")));
 	}
 	else
 	{
-		path_decode(s, true, 2, &(lseg.p[0]), &isopen, NULL, "line", str);
-		if (FPeq(lseg.p[0].x, lseg.p[1].x) && FPeq(lseg.p[0].y, lseg.p[1].y))
+		path_decode(s, true, 2, &lseg.p[0], &isopen, NULL, "line", str);
+		if (point_eq_point(&lseg.p[0], &lseg.p[1]))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: must be two distinct points")));
-		line_construct_pts(line, &lseg.p[0], &lseg.p[1]);
+		line_construct(line, &lseg.p[0], lseg_sl(&lseg));
 	}
 
 	PG_RETURN_LINE_P(line);
 }
 
 
 Datum
 line_out(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	char	   *astr = float8out_internal(line->A);
 	char	   *bstr = float8out_internal(line->B);
 	char	   *cstr = float8out_internal(line->C);
 
-	PG_RETURN_CSTRING(psprintf("{%s,%s,%s}", astr, bstr, cstr));
+	PG_RETURN_CSTRING(psprintf("%c%s%c%s%c%s%c", LDELIM_L, astr, DELIM, bstr,
+							   DELIM, cstr, RDELIM_L));
 }
 
 /*
  *		line_recv			- converts external binary format to line
  */
 Datum
 line_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LINE	   *line;
@@ -996,128 +1001,78 @@ line_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, line->C);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*----------------------------------------------------------
  *	Conversion routines from one line formula to internal.
  *		Internal form:	Ax+By+C=0
  *---------------------------------------------------------*/
 
-/* line_construct_pm()
- * point-slope
+/*
+ * Fill already-allocated LINE struct from the point and the slope
  */
-static LINE *
-line_construct_pm(Point *pt, double m)
+static inline void
+line_construct(LINE *result, Point *pt, float8 m)
 {
-	LINE	   *result = (LINE *) palloc(sizeof(LINE));
-
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
 		result->A = -1;
 		result->B = 0;
 		result->C = pt->x;
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
 		result->C = pt->y - m * pt->x;
 	}
-
-	return result;
-}
-
-/*
- * Fill already-allocated LINE struct from two points on the line
- */
-static void
-line_construct_pts(LINE *line, Point *pt1, Point *pt2)
-{
-	if (FPeq(pt1->x, pt2->x))
-	{							/* vertical */
-		/* use "x = C" */
-		line->A = -1;
-		line->B = 0;
-		line->C = pt1->x;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is vertical\n");
-#endif
-	}
-	else if (FPeq(pt1->y, pt2->y))
-	{							/* horizontal */
-		/* use "y = C" */
-		line->A = 0;
-		line->B = -1;
-		line->C = pt1->y;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is horizontal\n");
-#endif
-	}
-	else
-	{
-		/* use "mx - y + yinter = 0" */
-		line->A = (pt2->y - pt1->y) / (pt2->x - pt1->x);
-		line->B = -1.0;
-		line->C = pt1->y - line->A * pt1->x;
-		/* on some platforms, the preceding expression tends to produce -0 */
-		if (line->C == 0.0)
-			line->C = 0.0;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is neither vertical nor horizontal (diffs x=%.*g, y=%.*g\n",
-			   DBL_DIG, (pt2->x - pt1->x), DBL_DIG, (pt2->y - pt1->y));
-#endif
-	}
 }
 
 /* line_construct_pp()
  * two points
  */
 Datum
 line_construct_pp(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 	LINE	   *result = (LINE *) palloc(sizeof(LINE));
 
-	line_construct_pts(result, pt1, pt2);
+	line_construct(result, pt1, point_sl(pt1, pt2));
+
 	PG_RETURN_LINE_P(result);
 }
 
 
 /*----------------------------------------------------------
  *	Relative position routines.
  *---------------------------------------------------------*/
 
 Datum
 line_intersect(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(!DatumGetBool(DirectFunctionCall2(line_parallel,
-													 LinePGetDatum(l1),
-													 LinePGetDatum(l2))));
+	PG_RETURN_BOOL(line_interpt_line(NULL, l1, l2));
 }
 
 Datum
 line_parallel(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
-	if (FPzero(l1->B))
-		PG_RETURN_BOOL(FPzero(l2->B));
-
-	PG_RETURN_BOOL(FPeq(l2->A, l1->A * (l2->B / l1->B)));
+	PG_RETURN_BOOL(!line_interpt_line(NULL, l1, l2));
 }
 
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
@@ -1162,105 +1117,114 @@ line_eq(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(FPeq(l1->A, k * l2->A) &&
 				   FPeq(l1->B, k * l2->B) &&
 				   FPeq(l1->C, k * l2->C));
 }
 
 
 /*----------------------------------------------------------
  *	Line arithmetic routines.
  *---------------------------------------------------------*/
 
+/*
+ * Return inverse slope of the line
+ */
+static inline float8
+line_invsl(LINE *line)
+{
+	if (FPzero(line->A))
+		return DBL_MAX;
+	if (FPzero(line->B))
+		return 0.0;
+	return line->B / line->A;
+}
+
+
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
-	Point	   *tmp;
+	Point		tmp;
 
-	if (!DatumGetBool(DirectFunctionCall2(line_parallel,
-										  LinePGetDatum(l1),
-										  LinePGetDatum(l2))))
+	if (line_interpt_line(NULL, l1, l2))	/* intersecting? */
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
 		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
-	tmp = point_construct(0.0, l1->C);
-	result = dist_pl_internal(tmp, l2);
+	point_construct(&tmp, 0.0, l1->C);
+	result = line_closept_point(NULL, l2, &tmp);
 	PG_RETURN_FLOAT8(result);
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
-	result = line_interpt_internal(l1, l2);
+	result = (Point *) palloc(sizeof(Point));
 
-	if (result == NULL)
+	if (!line_interpt_line(result, l1, l2))
 		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
 
 /*
  * Internal version of line_interpt
  *
- * returns a NULL pointer if no intersection point
+ * This returns true if two lines intersect (they do, if they are not
+ * parallel), false if they do not.  This also sets the intersection point
+ * to *result, if it is not NULL.
+ *
+ * NOTE: If the lines are identical then we will find they are parallel
+ * and report "no intersection".  This is a little weird, but since
+ * there's no *unique* intersection, maybe it's appropriate behavior.
  */
-static Point *
-line_interpt_internal(LINE *l1, LINE *l2)
+static bool
+line_interpt_line(Point *result, LINE *l1, LINE *l2)
 {
-	Point	   *result;
 	double		x,
 				y;
 
-	/*
-	 * NOTE: if the lines are identical then we will find they are parallel
-	 * and report "no intersection".  This is a little weird, but since
-	 * there's no *unique* intersection, maybe it's appropriate behavior.
-	 */
-	if (DatumGetBool(DirectFunctionCall2(line_parallel,
-										 LinePGetDatum(l1),
-										 LinePGetDatum(l2))))
-		return NULL;
-
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
+		if (FPzero(l2->B))		/* l2 vertical? */
+			return false;
+
 		x = l1->C;
 		y = (l2->A * x + l2->C);
 	}
 	else if (FPzero(l2->B))		/* l2 vertical? */
 	{
 		x = l2->C;
 		y = (l1->A * x + l1->C);
 	}
 	else
 	{
+		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+			return false;
+
 		x = (l1->C - l2->C) / (l2->A - l1->A);
 		y = (l1->A * x + l1->C);
 	}
-	result = point_construct(x, y);
 
-#ifdef GEODEBUG
-	printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
-		   DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
-	printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
-#endif
+	if (result != NULL)
+		point_construct(result, x, y);
 
-	return result;
+	return true;
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D paths (sequences of line segments, also
  **				called `polylines').
  **
  **				This is not a general package for geometric paths,
  **				which of course include polygons; the emphasis here
@@ -1555,22 +1519,21 @@ path_inter(PG_FUNCTION_ARGS)
 {
 	PATH	   *p1 = PG_GETARG_PATH_P(0);
 	PATH	   *p2 = PG_GETARG_PATH_P(1);
 	BOX			b1,
 				b2;
 	int			i,
 				j;
 	LSEG		seg1,
 				seg2;
 
-	if (p1->npts <= 0 || p2->npts <= 0)
-		PG_RETURN_BOOL(false);
+	Assert(p1->npts > 0 && p2->npts > 0);
 
 	b1.high.x = b1.low.x = p1->p[0].x;
 	b1.high.y = b1.low.y = p1->p[0].y;
 	for (i = 1; i < p1->npts; i++)
 	{
 		b1.high.x = Max(p1->p[i].x, b1.high.x);
 		b1.high.y = Max(p1->p[i].y, b1.high.y);
 		b1.low.x = Min(p1->p[i].x, b1.low.x);
 		b1.low.y = Min(p1->p[i].y, b1.low.y);
 	}
@@ -1608,21 +1571,21 @@ path_inter(PG_FUNCTION_ARGS)
 				jprev = j - 1;
 			else
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
-			if (lseg_intersect_internal(&seg1, &seg2))
+			if (lseg_interpt_lseg(NULL, &seg1, &seg2))
 				PG_RETURN_BOOL(true);
 		}
 	}
 
 	/* if we dropped through, no two segs intersected */
 	PG_RETURN_BOOL(false);
 }
 
 /* path_distance()
  * This essentially does a cartesian product of the lsegs in the
@@ -1663,23 +1626,21 @@ path_distance(PG_FUNCTION_ARGS)
 			else
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
-			tmp = DatumGetFloat8(DirectFunctionCall2(lseg_distance,
-													 LsegPGetDatum(&seg1),
-													 LsegPGetDatum(&seg2)));
+			tmp = lseg_closept_lseg(NULL, &seg1, &seg2);
 			if (!have_min || tmp < min)
 			{
 				min = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	if (!have_min)
 		PG_RETURN_NULL();
@@ -1773,44 +1734,28 @@ point_send(PG_FUNCTION_ARGS)
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	StringInfoData buf;
 
 	pq_begintypsend(&buf);
 	pq_sendfloat8(&buf, pt->x);
 	pq_sendfloat8(&buf, pt->y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
-static Point *
-point_construct(double x, double y)
+/*
+ * Initialize a point
+ */
+static inline void
+point_construct(Point *result, float8 x, float8 y)
 {
-	Point	   *result = (Point *) palloc(sizeof(Point));
-
 	result->x = x;
 	result->y = y;
-	return result;
-}
-
-
-static Point *
-point_copy(Point *pt)
-{
-	Point	   *result;
-
-	if (!PointerIsValid(pt))
-		return NULL;
-
-	result = (Point *) palloc(sizeof(Point));
-
-	result->x = pt->x;
-	result->y = pt->y;
-	return result;
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for Points.
  *		Since we do have a sense of coordinates being
  *		"equal" to a given accuracy (point_vert, point_horiz),
  *		the other ops must preserve that sense.  This means
  *		that results may, strictly speaking, be a lie (unless
  *		EPSILON = 0.0).
@@ -1869,71 +1814,97 @@ point_horiz(PG_FUNCTION_ARGS)
 
 	PG_RETURN_BOOL(FPeq(pt1->y, pt2->y));
 }
 
 Datum
 point_eq(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y));
+	PG_RETURN_BOOL(point_eq_point(pt1, pt2));
 }
 
 Datum
 point_ne(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPne(pt1->x, pt2->x) || FPne(pt1->y, pt2->y));
+	PG_RETURN_BOOL(!point_eq_point(pt1, pt2));
 }
 
+static inline bool
+point_eq_point(Point *pt1, Point *pt2)
+{
+	return FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y);
+}
+
+
 /*----------------------------------------------------------
  *	"Arithmetic" operators on points.
  *---------------------------------------------------------*/
 
 Datum
 point_distance(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_FLOAT8(HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
+	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
-double
+static inline float8
 point_dt(Point *pt1, Point *pt2)
 {
-#ifdef GEODEBUG
-	printf("point_dt- segment (%f,%f),(%f,%f) length is %f\n",
-		   pt1->x, pt1->y, pt2->x, pt2->y, HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
-#endif
 	return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
 }
 
 Datum
 point_slope(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_sl(pt1, pt2));
 }
 
 
-double
+/*
+ * Return slope of two points
+ *
+ * Note that this function returns DBL_MAX when the points are the same.
+ */
+static inline float8
 point_sl(Point *pt1, Point *pt2)
 {
-	return (FPeq(pt1->x, pt2->x)
-			? (double) DBL_MAX
-			: (pt1->y - pt2->y) / (pt1->x - pt2->x));
+	if (FPeq(pt1->x, pt2->x))
+		return DBL_MAX;
+	if (FPeq(pt1->y, pt2->y))
+		return 0.0;
+	return (pt1->y - pt2->y) / (pt1->x - pt2->x);
+}
+
+
+/*
+ * Return inverse slope of two points
+ *
+ * Note that this function returns 0.0 when the points are the same.
+ */
+static inline float8
+point_invsl(Point *pt1, Point *pt2)
+{
+	if (FPeq(pt1->x, pt2->x))
+		return 0.0;
+	if (FPeq(pt1->y, pt2->y))
+		return DBL_MAX;
+	return (pt1->x - pt2->x) / (pt2->y - pt1->y);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D line segments.
  **
  ***********************************************************************/
 
 /*----------------------------------------------------------
@@ -1945,31 +1916,31 @@ point_sl(Point *pt1, Point *pt2)
  *		(old form)		"(x1, y1, x2, y2)"
  *---------------------------------------------------------*/
 
 Datum
 lseg_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	LSEG	   *lseg = (LSEG *) palloc(sizeof(LSEG));
 	bool		isopen;
 
-	path_decode(str, true, 2, &(lseg->p[0]), &isopen, NULL, "lseg", str);
+	path_decode(str, true, 2, &lseg->p[0], &isopen, NULL, "lseg", str);
 	PG_RETURN_LSEG_P(lseg);
 }
 
 
 Datum
 lseg_out(PG_FUNCTION_ARGS)
 {
 	LSEG	   *ls = PG_GETARG_LSEG_P(0);
 
-	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, (Point *) &(ls->p[0])));
+	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, &ls->p[0]));
 }
 
 /*
  *		lseg_recv			- converts external binary format to lseg
  */
 Datum
 lseg_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LSEG	   *lseg;
@@ -2005,38 +1976,56 @@ lseg_send(PG_FUNCTION_ARGS)
 /* lseg_construct -
  *		form a LSEG from two Points.
  */
 Datum
 lseg_construct(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 	LSEG	   *result = (LSEG *) palloc(sizeof(LSEG));
 
-	result->p[0].x = pt1->x;
-	result->p[0].y = pt1->y;
-	result->p[1].x = pt2->x;
-	result->p[1].y = pt2->y;
+	statlseg_construct(result, pt1, pt2);
 
 	PG_RETURN_LSEG_P(result);
 }
 
 /* like lseg_construct, but assume space already allocated */
-static void
+static inline void
 statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2)
 {
 	lseg->p[0].x = pt1->x;
 	lseg->p[0].y = pt1->y;
 	lseg->p[1].x = pt2->x;
 	lseg->p[1].y = pt2->y;
 }
 
+
+/*
+ * Return slope of the line segment
+ */
+static inline float8
+lseg_sl(LSEG *lseg)
+{
+	return point_sl(&lseg->p[0], &lseg->p[1]);
+}
+
+
+/*
+ * Return inverse slope of the line segment
+ */
+static inline float8
+lseg_invsl(LSEG *lseg)
+{
+	return point_invsl(&lseg->p[0], &lseg->p[1]);
+}
+
+
 Datum
 lseg_length(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 
 	PG_RETURN_FLOAT8(point_dt(&lseg->p[0], &lseg->p[1]));
 }
 
 /*----------------------------------------------------------
  *	Relative position routines.
@@ -2045,79 +2034,43 @@ lseg_length(PG_FUNCTION_ARGS)
 /*
  **  find intersection of the two lines, and see if it falls on
  **  both segments.
  */
 Datum
 lseg_intersect(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(lseg_intersect_internal(l1, l2));
+	PG_RETURN_BOOL(lseg_interpt_lseg(NULL, l1, l2));
 }
 
-static bool
-lseg_intersect_internal(LSEG *l1, LSEG *l2)
-{
-	LINE		ln;
-	Point	   *interpt;
-	bool		retval;
-
-	line_construct_pts(&ln, &l2->p[0], &l2->p[1]);
-	interpt = interpt_sl(l1, &ln);
-
-	if (interpt != NULL && on_ps_internal(interpt, l2))
-		retval = true;			/* interpt on l1 and l2 */
-	else
-		retval = false;
-	return retval;
-}
 
 Datum
 lseg_parallel(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPeq(point_sl(&l1->p[0], &l1->p[1]),
-						point_sl(&l2->p[0], &l2->p[1])));
+	PG_RETURN_BOOL(FPeq(lseg_sl(l1), lseg_sl(l2)));
 }
 
-/* lseg_perp()
+/*
  * Determine if two line segments are perpendicular.
- *
- * This code did not get the correct answer for
- *	'((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg
- * So, modified it to check explicitly for slope of vertical line
- *	returned by point_sl() and the results seem better.
- * - thomas 1998-01-31
  */
 Datum
 lseg_perp(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	double		m1,
-				m2;
 
-	m1 = point_sl(&(l1->p[0]), &(l1->p[1]));
-	m2 = point_sl(&(l2->p[0]), &(l2->p[1]));
-
-#ifdef GEODEBUG
-	printf("lseg_perp- slopes are %g and %g\n", m1, m2);
-#endif
-	if (FPzero(m1))
-		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
-	else if (FPzero(m2))
-		PG_RETURN_BOOL(FPeq(m1, DBL_MAX));
-
-	PG_RETURN_BOOL(FPeq(m1 / m2, -1.0));
+	PG_RETURN_BOOL(FPeq(lseg_sl(l1), lseg_invsl(l2)));
 }
 
 Datum
 lseg_vertical(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 
 	PG_RETURN_BOOL(FPeq(lseg->p[0].x, lseg->p[1].x));
 }
 
@@ -2129,36 +2082,32 @@ lseg_horizontal(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(FPeq(lseg->p[0].y, lseg->p[1].y));
 }
 
 
 Datum
 lseg_eq(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPeq(l1->p[0].x, l2->p[0].x) &&
-				   FPeq(l1->p[0].y, l2->p[0].y) &&
-				   FPeq(l1->p[1].x, l2->p[1].x) &&
-				   FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(point_eq_point(&l1->p[0], &l2->p[0]) &&
+				   point_eq_point(&l1->p[1], &l2->p[1]));
 }
 
 Datum
 lseg_ne(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(!FPeq(l1->p[0].x, l2->p[0].x) ||
-				   !FPeq(l1->p[0].y, l2->p[0].y) ||
-				   !FPeq(l1->p[1].x, l2->p[1].x) ||
-				   !FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(!point_eq_point(&l1->p[0], &l2->p[0]) ||
+				   !point_eq_point(&l1->p[1], &l2->p[1]));
 }
 
 Datum
 lseg_lt(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
 	PG_RETURN_BOOL(FPlt(point_dt(&l1->p[0], &l1->p[1]),
 						point_dt(&l2->p[0], &l2->p[1])));
@@ -2203,126 +2152,81 @@ lseg_ge(PG_FUNCTION_ARGS)
  *		If two segments don't intersect, then the closest
  *		point will be from one of the endpoints to the other
  *		segment.
  */
 Datum
 lseg_distance(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_FLOAT8(lseg_dt(l1, l2));
-}
-
-/* lseg_dt()
- * Distance between two line segments.
- * Must check both sets of endpoints to ensure minimum distance is found.
- * - thomas 1998-02-01
- */
-static double
-lseg_dt(LSEG *l1, LSEG *l2)
-{
-	double		result,
-				d;
-
-	if (lseg_intersect_internal(l1, l2))
-		return 0.0;
-
-	d = dist_ps_internal(&l1->p[0], l2);
-	result = d;
-	d = dist_ps_internal(&l1->p[1], l2);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[0], l1);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[1], l1);
-	result = Min(result, d);
-
-	return result;
+	PG_RETURN_FLOAT8(lseg_closept_lseg(NULL, l1, l2));
 }
 
 
 Datum
 lseg_center(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
 	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
 
 	PG_RETURN_POINT_P(result);
 }
 
-static Point *
-lseg_interpt_internal(LSEG *l1, LSEG *l2)
+
+/*
+ *		Find the intersection point of two segments (if any).
+ *
+ * This returns true if two line segments intersect, false if they do not.
+ * This also sets the intersection point to *result, if it is not NULL.
+ * This function is almost perfectly symmetric, even though it doesn't look
+ * like it.  See lseg_interpt_line() for the other half of it.
+ */
+static bool
+lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2)
 {
-	Point	   *result;
-	LINE		tmp1,
-				tmp2;
+	Point		interpt;
+	LINE		tmp;
+
+	line_construct(&tmp, &l2->p[0], lseg_sl(l2));
+	if (!lseg_interpt_line(&interpt, l1, &tmp))
+		return false;
 
 	/*
-	 * Find the intersection of the appropriate lines, if any.
+	 * If the line intersection point isn't within l2, there is no valid
+	 * segment intersection point at all.
 	 */
-	line_construct_pts(&tmp1, &l1->p[0], &l1->p[1]);
-	line_construct_pts(&tmp2, &l2->p[0], &l2->p[1]);
-	result = line_interpt_internal(&tmp1, &tmp2);
-	if (!PointerIsValid(result))
-		return NULL;
+	if (!lseg_contain_point(l2, &interpt))
+		return false;
 
-	/*
-	 * If the line intersection point isn't within l1 (or equivalently l2),
-	 * there is no valid segment intersection point at all.
-	 */
-	if (!on_ps_internal(result, l1) ||
-		!on_ps_internal(result, l2))
-	{
-		pfree(result);
-		return NULL;
-	}
+	if (result != NULL)
+		*result = interpt;
 
-	/*
-	 * If there is an intersection, then check explicitly for matching
-	 * endpoints since there may be rounding effects with annoying lsb
-	 * residue. - tgl 1997-07-09
-	 */
-	if ((FPeq(l1->p[0].x, l2->p[0].x) && FPeq(l1->p[0].y, l2->p[0].y)) ||
-		(FPeq(l1->p[0].x, l2->p[1].x) && FPeq(l1->p[0].y, l2->p[1].y)))
-	{
-		result->x = l1->p[0].x;
-		result->y = l1->p[0].y;
-	}
-	else if ((FPeq(l1->p[1].x, l2->p[0].x) && FPeq(l1->p[1].y, l2->p[0].y)) ||
-			 (FPeq(l1->p[1].x, l2->p[1].x) && FPeq(l1->p[1].y, l2->p[1].y)))
-	{
-		result->x = l1->p[1].x;
-		result->y = l1->p[1].y;
-	}
-
-	return result;
+	return true;
 }
 
-/* lseg_interpt -
- *		Find the intersection point of two segments (if any).
- */
 Datum
 lseg_interpt(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
-	result = lseg_interpt_internal(l1, l2);
-	if (!PointerIsValid(result))
-		PG_RETURN_NULL();
+	result = (Point *) palloc(sizeof(Point));
 
+	if (!lseg_interpt_lseg(result, l1, l2))
+		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
 
 /***********************************************************************
  **
  **		Routines for position comparisons of differently-typed
  **				2D objects.
  **
  ***********************************************************************/
 
@@ -2333,215 +2237,128 @@ lseg_interpt(PG_FUNCTION_ARGS)
 
 /*
  * Distance from a point to a line
  */
 Datum
 dist_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_FLOAT8(dist_pl_internal(pt, line));
+	PG_RETURN_FLOAT8(line_closept_point(NULL, line, pt));
 }
 
-static double
-dist_pl_internal(Point *pt, LINE *line)
-{
-	return fabs((line->A * pt->x + line->B * pt->y + line->C) /
-				HYPOT(line->A, line->B));
-}
 
 /*
  * Distance from a point to a lseg
  */
 Datum
 dist_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_FLOAT8(dist_ps_internal(pt, lseg));
-}
-
-static double
-dist_ps_internal(Point *pt, LSEG *lseg)
-{
-	double		m;				/* slope of perp. */
-	LINE	   *ln;
-	double		result,
-				tmpdist;
-	Point	   *ip;
-
-	/*
-	 * Construct a line perpendicular to the input segment and through the
-	 * input point
-	 */
-	if (lseg->p[1].x == lseg->p[0].x)
-		m = 0;
-	else if (lseg->p[1].y == lseg->p[0].y)
-		m = (double) DBL_MAX;	/* slope is infinite */
-	else
-		m = (lseg->p[0].x - lseg->p[1].x) / (lseg->p[1].y - lseg->p[0].y);
-	ln = line_construct_pm(pt, m);
-
-#ifdef GEODEBUG
-	printf("dist_ps- line is A=%g B=%g C=%g from (point) slope (%f,%f) %g\n",
-		   ln->A, ln->B, ln->C, pt->x, pt->y, m);
-#endif
-
-	/*
-	 * Calculate distance to the line segment or to the nearest endpoint of
-	 * the segment.
-	 */
-
-	/* intersection is on the line segment? */
-	if ((ip = interpt_sl(lseg, ln)) != NULL)
-	{
-		/* yes, so use distance to the intersection point */
-		result = point_dt(pt, ip);
-#ifdef GEODEBUG
-		printf("dist_ps- distance is %f to intersection point is (%f,%f)\n",
-			   result, ip->x, ip->y);
-#endif
-	}
-	else
-	{
-		/* no, so use distance to the nearer endpoint */
-		result = point_dt(pt, &lseg->p[0]);
-		tmpdist = point_dt(pt, &lseg->p[1]);
-		if (tmpdist < result)
-			result = tmpdist;
-	}
-
-	return result;
+	PG_RETURN_FLOAT8(lseg_closept_point(NULL, lseg, pt));
 }
 
 /*
  * Distance from a point to a path
  */
 Datum
 dist_ppath(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	PATH	   *path = PG_GETARG_PATH_P(1);
 	float8		result = 0.0;	/* keep compiler quiet */
 	bool		have_min = false;
 	float8		tmp;
 	int			i;
 	LSEG		lseg;
 
-	switch (path->npts)
+	Assert(path->npts > 0);
+
+	/*
+	 * The distance from a point to a path is the smallest distance
+	 * from the point to any of its constituent segments.
+	 */
+	for (i = 0; i < path->npts; i++)
 	{
-		case 0:
-			/* no points in path? then result is undefined... */
-			PG_RETURN_NULL();
-		case 1:
-			/* one point in path? then get distance between two points... */
-			result = point_dt(pt, &path->p[0]);
-			break;
-		default:
-			/* make sure the path makes sense... */
-			Assert(path->npts > 1);
+		int			iprev;
 
-			/*
-			 * the distance from a point to a path is the smallest distance
-			 * from the point to any of its constituent segments.
-			 */
-			for (i = 0; i < path->npts; i++)
-			{
-				int			iprev;
+		if (i > 0)
+			iprev = i - 1;
+		else
+		{
+			if (!path->closed)
+				continue;
+			iprev = path->npts - 1; /* Include the closure segment */
+		}
 
-				if (i > 0)
-					iprev = i - 1;
-				else
-				{
-					if (!path->closed)
-						continue;
-					iprev = path->npts - 1; /* include the closure segment */
-				}
-
-				statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
-				tmp = dist_ps_internal(pt, &lseg);
-				if (!have_min || tmp < result)
-				{
-					result = tmp;
-					have_min = true;
-				}
-			}
-			break;
+		statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
+		tmp = lseg_closept_point(NULL, &lseg, pt);
+		if (!have_min || tmp < result)
+		{
+			result = tmp;
+			have_min = true;
+		}
 	}
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a point to a box
  */
 Datum
 dist_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
-	float8		result;
-	Point	   *near;
 
-	near = DatumGetPointP(DirectFunctionCall2(close_pb,
-											  PointPGetDatum(pt),
-											  BoxPGetDatum(box)));
-	result = point_dt(near, pt);
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(box_closept_point(NULL, box, pt));
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	float8		result,
 				d2;
 
-	if (has_interpt_sl(lseg, line))
+	if (lseg_interpt_line(NULL, lseg, line))
 		result = 0.0;
 	else
 	{
-		result = dist_pl_internal(&lseg->p[0], line);
-		d2 = dist_pl_internal(&lseg->p[1], line);
+		result = line_closept_point(NULL, line, &lseg->p[0]);
+		d2 = line_closept_point(NULL, line, &lseg->p[1]);
 		/* XXX shouldn't we take the min not max? */
 		if (d2 > result)
 			result = d2;
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
-	Point	   *tmp;
-	Datum		result;
 
-	tmp = DatumGetPointP(DirectFunctionCall2(close_sb,
-											 LsegPGetDatum(lseg),
-											 BoxPGetDatum(box)));
-	result = DirectFunctionCall2(dist_pb,
-								 PointPGetDatum(tmp),
-								 BoxPGetDatum(box));
-
-	PG_RETURN_DATUM(result);
+	PG_RETURN_FLOAT8(box_closept_lseg(NULL, box, lseg));
 }
 
 /*
  * Distance from a line to a box
  */
 Datum
 dist_lb(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -2577,37 +2394,31 @@ dist_cpoly(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a point to a polygon
  */
 Datum
 dist_ppoly(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	POLYGON    *poly = PG_GETARG_POLYGON_P(1);
-	float8		result;
 
-	result = dist_ppoly_internal(point, poly);
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(dist_ppoly_internal(point, poly));
 }
 
 Datum
 dist_polyp(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	float8		result;
 
-	result = dist_ppoly_internal(point, poly);
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(dist_ppoly_internal(point, poly));
 }
 
 static double
 dist_ppoly_internal(Point *pt, POLYGON *poly)
 {
 	float8		result;
 	float8		d;
 	int			i;
 	LSEG		seg;
 
@@ -2617,498 +2428,481 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
 		printf("dist_ppoly_internal- point inside of polygon\n");
 #endif
 		return 0.0;
 	}
 
 	/* initialize distance with segment between first and last points */
 	seg.p[0].x = poly->p[0].x;
 	seg.p[0].y = poly->p[0].y;
 	seg.p[1].x = poly->p[poly->npts - 1].x;
 	seg.p[1].y = poly->p[poly->npts - 1].y;
-	result = dist_ps_internal(pt, &seg);
+	result = lseg_closept_point(NULL, &seg, pt);
 #ifdef GEODEBUG
 	printf("dist_ppoly_internal- segment 0/n distance is %f\n", result);
 #endif
 
 	/* check distances for other segments */
-	for (i = 0; (i < poly->npts - 1); i++)
+	for (i = 0; i < poly->npts - 1; i++)
 	{
 		seg.p[0].x = poly->p[i].x;
 		seg.p[0].y = poly->p[i].y;
 		seg.p[1].x = poly->p[i + 1].x;
 		seg.p[1].y = poly->p[i + 1].y;
-		d = dist_ps_internal(pt, &seg);
+		d = lseg_closept_point(NULL, &seg, pt);
 #ifdef GEODEBUG
 		printf("dist_ppoly_internal- segment %d distance is %f\n", (i + 1), d);
 #endif
 		if (d < result)
 			result = d;
 	}
 
 	return result;
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
  *				Intersection point of objects.
  *				We choose to ignore the "point" of intersection between
  *				  lines and boxes, since there are typically two.
  *-------------------------------------------------------------------*/
 
-/* Get intersection point of lseg and line; returns NULL if no intersection */
-static Point *
-interpt_sl(LSEG *lseg, LINE *line)
-{
-	LINE		tmp;
-	Point	   *p;
-
-	line_construct_pts(&tmp, &lseg->p[0], &lseg->p[1]);
-	p = line_interpt_internal(&tmp, line);
-#ifdef GEODEBUG
-	printf("interpt_sl- segment is (%.*g %.*g) (%.*g %.*g)\n",
-		   DBL_DIG, lseg->p[0].x, DBL_DIG, lseg->p[0].y, DBL_DIG, lseg->p[1].x, DBL_DIG, lseg->p[1].y);
-	printf("interpt_sl- segment becomes line A=%.*g B=%.*g C=%.*g\n",
-		   DBL_DIG, tmp.A, DBL_DIG, tmp.B, DBL_DIG, tmp.C);
-#endif
-	if (PointerIsValid(p))
-	{
-#ifdef GEODEBUG
-		printf("interpt_sl- intersection point is (%.*g %.*g)\n", DBL_DIG, p->x, DBL_DIG, p->y);
-#endif
-		if (on_ps_internal(p, lseg))
-		{
-#ifdef GEODEBUG
-			printf("interpt_sl- intersection point is on segment\n");
-#endif
-		}
-		else
-			p = NULL;
-	}
-
-	return p;
-}
-
-/* variant: just indicate if intersection point exists */
+/*
+ * Check if the line segment intersects with the line
+ *
+ * This returns true if line segment intersects with line, false if they
+ * do not.  This also sets the intersection point to *result, if it is not
+ * NULL.
+ */
 static bool
-has_interpt_sl(LSEG *lseg, LINE *line)
+lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
 {
-	Point	   *tmp;
+	Point		interpt;
+	LINE		tmp;
 
-	tmp = interpt_sl(lseg, line);
-	if (tmp)
+	/*
+	 * First, we promote the line segment to a line, because we know how
+	 * to find the intersection point of two lines.  If they don't have
+	 * an intersection point, we are done.
+	 */
+	line_construct(&tmp, &lseg->p[0], lseg_sl(lseg));
+	if (!line_interpt_line(&interpt, &tmp, line))
+		return false;
+
+	/*
+	 * Then, we check whether the intersection point is actually on the line
+	 * segment.
+	 */
+	if (!lseg_contain_point(lseg, &interpt))
+		return false;
+
+	if (result == NULL)
 		return true;
-	return false;
+
+	/*
+	 * If there is an intersection, then check explicitly for matching
+	 * endpoints since there may be rounding effects with annoying LSB
+	 * residue.
+	 */
+	if (point_eq_point(&lseg->p[0], &interpt))
+		*result = lseg->p[0];
+	else if (point_eq_point(&lseg->p[1], &interpt))
+		*result = lseg->p[1];
+	else
+		*result = interpt;
+
+	return true;
 }
 
 /*---------------------------------------------------------------------
  *		close_
  *				Point of closest proximity between objects.
  *-------------------------------------------------------------------*/
 
-/* close_pl -
+/*
  *		The intersection point of a perpendicular of the line
  *		through the point.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
+static float8
+line_closept_point(Point *result, LINE *line, Point *point)
+{
+	bool		retval;
+	Point       closept;
+	LINE		tmp;
+
+	/* We drop a perpendicular to find the intersection point. */
+	line_construct(&tmp, point, line_invsl(line));
+	retval = line_interpt_line(&closept, line, &tmp);
+	Assert(retval);		/* XXX: We need something better. */
+
+	if (result != NULL)
+		*result = closept;
+
+	/* Then we calculate the distance between the points. */
+	return point_dt(&closept, point);
+}
+
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
-	LINE	   *tmp;
-	double		invm;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	if (FPzero(line->B))		/* vertical? */
-	{
-		result->x = line->C;
-		result->y = pt->y;
-		PG_RETURN_POINT_P(result);
-	}
-	if (FPzero(line->A))		/* horizontal? */
-	{
-		result->x = pt->x;
-		result->y = line->C;
-		PG_RETURN_POINT_P(result);
-	}
-	/* drop a perpendicular and find the intersection point */
+	line_closept_point(result, line, pt);
 
-	/* invert and flip the sign on the slope to get a perpendicular */
-	invm = line->B / line->A;
-	tmp = line_construct_pm(pt, invm);
-	result = line_interpt_internal(tmp, line);
-	Assert(result != NULL);
 	PG_RETURN_POINT_P(result);
 }
 
 
-/* close_ps()
+/*
  * Closest point on line segment to specified point.
- * Take the closest endpoint if the point is left, right,
- *	above, or below the segment, otherwise find the intersection
- *	point of the segment and its perpendicular through the point.
  *
- * Some tricky code here, relying on boolean expressions
- *	evaluating to only zero or one to use as an array index.
- *		bug fixes by gthaker@atl.lmco.com; May 1, 1998
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
+static float8
+lseg_closept_point(Point *result, LSEG *lseg, Point *pt)
+{
+	Point		closept;
+	LINE		tmp;
+
+	/*
+	 * To find the closest point, we draw a perpendicular line from the point
+	 * to the line segment.
+	 */
+	line_construct(&tmp, pt, point_invsl(&lseg->p[0], &lseg->p[1]));
+	lseg_closept_line(&closept, lseg, &tmp);
+
+	if (result != NULL)
+		*result = closept;
+
+	return point_dt(&closept, pt);
+}
+
 Datum
 close_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
-	LINE	   *tmp;
-	double		invm;
-	int			xh,
-				yh;
+	Point	   *result;
 
-#ifdef GEODEBUG
-	printf("close_sp:pt->x %f pt->y %f\nlseg(0).x %f lseg(0).y %f  lseg(1).x %f lseg(1).y %f\n",
-		   pt->x, pt->y, lseg->p[0].x, lseg->p[0].y,
-		   lseg->p[1].x, lseg->p[1].y);
-#endif
+	result = (Point *) palloc(sizeof(Point));
 
-	/* xh (or yh) is the index of upper x( or y) end point of lseg */
-	/* !xh (or !yh) is the index of lower x( or y) end point of lseg */
-	xh = lseg->p[0].x < lseg->p[1].x;
-	yh = lseg->p[0].y < lseg->p[1].y;
-
-	if (FPeq(lseg->p[0].x, lseg->p[1].x))	/* vertical? */
-	{
-#ifdef GEODEBUG
-		printf("close_ps- segment is vertical\n");
-#endif
-		/* first check if point is below or above the entire lseg. */
-		if (pt->y < lseg->p[!yh].y)
-			result = point_copy(&lseg->p[!yh]); /* below the lseg */
-		else if (pt->y > lseg->p[yh].y)
-			result = point_copy(&lseg->p[yh]);	/* above the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
-
-		/* point lines along (to left or right) of the vertical lseg. */
-
-		result = (Point *) palloc(sizeof(Point));
-		result->x = lseg->p[0].x;
-		result->y = pt->y;
-		PG_RETURN_POINT_P(result);
-	}
-	else if (FPeq(lseg->p[0].y, lseg->p[1].y))	/* horizontal? */
-	{
-#ifdef GEODEBUG
-		printf("close_ps- segment is horizontal\n");
-#endif
-		/* first check if point is left or right of the entire lseg. */
-		if (pt->x < lseg->p[!xh].x)
-			result = point_copy(&lseg->p[!xh]); /* left of the lseg */
-		else if (pt->x > lseg->p[xh].x)
-			result = point_copy(&lseg->p[xh]);	/* right of the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
-
-		/* point lines along (at top or below) the horiz. lseg. */
-		result = (Point *) palloc(sizeof(Point));
-		result->x = pt->x;
-		result->y = lseg->p[0].y;
-		PG_RETURN_POINT_P(result);
-	}
-
-	/*
-	 * vert. and horiz. cases are down, now check if the closest point is one
-	 * of the end points or someplace on the lseg.
-	 */
-
-	invm = -1.0 / point_sl(&(lseg->p[0]), &(lseg->p[1]));
-	tmp = line_construct_pm(&lseg->p[!yh], invm);	/* lower edge of the
-													 * "band" */
-	if (pt->y < (tmp->A * pt->x + tmp->C))
-	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[!yh]); /* below the lseg, take lower end
-											 * pt */
-#ifdef GEODEBUG
-		printf("close_ps below: tmp A %f  B %f   C %f\n",
-			   tmp->A, tmp->B, tmp->C);
-#endif
-		PG_RETURN_POINT_P(result);
-	}
-	tmp = line_construct_pm(&lseg->p[yh], invm);	/* upper edge of the
-													 * "band" */
-	if (pt->y > (tmp->A * pt->x + tmp->C))
-	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[yh]);	/* above the lseg, take higher end
-											 * pt */
-#ifdef GEODEBUG
-		printf("close_ps above: tmp A %f  B %f   C %f\n",
-			   tmp->A, tmp->B, tmp->C);
-#endif
-		PG_RETURN_POINT_P(result);
-	}
-
-	/*
-	 * at this point the "normal" from point will hit lseg. The closest point
-	 * will be somewhere on the lseg
-	 */
-	tmp = line_construct_pm(pt, invm);
-#ifdef GEODEBUG
-	printf("close_ps- tmp A %f  B %f   C %f\n",
-		   tmp->A, tmp->B, tmp->C);
-#endif
-	result = interpt_sl(lseg, tmp);
-
-	/*
-	 * ordinarily we should always find an intersection point, but that could
-	 * fail in the presence of NaN coordinates, and perhaps even from simple
-	 * roundoff issues.  Return a SQL NULL if so.
-	 */
-	if (result == NULL)
+	if (isnan(lseg_closept_point(result, lseg, pt)))
 		PG_RETURN_NULL();
 
-#ifdef GEODEBUG
-	printf("close_ps- result.x %f  result.y %f\n", result->x, result->y);
-#endif
 	PG_RETURN_POINT_P(result);
 }
 
 
-/* close_lseg()
- * Closest point to l1 on l2.
+/*
+ * Closest point on line segment to line segment
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
+static float8
+lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
+{
+	Point		point;
+	double		dist;
+	double		d;
+
+	d = lseg_closept_point(NULL, l1, &l2->p[0]);
+	dist = d;
+	if (result != NULL)
+		*result = l2->p[0];
+
+	d = lseg_closept_point(NULL, l1, &l2->p[1]);
+	if (d < dist)
+	{
+		dist = d;
+		if (result != NULL)
+			*result = l2->p[1];
+	}
+
+	if (lseg_closept_point(&point, l2, &l1->p[0]) < dist)
+		d = lseg_closept_point(result, l1, &point);
+
+	if (lseg_closept_point(&point, l2, &l1->p[1]) < dist)
+		d = lseg_closept_point(result, l1, &point);
+
+	if (d < dist)
+		dist = d;
+
+	return dist;
+}
+
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
-	Point		point;
-	double		dist;
-	double		d;
+	Point	   *result;
 
-	d = dist_ps_internal(&l1->p[0], l2);
-	dist = d;
-	memcpy(&point, &l1->p[0], sizeof(Point));
+	result = (Point *) palloc(sizeof(Point));
 
-	if ((d = dist_ps_internal(&l1->p[1], l2)) < dist)
-	{
-		dist = d;
-		memcpy(&point, &l1->p[1], sizeof(Point));
-	}
-
-	if (dist_ps_internal(&l2->p[0], l1) < dist)
-	{
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&l2->p[0]),
-													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
-													LsegPGetDatum(l2)));
-	}
-
-	if (dist_ps_internal(&l2->p[1], l1) < dist)
-	{
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&l2->p[1]),
-													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
-													LsegPGetDatum(l2)));
-	}
-
-	if (result == NULL)
-		result = point_copy(&point);
+	lseg_closept_lseg(result, l2, l1);
 
 	PG_RETURN_POINT_P(result);
 }
 
-/* close_pb()
+
+/*
  * Closest point on or in box to specified point.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
-Datum
-close_pb(PG_FUNCTION_ARGS)
+static float8
+box_closept_point(Point *result, BOX *box, Point *pt)
 {
-	Point	   *pt = PG_GETARG_POINT_P(0);
-	BOX		   *box = PG_GETARG_BOX_P(1);
-	LSEG		lseg,
-				seg;
-	Point		point;
+	LSEG		lseg;
+	Point		point,
+				closept;
 	double		dist,
 				d;
 
-	if (DatumGetBool(DirectFunctionCall2(on_pb,
-										 PointPGetDatum(pt),
-										 BoxPGetDatum(box))))
-		PG_RETURN_POINT_P(pt);
+	if (box_contain_point(box, pt))
+	{
+		if (result != NULL)
+			*result = *pt;
+
+		return 0.0;
+	}
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&lseg, &box->low, &point);
-	dist = dist_ps_internal(pt, &lseg);
+	dist = lseg_closept_point(result, &lseg, pt);
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	statlseg_construct(&lseg, &box->high, &point);
+	d = lseg_closept_point(&closept, &lseg, pt);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&lseg, &seg, sizeof(lseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
-	statlseg_construct(&seg, &box->low, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	statlseg_construct(&lseg, &box->low, &point);
+	d = lseg_closept_point(&closept, &lseg, pt);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&lseg, &seg, sizeof(lseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	statlseg_construct(&lseg, &box->high, &point);
+	d = lseg_closept_point(&closept, &lseg, pt);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&lseg, &seg, sizeof(lseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
-										PointPGetDatum(pt),
-										LsegPGetDatum(&lseg)));
+	return dist;
 }
 
+Datum
+close_pb(PG_FUNCTION_ARGS)
+{
+	Point	   *pt = PG_GETARG_POINT_P(0);
+	BOX		   *box = PG_GETARG_BOX_P(1);
+	Point	   *result;
+
+	result = (Point *) palloc(sizeof(Point));
+
+	box_closept_point(result, box, pt);
+
+	PG_RETURN_POINT_P(result);
+}
+
+
 /* close_sl()
  * Closest point on line to line segment.
  *
  * XXX THIS CODE IS WRONG
  * The code is actually calculating the point on the line segment
  *	which is backwards from the routine naming convention.
  * Copied code to new routine close_ls() but haven't fixed this one yet.
  * - thomas 1998-01-31
  */
 Datum
 close_sl(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 	float8		d1,
 				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
+	result = (Point *) palloc(sizeof(Point));
+
+	if (lseg_interpt_line(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
-	d1 = dist_pl_internal(&lseg->p[0], line);
-	d2 = dist_pl_internal(&lseg->p[1], line);
+	d1 = line_closept_point(NULL, line, &lseg->p[0]);
+	d2 = line_closept_point(NULL, line, &lseg->p[1]);
 	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
+		*result = lseg->p[0];
 	else
-		result = point_copy(&lseg->p[1]);
+		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
 
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_sl\" not implemented")));
 
 	PG_RETURN_NULL();
 }
 
-/* close_ls()
+/*
  * Closest point on line segment to line.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
+ *
+ * NOTE: When the lines are parallel, endpoints of one of the line segment
+ * are FPeq(), in presence of NaN or Infinitive coordinates, or perhaps =
+ * even because of simple roundoff issues, there may not be a single closest
+ * point.  We are likely to set the result to the second endpoint in these
+ * cases.
  */
+static float8
+lseg_closept_line(Point *result, LSEG *lseg, LINE *line)
+{
+	float8		dist1,
+				dist2;
+
+	if (lseg_interpt_line(result, lseg, line))
+		return 0.0;
+
+	dist1 = line_closept_point(NULL, line, &lseg->p[0]);
+	dist2 = line_closept_point(NULL, line, &lseg->p[1]);
+
+	if (dist1 < dist2)
+	{
+		if (result != NULL)
+			*result = lseg->p[0];
+
+		return dist1;
+	}
+	else
+	{
+		if (result != NULL)
+			*result = lseg->p[1];
+
+		return dist2;
+	}
+}
+
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
-	float8		d1,
-				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
-		PG_RETURN_POINT_P(result);
+	result = (Point *) palloc(sizeof(Point));
 
-	d1 = dist_pl_internal(&lseg->p[0], line);
-	d2 = dist_pl_internal(&lseg->p[1], line);
-	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
-	else
-		result = point_copy(&lseg->p[1]);
+	lseg_closept_line(result, lseg, line);
 
 	PG_RETURN_POINT_P(result);
 }
 
-/* close_sb()
+
+/*
  * Closest point on or in box to line segment.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
-Datum
-close_sb(PG_FUNCTION_ARGS)
+static float8
+box_closept_lseg(Point *result, BOX *box, LSEG *lseg)
 {
-	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
-	BOX		   *box = PG_GETARG_BOX_P(1);
-	Point		point;
-	LSEG		bseg,
-				seg;
+	Point		point,
+				closept;
+	LSEG		bseg;
 	double		dist,
 				d;
 
-	/* segment intersects box? then just return closest point to center */
-	if (DatumGetBool(DirectFunctionCall2(inter_sb,
-										 LsegPGetDatum(lseg),
-										 BoxPGetDatum(box))))
-	{
-		box_cn(&point, box);
-		PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
-											PointPGetDatum(&point),
-											LsegPGetDatum(lseg)));
-	}
+	if (box_interpt_lseg(result, box, lseg))
+		return 0.0;
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	dist = lseg_dt(lseg, &bseg);
+	dist = lseg_closept_lseg(result, &bseg, lseg);
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	statlseg_construct(&bseg, &box->high, &point);
+	d = lseg_closept_lseg(&closept, &bseg, lseg);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&bseg, &seg, sizeof(bseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
-	statlseg_construct(&seg, &box->low, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	statlseg_construct(&bseg, &box->low, &point);
+	d = lseg_closept_lseg(&closept, &bseg, lseg);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&bseg, &seg, sizeof(bseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	statlseg_construct(&bseg, &box->high, &point);
+	d = lseg_closept_lseg(&closept, &bseg, lseg);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&bseg, &seg, sizeof(bseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	/* OK, we now have the closest line segment on the box boundary */
-	PG_RETURN_DATUM(DirectFunctionCall2(close_lseg,
-										LsegPGetDatum(lseg),
-										LsegPGetDatum(&bseg)));
+	return dist;
 }
 
+Datum
+close_sb(PG_FUNCTION_ARGS)
+{
+	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
+	BOX		   *box = PG_GETARG_BOX_P(1);
+	Point	   *result;
+
+	result = (Point *) palloc(sizeof(Point));
+
+	box_closept_lseg(result, box, lseg);
+
+	PG_RETURN_POINT_P(result);
+}
+
+
 Datum
 close_lb(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 #endif
 
 	/* think about this one for a while */
 	ereport(ERROR,
@@ -3116,71 +2910,87 @@ close_lb(PG_FUNCTION_ARGS)
 			 errmsg("function \"close_lb\" not implemented")));
 
 	PG_RETURN_NULL();
 }
 
 /*---------------------------------------------------------------------
  *		on_
  *				Whether one object lies completely within another.
  *-------------------------------------------------------------------*/
 
-/* on_pl -
+/*
  *		Does the point satisfy the equation?
  */
+static bool
+line_contain_point(LINE *line, Point *point)
+{
+	return FPzero(line->A * point->x + line->B * point->y + line->C);
+}
+
 Datum
 on_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(FPzero(line->A * pt->x + line->B * pt->y + line->C));
+	PG_RETURN_BOOL(line_contain_point(line, pt));
 }
 
 
-/* on_ps -
+/*
  *		Determine colinearity by detecting a triangle inequality.
  * This algorithm seems to behave nicely even with lsb residues - tgl 1997-07-09
  */
+static bool
+lseg_contain_point(LSEG *lseg, Point *pt)
+{
+	return FPeq(point_dt(pt, &lseg->p[0]) +
+				point_dt(pt, &lseg->p[1]),
+				point_dt(&lseg->p[0], &lseg->p[1]));
+}
+
 Datum
 on_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(on_ps_internal(pt, lseg));
+	PG_RETURN_BOOL(lseg_contain_point(lseg, pt));
 }
 
+
+/*
+ * Check whether the point is in the box or on its border
+ */
 static bool
-on_ps_internal(Point *pt, LSEG *lseg)
+box_contain_point(BOX *box, Point *point)
 {
-	return FPeq(point_dt(pt, &lseg->p[0]) + point_dt(pt, &lseg->p[1]),
-				point_dt(&lseg->p[0], &lseg->p[1]));
+	return box->high.x >= point->x && box->low.x <= point->x &&
+		   box->high.y >= point->y && box->low.y <= point-> y;
 }
 
 Datum
 on_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_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);
+	PG_RETURN_BOOL(box_contain_point(box, pt));
 }
 
 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);
+	PG_RETURN_BOOL(box_contain_point(box, pt));
 }
 
 /* on_ppath -
  *		Whether a point lies within (on) a polyline.
  *		If open, we have to (groan) check each segment.
  * (uses same algorithm as for point intersecting segment - tgl 1997-07-09)
  *		If closed, we use the old O(n) ray method for point-in-polygon.
  *				The ray is horizontal, from pt out to the right.
  *				Each segment that crosses the ray counts as an
  *				intersection; note that an endpoint or edge may touch
@@ -3210,158 +3020,184 @@ on_ppath(PG_FUNCTION_ARGS)
 				PG_RETURN_BOOL(true);
 			a = b;
 		}
 		PG_RETURN_BOOL(false);
 	}
 
 	/*-- CLOSED --*/
 	PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
 }
 
+
+/*
+ * Check whether the line segment is on the line or close enough
+ *
+ * It is, if both of its points are on the line or close enough.
+ */
 Datum
 on_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(DatumGetBool(DirectFunctionCall2(on_pl,
-													PointPGetDatum(&lseg->p[0]),
-													LinePGetDatum(line))) &&
-				   DatumGetBool(DirectFunctionCall2(on_pl,
-													PointPGetDatum(&lseg->p[1]),
-													LinePGetDatum(line))));
+	PG_RETURN_BOOL(line_contain_point(line, &lseg->p[0]) &&
+				   line_contain_point(line, &lseg->p[1]));
+}
+
+
+/*
+ * Check whether the line segment is in the box or on its border
+ *
+ * It is, if both of its points are in the box or on its border.
+ */
+static bool
+box_contain_lseg(BOX *box, LSEG *lseg)
+{
+	return box_contain_point(box, &lseg->p[0]) &&
+		   box_contain_point(box, &lseg->p[1]);
 }
 
 Datum
 on_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(DatumGetBool(DirectFunctionCall2(on_pb,
-													PointPGetDatum(&lseg->p[0]),
-													BoxPGetDatum(box))) &&
-				   DatumGetBool(DirectFunctionCall2(on_pb,
-													PointPGetDatum(&lseg->p[1]),
-													BoxPGetDatum(box))));
+	PG_RETURN_BOOL(box_contain_lseg(box, lseg));
 }
 
 /*---------------------------------------------------------------------
  *		inter_
  *				Whether one object intersects another.
  *-------------------------------------------------------------------*/
 
 Datum
 inter_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(has_interpt_sl(lseg, line));
+	PG_RETURN_BOOL(lseg_interpt_line(NULL, lseg, line));
 }
 
-/* inter_sb()
+
+/*
  * Do line segment and box intersect?
  *
  * Segment completely inside box counts as intersection.
  * If you want only segments crossing box boundaries,
  *	try converting box to path first.
  *
+ * This function also sets the *result to the closest point on the line
+ * segment to the center of the box when they overlap and the result is
+ * not NULL.  It is somewhat arbitrary, but maybe the best we can do as
+ * there are typically two points they intersect.
+ *
  * Optimize for non-intersection by checking for box intersection first.
  * - thomas 1998-01-30
  */
-Datum
-inter_sb(PG_FUNCTION_ARGS)
+static bool
+box_interpt_lseg(Point *result, BOX *box, LSEG *lseg)
 {
-	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
-	BOX		   *box = PG_GETARG_BOX_P(1);
 	BOX			lbox;
 	LSEG		bseg;
 	Point		point;
 
 	lbox.low.x = Min(lseg->p[0].x, lseg->p[1].x);
 	lbox.low.y = Min(lseg->p[0].y, lseg->p[1].y);
 	lbox.high.x = Max(lseg->p[0].x, lseg->p[1].x);
 	lbox.high.y = Max(lseg->p[0].y, lseg->p[1].y);
 
 	/* nothing close to overlap? then not going to intersect */
 	if (!box_ov(&lbox, box))
-		PG_RETURN_BOOL(false);
+		return false;
+
+	if (result != NULL)
+	{
+		box_cn(&point, box);
+		lseg_closept_point(result, lseg, &point);
+	}
 
 	/* an endpoint of segment is inside box? then clearly intersects */
-	if (DatumGetBool(DirectFunctionCall2(on_pb,
-										 PointPGetDatum(&lseg->p[0]),
-										 BoxPGetDatum(box))) ||
-		DatumGetBool(DirectFunctionCall2(on_pb,
-										 PointPGetDatum(&lseg->p[1]),
-										 BoxPGetDatum(box))))
-		PG_RETURN_BOOL(true);
+	if (box_contain_point(box, &lseg->p[0]) ||
+		box_contain_point(box, &lseg->p[1]))
+		return true;
 
 	/* pairwise check lseg intersections */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	/* if we dropped through, no two segs intersected */
-	PG_RETURN_BOOL(false);
+	return false;
 }
 
+Datum
+inter_sb(PG_FUNCTION_ARGS)
+{
+	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
+	BOX		   *box = PG_GETARG_BOX_P(1);
+
+	PG_RETURN_BOOL(box_interpt_lseg(NULL, box, lseg));
+}
+
+
 /* inter_lb()
  * Do line and box intersect?
  */
 Datum
 inter_lb(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	LSEG		bseg;
 	Point		p1,
 				p2;
 
 	/* pairwise check lseg intersections */
 	p1.x = box->low.x;
 	p1.y = box->low.y;
 	p2.x = box->low.x;
 	p2.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->high.x;
 	p1.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p2.x = box->high.x;
 	p2.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->low.x;
 	p1.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 
 	/* if we dropped through, no intersection */
 	PG_RETURN_BOOL(false);
 }
 
 /*------------------------------------------------------------------
  * The following routines define a data type and operator class for
  * POLYGONS .... Part of which (the polygon's bounding box) is built on
  * top of the BOX data type.
@@ -3374,42 +3210,40 @@ inter_lb(PG_FUNCTION_ARGS)
  *---------------------------------------------------------------------*/
 static void
 make_bound_box(POLYGON *poly)
 {
 	int			i;
 	double		x1,
 				y1,
 				x2,
 				y2;
 
-	if (poly->npts > 0)
-	{
-		x2 = x1 = poly->p[0].x;
-		y2 = y1 = poly->p[0].y;
-		for (i = 1; i < poly->npts; i++)
-		{
-			if (poly->p[i].x < x1)
-				x1 = poly->p[i].x;
-			if (poly->p[i].x > x2)
-				x2 = poly->p[i].x;
-			if (poly->p[i].y < y1)
-				y1 = poly->p[i].y;
-			if (poly->p[i].y > y2)
-				y2 = poly->p[i].y;
-		}
+	Assert(poly->npts > 0);
 
-		box_fill(&(poly->boundbox), x1, x2, y1, y2);
+	x1 = x2 = poly->p[0].x;
+	y2 = y1 = poly->p[0].y;
+	for (i = 1; i < poly->npts; i++)
+	{
+		if (poly->p[i].x < x1)
+			x1 = poly->p[i].x;
+		if (poly->p[i].x > x2)
+			x2 = poly->p[i].x;
+		if (poly->p[i].y < y1)
+			y1 = poly->p[i].y;
+		if (poly->p[i].y > y2)
+			y2 = poly->p[i].y;
 	}
-	else
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot create bounding box for empty polygon")));
+
+	poly->boundbox.low.x = x1;
+	poly->boundbox.high.x = x2;
+	poly->boundbox.low.y = y1;
+	poly->boundbox.high.y = y2;
 }
 
 /*------------------------------------------------------------------
  * poly_in - read in the polygon from a string specification
  *
  *		External format:
  *				"((x0,y0),...,(xn,yn))"
  *				"x0,y0,...,xn,yn"
  *				also supports the older style "(x1,...,xn,y1,...yn)"
  *------------------------------------------------------------------*/
@@ -3739,65 +3573,65 @@ poly_same(PG_FUNCTION_ARGS)
 /*-----------------------------------------------------------------
  * Determine if polygon A overlaps polygon B
  *-----------------------------------------------------------------*/
 Datum
 poly_overlap(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
+	Assert(polya->npts > 0 && polyb->npts > 0);
+
 	/* Quick check by bounding box */
-	result = (polya->npts > 0 && polyb->npts > 0 &&
-			  box_ov(&polya->boundbox, &polyb->boundbox)) ? true : false;
+	result = box_ov(&polya->boundbox, &polyb->boundbox);
 
 	/*
 	 * Brute-force algorithm - try to find intersected edges, if so then
 	 * polygons are overlapped else check is one polygon inside other or not
 	 * by testing single point of them.
 	 */
 	if (result)
 	{
 		int			ia,
 					ib;
 		LSEG		sa,
 					sb;
 
 		/* Init first of polya's edge with last point */
 		sa.p[0] = polya->p[polya->npts - 1];
 		result = false;
 
-		for (ia = 0; ia < polya->npts && result == false; ia++)
+		for (ia = 0; ia < polya->npts && !result; ia++)
 		{
 			/* Second point of polya's edge is a current one */
 			sa.p[1] = polya->p[ia];
 
 			/* Init first of polyb's edge with last point */
 			sb.p[0] = polyb->p[polyb->npts - 1];
 
-			for (ib = 0; ib < polyb->npts && result == false; ib++)
+			for (ib = 0; ib < polyb->npts && !result; ib++)
 			{
 				sb.p[1] = polyb->p[ib];
-				result = lseg_intersect_internal(&sa, &sb);
+				result = lseg_interpt_lseg(NULL, &sa, &sb);
 				sb.p[0] = sb.p[1];
 			}
 
 			/*
 			 * move current endpoint to the first point of next edge
 			 */
 			sa.p[0] = sa.p[1];
 		}
 
-		if (result == false)
+		if (!result)
 		{
-			result = (point_inside(polya->p, polyb->npts, polyb->p)
-					  ||
+			result = (point_inside(polya->p, polyb->npts, polyb->p) ||
 					  point_inside(polyb->p, polya->npts, polya->p));
 		}
 	}
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
@@ -3817,36 +3651,35 @@ poly_overlap(PG_FUNCTION_ARGS)
 
 static bool
 touched_lseg_inside_poly(Point *a, Point *b, LSEG *s, POLYGON *poly, int start)
 {
 	/* point a is on s, b is not */
 	LSEG		t;
 
 	t.p[0] = *a;
 	t.p[1] = *b;
 
-#define POINTEQ(pt1, pt2)	(FPeq((pt1)->x, (pt2)->x) && FPeq((pt1)->y, (pt2)->y))
-	if (POINTEQ(a, s->p))
+	if (point_eq_point(a, s->p))
 	{
-		if (on_ps_internal(s->p + 1, &t))
+		if (lseg_contain_point(&t, s->p + 1))
 			return lseg_inside_poly(b, s->p + 1, poly, start);
 	}
-	else if (POINTEQ(a, s->p + 1))
+	else if (point_eq_point(a, s->p + 1))
 	{
-		if (on_ps_internal(s->p, &t))
+		if (lseg_contain_point(&t, s->p))
 			return lseg_inside_poly(b, s->p, poly, start);
 	}
-	else if (on_ps_internal(s->p, &t))
+	else if (lseg_contain_point(&t, s->p))
 	{
 		return lseg_inside_poly(b, s->p, poly, start);
 	}
-	else if (on_ps_internal(s->p + 1, &t))
+	else if (lseg_contain_point(&t, s->p + 1))
 	{
 		return lseg_inside_poly(b, s->p + 1, poly, start);
 	}
 
 	return true;				/* may be not true, but that will check later */
 }
 
 /*
  * Returns true if segment (a,b) is in polygon, option
  * start is used for optimization - function checks
@@ -3860,50 +3693,49 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 	int			i;
 	bool		res = true,
 				intersection = false;
 
 	t.p[0] = *a;
 	t.p[1] = *b;
 	s.p[0] = poly->p[(start == 0) ? (poly->npts - 1) : (start - 1)];
 
 	for (i = start; i < poly->npts && res; i++)
 	{
-		Point	   *interpt;
+		Point		interpt;
 
 		CHECK_FOR_INTERRUPTS();
 
 		s.p[1] = poly->p[i];
 
-		if (on_ps_internal(t.p, &s))
+		if (lseg_contain_point(&s, t.p))
 		{
-			if (on_ps_internal(t.p + 1, &s))
+			if (lseg_contain_point(&s, t.p + 1))
 				return true;	/* t is contained by s */
 
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p, t.p + 1, &s, poly, i + 1);
 		}
-		else if (on_ps_internal(t.p + 1, &s))
+		else if (lseg_contain_point(&s, t.p + 1))
 		{
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p + 1, t.p, &s, poly, i + 1);
 		}
-		else if ((interpt = lseg_interpt_internal(&t, &s)) != NULL)
+		else if (lseg_interpt_lseg(&interpt, &t, &s))
 		{
 			/*
 			 * segments are X-crossing, go to check each subsegment
 			 */
 
 			intersection = true;
-			res = lseg_inside_poly(t.p, interpt, poly, i + 1);
+			res = lseg_inside_poly(t.p, &interpt, poly, i + 1);
 			if (res)
-				res = lseg_inside_poly(t.p + 1, interpt, poly, i + 1);
-			pfree(interpt);
+				res = lseg_inside_poly(t.p + 1, &interpt, poly, i + 1);
 		}
 
 		s.p[0] = s.p[1];
 	}
 
 	if (res && !intersection)
 	{
 		Point		p;
 
 		/*
@@ -3915,74 +3747,86 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 
 		res = point_inside(&p, poly->npts, poly->p);
 	}
 
 	return res;
 }
 
 /*-----------------------------------------------------------------
  * Determine if polygon A contains polygon B.
  *-----------------------------------------------------------------*/
+static bool
+poly_contain_poly(POLYGON *polya, POLYGON *polyb)
+{
+	int			i;
+	LSEG		s;
+
+	Assert(polya->npts > 0 && polyb->npts > 0);
+
+	/*
+	 * Quick check to see if bounding box is contained.
+	 */
+	if (!box_contain_box(&polya->boundbox, &polyb->boundbox))
+		return false;
+
+	s.p[0] = polyb->p[polyb->npts - 1];
+
+	for (i = 0; i < polyb->npts; i++)
+	{
+		s.p[1] = polyb->p[i];
+		if (!lseg_inside_poly(s.p, s.p + 1, polya, 0))
+			return false;
+		s.p[0] = s.p[1];
+	}
+
+	return true;
+}
+
 Datum
 poly_contain(PG_FUNCTION_ARGS)
 {
 	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
-	/*
-	 * Quick check to see if bounding box is contained.
-	 */
-	if (polya->npts > 0 && polyb->npts > 0 &&
-		DatumGetBool(DirectFunctionCall2(box_contain,
-										 BoxPGetDatum(&polya->boundbox),
-										 BoxPGetDatum(&polyb->boundbox))))
-	{
-		int			i;
-		LSEG		s;
-
-		s.p[0] = polyb->p[polyb->npts - 1];
-		result = true;
-
-		for (i = 0; i < polyb->npts && result; i++)
-		{
-			s.p[1] = polyb->p[i];
-			result = lseg_inside_poly(s.p, s.p + 1, polya, 0);
-			s.p[0] = s.p[1];
-		}
-	}
-	else
-	{
-		result = false;
-	}
+	result = poly_contain_poly(polya, polyb);
 
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
 	PG_FREE_IF_COPY(polya, 0);
 	PG_FREE_IF_COPY(polyb, 1);
 
 	PG_RETURN_BOOL(result);
 }
 
 
 /*-----------------------------------------------------------------
  * Determine if polygon A is contained by polygon B
  *-----------------------------------------------------------------*/
 Datum
 poly_contained(PG_FUNCTION_ARGS)
 {
-	Datum		polya = PG_GETARG_DATUM(0);
-	Datum		polyb = PG_GETARG_DATUM(1);
+	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
+	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
+	bool		result;
 
 	/* Just switch the arguments and pass it off to poly_contain */
-	PG_RETURN_DATUM(DirectFunctionCall2(poly_contain, polyb, polya));
+	result = poly_contain_poly(polyb, polya);
+
+	/*
+	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
+	 */
+	PG_FREE_IF_COPY(polya, 0);
+	PG_FREE_IF_COPY(polyb, 1);
+
+	PG_RETURN_BOOL(result);
 }
 
 
 Datum
 poly_contain_pt(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_BOOL(point_inside(p, poly->npts, poly->p) != 0);
@@ -4018,170 +3862,215 @@ poly_distance(PG_FUNCTION_ARGS)
  **
  **		Routines for 2D points.
  **
  ***********************************************************************/
 
 Datum
 construct_point(PG_FUNCTION_ARGS)
 {
 	float8		x = PG_GETARG_FLOAT8(0);
 	float8		y = PG_GETARG_FLOAT8(1);
+	Point	   *result;
 
-	PG_RETURN_POINT_P(point_construct(x, y));
+	result = (Point *) palloc(sizeof(Point));
+
+	point_construct(result, x, y);
+
+	PG_RETURN_POINT_P(result);
+}
+
+
+static inline void
+point_add_point(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x + pt2->x,
+					pt1->y + pt2->y);
 }
 
 Datum
 point_add(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x + p2->x);
-	result->y = (p1->y + p2->y);
+	point_add_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+
+static inline void
+point_sub_point(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x - pt2->x,
+					pt1->y - pt2->y);
+}
+
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x - p2->x);
-	result->y = (p1->y - p2->y);
+	point_sub_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+
+static inline void
+point_mul_point(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					(pt1->x * pt2->x) - (pt1->y * pt2->y),
+					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+}
+
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x * p2->x) - (p1->y * p2->y);
-	result->y = (p1->x * p2->y) + (p1->y * p2->x);
+	point_mul_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+
+static inline void
+point_div_point(Point *result, Point *pt1, Point *pt2)
+{
+	double		div;
+
+	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
+
+	if (div == 0.0)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	point_construct(result,
+					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
+					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+}
+
 Datum
 point_div(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
-	double		div;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	div = (p2->x * p2->x) + (p2->y * p2->y);
-
-	if (div == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result->x = ((p1->x * p2->x) + (p1->y * p2->y)) / div;
-	result->y = ((p2->x * p1->y) - (p2->y * p1->x)) / div;
+	point_div_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D boxes.
  **
  ***********************************************************************/
 
 Datum
 points_box(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct(p1->x, p2->x, p1->y, p2->y));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	box_construct(result, p1, p2);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_add(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct((box->high.x + p->x),
-								  (box->low.x + p->x),
-								  (box->high.y + p->y),
-								  (box->low.y + p->y)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_add_point(&result->high, &box->high, p);
+	point_add_point(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_sub(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct((box->high.x - p->x),
-								  (box->low.x - p->x),
-								  (box->high.y - p->y),
-								  (box->low.y - p->y)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_sub_point(&result->high, &box->high, p);
+	point_sub_point(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_mul(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
 
-	high = DatumGetPointP(DirectFunctionCall2(point_mul,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_mul,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	result = (BOX *) palloc(sizeof(BOX));
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	point_mul_point(&high, &box->high, p);
+	point_mul_point(&low, &box->low, p);
+
+	box_construct(result, &high, &low);
 
 	PG_RETURN_BOX_P(result);
 }
 
 Datum
 box_div(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
 
-	high = DatumGetPointP(DirectFunctionCall2(point_div,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_div,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	result = (BOX *) palloc(sizeof(BOX));
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	point_div_point(&high, &box->high, p);
+	point_div_point(&low, &box->low, p);
+
+	box_construct(result, &high, &low);
 
 	PG_RETURN_BOX_P(result);
 }
 
 /*
  * Convert point to empty box
  */
 Datum
 point_box(PG_FUNCTION_ARGS)
 {
@@ -4277,83 +4166,63 @@ path_add(PG_FUNCTION_ARGS)
  * Translation operators.
  */
 Datum
 path_add_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x += point->x;
-		path->p[i].y += point->y;
-	}
+		point_add_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_sub_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x -= point->x;
-		path->p[i].y -= point->y;
-	}
+		point_sub_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 /* path_mul_pt()
  * Rotation and scaling operators.
  */
 Datum
 path_mul_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_mul,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_mul_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 Datum
 path_div_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_div,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_div_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
 
 
 Datum
 path_center(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	PATH	   *path = PG_GETARG_PATH_P(0);
@@ -4414,42 +4283,40 @@ poly_npoints(PG_FUNCTION_ARGS)
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 
 	PG_RETURN_INT32(poly->npts);
 }
 
 
 Datum
 poly_center(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
-	Datum		result;
-	CIRCLE	   *circle;
+	Point	   *result;
+	CIRCLE		circle;
 
-	circle = DatumGetCircleP(DirectFunctionCall1(poly_circle,
-												 PolygonPGetDatum(poly)));
-	result = DirectFunctionCall1(circle_center,
-								 CirclePGetDatum(circle));
+	result = (Point *) palloc(sizeof(Point));
 
-	PG_RETURN_DATUM(result);
+	poly_to_circle(&circle, poly);
+	*result = circle.center;
+
+	PG_RETURN_POINT_P(result);
 }
 
 
 Datum
 poly_box(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	BOX		   *box;
 
-	if (poly->npts < 1)
-		PG_RETURN_NULL();
-
-	box = box_copy(&poly->boundbox);
+	box = (BOX *) palloc(sizeof(BOX));
+	*box = poly->boundbox;
 
 	PG_RETURN_BOX_P(box);
 }
 
 
 /* box_poly()
  * Convert a box to a polygon.
  */
 Datum
 box_poly(PG_FUNCTION_ARGS)
@@ -4467,22 +4334,21 @@ box_poly(PG_FUNCTION_ARGS)
 
 	poly->p[0].x = box->low.x;
 	poly->p[0].y = box->low.y;
 	poly->p[1].x = box->low.x;
 	poly->p[1].y = box->high.y;
 	poly->p[2].x = box->high.x;
 	poly->p[2].y = box->high.y;
 	poly->p[3].x = box->high.x;
 	poly->p[3].y = box->low.y;
 
-	box_fill(&poly->boundbox, box->high.x, box->low.x,
-			 box->high.y, box->low.y);
+	box_construct(&poly->boundbox, &box->high, &box->low);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
 
 Datum
 poly_path(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	PATH	   *path;
@@ -4557,22 +4423,21 @@ circle_in(PG_FUNCTION_ARGS)
 
 	circle->radius = single_decode(s, &s, "circle", str);
 	if (circle->radius < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
 
 	while (depth > 0)
 	{
-		if ((*s == RDELIM)
-			|| ((*s == RDELIM_C) && (depth == 1)))
+		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
 			s++;
 			while (isspace((unsigned char) *s))
 				s++;
 		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
@@ -4656,22 +4521,21 @@ circle_send(PG_FUNCTION_ARGS)
 
 /*		circles identical?
  */
 Datum
 circle_same(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPeq(circle1->radius, circle2->radius) &&
-				   FPeq(circle1->center.x, circle2->center.x) &&
-				   FPeq(circle1->center.y, circle2->center.y));
+				   point_eq_point(&circle1->center, &circle2->center));
 }
 
 /*		circle_overlap	-		does circle1 overlap circle2?
  */
 Datum
 circle_overlap(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
@@ -4730,32 +4594,34 @@ circle_overright(PG_FUNCTION_ARGS)
 }
 
 /*		circle_contained		-		is circle1 contained by circle2?
  */
 Datum
 circle_contained(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle1->radius), circle2->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						circle2->radius - circle1->radius));
 }
 
 /*		circle_contain	-		does circle1 contain circle2?
  */
 Datum
 circle_contain(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle2->radius), circle1->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						circle1->radius - circle2->radius));
 }
 
 
 /*		circle_below		-		is circle1 strictly below circle2?
  */
 Datum
 circle_below(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
@@ -4858,107 +4724,83 @@ circle_ge(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPge(circle_ar(circle1), circle_ar(circle2)));
 }
 
 
 /*----------------------------------------------------------
  *	"Arithmetic" operators on circles.
  *---------------------------------------------------------*/
 
-static CIRCLE *
-circle_copy(CIRCLE *circle)
-{
-	CIRCLE	   *result;
-
-	if (!PointerIsValid(circle))
-		return NULL;
-
-	result = (CIRCLE *) palloc(sizeof(CIRCLE));
-	memcpy((char *) result, (char *) circle, sizeof(CIRCLE));
-	return result;
-}
-
-
 /* circle_add_pt()
  * Translation operator.
  */
 Datum
 circle_add_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x += point->x;
-	result->center.y += point->y;
+	point_add_point(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_sub_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x -= point->x;
-	result->center.y -= point->y;
+	point_sub_point(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /* circle_mul_pt()
  * Rotation and scaling operators.
  */
 Datum
 circle_mul_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_mul,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
-	result->radius *= HYPOT(point->x, point->y);
+	point_mul_point(&result->center, &circle->center, point);
+	result->radius = circle->radius * HYPOT(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_div_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_div,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
-	result->radius /= HYPOT(point->x, point->y);
+	point_div_point(&result->center, &circle->center, point);
+	result->radius = circle->radius / HYPOT(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /*		circle_area		-		returns the area of the circle.
  */
 Datum
 circle_area(PG_FUNCTION_ARGS)
 {
@@ -4993,22 +4835,22 @@ circle_radius(PG_FUNCTION_ARGS)
 /*		circle_distance -		returns the distance between
  *								  two circles.
  */
 Datum
 circle_distance(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(&circle1->center, &circle2->center)
-		- (circle1->radius + circle2->radius);
+	result = point_dt(&circle1->center, &circle2->center) -
+		(circle1->radius + circle2->radius);
 	if (result < 0)
 		result = 0;
 	PG_RETURN_FLOAT8(result);
 }
 
 
 Datum
 circle_contain_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
@@ -5190,56 +5032,60 @@ circle_poly(PG_FUNCTION_ARGS)
 		angle = i * anglestep;
 		poly->p[i].x = circle->center.x - (circle->radius * cos(angle));
 		poly->p[i].y = circle->center.y + (circle->radius * sin(angle));
 	}
 
 	make_bound_box(poly);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
-/*		poly_circle		- convert polygon to circle
+/*
+ * Convert polygon to circle
+ *
+ * The result must be preallocated.
  *
  * XXX This algorithm should use weighted means of line segments
  *	rather than straight average values of points - tgl 97/01/21.
  */
+static void
+poly_to_circle(CIRCLE *result, POLYGON *poly)
+{
+	int			i;
+
+	Assert(poly->npts > 0);
+
+	result->center.x = 0;
+	result->center.y = 0;
+	result->radius = 0;
+
+	for (i = 0; i < poly->npts; i++)
+		point_add_point(&result->center, &result->center, &poly->p[i]);
+	result->center.x /= poly->npts;
+	result->center.y /= poly->npts;
+
+	for (i = 0; i < poly->npts; i++)
+		result->radius += point_dt(&poly->p[i], &result->center);
+	result->radius /= poly->npts;
+}
+
 Datum
 poly_circle(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
-	CIRCLE	   *circle;
-	int			i;
+	CIRCLE	   *result;
 
-	if (poly->npts < 1)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot convert empty polygon to circle")));
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
+	poly_to_circle(result, poly);
 
-	circle->center.x = 0;
-	circle->center.y = 0;
-	circle->radius = 0;
-
-	for (i = 0; i < poly->npts; i++)
-	{
-		circle->center.x += poly->p[i].x;
-		circle->center.y += poly->p[i].y;
-	}
-	circle->center.x /= poly->npts;
-	circle->center.y /= poly->npts;
-
-	for (i = 0; i < poly->npts; i++)
-		circle->radius += point_dt(&poly->p[i], &circle->center);
-	circle->radius /= poly->npts;
-
-	PG_RETURN_CIRCLE_P(circle);
+	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /***********************************************************************
  **
  **		Private routines for multiple types.
  **
  ***********************************************************************/
 
 /*
@@ -5261,22 +5107,21 @@ point_inside(Point *p, int npts, Point *plist)
 	double		x0,
 				y0;
 	double		prev_x,
 				prev_y;
 	int			i = 0;
 	double		x,
 				y;
 	int			cross,
 				total_cross = 0;
 
-	if (npts <= 0)
-		return 0;
+	Assert(npts > 0);
 
 	/* compute first polygon point relative to single point */
 	x0 = plist[0].x - p->x;
 	y0 = plist[0].y - p->y;
 
 	prev_x = x0;
 	prev_y = y0;
 	/* loop over polygon points and aggregate total_cross */
 	for (i = 1; i < npts; i++)
 	{
@@ -5371,51 +5216,48 @@ lseg_crossing(double x, double y, double prev_x, double prev_y)
 static bool
 plist_same(int npts, Point *p1, Point *p2)
 {
 	int			i,
 				ii,
 				j;
 
 	/* find match for first point */
 	for (i = 0; i < npts; i++)
 	{
-		if ((FPeq(p2[i].x, p1[0].x))
-			&& (FPeq(p2[i].y, p1[0].y)))
+		if (point_eq_point(&p2[i], &p1[0]))
 		{
 
 			/* match found? then look forward through remaining points */
 			for (ii = 1, j = i + 1; ii < npts; ii++, j++)
 			{
 				if (j >= npts)
 					j = 0;
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_point(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed forward match with %d\n", j, ii);
 #endif
 					break;
 				}
 			}
 #ifdef GEODEBUG
 			printf("plist_same- ii = %d/%d after forward match\n", ii, npts);
 #endif
 			if (ii == npts)
 				return true;
 
 			/* match not found forwards? then look backwards */
 			for (ii = 1, j = i - 1; ii < npts; ii++, j--)
 			{
 				if (j < 0)
 					j = (npts - 1);
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_point(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed reverse match with %d\n", j, ii);
 #endif
 					break;
 				}
 			}
 #ifdef GEODEBUG
 			printf("plist_same- ii = %d/%d after reverse match\n", ii, npts);
 #endif
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index 06411aea9e..d7c807f8d9 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -786,14 +786,15 @@ spg_bbox_quad_config(PG_FUNCTION_ARGS)
 
 /*
  * 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);
+	box = (BOX *) palloc(sizeof(BOX));
+	*box = polygon->boundbox;
 
 	PG_RETURN_BOX_P(box);
 }
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index a589e4239f..0e066894cd 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -171,17 +171,13 @@ typedef struct
 #define DatumGetCircleP(X)	  ((CIRCLE *) DatumGetPointer(X))
 #define CirclePGetDatum(X)	  PointerGetDatum(X)
 #define PG_GETARG_CIRCLE_P(n) DatumGetCircleP(PG_GETARG_DATUM(n))
 #define PG_RETURN_CIRCLE_P(x) return CirclePGetDatum(x)
 
 
 /*
  * 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/regress.c b/src/test/regress/regress.c
index 97a50f30e7..82eaa79df5 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -169,22 +169,27 @@ widget_out(PG_FUNCTION_ARGS)
 	PG_RETURN_CSTRING(str);
 }
 
 PG_FUNCTION_INFO_V1(pt_in_widget);
 
 Datum
 pt_in_widget(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	WIDGET	   *widget = (WIDGET *) PG_GETARG_POINTER(1);
+	float8		distance;
 
-	PG_RETURN_BOOL(point_dt(point, &widget->center) < widget->radius);
+	distance = DatumGetFloat8(DirectFunctionCall2(point_distance,
+												  PointPGetDatum(point),
+											PointPGetDatum(&widget->center)));
+
+	PG_RETURN_BOOL(distance < widget->radius);
 }
 
 PG_FUNCTION_INFO_V1(reverse_name);
 
 Datum
 reverse_name(PG_FUNCTION_ARGS)
 {
 	char	   *string = PG_GETARG_CSTRING(0);
 	int			i;
 	int			len;
-- 
2.14.3 (Apple Git-98)

0002-float-header-v15.patchapplication/octet-stream; name=0002-float-header-v15.patchDownload
From d2c45b83a524fc286cb899c6b68dcaf9ec034040 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 28 May 2016 18:16:05 +0200
Subject: [PATCH 2/6] float-header-v15

Provide header file for built-in float datatypes

Even though, some datatypes under adt/ have separate header files,
most of the simple ones do not.  Their public functions were on
the builtins.h.  We would need to make more functions of floats public
to let the geometric types built on top of them.  This is a good
opportunity to make a separate header file for floats.

1acf7572554515b99ef6e783750aaea8777524ec made _cmp functions public
to solve NaN problem locally for GiST indexes.  This patch reworks it
in favour of a more extensive API.  The API uses inline functions
instead of macros, as they are easier to use compared to macros,
and avoid double-evaluation hazards.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com
---
 contrib/btree_gin/btree_gin.c                 |   1 +
 contrib/btree_gist/btree_ts.c                 |   1 +
 contrib/cube/cube.c                           |   2 +-
 contrib/cube/cubeparse.y                      |   2 +-
 contrib/postgres_fdw/postgres_fdw.c           |   1 +
 src/backend/access/gist/gistget.c             |   2 +-
 src/backend/access/gist/gistproc.c            |  55 +--
 src/backend/access/gist/gistutil.c            |   2 +-
 src/backend/utils/adt/float.c                 | 589 ++++++--------------------
 src/backend/utils/adt/formatting.c            |   1 +
 src/backend/utils/adt/geo_ops.c               |   6 +-
 src/backend/utils/adt/geo_spgist.c            |   3 +-
 src/backend/utils/adt/numeric.c               |   1 +
 src/backend/utils/adt/rangetypes_gist.c       |   3 +-
 src/backend/utils/adt/rangetypes_selfuncs.c   |   3 +-
 src/backend/utils/adt/rangetypes_typanalyze.c |   3 +-
 src/backend/utils/adt/timestamp.c             |   1 +
 src/backend/utils/misc/guc.c                  |   1 +
 src/include/utils/builtins.h                  |  14 -
 src/include/utils/float.h                     | 376 ++++++++++++++++
 20 files changed, 554 insertions(+), 513 deletions(-)
 create mode 100644 src/include/utils/float.h

diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index b6d22d2b00..2ecf7a2d87 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -3,20 +3,21 @@
  */
 #include "postgres.h"
 
 #include <limits.h>
 
 #include "access/stratnum.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/cash.h"
 #include "utils/date.h"
+#include "utils/float.h"
 #include "utils/inet.h"
 #include "utils/numeric.h"
 #include "utils/timestamp.h"
 #include "utils/varbit.h"
 #include "utils/uuid.h"
 
 PG_MODULE_MAGIC;
 
 typedef struct QueryInfo
 {
diff --git a/contrib/btree_gist/btree_ts.c b/contrib/btree_gist/btree_ts.c
index 18740cad38..49d1849d88 100644
--- a/contrib/btree_gist/btree_ts.c
+++ b/contrib/btree_gist/btree_ts.c
@@ -2,20 +2,21 @@
  * contrib/btree_gist/btree_ts.c
  */
 #include "postgres.h"
 
 #include <limits.h>
 
 #include "btree_gist.h"
 #include "btree_utils_num.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 typedef struct
 {
 	Timestamp	lower;
 	Timestamp	upper;
 } tsKEY;
 
 /*
 ** timestamp ops
 */
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c
index f02ac24ea1..dfa8465d74 100644
--- a/contrib/cube/cube.c
+++ b/contrib/cube/cube.c
@@ -6,21 +6,21 @@
   format for these routines is dictated by Postgres architecture.
 ******************************************************************************/
 
 #include "postgres.h"
 
 #include <math.h>
 
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 
 #include "cubedata.h"
 
 PG_MODULE_MAGIC;
 
 /*
  * Taken from the intarray contrib header
  */
 #define ARRPTR(x)  ( (double *) ARR_DATA_PTR(x) )
 #define ARRNELEMS(x)  ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x))
diff --git a/contrib/cube/cubeparse.y b/contrib/cube/cubeparse.y
index 1b65fa967c..deb2efdc0d 100644
--- a/contrib/cube/cubeparse.y
+++ b/contrib/cube/cubeparse.y
@@ -1,20 +1,20 @@
 %{
 /* contrib/cube/cubeparse.y */
 
 /* NdBox = [(lowerleft),(upperright)] */
 /* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */
 
 #include "postgres.h"
 
 #include "cubedata.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 
 /* All grammar constructs return strings */
 #define YYSTYPE char *
 
 /*
  * Bison doesn't allocate anything that needs to live across parser calls,
  * so we can easily have it use palloc instead of malloc.  This prevents
  * memory leaks if we error out during parsing.  Note this only works with
  * bison >= 2.0.  However, in bison 1.875 the default is to use alloca()
  * if possible, so there's not really much problem anyhow, at least if
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 5699252091..0803c30a48 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -28,20 +28,21 @@
 #include "optimizer/cost.h"
 #include "optimizer/clauses.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
 #include "optimizer/planmain.h"
 #include "optimizer/restrictinfo.h"
 #include "optimizer/var.h"
 #include "optimizer/tlist.h"
 #include "parser/parsetree.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 #include "utils/sampling.h"
 #include "utils/selfuncs.h"
 
 PG_MODULE_MAGIC;
 
 /* Default CPU cost to start up a foreign query. */
diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c
index c4e8a3b913..ad07b9e63c 100644
--- a/src/backend/access/gist/gistget.c
+++ b/src/backend/access/gist/gistget.c
@@ -15,21 +15,21 @@
 #include "postgres.h"
 
 #include "access/gist_private.h"
 #include "access/relscan.h"
 #include "catalog/pg_type.h"
 #include "miscadmin.h"
 #include "storage/lmgr.h"
 #include "storage/predicate.h"
 #include "pgstat.h"
 #include "lib/pairingheap.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 
 /*
  * gistkillitems() -- set LP_DEAD state for items an indexscan caller has
  * told us were killed.
  *
  * We re-read page here, so it's important to check page LSN. If the page
  * has been modified since the last read (as determined by LSN), we cannot
  * flag any entries because it is possible that the old entry was vacuumed
diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index 0536b318cc..76907b496d 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -26,62 +26,53 @@
 
 
 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
 						 StrategyNumber strategy);
 static bool rtree_internal_consistent(BOX *key, BOX *query,
 						  StrategyNumber strategy);
 
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
 
-/* Convenience macros for NaN-aware comparisons */
-#define FLOAT8_EQ(a,b)	(float8_cmp_internal(a, b) == 0)
-#define FLOAT8_LT(a,b)	(float8_cmp_internal(a, b) < 0)
-#define FLOAT8_LE(a,b)	(float8_cmp_internal(a, b) <= 0)
-#define FLOAT8_GT(a,b)	(float8_cmp_internal(a, b) > 0)
-#define FLOAT8_GE(a,b)	(float8_cmp_internal(a, b) >= 0)
-#define FLOAT8_MAX(a,b)  (FLOAT8_GT(a, b) ? (a) : (b))
-#define FLOAT8_MIN(a,b)  (FLOAT8_LT(a, b) ? (a) : (b))
-
 
 /**************************************************
  * Box ops
  **************************************************/
 
 /*
  * Calculates union of two boxes, a and b. The result is stored in *n.
  */
 static void
 rt_box_union(BOX *n, const BOX *a, const BOX *b)
 {
-	n->high.x = FLOAT8_MAX(a->high.x, b->high.x);
-	n->high.y = FLOAT8_MAX(a->high.y, b->high.y);
-	n->low.x = FLOAT8_MIN(a->low.x, b->low.x);
-	n->low.y = FLOAT8_MIN(a->low.y, b->low.y);
+	n->high.x = float8_max(a->high.x, b->high.x);
+	n->high.y = float8_max(a->high.y, b->high.y);
+	n->low.x = float8_min(a->low.x, b->low.x);
+	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
 static double
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
-	if (FLOAT8_LE(box->high.x, box->low.x) ||
-		FLOAT8_LE(box->high.y, box->low.y))
+	if (float8_le(box->high.x, box->low.x) ||
+		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
 	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
@@ -136,27 +127,27 @@ gist_box_consistent(PG_FUNCTION_ARGS)
 												 query,
 												 strategy));
 }
 
 /*
  * Increase BOX b to include addon.
  */
 static void
 adjustBox(BOX *b, const BOX *addon)
 {
-	if (FLOAT8_LT(b->high.x, addon->high.x))
+	if (float8_lt(b->high.x, addon->high.x))
 		b->high.x = addon->high.x;
-	if (FLOAT8_GT(b->low.x, addon->low.x))
+	if (float8_gt(b->low.x, addon->low.x))
 		b->low.x = addon->low.x;
-	if (FLOAT8_LT(b->high.y, addon->high.y))
+	if (float8_lt(b->high.y, addon->high.y))
 		b->high.y = addon->high.y;
-	if (FLOAT8_GT(b->low.y, addon->low.y))
+	if (float8_gt(b->low.y, addon->low.y))
 		b->low.y = addon->low.y;
 }
 
 /*
  * The GiST Union method for boxes
  *
  * returns the minimal bounding box that encloses all the entries in entryvec
  */
 Datum
 gist_box_union(PG_FUNCTION_ARGS)
@@ -608,36 +599,36 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		i1 = 0;
 		i2 = 0;
 		rightLower = intervalsLower[i1].lower;
 		leftUpper = intervalsUpper[i2].lower;
 		while (true)
 		{
 			/*
 			 * Find next lower bound of right group.
 			 */
 			while (i1 < nentries &&
-				   FLOAT8_EQ(rightLower, intervalsLower[i1].lower))
+				   float8_eq(rightLower, intervalsLower[i1].lower))
 			{
-				if (FLOAT8_LT(leftUpper, intervalsLower[i1].upper))
+				if (float8_lt(leftUpper, intervalsLower[i1].upper))
 					leftUpper = intervalsLower[i1].upper;
 				i1++;
 			}
 			if (i1 >= nentries)
 				break;
 			rightLower = intervalsLower[i1].lower;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * left group.
 			 */
 			while (i2 < nentries &&
-				   FLOAT8_LE(intervalsUpper[i2].upper, leftUpper))
+				   float8_le(intervalsUpper[i2].upper, leftUpper))
 				i2++;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim, rightLower, i1, leftUpper, i2);
 		}
 
 		/*
 		 * Iterate over upper bound of left group finding greatest possible
@@ -645,35 +636,35 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		 */
 		i1 = nentries - 1;
 		i2 = nentries - 1;
 		rightLower = intervalsLower[i1].upper;
 		leftUpper = intervalsUpper[i2].upper;
 		while (true)
 		{
 			/*
 			 * Find next upper bound of left group.
 			 */
-			while (i2 >= 0 && FLOAT8_EQ(leftUpper, intervalsUpper[i2].upper))
+			while (i2 >= 0 && float8_eq(leftUpper, intervalsUpper[i2].upper))
 			{
-				if (FLOAT8_GT(rightLower, intervalsUpper[i2].lower))
+				if (float8_gt(rightLower, intervalsUpper[i2].lower))
 					rightLower = intervalsUpper[i2].lower;
 				i2--;
 			}
 			if (i2 < 0)
 				break;
 			leftUpper = intervalsUpper[i2].upper;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * right group.
 			 */
-			while (i1 >= 0 && FLOAT8_GE(intervalsLower[i1].lower, rightLower))
+			while (i1 >= 0 && float8_ge(intervalsLower[i1].lower, rightLower))
 				i1--;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim,
 								 rightLower, i1 + 1, leftUpper, i2 + 1);
 		}
 	}
 
@@ -747,42 +738,42 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
 		}
 		else
 		{
 			lower = box->low.y;
 			upper = box->high.y;
 		}
 
-		if (FLOAT8_LE(upper, context.leftUpper))
+		if (float8_le(upper, context.leftUpper))
 		{
 			/* Fits to the left group */
-			if (FLOAT8_GE(lower, context.rightLower))
+			if (float8_ge(lower, context.rightLower))
 			{
 				/* Fits also to the right group, so "common entry" */
 				commonEntries[commonEntriesCount++].index = i;
 			}
 			else
 			{
 				/* Doesn't fit to the right group, so join to the left group */
 				PLACE_LEFT(box, i);
 			}
 		}
 		else
 		{
 			/*
 			 * Each entry should fit on either left or right group. Since this
 			 * entry didn't fit on the left group, it better fit in the right
 			 * group.
 			 */
-			Assert(FLOAT8_GE(lower, context.rightLower));
+			Assert(float8_ge(lower, context.rightLower));
 
 			/* Doesn't fit to the left group, so join to the right group */
 			PLACE_RIGHT(box, i);
 		}
 	}
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
@@ -852,24 +843,24 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
  * equivalent to box_same().
  */
 Datum
 gist_box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *b1 = PG_GETARG_BOX_P(0);
 	BOX		   *b2 = PG_GETARG_BOX_P(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
 	if (b1 && b2)
-		*result = (FLOAT8_EQ(b1->low.x, b2->low.x) &&
-				   FLOAT8_EQ(b1->low.y, b2->low.y) &&
-				   FLOAT8_EQ(b1->high.x, b2->high.x) &&
-				   FLOAT8_EQ(b1->high.y, b2->high.y));
+		*result = (float8_eq(b1->low.x, b2->low.x) &&
+				   float8_eq(b1->low.y, b2->low.y) &&
+				   float8_eq(b1->high.x, b2->high.x) &&
+				   float8_eq(b1->high.y, b2->high.y));
 	else
 		*result = (b1 == NULL && b2 == NULL);
 	PG_RETURN_POINTER(result);
 }
 
 /*
  * Leaf-level consistency for boxes: just apply the query operator
  */
 static bool
 gist_box_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy)
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 12804c321c..dddfe0ae2c 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -14,21 +14,21 @@
 #include "postgres.h"
 
 #include <math.h>
 
 #include "access/gist_private.h"
 #include "access/htup_details.h"
 #include "access/reloptions.h"
 #include "catalog/pg_opclass.h"
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/syscache.h"
 
 
 /*
  * Write itup vector to page, has no control of free space.
  */
 void
 gistfillbuffer(Page page, IndexTuple *itup, int len, OffsetNumber off)
 {
 	OffsetNumber l = InvalidOffsetNumber;
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index b86205b098..df35557b73 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -16,58 +16,25 @@
 
 #include <ctype.h>
 #include <float.h>
 #include <math.h>
 #include <limits.h>
 
 #include "catalog/pg_type.h"
 #include "common/int.h"
 #include "libpq/pqformat.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/sortsupport.h"
 
 
-#ifndef M_PI
-/* from my RH5.2 gcc math.h file - thomas 2000-04-03 */
-#define M_PI 3.14159265358979323846
-#endif
-
-/* Radians per degree, a.k.a. PI / 180 */
-#define RADIANS_PER_DEGREE 0.0174532925199432957692
-
-/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0.  NAN definition from
- * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfNotNumberNANItems.asp
- */
-#if defined(WIN32) && !defined(NAN)
-static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
-
-#define NAN (*(const double *) nan)
-#endif
-
-/*
- * check to see if a float4/8 val has underflowed or overflowed
- */
-#define CHECKFLOATVAL(val, inf_is_valid, zero_is_valid)			\
-do {															\
-	if (isinf(val) && !(inf_is_valid))							\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		  errmsg("value out of range: overflow")));				\
-																\
-	if ((val) == 0.0 && !(zero_is_valid))						\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		 errmsg("value out of range: underflow")));				\
-} while(0)
-
-
 /* Configurable GUC parameter */
 int			extra_float_digits = 0; /* Added to DBL_DIG or FLT_DIG */
 
 /* Cached constants for degree-based trig functions */
 static bool degree_consts_set = false;
 static float8 sin_30 = 0;
 static float8 one_minus_cos_60 = 0;
 static float8 asin_0_5 = 0;
 static float8 acos_0_5 = 0;
 static float8 atan_1_0 = 0;
@@ -98,100 +65,20 @@ static void init_degree_constants(void);
  * function, which causes configure to not set HAVE_CBRT.  Furthermore,
  * their compilers spit up at the mismatch between extern declaration
  * and static definition.  We work around that here by the expedient
  * of a #define to make the actual name of the static function different.
  */
 #define cbrt my_cbrt
 static double cbrt(double x);
 #endif							/* HAVE_CBRT */
 
 
-/*
- * Routines to provide reasonably platform-independent handling of
- * infinity and NaN.  We assume that isinf() and isnan() are available
- * and work per spec.  (On some platforms, we have to supply our own;
- * see src/port.)  However, generating an Infinity or NaN in the first
- * place is less well standardized; pre-C99 systems tend not to have C99's
- * INFINITY and NAN macros.  We centralize our workarounds for this here.
- */
-
-double
-get_float8_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (double) INFINITY;
-#else
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (double) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-/*
-* The funny placements of the two #pragmas is necessary because of a
-* long lived bug in the Microsoft compilers.
-* See http://support.microsoft.com/kb/120968/en-us for details
-*/
-#if (_MSC_VER >= 1800)
-#pragma warning(disable:4756)
-#endif
-float
-get_float4_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (float) INFINITY;
-#else
-#if (_MSC_VER >= 1800)
-#pragma warning(default:4756)
-#endif
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (float) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-double
-get_float8_nan(void)
-{
-	/* (double) NAN doesn't work on some NetBSD/MIPS releases */
-#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
-	/* C99 standard way */
-	return (double) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (double) (0.0 / 0.0);
-#endif
-}
-
-float
-get_float4_nan(void)
-{
-#ifdef NAN
-	/* C99 standard way */
-	return (float) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (float) (0.0 / 0.0);
-#endif
-}
-
-
 /*
  * Returns -1 if 'val' represents negative infinity, 1 if 'val'
  * represents (positive) infinity, and 0 otherwise. On some platforms,
  * this is equivalent to the isinf() macro, but not everywhere: C99
  * does not specify that isinf() needs to distinguish between positive
  * and negative infinity.
  */
 int
 is_infinite(double val)
 {
@@ -336,21 +223,21 @@ float4in(PG_FUNCTION_ARGS)
 	if (*endptr != '\0')
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"real", orig_num)));
 
 	/*
 	 * if we get here, we have a legal double, still need to check to see if
 	 * it's a legal float4
 	 */
-	CHECKFLOATVAL((float4) val, isinf(val), val == 0);
+	check_float4_val((float4) val, isinf(val), val == 0);
 
 	PG_RETURN_FLOAT4((float4) val);
 }
 
 /*
  *		float4out		- converts a float4 number to a string
  *						  using a standard output format
  */
 Datum
 float4out(PG_FUNCTION_ARGS)
@@ -686,35 +573,35 @@ float4up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT4(arg);
 }
 
 Datum
 float4larger(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) > 0)
+	if (float4_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 Datum
 float4smaller(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) < 0)
+	if (float4_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 /*
  *		======================
  *		FLOAT8 BASE OPERATIONS
  *		======================
@@ -753,35 +640,35 @@ float8up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT8(arg);
 }
 
 Datum
 float8larger(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) > 0)
+	if (float8_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 Datum
 float8smaller(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) < 0)
+	if (float8_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		====================
  *		ARITHMETIC OPERATORS
@@ -792,234 +679,165 @@ float8smaller(PG_FUNCTION_ARGS)
  *		float4pl		- returns arg1 + arg2
  *		float4mi		- returns arg1 - arg2
  *		float4mul		- returns arg1 * arg2
  *		float4div		- returns arg1 / arg2
  */
 Datum
 float4pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 + arg2;
-
-	/*
-	 * There isn't any way to check for underflow of addition/subtraction
-	 * because numbers near the underflow value have already been rounded to
-	 * the point where we can't detect that the two values were originally
-	 * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
-	 * 1.4013e-45.
-	 */
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_pl(arg1, arg2));
 }
 
 Datum
 float4mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mi(arg1, arg2));
 }
 
 Datum
 float4mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mul(arg1, arg2));
 }
 
 Datum
 float4div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_div(arg1, arg2));
 }
 
 /*
  *		float8pl		- returns arg1 + arg2
  *		float8mi		- returns arg1 - arg2
  *		float8mul		- returns arg1 * arg2
  *		float8div		- returns arg1 / arg2
  */
 Datum
 float8pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 + arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, arg2));
 }
 
 Datum
 float8mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 - arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, arg2));
 }
 
 Datum
 float8mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 * arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, arg2));
 }
 
 Datum
 float8div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, arg2));
 }
 
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float4{eq,ne,lt,le,gt,ge}		- float4/float4 comparison operations
  */
 int
 float4_cmp_internal(float4 a, float4 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float4_gt(a, b))
+		return 1;
+	if (float4_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
 float4eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float4_eq(arg1, arg2));
 }
 
 Datum
 float4ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float4_ne(arg1, arg2));
 }
 
 Datum
 float4lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float4_lt(arg1, arg2));
 }
 
 Datum
 float4le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float4_le(arg1, arg2));
 }
 
 Datum
 float4gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float4_gt(arg1, arg2));
 }
 
 Datum
 float4ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float4_ge(arg1, arg2));
 }
 
 Datum
 btfloat4cmp(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
 	PG_RETURN_INT32(float4_cmp_internal(arg1, arg2));
 }
@@ -1041,99 +859,79 @@ btfloat4sortsupport(PG_FUNCTION_ARGS)
 	ssup->comparator = btfloat4fastcmp;
 	PG_RETURN_VOID();
 }
 
 /*
  *		float8{eq,ne,lt,le,gt,ge}		- float8/float8 comparison operations
  */
 int
 float8_cmp_internal(float8 a, float8 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float8_gt(a, b))
+		return 1;
+	if (float8_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
 float8eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, arg2));
 }
 
 Datum
 float8ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, arg2));
 }
 
 Datum
 float8lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, arg2));
 }
 
 Datum
 float8le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, arg2));
 }
 
 Datum
 float8gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, arg2));
 }
 
 Datum
 float8ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, arg2));
 }
 
 Datum
 btfloat8cmp(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
 	PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
 }
@@ -1334,21 +1132,21 @@ ftod(PG_FUNCTION_ARGS)
 
 
 /*
  *		dtof			- converts a float8 number to a float4 number
  */
 Datum
 dtof(PG_FUNCTION_ARGS)
 {
 	float8		num = PG_GETARG_FLOAT8(0);
 
-	CHECKFLOATVAL((float4) num, isinf(num), num == 0);
+	check_float4_val((float4) num, isinf(num), num == 0);
 
 	PG_RETURN_FLOAT4((float4) num);
 }
 
 
 /*
  *		dtoi4			- converts a float8 number to an int4 number
  */
 Datum
 dtoi4(PG_FUNCTION_ARGS)
@@ -1559,36 +1357,36 @@ dsqrt(PG_FUNCTION_ARGS)
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
 				 errmsg("cannot take square root of a negative number")));
 
 	result = sqrt(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcbrt			- returns cube root of arg1
  */
 Datum
 dcbrt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	result = cbrt(arg1);
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dpow			- returns pow(arg1,arg2)
  */
 Datum
 dpow(PG_FUNCTION_ARGS)
 {
@@ -1646,40 +1444,40 @@ dpow(PG_FUNCTION_ARGS)
 			/* The sign of Inf is not significant in this case. */
 			result = get_float8_infinity();
 		else if (fabs(arg1) != 1)
 			result = 0;
 		else
 			result = 1;
 	}
 	else if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
+	check_float8_val(result, isinf(arg1) || isinf(arg2), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dexp			- returns the exponential function of arg1
  */
 Datum
 dexp(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
 	errno = 0;
 	result = exp(arg1);
 	if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1), false);
+	check_float8_val(result, isinf(arg1), false);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dlog1			- returns the natural logarithm of arg1
  */
 Datum
 dlog1(PG_FUNCTION_ARGS)
 {
@@ -1694,21 +1492,21 @@ dlog1(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of zero")));
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of a negative number")));
 
 	result = log(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dlog10			- returns the base 10 logarithm of arg1
  */
 Datum
 dlog10(PG_FUNCTION_ARGS)
 {
@@ -1724,21 +1522,21 @@ dlog10(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of zero")));
 	if (arg1 < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
 				 errmsg("cannot take logarithm of a negative number")));
 
 	result = log10(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dacos			- returns the arccos of arg1 (radians)
  */
 Datum
 dacos(PG_FUNCTION_ARGS)
 {
@@ -1754,21 +1552,21 @@ dacos(PG_FUNCTION_ARGS)
 	 * range [-1, 1] to values in the range [0, Pi], so we should reject any
 	 * inputs outside that range and the result will always be finite.
 	 */
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = acos(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dasin			- returns the arcsin of arg1 (radians)
  */
 Datum
 dasin(PG_FUNCTION_ARGS)
 {
@@ -1784,21 +1582,21 @@ dasin(PG_FUNCTION_ARGS)
 	 * range [-1, 1] to values in the range [-Pi/2, Pi/2], so we should reject
 	 * any inputs outside that range and the result will always be finite.
 	 */
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = asin(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		datan			- returns the arctan of arg1 (radians)
  */
 Datum
 datan(PG_FUNCTION_ARGS)
 {
@@ -1809,21 +1607,21 @@ datan(PG_FUNCTION_ARGS)
 	if (isnan(arg1))
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/*
 	 * The principal branch of the inverse tangent function maps all inputs to
 	 * values in the range [-Pi/2, Pi/2], so the result should always be
 	 * finite, even if the input is infinite.
 	 */
 	result = atan(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		atan2			- returns the arctan of arg1/arg2 (radians)
  */
 Datum
 datan2(PG_FUNCTION_ARGS)
 {
@@ -1834,21 +1632,21 @@ datan2(PG_FUNCTION_ARGS)
 	/* Per the POSIX spec, return NaN if either input is NaN */
 	if (isnan(arg1) || isnan(arg2))
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/*
 	 * atan2 maps all inputs to values in the range [-Pi, Pi], so the result
 	 * should always be finite, even if the inputs are infinite.
 	 */
 	result = atan2(arg1, arg2);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcos			- returns the cosine of arg1 (radians)
  */
 Datum
 dcos(PG_FUNCTION_ARGS)
 {
@@ -1874,21 +1672,21 @@ dcos(PG_FUNCTION_ARGS)
 	 * platform reports via errno, so also explicitly test for infinite
 	 * inputs.
 	 */
 	errno = 0;
 	result = cos(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcot			- returns the cotangent of arg1 (radians)
  */
 Datum
 dcot(PG_FUNCTION_ARGS)
 {
@@ -1901,21 +1699,21 @@ dcot(PG_FUNCTION_ARGS)
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = tan(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	result = 1.0 / result;
-	CHECKFLOATVAL(result, true /* cot(0) == Inf */ , true);
+	check_float8_val(result, true /* cot(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dsin			- returns the sine of arg1 (radians)
  */
 Datum
 dsin(PG_FUNCTION_ARGS)
 {
@@ -1927,21 +1725,21 @@ dsin(PG_FUNCTION_ARGS)
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = sin(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dtan			- returns the tangent of arg1 (radians)
  */
 Datum
 dtan(PG_FUNCTION_ARGS)
 {
@@ -1953,21 +1751,21 @@ dtan(PG_FUNCTION_ARGS)
 		PG_RETURN_FLOAT8(get_float8_nan());
 
 	/* Be sure to throw an error if the input is infinite --- see dcos() */
 	errno = 0;
 	result = tan(arg1);
 	if (errno != 0 || isinf(arg1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, true /* tan(pi/2) == Inf */ , true);
+	check_float8_val(result, true /* tan(pi/2) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /* ========== DEGREE-BASED TRIGONOMETRIC FUNCTIONS ========== */
 
 
 /*
  * Initialize the cached constants declared at the head of this file
  * (sin_30 etc).  The fact that we need those at all, let alone need this
@@ -2105,21 +1903,21 @@ dacosd(PG_FUNCTION_ARGS)
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	if (arg1 >= 0.0)
 		result = acosd_q1(arg1);
 	else
 		result = 90.0 + asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dasind			- returns the arcsin of arg1 (degrees)
  */
 Datum
 dasind(PG_FUNCTION_ARGS)
 {
@@ -2140,21 +1938,21 @@ dasind(PG_FUNCTION_ARGS)
 	if (arg1 < -1.0 || arg1 > 1.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
 	if (arg1 >= 0.0)
 		result = asind_q1(arg1);
 	else
 		result = -asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		datand			- returns the arctan of arg1 (degrees)
  */
 Datum
 datand(PG_FUNCTION_ARGS)
 {
@@ -2170,21 +1968,21 @@ datand(PG_FUNCTION_ARGS)
 
 	/*
 	 * The principal branch of the inverse tangent function maps all inputs to
 	 * values in the range [-90, 90], so the result should always be finite,
 	 * even if the input is infinite.  Additionally, we take care to ensure
 	 * than when arg1 is 1, the result is exactly 45.
 	 */
 	atan_arg1 = atan(arg1);
 	result = (atan_arg1 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		atan2d			- returns the arctan of arg1/arg2 (degrees)
  */
 Datum
 datan2d(PG_FUNCTION_ARGS)
 {
@@ -2204,21 +2002,21 @@ datan2d(PG_FUNCTION_ARGS)
 	 * result should always be finite, even if the inputs are infinite.
 	 *
 	 * Note: this coding assumes that atan(1.0) is a suitable scaling constant
 	 * to get an exact result from atan2().  This might well fail on us at
 	 * some point, requiring us to decide exactly what inputs we think we're
 	 * going to guarantee an exact result for.
 	 */
 	atan2_arg1_arg2 = atan2(arg1, arg2);
 	result = (atan2_arg1_arg2 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		sind_0_to_30	- returns the sine of an angle that lies between 0 and
  *						  30 degrees.  This will return exactly 0 when x is 0,
  *						  and exactly 0.5 when x is 30 degrees.
  */
 static double
@@ -2325,21 +2123,21 @@ dcosd(PG_FUNCTION_ARGS)
 
 	if (arg1 > 90.0)
 	{
 		/* cosd(180-x) = -cosd(x) */
 		arg1 = 180.0 - arg1;
 		sign = -sign;
 	}
 
 	result = sign * cosd_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dcotd			- returns the cotangent of arg1 (degrees)
  */
 Datum
 dcotd(PG_FUNCTION_ARGS)
 {
@@ -2390,21 +2188,21 @@ dcotd(PG_FUNCTION_ARGS)
 	result = sign * (cot_arg1 / cot_45);
 
 	/*
 	 * On some machines we get cotd(270) = minus zero, but this isn't always
 	 * true.  For portability, and because the user constituency for this
 	 * function probably doesn't want minus zero, force it to plain zero.
 	 */
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* cotd(0) == Inf */ , true);
+	check_float8_val(result, true /* cotd(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dsind			- returns the sine of arg1 (degrees)
  */
 Datum
 dsind(PG_FUNCTION_ARGS)
 {
@@ -2444,21 +2242,21 @@ dsind(PG_FUNCTION_ARGS)
 	}
 
 	if (arg1 > 90.0)
 	{
 		/* sind(180-x) = sind(x) */
 		arg1 = 180.0 - arg1;
 	}
 
 	result = sign * sind_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dtand			- returns the tangent of arg1 (degrees)
  */
 Datum
 dtand(PG_FUNCTION_ARGS)
 {
@@ -2509,64 +2307,56 @@ dtand(PG_FUNCTION_ARGS)
 	result = sign * (tan_arg1 / tan_45);
 
 	/*
 	 * On some machines we get tand(180) = minus zero, but this isn't always
 	 * true.  For portability, and because the user constituency for this
 	 * function probably doesn't want minus zero, force it to plain zero.
 	 */
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* tand(90) == Inf */ , true);
+	check_float8_val(result, true /* tand(90) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		degrees		- returns degrees converted from radians
  */
 Datum
 degrees(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
 
-	result = arg1 / RADIANS_PER_DEGREE;
-
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, RADIANS_PER_DEGREE));
 }
 
 
 /*
  *		dpi				- returns the constant PI
  */
 Datum
 dpi(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_FLOAT8(M_PI);
 }
 
 
 /*
  *		radians		- returns radians converted from degrees
  */
 Datum
 radians(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
 
-	result = arg1 * RADIANS_PER_DEGREE;
-
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, RADIANS_PER_DEGREE));
 }
 
 
 /*
  *		drandom		- returns a random number
  */
 Datum
 drandom(PG_FUNCTION_ARGS)
 {
 	float8		result;
@@ -2644,144 +2434,105 @@ check_float8_array(ArrayType *transarray, const char *caller, int n)
  * This function is used only in two stage aggregation and
  * shouldn't be called outside aggregate context.
  */
 Datum
 float8_combine(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_combine", 3);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-
 	transvalues2 = check_float8_array(transarray2, "float8_combine", 3);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
 
 Datum
 float8_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8		newval = PG_GETARG_FLOAT8(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float8_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
 	else
 	{
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
 								 sizeof(float8), FLOAT8PASSBYVAL, 'd');
 
 		PG_RETURN_ARRAYTYPE_P(result);
 	}
 }
 
 Datum
 float4_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 
 	/* do computations as float8 */
 	float8		newval = PG_GETARG_FLOAT4(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float4_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
 	else
 	{
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
 								 sizeof(float8), FLOAT8PASSBYVAL, 'd');
 
 		PG_RETURN_ARRAYTYPE_P(result);
 	}
 }
 
 Datum
@@ -2817,21 +2568,21 @@ float8_var_pop(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_var_pop", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Population variance is undefined when N is 0, so return NULL */
 	if (N == 0.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / (N * N));
 }
 
 Datum
 float8_var_samp(PG_FUNCTION_ARGS)
@@ -2846,21 +2597,21 @@ float8_var_samp(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_var_samp", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Sample variance is undefined when N is 0 or 1, so return NULL */
 	if (N <= 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
 }
 
 Datum
 float8_stddev_pop(PG_FUNCTION_ARGS)
@@ -2875,21 +2626,21 @@ float8_stddev_pop(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_stddev_pop", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Population stddev is undefined when N is 0, so return NULL */
 	if (N == 0.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(sqrt(numerator / (N * N)));
 }
 
 Datum
 float8_stddev_samp(PG_FUNCTION_ARGS)
@@ -2904,21 +2655,21 @@ float8_stddev_samp(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_stddev_samp", 3);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* Sample stddev is undefined when N is 0 or 1, so return NULL */
 	if (N <= 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(sqrt(numerator / (N * (N - 1.0))));
 }
 
 /*
  *		=========================
@@ -2953,30 +2704,30 @@ float8_regr_accum(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_accum", 6);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	N += 1.0;
 	sumX += newvalX;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
+	check_float8_val(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
 	sumX2 += newvalX * newvalX;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
+	check_float8_val(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
 	sumY += newvalY;
-	CHECKFLOATVAL(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
+	check_float8_val(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
 	sumY2 += newvalY * newvalY;
-	CHECKFLOATVAL(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
+	check_float8_val(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
 	sumXY += newvalX * newvalY;
-	CHECKFLOATVAL(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
-				  isinf(newvalY), true);
+	check_float8_val(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
+					 isinf(newvalY), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
 		transvalues[0] = N;
 		transvalues[1] = sumX;
@@ -3015,63 +2766,33 @@ float8_regr_accum(PG_FUNCTION_ARGS)
  * This function is used only in two stage aggregation and
  * shouldn't be called outside aggregate context.
  */
 Datum
 float8_regr_combine(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2,
-				sumY,
-				sumY2,
-				sumXY;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_regr_combine", 6);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-	sumY = transvalues1[3];
-	sumY2 = transvalues1[4];
-	sumXY = transvalues1[5];
-
 	transvalues2 = check_float8_array(transarray2, "float8_regr_combine", 6);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-	sumY += transvalues2[3];
-	CHECKFLOATVAL(sumY, isinf(transvalues1[3]) || isinf(transvalues2[3]),
-				  true);
-	sumY2 += transvalues2[4];
-	CHECKFLOATVAL(sumY2, isinf(transvalues1[4]) || isinf(transvalues2[4]),
-				  true);
-	sumXY += transvalues2[5];
-	CHECKFLOATVAL(sumXY, isinf(transvalues1[5]) || isinf(transvalues2[5]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
-	transvalues1[3] = sumY;
-	transvalues1[4] = sumY2;
-	transvalues1[5] = sumXY;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
+	transvalues1[3] = float8_pl(transvalues1[3], transvalues2[3]);
+	transvalues1[4] = float8_pl(transvalues1[4], transvalues2[4]);
+	transvalues1[5] = float8_pl(transvalues1[5], transvalues2[5]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
 
 
 Datum
 float8_regr_sxx(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
@@ -3083,21 +2804,21 @@ float8_regr_sxx(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_sxx", 6);
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_syy(PG_FUNCTION_ARGS)
@@ -3112,21 +2833,21 @@ float8_regr_syy(PG_FUNCTION_ARGS)
 	transvalues = check_float8_array(transarray, "float8_regr_syy", 6);
 	N = transvalues[0];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumY2) || isinf(sumY), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
 		PG_RETURN_FLOAT8(0.0);
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_sxy(PG_FUNCTION_ARGS)
@@ -3143,22 +2864,22 @@ float8_regr_sxy(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	/* A negative result is valid here */
 
 	PG_RETURN_FLOAT8(numerator / N);
 }
 
 Datum
 float8_regr_avgx(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3211,22 +2932,22 @@ float8_covar_pop(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * N));
 }
 
 Datum
 float8_covar_samp(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
 	float8		N,
@@ -3239,22 +2960,22 @@ float8_covar_samp(PG_FUNCTION_ARGS)
 	N = transvalues[0];
 	sumX = transvalues[1];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is <= 1 we should return NULL */
 	if (N < 2.0)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
 }
 
 Datum
 float8_corr(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8	   *transvalues;
 	float8		N,
@@ -3273,26 +2994,26 @@ float8_corr(PG_FUNCTION_ARGS)
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0 || numeratorY <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXY / sqrt(numeratorX * numeratorY));
 }
 
 Datum
 float8_regr_r2(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3313,26 +3034,26 @@ float8_regr_r2(PG_FUNCTION_ARGS)
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumY2 = transvalues[4];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 	/* per spec, horizontal line produces 1.0 */
 	if (numeratorY <= 0)
 		PG_RETURN_FLOAT8(1.0);
 
 	PG_RETURN_FLOAT8((numeratorXY * numeratorXY) /
 					 (numeratorX * numeratorY));
 }
 
@@ -3354,24 +3075,24 @@ float8_regr_slope(PG_FUNCTION_ARGS)
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXY / numeratorX);
 }
 
 Datum
 float8_regr_intercept(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
@@ -3389,24 +3110,24 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
 	sumX = transvalues[1];
 	sumX2 = transvalues[2];
 	sumY = transvalues[3];
 	sumXY = transvalues[5];
 
 	/* if N is 0 we should return NULL */
 	if (N < 1.0)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXXY = sumY * sumX2 - sumX * sumXY;
-	CHECKFLOATVAL(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
-				  isinf(sumX) || isinf(sumXY), true);
+	check_float8_val(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
+					 isinf(sumX) || isinf(sumXY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
 	PG_RETURN_FLOAT8(numeratorXXY / numeratorX);
 }
 
 
 /*
  *		====================================
  *		MIXED-PRECISION ARITHMETIC OPERATORS
@@ -3417,251 +3138,211 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
  *		float48pl		- returns arg1 + arg2
  *		float48mi		- returns arg1 - arg2
  *		float48mul		- returns arg1 * arg2
  *		float48div		- returns arg1 / arg2
  */
 Datum
 float48pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 + arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl((float8) arg1, arg2));
 }
 
 Datum
 float48mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi((float8) arg1, arg2));
 }
 
 Datum
 float48mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul((float8) arg1, arg2));
 }
 
 Datum
 float48div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div((float8) arg1, arg2));
 }
 
 /*
  *		float84pl		- returns arg1 + arg2
  *		float84mi		- returns arg1 - arg2
  *		float84mul		- returns arg1 * arg2
  *		float84div		- returns arg1 / arg2
  */
 Datum
 float84pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 + arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, (float8) arg2));
 }
 
 Datum
 float84mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 - arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, (float8) arg2));
 }
 
 Datum
 float84mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	result = arg1 * arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, (float8) arg2));
 }
 
 Datum
 float84div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, (float8) arg2));
 }
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float48{eq,ne,lt,le,gt,ge}		- float4/float8 comparison operations
  */
 Datum
 float48eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq((float8) arg1, arg2));
 }
 
 Datum
 float48ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne((float8) arg1, arg2));
 }
 
 Datum
 float48lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt((float8) arg1, arg2));
 }
 
 Datum
 float48le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le((float8) arg1, arg2));
 }
 
 Datum
 float48gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt((float8) arg1, arg2));
 }
 
 Datum
 float48ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge((float8) arg1, arg2));
 }
 
 /*
  *		float84{eq,ne,lt,le,gt,ge}		- float8/float4 comparison operations
  */
 Datum
 float84eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, (float8) arg2));
 }
 
 Datum
 float84ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, (float8) arg2));
 }
 
 Datum
 float84lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, (float8) arg2));
 }
 
 Datum
 float84le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, (float8) arg2));
 }
 
 Datum
 float84gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, (float8) arg2));
 }
 
 Datum
 float84ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, (float8) arg2));
 }
 
 /*
  * Implements the float8 version of the width_bucket() function
  * defined by SQL2003. See also width_bucket_numeric().
  *
  * 'bound1' and 'bound2' are the lower and upper bounds of the
  * histogram's range, respectively. 'count' is the number of buckets
  * in the histogram. width_bucket() returns an integer indicating the
  * bucket number that 'operand' belongs to in an equiwidth histogram
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c
index a345c65605..30696e3575 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -84,20 +84,21 @@
 
 #ifdef USE_ICU
 #include <unicode/ustring.h>
 #endif
 
 #include "catalog/pg_collation.h"
 #include "mb/pg_wchar.h"
 #include "utils/builtins.h"
 #include "utils/date.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 #include "utils/formatting.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/pg_locale.h"
 
 /* ----------
  * Routines type
  * ----------
  */
 #define DCH_TYPE		1		/* DATE-TIME version	*/
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 3e7519015d..0f12684478 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -14,27 +14,23 @@
  */
 #include "postgres.h"
 
 #include <math.h>
 #include <limits.h>
 #include <float.h>
 #include <ctype.h>
 
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
-#include "utils/builtins.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index d7c807f8d9..fea36f361a 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -69,21 +69,22 @@
  *			src/backend/utils/adt/geo_spgist.c
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
 
 #include "access/spgist.h"
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
  * is going only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 82a14295ee..5a21160eb0 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -29,20 +29,21 @@
 #include "access/hash.h"
 #include "catalog/pg_type.h"
 #include "common/int.h"
 #include "funcapi.h"
 #include "lib/hyperloglog.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/sortsupport.h"
 
 /* ----------
  * Uncomment the following to enable compilation of dump_numeric()
  * and dump_var() and to get a dump of any result produced by make_result().
  * ----------
 #define NUMERIC_DEBUG
diff --git a/src/backend/utils/adt/rangetypes_gist.c b/src/backend/utils/adt/rangetypes_gist.c
index 2fe61043d9..450479e31c 100644
--- a/src/backend/utils/adt/rangetypes_gist.c
+++ b/src/backend/utils/adt/rangetypes_gist.c
@@ -9,21 +9,22 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_gist.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/gist.h"
 #include "access/stratnum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/datum.h"
 #include "utils/rangetypes.h"
 
 
 /*
  * Range class properties used to segregate different classes of ranges in
  * GiST.  Each unique combination of properties is a class.  CLS_EMPTY cannot
  * be combined with anything else.
  */
 #define CLS_NORMAL			0	/* Ordinary finite range (no bits set) */
diff --git a/src/backend/utils/adt/rangetypes_selfuncs.c b/src/backend/utils/adt/rangetypes_selfuncs.c
index 59761ecf34..f9a5117492 100644
--- a/src/backend/utils/adt/rangetypes_selfuncs.c
+++ b/src/backend/utils/adt/rangetypes_selfuncs.c
@@ -14,21 +14,22 @@
  *	  src/backend/utils/adt/rangetypes_selfuncs.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/htup_details.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 #include "utils/selfuncs.h"
 #include "utils/typcache.h"
 
 static double calc_rangesel(TypeCacheEntry *typcache, VariableStatData *vardata,
 			  RangeType *constval, Oid operator);
 static double default_range_selectivity(Oid operator);
 static double calc_hist_selectivity(TypeCacheEntry *typcache,
 					  VariableStatData *vardata, RangeType *constval,
diff --git a/src/backend/utils/adt/rangetypes_typanalyze.c b/src/backend/utils/adt/rangetypes_typanalyze.c
index f2c11f54bc..9c50e4c1be 100644
--- a/src/backend/utils/adt/rangetypes_typanalyze.c
+++ b/src/backend/utils/adt/rangetypes_typanalyze.c
@@ -19,21 +19,22 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_typanalyze.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "catalog/pg_operator.h"
 #include "commands/vacuum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 
 static int	float8_qsort_cmp(const void *a1, const void *a2);
 static int	range_bound_qsort_cmp(const void *a1, const void *a2, void *arg);
 static void compute_range_stats(VacAttrStats *stats,
 					AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows);
 
 /*
  * range_typanalyze -- typanalyze function for range columns
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index b98036f200..b3be5dc7ac 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -26,20 +26,21 @@
 #include "common/int128.h"
 #include "funcapi.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
 #include "parser/scansup.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 /*
  * gcc's -ffast-math switch breaks routines that expect exact results from
  * expressions like timeval / SECS_PER_HOUR, where timeval is double.
  */
 #ifdef __FAST_MATH__
 #error -ffast-math is known to break this code
 #endif
 
 #define SAMESIGN(a,b)	(((a) < 0) == ((b) < 0))
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 17292e04fe..9484657030 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -73,20 +73,21 @@
 #include "storage/fd.h"
 #include "storage/large_object.h"
 #include "storage/pg_shmem.h"
 #include "storage/proc.h"
 #include "storage/predicate.h"
 #include "tcop/tcopprot.h"
 #include "tsearch/ts_cache.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/guc_tables.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/pg_locale.h"
 #include "utils/plancache.h"
 #include "utils/portal.h"
 #include "utils/ps_status.h"
 #include "utils/rls.h"
 #include "utils/snapmgr.h"
 #include "utils/tzparser.h"
 #include "utils/varlena.h"
 #include "utils/xml.h"
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index d0416e90fc..b83a22767a 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -43,34 +43,20 @@ extern int	namestrcmp(Name name, const char *str);
 
 /* numutils.c */
 extern int32 pg_atoi(const char *s, int size, int c);
 extern void pg_itoa(int16 i, char *a);
 extern void pg_ltoa(int32 l, char *a);
 extern void pg_lltoa(int64 ll, char *a);
 extern char *pg_ltostr_zeropad(char *str, int32 value, int32 minwidth);
 extern char *pg_ltostr(char *str, int32 value);
 extern uint64 pg_strtouint64(const char *str, char **endptr, int base);
 
-/* float.c */
-extern PGDLLIMPORT int extra_float_digits;
-
-extern double get_float8_infinity(void);
-extern float get_float4_infinity(void);
-extern double get_float8_nan(void);
-extern float get_float4_nan(void);
-extern int	is_infinite(double val);
-extern double float8in_internal(char *num, char **endptr_p,
-				  const char *type_name, const char *orig_string);
-extern char *float8out_internal(double num);
-extern int	float4_cmp_internal(float4 a, float4 b);
-extern int	float8_cmp_internal(float8 a, float8 b);
-
 /* oid.c */
 extern oidvector *buildoidvector(const Oid *oids, int n);
 extern Oid	oidparse(Node *node);
 extern int	oid_cmp(const void *p1, const void *p2);
 
 /* regexp.c */
 extern char *regexp_fixed_prefix(text *text_re, bool case_insensitive,
 					Oid collation, bool *exact);
 
 /* ruleutils.c */
diff --git a/src/include/utils/float.h b/src/include/utils/float.h
new file mode 100644
index 0000000000..0e8483c930
--- /dev/null
+++ b/src/include/utils/float.h
@@ -0,0 +1,376 @@
+/*-------------------------------------------------------------------------
+ *
+ * float.h
+ *	  Definitions for the built-in floating-point types
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/include/utils/float.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef FLOAT_H
+#define FLOAT_H
+
+#include <math.h>
+
+#ifndef M_PI
+/* From my RH5.2 gcc math.h file - thomas 2000-04-03 */
+#define M_PI 3.14159265358979323846
+#endif
+
+/* Radians per degree, a.k.a. PI / 180 */
+#define RADIANS_PER_DEGREE 0.0174532925199432957692
+
+/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0. */
+#if defined(WIN32) && !defined(NAN)
+static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
+
+#define NAN (*(const float8 *) nan)
+#endif
+
+extern PGDLLIMPORT int extra_float_digits;
+
+/*
+ * Utility functions in float.c
+ */
+extern int	is_infinite(float8 val);
+extern float8 float8in_internal(char *num, char **endptr_p,
+				  const char *type_name, const char *orig_string);
+extern char *float8out_internal(float8 num);
+extern int	float4_cmp_internal(float4 a, float4 b);
+extern int	float8_cmp_internal(float8 a, float8 b);
+
+/*
+ * Routines to provide reasonably platform-independent handling of
+ * infinity and NaN
+ *
+ * We assume that isinf() and isnan() are available and work per spec.
+ * (On some platforms, we have to supply our own; see src/port.)  However,
+ * generating an Infinity or NaN in the first place is less well standardized;
+ * pre-C99 systems tend not to have C99's INFINITY and NaN macros.  We
+ * centralize our workarounds for this here.
+ */
+
+/*
+ * The funny placements of the two #pragmas is necessary because of a
+ * long lived bug in the Microsoft compilers.
+ * See http://support.microsoft.com/kb/120968/en-us for details
+ */
+#if (_MSC_VER >= 1800)
+#pragma warning(disable:4756)
+#endif
+static inline float4
+get_float4_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float4) INFINITY;
+#else
+#if (_MSC_VER >= 1800)
+#pragma warning(default:4756)
+#endif
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float4) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float8
+get_float8_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float8) INFINITY;
+#else
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float8) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float4
+get_float4_nan(void)
+{
+#ifdef NAN
+	/* C99 standard way */
+	return (float4) NAN;
+#else
+	/* Assume we can get a NAN via zero divide */
+	return (float4) (0.0 / 0.0);
+#endif
+}
+
+static inline float8
+get_float8_nan(void)
+{
+	/* (float8) NAN doesn't work on some NetBSD/MIPS releases */
+#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
+	/* C99 standard way */
+	return (float8) NAN;
+#else
+	/* Assume we can get a NaN via zero divide */
+	return (float8) (0.0 / 0.0);
+#endif
+}
+
+/*
+ * Checks to see if a float4/8 val has underflowed or overflowed
+ */
+
+static inline void
+check_float4_val(const float4 val, const bool inf_is_valid,
+				 const bool zero_is_valid)
+{
+	if (!inf_is_valid && unlikely(isinf(val)))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if (!zero_is_valid && unlikely(val == 0.0))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+static inline void
+check_float8_val(const float8 val, const bool inf_is_valid,
+				 const bool zero_is_valid)
+{
+	if (!inf_is_valid && unlikely(isinf(val)))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if (!zero_is_valid && unlikely(val == 0.0))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+/*
+ * Routines for operations with the checks above
+ *
+ * There isn't any way to check for underflow of addition/subtraction
+ * because numbers near the underflow value have already been rounded to
+ * the point where we can't detect that the two values were originally
+ * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
+ * 1.4013e-45.
+ */
+
+static inline float4
+float4_pl(const float4 val1, const float4 val2)
+{
+	float4		result;
+
+	result = val1 + val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_pl(const float8 val1, const float8 val2)
+{
+	float8		result;
+
+	result = val1 + val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mi(const float4 val1, const float4 val2)
+{
+	float4		result;
+
+	result = val1 - val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_mi(const float8 val1, const float8 val2)
+{
+	float8		result;
+
+	result = val1 - val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mul(const float4 val1, const float4 val2)
+{
+	float4		result;
+
+	result = val1 * val2;
+	check_float4_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0f || val2 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_mul(const float8 val1, const float8 val2)
+{
+	float8		result;
+
+	result = val1 * val2;
+	check_float8_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0 || val2 == 0.0);
+
+	return result;
+}
+
+static inline float4
+float4_div(const float4 val1, const float4 val2)
+{
+	float4		result;
+
+	if (val2 == 0.0f)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), val1 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_div(const float8 val1, const float8 val2)
+{
+	float8		result;
+
+	if (val2 == 0.0)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
+
+	return result;
+}
+
+/*
+ * Routines for NaN-aware comparisons
+ *
+ * We consider all NaNs to be equal and larger than any non-NaN. This is
+ * somewhat arbitrary; the important thing is to have a consistent sort
+ * order.
+ */
+
+static inline bool
+float4_eq(const float4 val1, const float4 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float8_eq(const float8 val1, const float8 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float4_ne(const float4 val1, const float4 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float8_ne(const float8 val1, const float8 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float4_lt(const float4 val1, const float4 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float8_lt(const float8 val1, const float8 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float4_le(const float4 val1, const float4 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float8_le(const float8 val1, const float8 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float4_gt(const float4 val1, const float4 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float8_gt(const float8 val1, const float8 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float4_ge(const float4 val1, const float4 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline bool
+float8_ge(const float8 val1, const float8 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline float4
+float4_min(const float4 val1, const float4 val2)
+{
+	return float4_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_min(const float8 val1, const float8 val2)
+{
+	return float8_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float4
+float4_max(const float4 val1, const float4 val2)
+{
+	return float4_gt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_max(const float8 val1, const float8 val2)
+{
+	return float8_gt(val1, val2) ? val1 : val2;
+}
+
+#endif							/* FLOAT_H */
-- 
2.14.3 (Apple Git-98)

0003-geo-float-v12.patchapplication/octet-stream; name=0003-geo-float-v12.patchDownload
From 83eabd9acdf6650298600cc60556a9251d82d186 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 27 May 2017 16:17:42 -0400
Subject: [PATCH 3/6] geo-float-v12

Use the built-in float datatype to implement geometric types

This patch makes the geometric operators and functions use the exported
function of the float datatype.  The main reason of doing so is to check
for underflow and overflow, and to handle NaNs consciously.

The float datatypes consider NaNs to be equal and greater than any
non-NaN.  This change considers NaNs equal only for the equality
operators.  The placement operators, contains, overlaps, left/right of
etc. continues to return false when NaNs are involved.  We don't need
to worry about them being considered greater than any-NaN because there
aren't any basic comparison operators like less/greater than for the
geometric datatypes.

All changes can be summarised as:

* Check for underflow and overflow
* Check for division by zero
* Let the objects with NaN values to be the same
* Return NULL when the distance is NaN for all closest point operators
* Favour not-NaN over NaN where it makes sense

The patch also replaces all occurrences of "double" as "float8".  They
are the same, but were randomly spread on the same file.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com

Parallel discussions:

* https://www.postgresql.org/message-id/28685.1468246504%40sss.pgh.pa.us
---
 src/backend/access/gist/gistproc.c |  93 +++----
 src/backend/utils/adt/geo_ops.c    | 500 ++++++++++++++++++++-----------------
 src/backend/utils/adt/geo_spgist.c |  28 +--
 src/include/utils/geo_decls.h      |  19 +-
 4 files changed, 342 insertions(+), 298 deletions(-)

diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index 76907b496d..5e416ccfa7 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -10,25 +10,24 @@
  * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
  *	src/backend/access/gist/gistproc.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
-#include <math.h>
-
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/geo_decls.h"
 
 
 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
 						 StrategyNumber strategy);
 static bool rtree_internal_consistent(BOX *key, BOX *query,
 						  StrategyNumber strategy);
 
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
@@ -47,55 +46,56 @@ rt_box_union(BOX *n, const BOX *a, const BOX *b)
 	n->high.x = float8_max(a->high.x, b->high.x);
 	n->high.y = float8_max(a->high.y, b->high.y);
 	n->low.x = float8_min(a->low.x, b->low.x);
 	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
 	if (float8_le(box->high.x, box->low.x) ||
 		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
-	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
+	return float8_mul(float8_mi(box->high.x, box->low.x),
+					  float8_mi(box->high.y, box->low.y));
 }
 
 /*
  * Return amount by which the union of the two boxes is larger than
  * the original BOX's area.  The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 box_penalty(const BOX *original, const BOX *new)
 {
 	BOX			unionbox;
 
 	rt_box_union(&unionbox, original, new);
-	return size_box(&unionbox) - size_box(original);
+	return float8_mi(size_box(&unionbox), size_box(original));
 }
 
 /*
  * The GiST Consistent method for boxes
  *
  * Should return false if for all data items x below entry,
  * the predicate x op query must be false, where op is the oper
  * corresponding to strategy in the pg_amop table.
  */
 Datum
@@ -255,74 +255,74 @@ fallbackSplit(GistEntryVector *entryvec, GIST_SPLITVEC *v)
 
 /*
  * Represents information about an entry that can be placed to either group
  * without affecting overlap over selected axis ("common entry").
  */
 typedef struct
 {
 	/* Index of entry in the initial array */
 	int			index;
 	/* Delta between penalties of entry insertion into different groups */
-	double		delta;
+	float8		delta;
 } CommonEntry;
 
 /*
  * Context for g_box_consider_split. Contains information about currently
  * selected split and some general information.
  */
 typedef struct
 {
 	int			entriesCount;	/* total number of entries being split */
 	BOX			boundingBox;	/* minimum bounding box across all entries */
 
 	/* Information about currently selected split follows */
 
 	bool		first;			/* true if no split was selected yet */
 
-	double		leftUpper;		/* upper bound of left interval */
-	double		rightLower;		/* lower bound of right interval */
+	float8		leftUpper;		/* upper bound of left interval */
+	float8		rightLower;		/* lower bound of right interval */
 
 	float4		ratio;
 	float4		overlap;
 	int			dim;			/* axis of this split */
-	double		range;			/* width of general MBR projection to the
+	float8		range;			/* width of general MBR projection to the
 								 * selected axis */
 } ConsiderSplitContext;
 
 /*
  * Interval represents projection of box to axis.
  */
 typedef struct
 {
-	double		lower,
+	float8		lower,
 				upper;
 } SplitInterval;
 
 /*
  * Interval comparison function by lower bound of the interval;
  */
 static int
 interval_cmp_lower(const void *i1, const void *i2)
 {
-	double		lower1 = ((const SplitInterval *) i1)->lower,
+	float8		lower1 = ((const SplitInterval *) i1)->lower,
 				lower2 = ((const SplitInterval *) i2)->lower;
 
 	return float8_cmp_internal(lower1, lower2);
 }
 
 /*
  * Interval comparison function by upper bound of the interval;
  */
 static int
 interval_cmp_upper(const void *i1, const void *i2)
 {
-	double		upper1 = ((const SplitInterval *) i1)->upper,
+	float8		upper1 = ((const SplitInterval *) i1)->upper,
 				upper2 = ((const SplitInterval *) i2)->upper;
 
 	return float8_cmp_internal(upper1, upper2);
 }
 
 /*
  * Replace negative (or NaN) value with zero.
  */
 static inline float
 non_negative(float val)
@@ -331,28 +331,28 @@ non_negative(float val)
 		return val;
 	else
 		return 0.0f;
 }
 
 /*
  * Consider replacement of currently selected split with the better one.
  */
 static inline void
 g_box_consider_split(ConsiderSplitContext *context, int dimNum,
-					 double rightLower, int minLeftCount,
-					 double leftUpper, int maxLeftCount)
+					 float8 rightLower, int minLeftCount,
+					 float8 leftUpper, int maxLeftCount)
 {
 	int			leftCount,
 				rightCount;
 	float4		ratio,
 				overlap;
-	double		range;
+	float8		range;
 
 	/*
 	 * Calculate entries distribution ratio assuming most uniform distribution
 	 * of common entries.
 	 */
 	if (minLeftCount >= (context->entriesCount + 1) / 2)
 	{
 		leftCount = minLeftCount;
 	}
 	else
@@ -361,40 +361,41 @@ g_box_consider_split(ConsiderSplitContext *context, int dimNum,
 			leftCount = maxLeftCount;
 		else
 			leftCount = context->entriesCount / 2;
 	}
 	rightCount = context->entriesCount - leftCount;
 
 	/*
 	 * Ratio of split - quotient between size of lesser group and total
 	 * entries count.
 	 */
-	ratio = ((float4) Min(leftCount, rightCount)) /
-		((float4) context->entriesCount);
+	ratio = float4_div(Min(leftCount, rightCount), context->entriesCount);
 
 	if (ratio > LIMIT_RATIO)
 	{
 		bool		selectthis = false;
 
 		/*
 		 * The ratio is acceptable, so compare current split with previously
 		 * selected one. Between splits of one dimension we search for minimal
 		 * overlap (allowing negative values) and minimal ration (between same
 		 * overlaps. We switch dimension if find less overlap (non-negative)
 		 * or less range with same overlap.
 		 */
 		if (dimNum == 0)
-			range = context->boundingBox.high.x - context->boundingBox.low.x;
+			range = float8_mi(context->boundingBox.high.x,
+							  context->boundingBox.low.x);
 		else
-			range = context->boundingBox.high.y - context->boundingBox.low.y;
+			range = float8_mi(context->boundingBox.high.y,
+							  context->boundingBox.low.y);
 
-		overlap = (leftUpper - rightLower) / range;
+		overlap = float8_div(float8_mi(leftUpper, rightLower), range);
 
 		/* If there is no previous selection, select this */
 		if (context->first)
 			selectthis = true;
 		else if (context->dim == dimNum)
 		{
 			/*
 			 * Within the same dimension, choose the new split if it has a
 			 * smaller overlap, or same overlap but better ratio.
 			 */
@@ -523,21 +524,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		else
 			adjustBox(&context.boundingBox, box);
 	}
 
 	/*
 	 * Iterate over axes for optimal split searching.
 	 */
 	context.first = true;		/* nothing selected yet */
 	for (dim = 0; dim < 2; dim++)
 	{
-		double		leftUpper,
+		float8		leftUpper,
 					rightLower;
 		int			i1,
 					i2;
 
 		/* Project each entry as an interval on the selected axis. */
 		for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 		{
 			box = DatumGetBoxP(entryvec->vector[i].key);
 			if (dim == 0)
 			{
@@ -720,21 +721,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 			*rightBox = *(box);					\
 		v->spl_right[v->spl_nright++] = off;	\
 	} while(0)
 
 	/*
 	 * Distribute entries which can be distributed unambiguously, and collect
 	 * common entries.
 	 */
 	for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 	{
-		double		lower,
+		float8		lower,
 					upper;
 
 		/*
 		 * Get upper and lower bounds along selected axis.
 		 */
 		box = DatumGetBoxP(entryvec->vector[i].key);
 		if (context.dim == 0)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
@@ -775,31 +776,31 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
 	{
 		/*
 		 * Calculate minimum number of entries that must be placed in both
 		 * groups, to reach LIMIT_RATIO.
 		 */
-		int			m = ceil(LIMIT_RATIO * (double) nentries);
+		int			m = ceil(LIMIT_RATIO * (float8) nentries);
 
 		/*
 		 * Calculate delta between penalties of join "common entries" to
 		 * different groups.
 		 */
 		for (i = 0; i < commonEntriesCount; i++)
 		{
 			box = DatumGetBoxP(entryvec->vector[commonEntries[i].index].key);
-			commonEntries[i].delta = Abs(box_penalty(leftBox, box) -
-										 box_penalty(rightBox, box));
+			commonEntries[i].delta = Abs(float8_mi(box_penalty(leftBox, box),
+												   box_penalty(rightBox, box)));
 		}
 
 		/*
 		 * Sort "common entries" by calculated deltas in order to distribute
 		 * the most ambiguous entries first.
 		 */
 		qsort(commonEntries, commonEntriesCount, sizeof(CommonEntry), common_entry_cmp);
 
 		/*
 		 * Distribute "common entries" between groups.
@@ -1099,24 +1100,24 @@ gist_circle_compress(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	GISTENTRY  *retval;
 
 	if (entry->leafkey)
 	{
 		CIRCLE	   *in = DatumGetCircleP(entry->key);
 		BOX		   *r;
 
 		r = (BOX *) palloc(sizeof(BOX));
-		r->high.x = in->center.x + in->radius;
-		r->low.x = in->center.x - in->radius;
-		r->high.y = in->center.y + in->radius;
-		r->low.y = in->center.y - in->radius;
+		r->high.x = float8_pl(in->center.x, in->radius);
+		r->low.x = float8_mi(in->center.x, in->radius);
+		r->high.y = float8_pl(in->center.y, in->radius);
+		r->low.y = float8_mi(in->center.y, in->radius);
 
 		retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
 		gistentryinit(*retval, PointerGetDatum(r),
 					  entry->rel, entry->page,
 					  entry->offset, false);
 	}
 	else
 		retval = entry;
 	PG_RETURN_POINTER(retval);
 }
@@ -1140,24 +1141,24 @@ gist_circle_consistent(PG_FUNCTION_ARGS)
 	*recheck = true;
 
 	if (DatumGetBoxP(entry->key) == NULL || query == NULL)
 		PG_RETURN_BOOL(false);
 
 	/*
 	 * Since the operators require recheck anyway, we can just use
 	 * rtree_internal_consistent even at leaf nodes.  (This works in part
 	 * because the index entries are bounding boxes not circles.)
 	 */
-	bbox.high.x = query->center.x + query->radius;
-	bbox.low.x = query->center.x - query->radius;
-	bbox.high.y = query->center.y + query->radius;
-	bbox.low.y = query->center.y - query->radius;
+	bbox.high.x = float8_pl(query->center.x, query->radius);
+	bbox.low.x = float8_mi(query->center.x, query->radius);
+	bbox.high.y = float8_pl(query->center.y, query->radius);
+	bbox.low.y = float8_mi(query->center.y, query->radius);
 
 	result = rtree_internal_consistent(DatumGetBoxP(entry->key),
 									   &bbox, strategy);
 
 	PG_RETURN_BOOL(result);
 }
 
 /**************************************************
  * Point ops
  **************************************************/
@@ -1208,63 +1209,63 @@ gist_point_fetch(PG_FUNCTION_ARGS)
 				  entry->offset, false);
 
 	PG_RETURN_POINTER(retval);
 }
 
 
 #define point_point_distance(p1,p2) \
 	DatumGetFloat8(DirectFunctionCall2(point_distance, \
 									   PointPGetDatum(p1), PointPGetDatum(p2)))
 
-static double
+static float8
 computeDistance(bool isLeaf, BOX *box, Point *point)
 {
-	double		result = 0.0;
+	float8		result = 0.0;
 
 	if (isLeaf)
 	{
 		/* simple point to point distance */
 		result = point_point_distance(point, &box->low);
 	}
 	else if (point->x <= box->high.x && point->x >= box->low.x &&
 			 point->y <= box->high.y && point->y >= box->low.y)
 	{
 		/* point inside the box */
 		result = 0.0;
 	}
 	else if (point->x <= box->high.x && point->x >= box->low.x)
 	{
 		/* point is over or below box */
 		Assert(box->low.y <= box->high.y);
 		if (point->y > box->high.y)
-			result = point->y - box->high.y;
+			result = float8_mi(point->y, box->high.y);
 		else if (point->y < box->low.y)
-			result = box->low.y - point->y;
+			result = float8_mi(box->low.y, point->y);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
 	else if (point->y <= box->high.y && point->y >= box->low.y)
 	{
 		/* point is to left or right of box */
 		Assert(box->low.x <= box->high.x);
 		if (point->x > box->high.x)
-			result = point->x - box->high.x;
+			result = float8_mi(point->x, box->high.x);
 		else if (point->x < box->low.x)
-			result = box->low.x - point->x;
+			result = float8_mi(box->low.x, point->x);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
 	else
 	{
 		/* closest point will be a vertex */
 		Point		p;
-		double		subresult;
+		float8		subresult;
 
 		result = point_point_distance(point, &box->low);
 
 		subresult = point_point_distance(point, &box->high);
 		if (result > subresult)
 			result = subresult;
 
 		p.x = box->low.x;
 		p.y = box->high.y;
 		subresult = point_point_distance(point, &p);
@@ -1441,21 +1442,21 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 	}
 
 	PG_RETURN_BOOL(result);
 }
 
 Datum
 gist_point_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(GIST_LEAF(entry),
 									   DatumGetBoxP(entry->key),
 									   PG_GETARG_POINT_P(1));
 			break;
 		default:
@@ -1470,25 +1471,25 @@ gist_point_distance(PG_FUNCTION_ARGS)
 /*
  * The inexact GiST distance method for geometric types that store bounding
  * boxes.
  *
  * Compute lossy distance from point to index entries.  The result is inexact
  * because index entries are bounding boxes, not the exact shapes of the
  * indexed geometric types.  We use distance from point to MBR of index entry.
  * This is a lower bound estimate of distance from point to indexed geometric
  * type.
  */
-static double
+static float8
 gist_bbox_distance(GISTENTRY *entry, Datum query,
 				   StrategyNumber strategy, bool *recheck)
 {
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	/* Bounding box distance is always inexact. */
 	*recheck = true;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(false,
 									   DatumGetBoxP(entry->key),
@@ -1504,32 +1505,32 @@ gist_bbox_distance(GISTENTRY *entry, Datum query,
 
 Datum
 gist_circle_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
 
 Datum
 gist_poly_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 0f12684478..314e442f2e 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -14,20 +14,21 @@
  */
 #include "postgres.h"
 
 #include <math.h>
 #include <limits.h>
 #include <float.h>
 #include <ctype.h>
 
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
+#include "utils/float.h"
 #include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
@@ -51,56 +52,56 @@ static inline float8 line_invsl(LINE *line);
 static bool	line_interpt_line(Point *result, LINE *l1, LINE *l2);
 static bool line_contain_point(LINE *line, Point *point);
 static float8 line_closept_point(Point *result, LINE *line, Point *pt);
 
 /* Routines for line segments */
 static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
 static inline float8 lseg_sl(LSEG *lseg);
 static inline float8 lseg_invsl(LSEG *lseg);
 static bool	lseg_interpt_line(Point *result, LSEG *lseg, LINE *line);
 static bool	lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2);
-static int	lseg_crossing(double x, double y, double px, double py);
+static int	lseg_crossing(float8 x, float8 y, float8 px, float8 py);
 static bool	lseg_contain_point(LSEG *lseg, Point *point);
 static float8 lseg_closept_point(Point *result, LSEG *lseg, Point *pt);
 static float8 lseg_closept_line(Point *result, LSEG *lseg, LINE *line);
 static float8 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2);
 
 /* Routines for boxes */
 static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
 static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
-static double box_ar(BOX *box);
-static double box_ht(BOX *box);
-static double box_wd(BOX *box);
+static float8 box_ar(BOX *box);
+static float8 box_ht(BOX *box);
+static float8 box_wd(BOX *box);
 static bool box_contain_point(BOX *box, Point *point);
 static bool box_contain_box(BOX *box1, BOX *box2);
 static bool box_contain_lseg(BOX *box, LSEG *lseg);
 static bool box_interpt_lseg(Point *result, BOX *box, LSEG *lseg);
 static float8 box_closept_point(Point *result, BOX *box, Point *point);
 static float8 box_closept_lseg(Point *result, BOX *box, LSEG *lseg);
 
 /* Routines for circles */
-static double circle_ar(CIRCLE *circle);
+static float8 circle_ar(CIRCLE *circle);
 
 /* Routines for polygons */
 static void make_bound_box(POLYGON *poly);
 static void poly_to_circle(CIRCLE *result, POLYGON *poly);
 static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
 static bool poly_contain_poly(POLYGON *polya, POLYGON *polyb);
 static bool plist_same(int npts, Point *p1, Point *p2);
 static float8 dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 /* Routines for encoding and decoding */
-static double single_decode(char *num, char **endptr_p,
+static float8 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
-static void pair_decode(char *str, double *x, double *y, char **endptr_p,
+static void pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
 static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
 
 
 /*
@@ -138,38 +139,38 @@ static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
  *
  * For boxes, the points are opposite corners with the first point at the top right.
  * For closed paths and polygons, the points should be reordered to allow
  *	fast and correct equality comparisons.
  *
  * XXX perhaps points in complex shapes should be reordered internally
  *	to allow faster internal operations, but should keep track of input order
  *	and restore that order for text output - tgl 97/01/16
  */
 
-static double
+static float8
 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string)
 {
 	return float8in_internal(num, endptr_p, type_name, orig_string);
 }								/* single_decode() */
 
 static void
 single_encode(float8 x, StringInfo str)
 {
 	char	   *xstr = float8out_internal(x);
 
 	appendStringInfoString(str, xstr);
 	pfree(xstr);
 }								/* single_encode() */
 
 static void
-pair_decode(char *str, double *x, double *y, char **endptr_p,
+pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string)
 {
 	bool		has_delim;
 
 	while (isspace((unsigned char) *str))
 		str++;
 	if ((has_delim = (*str == LDELIM)))
 		str++;
 
 	*x = float8in_internal(str, &str, type_name, orig_string);
@@ -368,33 +369,33 @@ pair_count(char *s, char delim)
  *		External format: (two corners of box)
  *				"(f8, f8), (f8, f8)"
  *				also supports the older style "(f8, f8, f8, f8)"
  */
 Datum
 box_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	BOX		   *box = (BOX *) palloc(sizeof(BOX));
 	bool		isopen;
-	double		x,
+	float8		x,
 				y;
 
 	path_decode(str, false, 2, &(box->high), &isopen, NULL, "box", str);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*		box_out -		convert a box to external form.
@@ -408,38 +409,38 @@ box_out(PG_FUNCTION_ARGS)
 }
 
 /*
  *		box_recv			- converts external binary format to box
  */
 Datum
 box_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	BOX		   *box;
-	double		x,
+	float8		x,
 				y;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
 	box->high.x = pq_getmsgfloat8(buf);
 	box->high.y = pq_getmsgfloat8(buf);
 	box->low.x = pq_getmsgfloat8(buf);
 	box->low.y = pq_getmsgfloat8(buf);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*
@@ -458,31 +459,31 @@ box_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, box->low.y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*		box_construct	-		fill in a new box.
  */
 static inline void
 box_construct(BOX *result, Point *pt1, Point *pt2)
 {
-	if (pt1->x > pt2->x)
+	if (float8_gt(pt1->x, pt2->x))
 	{
 		result->high.x = pt1->x;
 		result->low.x = pt2->x;
 	}
 	else
 	{
 		result->high.x = pt2->x;
 		result->low.x = pt1->x;
 	}
-	if (pt1->y > pt2->y)
+	if (float8_gt(pt1->y, pt2->y))
 	{
 		result->high.y = pt1->y;
 		result->low.y = pt2->y;
 	}
 	else
 	{
 		result->high.y = pt2->y;
 		result->low.y = pt1->y;
 	}
 }
@@ -800,54 +801,54 @@ box_center(PG_FUNCTION_ARGS)
 	Point	   *result = (Point *) palloc(sizeof(Point));
 
 	box_cn(result, box);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		box_ar	-		returns the area of the box.
  */
-static double
+static float8
 box_ar(BOX *box)
 {
-	return box_wd(box) * box_ht(box);
+	return float8_mul(box_wd(box), box_ht(box));
 }
 
 
 /*		box_cn	-		stores the centerpoint of the box into *center.
  */
 static void
 box_cn(Point *center, BOX *box)
 {
-	center->x = (box->high.x + box->low.x) / 2.0;
-	center->y = (box->high.y + box->low.y) / 2.0;
+	center->x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	center->y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 }
 
 
 /*		box_wd	-		returns the width (length) of the box
  *								  (horizontal magnitude).
  */
-static double
+static float8
 box_wd(BOX *box)
 {
-	return box->high.x - box->low.x;
+	return float8_mi(box->high.x, box->low.x);
 }
 
 
 /*		box_ht	-		returns the height of the box
  *								  (vertical magnitude).
  */
-static double
+static float8
 box_ht(BOX *box)
 {
-	return box->high.y - box->low.y;
+	return float8_mi(box->high.y, box->low.y);
 }
 
 
 /*----------------------------------------------------------
  *	Funky operations.
  *---------------------------------------------------------*/
 
 /*		box_intersect	-
  *				returns the overlapping portion of two boxes,
  *				  or NULL if they do not intersect.
@@ -857,24 +858,24 @@ box_intersect(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 	BOX		   *result;
 
 	if (!box_ov(box1, box2))
 		PG_RETURN_NULL();
 
 	result = (BOX *) palloc(sizeof(BOX));
 
-	result->high.x = Min(box1->high.x, box2->high.x);
-	result->low.x = Max(box1->low.x, box2->low.x);
-	result->high.y = Min(box1->high.y, box2->high.y);
-	result->low.y = Max(box1->low.y, box2->low.y);
+	result->high.x = float8_min(box1->high.x, box2->high.x);
+	result->low.x = float8_max(box1->low.x, box2->low.x);
+	result->high.y = float8_min(box1->high.y, box2->high.y);
+	result->low.y = float8_max(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(result);
 }
 
 
 /*		box_diagonal	-
  *				returns a line segment which happens to be the
  *				  positive-slope diagonal of "box".
  */
 Datum
@@ -1006,30 +1007,30 @@ line_send(PG_FUNCTION_ARGS)
 
 /*
  * Fill already-allocated LINE struct from the point and the slope
  */
 static inline void
 line_construct(LINE *result, Point *pt, float8 m)
 {
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
-		result->A = -1;
-		result->B = 0;
+		result->A = -1.0;
+		result->B = 0.0;
 		result->C = pt->x;
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
-		result->C = pt->y - m * pt->x;
+		result->C = float8_mi(pt->y, float8_mul(m, pt->x));
 	}
 }
 
 /* line_construct_pp()
  * two points
  */
 Datum
 line_construct_pp(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
@@ -1068,94 +1069,105 @@ Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
 	else if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
 
-	PG_RETURN_BOOL(FPeq(((l1->A * l2->B) / (l1->B * l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
+								   float8_mul(l1->B, l2->A)), -1.0));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
 Datum
 line_horizontal(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->A));
 }
 
+
+/*
+ * Check whether the two lines are the same
+ *
+ * We consider NaNs values to be equal to each other to let those lines
+ * to be found.
+ */
 Datum
 line_eq(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	double		k;
+	float8		ratio;
 
-	if (!FPzero(l2->A))
-		k = l1->A / l2->A;
-	else if (!FPzero(l2->B))
-		k = l1->B / l2->B;
-	else if (!FPzero(l2->C))
-		k = l1->C / l2->C;
+	if (!FPzero(l2->A) && !isnan(l2->A))
+		ratio = float8_div(l1->A, l2->A);
+	else if (!FPzero(l2->B) && !isnan(l2->B))
+		ratio = float8_div(l1->B, l2->B);
+	else if (!FPzero(l2->C) && !isnan(l2->C))
+		ratio = float8_div(l1->C, l2->C);
 	else
-		k = 1.0;
+		ratio = 1.0;
 
-	PG_RETURN_BOOL(FPeq(l1->A, k * l2->A) &&
-				   FPeq(l1->B, k * l2->B) &&
-				   FPeq(l1->C, k * l2->C));
+	PG_RETURN_BOOL((FPeq(l1->A, float8_mul(ratio, l2->A)) &&
+					FPeq(l1->B, float8_mul(ratio, l2->B)) &&
+					FPeq(l1->C, float8_mul(ratio, l2->C))) ||
+				   (float8_eq(l1->A, l2->A) &&
+					float8_eq(l1->B, l2->B) &&
+					float8_eq(l1->C, l2->C)));
 }
 
 
 /*----------------------------------------------------------
  *	Line arithmetic routines.
  *---------------------------------------------------------*/
 
 /*
  * Return inverse slope of the line
  */
 static inline float8
 line_invsl(LINE *line)
 {
 	if (FPzero(line->A))
 		return DBL_MAX;
 	if (FPzero(line->B))
 		return 0.0;
-	return line->B / line->A;
+	return float8_div(line->B, line->A);
 }
 
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
 	Point		tmp;
 
 	if (line_interpt_line(NULL, l1, l2))	/* intersecting? */
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
+		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
 	point_construct(&tmp, 0.0, l1->C);
 	result = line_closept_point(NULL, l2, &tmp);
 	PG_RETURN_FLOAT8(result);
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
@@ -1174,47 +1186,51 @@ line_interpt(PG_FUNCTION_ARGS)
 /*
  * Internal version of line_interpt
  *
  * This returns true if two lines intersect (they do, if they are not
  * parallel), false if they do not.  This also sets the intersection point
  * to *result, if it is not NULL.
  *
  * NOTE: If the lines are identical then we will find they are parallel
  * and report "no intersection".  This is a little weird, but since
  * there's no *unique* intersection, maybe it's appropriate behavior.
+ *
+ * If the lines have NaN constants, we will return true, and the intersection
+ * point would have NaN coordinates.  We shouldn't return false in this case
+ * because that would mean the lines are parallel.
  */
 static bool
 line_interpt_line(Point *result, LINE *l1, LINE *l2)
 {
-	double		x,
+	float8		x,
 				y;
 
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
 		if (FPzero(l2->B))		/* l2 vertical? */
 			return false;
 
 		x = l1->C;
-		y = (l2->A * x + l2->C);
+		y = float8_pl(float8_mul(l2->A, x), l2->C);
 	}
 	else if (FPzero(l2->B))		/* l2 vertical? */
 	{
 		x = l2->C;
-		y = (l1->A * x + l1->C);
+		y = float8_pl(float8_mul(l1->A, x), l1->C);
 	}
 	else
 	{
-		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
 			return false;
 
-		x = (l1->C - l2->C) / (l2->A - l1->A);
-		y = (l1->A * x + l1->C);
+		x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
+		y = float8_pl(float8_mul(l1->A, x), l1->C);
 	}
 
 	if (result != NULL)
 		point_construct(result, x, y);
 
 	return true;
 }
 
 
 /***********************************************************************
@@ -1236,36 +1252,35 @@ line_interpt_line(Point *result, LINE *l1, LINE *l2)
  *				"(xcoord, ycoord),... "
  *				"[xcoord, ycoord,... ]"
  *		Also support older format:
  *				"(closed, npts, xcoord, ycoord,... )"
  *---------------------------------------------------------*/
 
 Datum
 path_area(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P(0);
-	double		area = 0.0;
+	float8		area = 0.0;
 	int			i,
 				j;
 
 	if (!path->closed)
 		PG_RETURN_NULL();
 
 	for (i = 0; i < path->npts; i++)
 	{
 		j = (i + 1) % path->npts;
-		area += path->p[i].x * path->p[j].y;
-		area -= path->p[i].y * path->p[j].x;
+		area = float8_pl(area, float8_mul(path->p[i].x, path->p[j].y));
+		area = float8_mi(area, float8_mul(path->p[i].y, path->p[j].x));
 	}
 
-	area *= 0.5;
-	PG_RETURN_FLOAT8(area < 0.0 ? -area : area);
+	PG_RETURN_FLOAT8(float8_div(fabs(area), 2.0));
 }
 
 
 Datum
 path_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	PATH	   *path;
 	bool		isopen;
 	char	   *s;
@@ -1521,33 +1536,33 @@ path_inter(PG_FUNCTION_ARGS)
 				j;
 	LSEG		seg1,
 				seg2;
 
 	Assert(p1->npts > 0 && p2->npts > 0);
 
 	b1.high.x = b1.low.x = p1->p[0].x;
 	b1.high.y = b1.low.y = p1->p[0].y;
 	for (i = 1; i < p1->npts; i++)
 	{
-		b1.high.x = Max(p1->p[i].x, b1.high.x);
-		b1.high.y = Max(p1->p[i].y, b1.high.y);
-		b1.low.x = Min(p1->p[i].x, b1.low.x);
-		b1.low.y = Min(p1->p[i].y, b1.low.y);
+		b1.high.x = float8_max(p1->p[i].x, b1.high.x);
+		b1.high.y = float8_max(p1->p[i].y, b1.high.y);
+		b1.low.x = float8_min(p1->p[i].x, b1.low.x);
+		b1.low.y = float8_min(p1->p[i].y, b1.low.y);
 	}
 	b2.high.x = b2.low.x = p2->p[0].x;
 	b2.high.y = b2.low.y = p2->p[0].y;
 	for (i = 1; i < p2->npts; i++)
 	{
-		b2.high.x = Max(p2->p[i].x, b2.high.x);
-		b2.high.y = Max(p2->p[i].y, b2.high.y);
-		b2.low.x = Min(p2->p[i].x, b2.low.x);
-		b2.low.y = Min(p2->p[i].y, b2.low.y);
+		b2.high.x = float8_max(p2->p[i].x, b2.high.x);
+		b2.high.y = float8_max(p2->p[i].y, b2.high.y);
+		b2.low.x = float8_min(p2->p[i].x, b2.low.x);
+		b2.low.y = float8_min(p2->p[i].y, b2.low.y);
 	}
 	if (!box_ov(&b1, &b2))
 		PG_RETURN_BOOL(false);
 
 	/* pairwise check lseg intersections */
 	for (i = 0; i < p1->npts; i++)
 	{
 		int			iprev;
 
 		if (i > 0)
@@ -1623,21 +1638,21 @@ path_distance(PG_FUNCTION_ARGS)
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
 			tmp = lseg_closept_lseg(NULL, &seg1, &seg2);
-			if (!have_min || tmp < min)
+			if (!have_min || float8_lt(tmp, min))
 			{
 				min = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	if (!have_min)
 		PG_RETURN_NULL();
 
@@ -1662,21 +1677,21 @@ path_length(PG_FUNCTION_ARGS)
 
 		if (i > 0)
 			iprev = i - 1;
 		else
 		{
 			if (!path->closed)
 				continue;
 			iprev = path->npts - 1; /* include the closure segment */
 		}
 
-		result += point_dt(&path->p[iprev], &path->p[i]);
+		result = float8_pl(result, point_dt(&path->p[iprev], &path->p[i]));
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /***********************************************************************
  **
  **		Routines for 2D points.
  **
  ***********************************************************************/
@@ -1822,44 +1837,52 @@ point_eq(PG_FUNCTION_ARGS)
 
 Datum
 point_ne(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_BOOL(!point_eq_point(pt1, pt2));
 }
 
+
+/*
+ * Check whether the two points are the same
+ *
+ * We consider NaNs coordinates to be equal to each other to let those points
+ * to be found.
+ */
 static inline bool
 point_eq_point(Point *pt1, Point *pt2)
 {
-	return FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y);
+	return ((FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y)) ||
+			(float8_eq(pt1->x, pt2->x) && float8_eq(pt1->y, pt2->y)));
 }
 
 
 /*----------------------------------------------------------
  *	"Arithmetic" operators on points.
  *---------------------------------------------------------*/
 
 Datum
 point_distance(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
 static inline float8
 point_dt(Point *pt1, Point *pt2)
 {
-	return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
+	return HYPOT(float8_mi(pt1->x, pt2->x), float8_mi(pt1->y, pt2->y));
 }
 
 Datum
 point_slope(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_sl(pt1, pt2));
 }
@@ -1870,37 +1893,37 @@ point_slope(PG_FUNCTION_ARGS)
  *
  * Note that this function returns DBL_MAX when the points are the same.
  */
 static inline float8
 point_sl(Point *pt1, Point *pt2)
 {
 	if (FPeq(pt1->x, pt2->x))
 		return DBL_MAX;
 	if (FPeq(pt1->y, pt2->y))
 		return 0.0;
-	return (pt1->y - pt2->y) / (pt1->x - pt2->x);
+	return float8_div(float8_mi(pt1->y, pt2->y), float8_mi(pt1->x, pt2->x));
 }
 
 
 /*
  * Return inverse slope of two points
  *
  * Note that this function returns 0.0 when the points are the same.
  */
 static inline float8
 point_invsl(Point *pt1, Point *pt2)
 {
 	if (FPeq(pt1->x, pt2->x))
 		return 0.0;
 	if (FPeq(pt1->y, pt2->y))
 		return DBL_MAX;
-	return (pt1->x - pt2->x) / (pt2->y - pt1->y);
+	return float8_div(float8_mi(pt1->x, pt2->x), float8_mi(pt2->y, pt1->y));
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D line segments.
  **
  ***********************************************************************/
 
 /*----------------------------------------------------------
@@ -2160,22 +2183,22 @@ lseg_distance(PG_FUNCTION_ARGS)
 
 
 Datum
 lseg_center(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
-	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
+	result->x = float8_div(float8_pl(lseg->p[0].x, lseg->p[1].x), 2.0);
+	result->y = float8_div(float8_pl(lseg->p[0].y, lseg->p[1].y), 2.0);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  *		Find the intersection point of two segments (if any).
  *
  * This returns true if two line segments intersect, false if they do not.
  * This also sets the intersection point to *result, if it is not NULL.
@@ -2284,21 +2307,21 @@ dist_ppath(PG_FUNCTION_ARGS)
 			iprev = i - 1;
 		else
 		{
 			if (!path->closed)
 				continue;
 			iprev = path->npts - 1; /* Include the closure segment */
 		}
 
 		statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
 		tmp = lseg_closept_point(NULL, &lseg, pt);
-		if (!have_min || tmp < result)
+		if (!have_min || float8_lt(tmp, result))
 		{
 			result = tmp;
 			have_min = true;
 		}
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
@@ -2314,33 +2337,28 @@ dist_pb(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
-	float8		result,
-				d2;
+	float8		result;
 
 	if (lseg_interpt_line(NULL, lseg, line))
 		result = 0.0;
 	else
-	{
-		result = line_closept_point(NULL, line, &lseg->p[0]);
-		d2 = line_closept_point(NULL, line, &lseg->p[1]);
 		/* XXX shouldn't we take the min not max? */
-		if (d2 > result)
-			result = d2;
-	}
+		result = float8_max(line_closept_point(NULL, line, &lseg->p[0]),
+							line_closept_point(NULL, line, &lseg->p[1]));
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
@@ -2373,25 +2391,24 @@ dist_lb(PG_FUNCTION_ARGS)
  * Distance from a circle to a polygon
  */
 Datum
 dist_cpoly(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	POLYGON    *poly = PG_GETARG_POLYGON_P(1);
 	float8		result;
 
 	/* calculate distance to center, and subtract radius */
-	result = dist_ppoly_internal(&circle->center, poly);
-
-	result -= circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(dist_ppoly_internal(&circle->center, poly),
+					   circle->radius);
+	if (result < 0.0)
+		result = 0.0;
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a point to a polygon
  */
 Datum
 dist_ppoly(PG_FUNCTION_ARGS)
 {
@@ -2403,21 +2420,21 @@ dist_ppoly(PG_FUNCTION_ARGS)
 
 Datum
 dist_polyp(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(dist_ppoly_internal(point, poly));
 }
 
-static double
+static float8
 dist_ppoly_internal(Point *pt, POLYGON *poly)
 {
 	float8		result;
 	float8		d;
 	int			i;
 	LSEG		seg;
 
 	if (point_inside(pt, poly->npts, poly->p) != 0)
 	{
 #ifdef GEODEBUG
@@ -2440,21 +2457,21 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
 	for (i = 0; i < poly->npts - 1; i++)
 	{
 		seg.p[0].x = poly->p[i].x;
 		seg.p[0].y = poly->p[i].y;
 		seg.p[1].x = poly->p[i + 1].x;
 		seg.p[1].y = poly->p[i + 1].y;
 		d = lseg_closept_point(NULL, &seg, pt);
 #ifdef GEODEBUG
 		printf("dist_ppoly_internal- segment %d distance is %f\n", (i + 1), d);
 #endif
-		if (d < result)
+		if (float8_lt(d, result))
 			result = d;
 	}
 
 	return result;
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
  *				Intersection point of objects.
@@ -2542,21 +2559,22 @@ line_closept_point(Point *result, LINE *line, Point *point)
 
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	line_closept_point(result, line, pt);
+	if (isnan(line_closept_point(result, line, pt)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point on line segment to specified point.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
@@ -2599,134 +2617,136 @@ close_ps(PG_FUNCTION_ARGS)
 /*
  * Closest point on line segment to line segment
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
 {
 	Point		point;
-	double		dist;
-	double		d;
+	float8		dist,
+				d;
 
 	d = lseg_closept_point(NULL, l1, &l2->p[0]);
 	dist = d;
 	if (result != NULL)
 		*result = l2->p[0];
 
 	d = lseg_closept_point(NULL, l1, &l2->p[1]);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = l2->p[1];
 	}
 
-	if (lseg_closept_point(&point, l2, &l1->p[0]) < dist)
+	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[0]), dist))
 		d = lseg_closept_point(result, l1, &point);
 
-	if (lseg_closept_point(&point, l2, &l1->p[1]) < dist)
+	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[1]), dist))
 		d = lseg_closept_point(result, l1, &point);
 
-	if (d < dist)
+	if (float8_lt(d, dist))
 		dist = d;
 
 	return dist;
 }
 
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	lseg_closept_lseg(result, l2, l1);
+	if (isnan(lseg_closept_lseg(result, l2, l1)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point on or in box to specified point.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 box_closept_point(Point *result, BOX *box, Point *pt)
 {
-	LSEG		lseg;
+	float8		dist,
+				d;
 	Point		point,
 				closept;
-	double		dist,
-				d;
+	LSEG		lseg;
 
 	if (box_contain_point(box, pt))
 	{
 		if (result != NULL)
 			*result = *pt;
 
 		return 0.0;
 	}
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&lseg, &box->low, &point);
 	dist = lseg_closept_point(result, &lseg, pt);
 
 	statlseg_construct(&lseg, &box->high, &point);
 	d = lseg_closept_point(&closept, &lseg, pt);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&lseg, &box->low, &point);
 	d = lseg_closept_point(&closept, &lseg, pt);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	statlseg_construct(&lseg, &box->high, &point);
 	d = lseg_closept_point(&closept, &lseg, pt);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	return dist;
 }
 
 Datum
 close_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	box_closept_point(result, box, pt);
+	if (isnan(box_closept_point(result, box, pt)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_sl()
  * Closest point on line to line segment.
  *
  * XXX THIS CODE IS WRONG
  * The code is actually calculating the point on the line segment
@@ -2744,21 +2764,21 @@ close_sl(PG_FUNCTION_ARGS)
 	float8		d1,
 				d2;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (lseg_interpt_line(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = line_closept_point(NULL, line, &lseg->p[0]);
 	d2 = line_closept_point(NULL, line, &lseg->p[1]);
-	if (d1 < d2)
+	if (float8_lt(d1, d2))
 		*result = lseg->p[0];
 	else
 		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
 
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_sl\" not implemented")));
@@ -2808,92 +2828,94 @@ lseg_closept_line(Point *result, LSEG *lseg, LINE *line)
 
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	lseg_closept_line(result, lseg, line);
+	if (isnan(lseg_closept_line(result, lseg, line)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point on or in box to line segment.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 box_closept_lseg(Point *result, BOX *box, LSEG *lseg)
 {
+	float8		dist,
+				d;
 	Point		point,
 				closept;
 	LSEG		bseg;
-	double		dist,
-				d;
 
 	if (box_interpt_lseg(result, box, lseg))
 		return 0.0;
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
 	dist = lseg_closept_lseg(result, &bseg, lseg);
 
 	statlseg_construct(&bseg, &box->high, &point);
 	d = lseg_closept_lseg(&closept, &bseg, lseg);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&bseg, &box->low, &point);
 	d = lseg_closept_lseg(&closept, &bseg, lseg);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	statlseg_construct(&bseg, &box->high, &point);
 	d = lseg_closept_lseg(&closept, &bseg, lseg);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	return dist;
 }
 
 Datum
 close_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	box_closept_lseg(result, box, lseg);
+	if (isnan(box_closept_lseg(result, box, lseg)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 Datum
 close_lb(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -2912,21 +2934,23 @@ close_lb(PG_FUNCTION_ARGS)
  *		on_
  *				Whether one object lies completely within another.
  *-------------------------------------------------------------------*/
 
 /*
  *		Does the point satisfy the equation?
  */
 static bool
 line_contain_point(LINE *line, Point *point)
 {
-	return FPzero(line->A * point->x + line->B * point->y + line->C);
+	return FPzero(float8_pl(float8_pl(float8_mul(line->A, point->x),
+									  float8_mul(line->B, point->y)),
+							line->C));
 }
 
 Datum
 on_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
 	PG_RETURN_BOOL(line_contain_point(line, pt));
 }
@@ -2993,33 +3017,32 @@ box_contain_pt(PG_FUNCTION_ARGS)
  *				but not cross.
  *				(we can do p-in-p in lg(n), but it takes preprocessing)
  */
 Datum
 on_ppath(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	PATH	   *path = PG_GETARG_PATH_P(1);
 	int			i,
 				n;
-	double		a,
+	float8		a,
 				b;
 
 	/*-- OPEN --*/
 	if (!path->closed)
 	{
 		n = path->npts - 1;
 		a = point_dt(pt, &path->p[0]);
 		for (i = 0; i < n; i++)
 		{
 			b = point_dt(pt, &path->p[i + 1]);
-			if (FPeq(a + b,
-					 point_dt(&path->p[i], &path->p[i + 1])))
+			if (FPeq(float8_pl(a, b), point_dt(&path->p[i], &path->p[i + 1])))
 				PG_RETURN_BOOL(true);
 			a = b;
 		}
 		PG_RETURN_BOOL(false);
 	}
 
 	/*-- CLOSED --*/
 	PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
 }
 
@@ -3091,24 +3114,24 @@ inter_sl(PG_FUNCTION_ARGS)
  * Optimize for non-intersection by checking for box intersection first.
  * - thomas 1998-01-30
  */
 static bool
 box_interpt_lseg(Point *result, BOX *box, LSEG *lseg)
 {
 	BOX			lbox;
 	LSEG		bseg;
 	Point		point;
 
-	lbox.low.x = Min(lseg->p[0].x, lseg->p[1].x);
-	lbox.low.y = Min(lseg->p[0].y, lseg->p[1].y);
-	lbox.high.x = Max(lseg->p[0].x, lseg->p[1].x);
-	lbox.high.y = Max(lseg->p[0].y, lseg->p[1].y);
+	lbox.low.x = float8_min(lseg->p[0].x, lseg->p[1].x);
+	lbox.low.y = float8_min(lseg->p[0].y, lseg->p[1].y);
+	lbox.high.x = float8_max(lseg->p[0].x, lseg->p[1].x);
+	lbox.high.y = float8_max(lseg->p[0].y, lseg->p[1].y);
 
 	/* nothing close to overlap? then not going to intersect */
 	if (!box_ov(&lbox, box))
 		return false;
 
 	if (result != NULL)
 	{
 		box_cn(&point, box);
 		lseg_closept_point(result, lseg, &point);
 	}
@@ -3201,38 +3224,38 @@ inter_lb(PG_FUNCTION_ARGS)
  * make_bound_box - create the bounding box for the input polygon
  *------------------------------------------------------------------*/
 
 /*---------------------------------------------------------------------
  * Make the smallest bounding box for the given polygon.
  *---------------------------------------------------------------------*/
 static void
 make_bound_box(POLYGON *poly)
 {
 	int			i;
-	double		x1,
+	float8		x1,
 				y1,
 				x2,
 				y2;
 
 	Assert(poly->npts > 0);
 
 	x1 = x2 = poly->p[0].x;
 	y2 = y1 = poly->p[0].y;
 	for (i = 1; i < poly->npts; i++)
 	{
-		if (poly->p[i].x < x1)
+		if (float8_lt(poly->p[i].x, x1))
 			x1 = poly->p[i].x;
-		if (poly->p[i].x > x2)
+		if (float8_gt(poly->p[i].x, x2))
 			x2 = poly->p[i].x;
-		if (poly->p[i].y < y1)
+		if (float8_lt(poly->p[i].y, y1))
 			y1 = poly->p[i].y;
-		if (poly->p[i].y > y2)
+		if (float8_gt(poly->p[i].y, y2))
 			y2 = poly->p[i].y;
 	}
 
 	poly->boundbox.low.x = x1;
 	poly->boundbox.high.x = x2;
 	poly->boundbox.low.y = y1;
 	poly->boundbox.high.y = y2;
 }
 
 /*------------------------------------------------------------------
@@ -3731,22 +3754,22 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 	}
 
 	if (res && !intersection)
 	{
 		Point		p;
 
 		/*
 		 * if X-intersection wasn't found  then check central point of tested
 		 * segment. In opposite case we already check all subsegments
 		 */
-		p.x = (t.p[0].x + t.p[1].x) / 2.0;
-		p.y = (t.p[0].y + t.p[1].y) / 2.0;
+		p.x = float8_div(float8_pl(t.p[0].x, t.p[1].x), 2.0);
+		p.y = float8_div(float8_pl(t.p[0].y, t.p[1].y), 2.0);
 
 		res = point_inside(&p, poly->npts, poly->p);
 	}
 
 	return res;
 }
 
 /*-----------------------------------------------------------------
  * Determine if polygon A contains polygon B.
  *-----------------------------------------------------------------*/
@@ -3872,22 +3895,22 @@ construct_point(PG_FUNCTION_ARGS)
 	point_construct(result, x, y);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_add_point(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x + pt2->x,
-					pt1->y + pt2->y);
+					float8_pl(pt1->x, pt2->x),
+					float8_pl(pt1->y, pt2->y));
 }
 
 Datum
 point_add(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -3895,22 +3918,22 @@ point_add(PG_FUNCTION_ARGS)
 	point_add_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_sub_point(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x - pt2->x,
-					pt1->y - pt2->y);
+					float8_mi(pt1->x, pt2->x),
+					float8_mi(pt1->y, pt2->y));
 }
 
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -3918,54 +3941,53 @@ point_sub(PG_FUNCTION_ARGS)
 	point_sub_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_mul_point(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					(pt1->x * pt2->x) - (pt1->y * pt2->y),
-					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+					float8_mi(float8_mul(pt1->x, pt2->x),
+							  float8_mul(pt1->y, pt2->y)),
+					float8_pl(float8_mul(pt1->x, pt2->y),
+							  float8_mul(pt1->y, pt2->x)));
 }
 
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	point_mul_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_div_point(Point *result, Point *pt1, Point *pt2)
 {
-	double		div;
+	float8		div;
 
-	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
-
-	if (div == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
+	div = float8_pl(float8_mul(pt2->x, pt2->x), float8_mul(pt2->y, pt2->y));
 
 	point_construct(result,
-					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
-					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+					float8_div(float8_pl(float8_mul(pt1->x, pt2->x),
+										 float8_mul(pt1->y, pt2->y)), div),
+					float8_div(float8_mi(float8_mul(pt1->y, pt2->x),
+										 float8_mul(pt1->x, pt2->y)), div));
 }
 
 Datum
 point_div(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -4088,24 +4110,24 @@ point_box(PG_FUNCTION_ARGS)
  */
 Datum
 boxes_bound_box(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0),
 			   *box2 = PG_GETARG_BOX_P(1),
 			   *container;
 
 	container = (BOX *) palloc(sizeof(BOX));
 
-	container->high.x = Max(box1->high.x, box2->high.x);
-	container->low.x = Min(box1->low.x, box2->low.x);
-	container->high.y = Max(box1->high.y, box2->high.y);
-	container->low.y = Min(box1->low.y, box2->low.y);
+	container->high.x = float8_max(box1->high.x, box2->high.x);
+	container->low.x = float8_min(box1->low.x, box2->low.x);
+	container->high.y = float8_max(box1->high.y, box2->high.y);
+	container->low.y = float8_min(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(container);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D paths.
  **
  ***********************************************************************/
@@ -4411,21 +4433,22 @@ circle_in(PG_FUNCTION_ARGS)
 		if (*cp == LDELIM)
 			s = cp;
 	}
 
 	pair_decode(s, &circle->center.x, &circle->center.y, &s, "circle", str);
 
 	if (*s == DELIM)
 		s++;
 
 	circle->radius = single_decode(s, &s, "circle", str);
-	if (circle->radius < 0)
+	/* We have to accept NaN. */
+	if (circle->radius < 0.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
 
 	while (depth > 0)
 	{
 		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
@@ -4478,21 +4501,22 @@ circle_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	circle->center.x = pq_getmsgfloat8(buf);
 	circle->center.y = pq_getmsgfloat8(buf);
 	circle->radius = pq_getmsgfloat8(buf);
 
-	if (circle->radius < 0)
+	/* We have to accept NaN. */
+	if (circle->radius < 0.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
 				 errmsg("invalid radius in external \"circle\" value")));
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 /*
  *		circle_send			- converts circle to binary format
  */
@@ -4509,166 +4533,170 @@ circle_send(PG_FUNCTION_ARGS)
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for CIRCLEs.
  *		<, >, <=, >=, and == are based on circle area.
  *---------------------------------------------------------*/
 
 /*		circles identical?
+ *
+ * We consider NaNs values to be equal to each other to let those circles
+ * to be found.
  */
 Datum
 circle_same(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPeq(circle1->radius, circle2->radius) &&
+	PG_RETURN_BOOL(((isnan(circle1->radius) && isnan(circle1->radius)) ||
+					FPeq(circle1->radius, circle2->radius)) &&
 				   point_eq_point(&circle1->center, &circle2->center));
 }
 
 /*		circle_overlap	-		does circle1 overlap circle2?
  */
 Datum
 circle_overlap(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle1->radius + circle2->radius));
+						float8_pl(circle1->radius, circle2->radius)));
 }
 
 /*		circle_overleft -		is the right edge of circle1 at or left of
  *								the right edge of circle2?
  */
 Datum
 circle_overleft(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.x + circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_left		-		is circle1 strictly left of circle2?
  */
 Datum
 circle_left(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.x + circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_right	-		is circle1 strictly right of circle2?
  */
 Datum
 circle_right(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.x - circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_overright	-	is the left edge of circle1 at or right of
  *								the left edge of circle2?
  */
 Datum
 circle_overright(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.x - circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_contained		-		is circle1 contained by circle2?
  */
 Datum
 circle_contained(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle2->radius - circle1->radius));
+						float8_mi(circle2->radius, circle1->radius)));
 }
 
 /*		circle_contain	-		does circle1 contain circle2?
  */
 Datum
 circle_contain(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle1->radius - circle2->radius));
+						float8_mi(circle1->radius, circle2->radius)));
 }
 
 
 /*		circle_below		-		is circle1 strictly below circle2?
  */
 Datum
 circle_below(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.y + circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_above	-		is circle1 strictly above circle2?
  */
 Datum
 circle_above(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.y - circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overbelow -		is the upper edge of circle1 at or below
  *								the upper edge of circle2?
  */
 Datum
 circle_overbelow(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.y + circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overabove	-	is the lower edge of circle1 at or above
  *								the lower edge of circle2?
  */
 Datum
 circle_overabove(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.y - circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 
 /*		circle_relop	-		is area(circle1) relop area(circle2), within
  *								our accuracy constraint?
  */
 Datum
 circle_eq(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
@@ -4767,36 +4795,36 @@ circle_sub_pt(PG_FUNCTION_ARGS)
 Datum
 circle_mul_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_mul_point(&result->center, &circle->center, point);
-	result->radius = circle->radius * HYPOT(point->x, point->y);
+	result->radius = float8_mul(circle->radius, HYPOT(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_div_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_div_point(&result->center, &circle->center, point);
-	result->radius = circle->radius / HYPOT(point->x, point->y);
+	result->radius = float8_div(circle->radius, HYPOT(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /*		circle_area		-		returns the area of the circle.
  */
 Datum
 circle_area(PG_FUNCTION_ARGS)
 {
@@ -4806,21 +4834,21 @@ circle_area(PG_FUNCTION_ARGS)
 }
 
 
 /*		circle_diameter -		returns the diameter of the circle.
  */
 Datum
 circle_diameter(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
-	PG_RETURN_FLOAT8(2 * circle->radius);
+	PG_RETURN_FLOAT8(float8_mul(circle->radius, 2.0));
 }
 
 
 /*		circle_radius	-		returns the radius of the circle.
  */
 Datum
 circle_radius(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
@@ -4831,81 +4859,85 @@ circle_radius(PG_FUNCTION_ARGS)
 /*		circle_distance -		returns the distance between
  *								  two circles.
  */
 Datum
 circle_distance(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(&circle1->center, &circle2->center) -
-		(circle1->radius + circle2->radius);
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(&circle1->center, &circle2->center),
+					   float8_pl(circle1->radius, circle2->radius));
+	if (result < 0.0)
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 
 Datum
 circle_contain_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
 	PG_RETURN_BOOL(d <= circle->radius);
 }
 
 
 Datum
 pt_contained_circle(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
 	PG_RETURN_BOOL(d <= circle->radius);
 }
 
 
 /*		dist_pc -		returns the distance between
  *						  a point and a circle.
  */
 Datum
 dist_pc(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center),
+					   circle->radius);
+	if (result < 0.0)
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a circle to a point
  */
 Datum
 dist_cpoint(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center), circle->radius);
+	if (result < 0.0)
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*		circle_center	-		returns the center point of the circle.
  */
 Datum
 circle_center(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *result;
@@ -4913,24 +4945,24 @@ circle_center(PG_FUNCTION_ARGS)
 	result = (Point *) palloc(sizeof(Point));
 	result->x = circle->center.x;
 	result->y = circle->center.y;
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		circle_ar		-		returns the area of the circle.
  */
-static double
+static float8
 circle_ar(CIRCLE *circle)
 {
-	return M_PI * (circle->radius * circle->radius);
+	return float8_mul(float8_mul(circle->radius, circle->radius), M_PI);
 }
 
 
 /*----------------------------------------------------------
  *	Conversion operators.
  *---------------------------------------------------------*/
 
 Datum
 cr_circle(PG_FUNCTION_ARGS)
 {
@@ -4945,65 +4977,65 @@ cr_circle(PG_FUNCTION_ARGS)
 	result->radius = radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_box(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	BOX		   *box;
-	double		delta;
+	float8		delta;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
-	delta = circle->radius / sqrt(2.0);
+	delta = float8_div(circle->radius, sqrt(2.0));
 
-	box->high.x = circle->center.x + delta;
-	box->low.x = circle->center.x - delta;
-	box->high.y = circle->center.y + delta;
-	box->low.y = circle->center.y - delta;
+	box->high.x = float8_pl(circle->center.x, delta);
+	box->low.x = float8_mi(circle->center.x, delta);
+	box->high.y = float8_pl(circle->center.y, delta);
+	box->low.y = float8_mi(circle->center.y, delta);
 
 	PG_RETURN_BOX_P(box);
 }
 
 /* box_circle()
  * Convert a box to a circle.
  */
 Datum
 box_circle(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	circle->center.x = (box->high.x + box->low.x) / 2;
-	circle->center.y = (box->high.y + box->low.y) / 2;
+	circle->center.x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	circle->center.y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 
 	circle->radius = point_dt(&circle->center, &box->high);
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 
 Datum
 circle_poly(PG_FUNCTION_ARGS)
 {
 	int32		npts = PG_GETARG_INT32(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	POLYGON    *poly;
 	int			base_size,
 				size;
 	int			i;
-	double		angle;
-	double		anglestep;
+	float8		angle;
+	float8		anglestep;
 
 	if (FPzero(circle->radius))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("cannot convert circle with radius zero to polygon")));
 
 	if (npts < 2)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("must request at least 2 points")));
@@ -5014,27 +5046,30 @@ circle_poly(PG_FUNCTION_ARGS)
 	/* Check for integer overflow */
 	if (base_size / npts != sizeof(poly->p[0]) || size <= base_size)
 		ereport(ERROR,
 				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 				 errmsg("too many points requested")));
 
 	poly = (POLYGON *) palloc0(size);	/* zero any holes */
 	SET_VARSIZE(poly, size);
 	poly->npts = npts;
 
-	anglestep = (2.0 * M_PI) / npts;
+	anglestep = float8_div(2.0 * M_PI, npts);
 
 	for (i = 0; i < npts; i++)
 	{
-		angle = i * anglestep;
-		poly->p[i].x = circle->center.x - (circle->radius * cos(angle));
-		poly->p[i].y = circle->center.y + (circle->radius * sin(angle));
+		angle = float8_mul(anglestep, i);
+
+		poly->p[i].x = float8_mi(circle->center.x,
+								 float8_mul(circle->radius, cos(angle)));
+		poly->p[i].y = float8_pl(circle->center.y,
+								 float8_mul(circle->radius, sin(angle)));
 	}
 
 	make_bound_box(poly);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
 /*
  * Convert polygon to circle
  *
@@ -5049,26 +5084,27 @@ poly_to_circle(CIRCLE *result, POLYGON *poly)
 	int			i;
 
 	Assert(poly->npts > 0);
 
 	result->center.x = 0;
 	result->center.y = 0;
 	result->radius = 0;
 
 	for (i = 0; i < poly->npts; i++)
 		point_add_point(&result->center, &result->center, &poly->p[i]);
-	result->center.x /= poly->npts;
-	result->center.y /= poly->npts;
+	result->center.x = float8_div(result->center.x, poly->npts);
+	result->center.y = float8_div(result->center.y, poly->npts);
 
 	for (i = 0; i < poly->npts; i++)
-		result->radius += point_dt(&poly->p[i], &result->center);
-	result->radius /= poly->npts;
+		result->radius = float8_pl(result->radius,
+								   point_dt(&poly->p[i], &result->center));
+	result->radius = float8_div(result->radius, poly->npts);
 }
 
 Datum
 poly_circle(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
@@ -5093,44 +5129,44 @@ poly_circle(PG_FUNCTION_ARGS)
  *	http://hopf.math.northwestern.edu/index.html
  *	Description of algorithm:  http://www.linuxjournal.com/article/2197
  *							   http://www.linuxjournal.com/article/2029
  */
 
 #define POINT_ON_POLYGON INT_MAX
 
 static int
 point_inside(Point *p, int npts, Point *plist)
 {
-	double		x0,
+	float8		x0,
 				y0;
-	double		prev_x,
+	float8		prev_x,
 				prev_y;
 	int			i = 0;
-	double		x,
+	float8		x,
 				y;
 	int			cross,
 				total_cross = 0;
 
 	Assert(npts > 0);
 
 	/* compute first polygon point relative to single point */
-	x0 = plist[0].x - p->x;
-	y0 = plist[0].y - p->y;
+	x0 = float8_mi(plist[0].x, p->x);
+	y0 = float8_mi(plist[0].y, p->y);
 
 	prev_x = x0;
 	prev_y = y0;
 	/* loop over polygon points and aggregate total_cross */
 	for (i = 1; i < npts; i++)
 	{
 		/* compute next polygon point relative to single point */
-		x = plist[i].x - p->x;
-		y = plist[i].y - p->y;
+		x = float8_mi(plist[i].x, p->x);
+		y = float8_mi(plist[i].y, p->y);
 
 		/* compute previous to current point crossing */
 		if ((cross = lseg_crossing(x, y, prev_x, prev_y)) == POINT_ON_POLYGON)
 			return 2;
 		total_cross += cross;
 
 		prev_x = x;
 		prev_y = y;
 	}
 
@@ -5148,69 +5184,74 @@ point_inside(Point *p, int npts, Point *plist)
 /* lseg_crossing()
  * Returns +/-2 if line segment crosses the positive X-axis in a +/- direction.
  * Returns +/-1 if one point is on the positive X-axis.
  * Returns 0 if both points are on the positive X-axis, or there is no crossing.
  * Returns POINT_ON_POLYGON if the segment contains (0,0).
  * Wow, that is one confusing API, but it is used above, and when summed,
  * can tell is if a point is in a polygon.
  */
 
 static int
-lseg_crossing(double x, double y, double prev_x, double prev_y)
+lseg_crossing(float8 x, float8 y, float8 prev_x, float8 prev_y)
 {
-	double		z;
+	float8		z;
 	int			y_sign;
 
 	if (FPzero(y))
 	{							/* y == 0, on X axis */
 		if (FPzero(x))			/* (x,y) is (0,0)? */
 			return POINT_ON_POLYGON;
 		else if (FPgt(x, 0))
 		{						/* x > 0 */
 			if (FPzero(prev_y)) /* y and prev_y are zero */
 				/* prev_x > 0? */
-				return FPgt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
-			return FPlt(prev_y, 0) ? 1 : -1;
+				return FPgt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
+			return FPlt(prev_y, 0.0) ? 1 : -1;
 		}
 		else
 		{						/* x < 0, x not on positive X axis */
 			if (FPzero(prev_y))
 				/* prev_x < 0? */
-				return FPlt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
+				return FPlt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
 			return 0;
 		}
 	}
 	else
 	{							/* y != 0 */
 		/* compute y crossing direction from previous point */
-		y_sign = FPgt(y, 0) ? 1 : -1;
+		y_sign = FPgt(y, 0.0) ? 1 : -1;
 
 		if (FPzero(prev_y))
 			/* previous point was on X axis, so new point is either off or on */
-			return FPlt(prev_x, 0) ? 0 : y_sign;
-		else if (FPgt(y_sign * prev_y, 0))
+			return FPlt(prev_x, 0.0) ? 0 : y_sign;
+		else if ((y_sign < 0 && FPlt(prev_y, 0.0)) ||
+				 (y_sign > 0 && FPgt(prev_y, 0.0)))
 			/* both above or below X axis */
 			return 0;			/* same sign */
 		else
 		{						/* y and prev_y cross X-axis */
-			if (FPge(x, 0) && FPgt(prev_x, 0))
+			if (FPge(x, 0.0) && FPgt(prev_x, 0.0))
 				/* both non-negative so cross positive X-axis */
 				return 2 * y_sign;
-			if (FPlt(x, 0) && FPle(prev_x, 0))
+			if (FPlt(x, 0.0) && FPle(prev_x, 0.0))
 				/* both non-positive so do not cross positive X-axis */
 				return 0;
 
 			/* x and y cross axises, see URL above point_inside() */
-			z = (x - prev_x) * y - (y - prev_y) * x;
+			z = float8_mi(float8_mul(float8_mi(x, prev_x), y),
+						  float8_mul(float8_mi(y, prev_y), x));
 			if (FPzero(z))
 				return POINT_ON_POLYGON;
-			return FPgt((y_sign * z), 0) ? 0 : 2 * y_sign;
+			if ((y_sign < 0 && FPlt(z, 0.0)) ||
+				(y_sign > 0 && FPgt(z, 0.0)))
+				return 0;
+			return 2 * y_sign;
 		}
 	}
 }
 
 
 static bool
 plist_same(int npts, Point *p1, Point *p2)
 {
 	int			i,
 				ii,
@@ -5280,47 +5321,52 @@ plist_same(int npts, Point *p1, Point *p2)
  *					 = x * sqrt( 1 + y^2/x^2 )
  *					 = x * sqrt( 1 + y/x * y/x )
  *
  * It is expected that this routine will eventually be replaced with the
  * C99 hypot() function.
  *
  * This implementation conforms to IEEE Std 1003.1 and GLIBC, in that the
  * case of hypot(inf,nan) results in INF, and not NAN.
  *-----------------------------------------------------------------------
  */
-double
-pg_hypot(double x, double y)
+float8
+pg_hypot(float8 x, float8 y)
 {
-	double		yx;
+	float8		yx,
+				result;
 
 	/* Handle INF and NaN properly */
 	if (isinf(x) || isinf(y))
 		return get_float8_infinity();
 
 	if (isnan(x) || isnan(y))
 		return get_float8_nan();
 
 	/* Else, drop any minus signs */
 	x = fabs(x);
 	y = fabs(y);
 
 	/* Swap x and y if needed to make x the larger one */
 	if (x < y)
 	{
-		double		temp = x;
+		float8		temp = x;
 
 		x = y;
 		y = temp;
 	}
 
 	/*
 	 * If y is zero, the hypotenuse is x.  This test saves a few cycles in
 	 * such cases, but more importantly it also protects against
 	 * divide-by-zero errors, since now x >= y.
 	 */
 	if (y == 0.0)
 		return x;
 
 	/* Determine the hypotenuse */
 	yx = y / x;
-	return x * sqrt(1.0 + (yx * yx));
+	result = x * sqrt(1.0 + (yx * yx));
+
+	check_float8_val(result, false, false);
+
+	return result;
 }
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index fea36f361a..4aff973ef3 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -77,38 +77,38 @@
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
 #include "utils/float.h"
 #include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
- * is going only going to be used in a place to effect the performance
+ * is only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
 compareDoubles(const void *a, const void *b)
 {
-	double		x = *(double *) a;
-	double		y = *(double *) b;
+	float8		x = *(float8 *) a;
+	float8		y = *(float8 *) b;
 
 	if (x == y)
 		return 0;
 	return (x > y) ? 1 : -1;
 }
 
 typedef struct
 {
-	double		low;
-	double		high;
+	float8		low;
+	float8		high;
 } Range;
 
 typedef struct
 {
 	Range		left;
 	Range		right;
 } RangeBox;
 
 typedef struct
 {
@@ -168,21 +168,21 @@ getRangeBox(BOX *box)
 /*
  * Initialize the traversal value
  *
  * In the beginning, we don't have any restrictions.  We have to
  * initialize the struct to cover the whole 4D space.
  */
 static RectBox *
 initRectBox(void)
 {
 	RectBox    *rect_box = (RectBox *) palloc(sizeof(RectBox));
-	double		infinity = get_float8_infinity();
+	float8		infinity = get_float8_infinity();
 
 	rect_box->range_box_x.left.low = -infinity;
 	rect_box->range_box_x.left.high = infinity;
 
 	rect_box->range_box_x.right.low = -infinity;
 	rect_box->range_box_x.right.high = infinity;
 
 	rect_box->range_box_y.left.low = -infinity;
 	rect_box->range_box_y.left.high = infinity;
 
@@ -411,40 +411,40 @@ spg_box_quad_choose(PG_FUNCTION_ARGS)
  * point as the median of the coordinates of the boxes.
  */
 Datum
 spg_box_quad_picksplit(PG_FUNCTION_ARGS)
 {
 	spgPickSplitIn *in = (spgPickSplitIn *) PG_GETARG_POINTER(0);
 	spgPickSplitOut *out = (spgPickSplitOut *) PG_GETARG_POINTER(1);
 	BOX		   *centroid;
 	int			median,
 				i;
-	double	   *lowXs = palloc(sizeof(double) * in->nTuples);
-	double	   *highXs = palloc(sizeof(double) * in->nTuples);
-	double	   *lowYs = palloc(sizeof(double) * in->nTuples);
-	double	   *highYs = palloc(sizeof(double) * in->nTuples);
+	float8	   *lowXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *lowYs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highYs = palloc(sizeof(float8) * in->nTuples);
 
 	/* Calculate median of all 4D coordinates */
 	for (i = 0; i < in->nTuples; i++)
 	{
 		BOX		   *box = DatumGetBoxP(in->datums[i]);
 
 		lowXs[i] = box->low.x;
 		highXs[i] = box->high.x;
 		lowYs[i] = box->low.y;
 		highYs[i] = box->high.y;
 	}
 
-	qsort(lowXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(lowYs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highYs, in->nTuples, sizeof(double), compareDoubles);
+	qsort(lowXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(lowYs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highYs, in->nTuples, sizeof(float8), compareDoubles);
 
 	median = in->nTuples / 2;
 
 	centroid = palloc(sizeof(BOX));
 
 	centroid->low.x = lowXs[median];
 	centroid->high.x = highXs[median];
 	centroid->low.y = lowYs[median];
 	centroid->high.y = highYs[median];
 
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 0e066894cd..9f8505804e 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -1,41 +1,38 @@
 /*-------------------------------------------------------------------------
  *
  * geo_decls.h - Declarations for various 2D constructs.
  *
  *
  * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * src/include/utils/geo_decls.h
  *
- * NOTE
- *	  These routines do *not* use the float types from adt/.
- *
  *	  XXX These routines were not written by a numerical analyst.
  *
  *	  XXX I have made some attempt to flesh out the operators
  *		and data types. There are still some more to do. - tgl 97/04/19
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEO_DECLS_H
 #define GEO_DECLS_H
 
-#include <math.h>
-
 #include "fmgr.h"
 
 /*--------------------------------------------------------------------
  * Useful floating point utilities and constants.
- *-------------------------------------------------------------------*/
-
+ *-------------------------------------------------------------------
+ *
+ * XXX: They are not NaN-aware.
+ */
 
 #define EPSILON					1.0E-06
 
 #ifdef EPSILON
 #define FPzero(A)				(fabs(A) <= EPSILON)
 #define FPeq(A,B)				(fabs((A) - (B)) <= EPSILON)
 #define FPne(A,B)				(fabs((A) - (B)) > EPSILON)
 #define FPlt(A,B)				((B) - (A) > EPSILON)
 #define FPle(A,B)				((A) - (B) <= EPSILON)
 #define FPgt(A,B)				((A) - (B) > EPSILON)
@@ -50,21 +47,21 @@
 #define FPge(A,B)				((A) >= (B))
 #endif
 
 #define HYPOT(A, B)				pg_hypot(A, B)
 
 /*---------------------------------------------------------------------
  * Point - (x,y)
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		x,
+	float8		x,
 				y;
 } Point;
 
 
 /*---------------------------------------------------------------------
  * LSEG - A straight line, specified by endpoints.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		p[2];
@@ -82,21 +79,21 @@ typedef struct
 	int32		dummy;			/* padding to make it double align */
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } PATH;
 
 
 /*---------------------------------------------------------------------
  * LINE - Specified by its general equation (Ax+By+C=0).
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		A,
+	float8		A,
 				B,
 				C;
 } LINE;
 
 
 /*---------------------------------------------------------------------
  * BOX	- Specified by two corner points, which are
  *		 sorted to save calculation time later.
  *-------------------------------------------------------------------*/
 typedef struct
@@ -117,21 +114,21 @@ typedef struct
 	BOX			boundbox;
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } POLYGON;
 
 /*---------------------------------------------------------------------
  * CIRCLE - Specified by a center point and radius.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		center;
-	double		radius;
+	float8		radius;
 } CIRCLE;
 
 /*
  * fmgr interface macros
  *
  * Path and Polygon are toastable varlena types, the others are just
  * fixed-size pass-by-reference types.
  */
 
 #define DatumGetPointP(X)	 ((Point *) DatumGetPointer(X))
@@ -171,13 +168,13 @@ typedef struct
 #define DatumGetCircleP(X)	  ((CIRCLE *) DatumGetPointer(X))
 #define CirclePGetDatum(X)	  PointerGetDatum(X)
 #define PG_GETARG_CIRCLE_P(n) DatumGetCircleP(PG_GETARG_DATUM(n))
 #define PG_RETURN_CIRCLE_P(x) return CirclePGetDatum(x)
 
 
 /*
  * in geo_ops.c
  */
 
-extern double pg_hypot(double x, double y);
+extern float8 pg_hypot(float8 x, float8 y);
 
 #endif							/* GEO_DECLS_H */
-- 
2.14.3 (Apple Git-98)

0004-line-fixes-v11.patchapplication/octet-stream; name=0004-line-fixes-v11.patchDownload
From 9e9c49fafd100406a3dbad30c3ae68343d625f3f Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sun, 28 May 2017 11:35:17 +0200
Subject: [PATCH 4/6] line-fixes-v11

Fix obvious problems around the line datatype

I have noticed some line operators retuning wrong results, and Tom Lane
spotted similar problems on more places.  Source history reveals that
during 1990s, the internal format of the line datatype is changed, but
most functions haven't got the hint.  The fixes include:

* Reject invalid specification A=B=0 on receive
* Reject same points on line_construct_pp()
* Fix perpendicular operator when negative values are involved
* Avoid division by zero on perpendicular operator
* Fix intersection and distance operators when neither A nor B are 1
* Return NULL for closest point when objects are parallel
* Check whether closest point of line segments is the intersection point
* Fix closest point of line segments being on the wrong segment

The changes are also aiming make line operators more symmetric and less
sensitive to floating point precision loss.  The EPSILON interferes with
every minor change in different ways.  It is hard to guess which
behaviour is more expected, but we can assume threating both sides of
the operators more equally is more expected.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com

Parallel discussions:

* https://www.postgresql.org/message-id/CAE2gYzw_-z%3DV2kh8QqFjenu%3D8MJXzOP44wRW%3DAzzeamrmTT1%3DQ%40mail.gmail.com
* https://www.postgresql.org/message-id/20180201.205138.34583581.horiguchi.kyotaro@lab.ntt.co.jp
---
 src/backend/utils/adt/geo_ops.c | 159 ++++++++++++++++++++++++++--------------
 1 file changed, 106 insertions(+), 53 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 314e442f2e..a72a9a28c9 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -41,20 +41,21 @@ static inline void point_add_point(Point *result, Point *pt1, Point *pt2);
 static inline void point_sub_point(Point *result, Point *pt1, Point *pt2);
 static inline void point_mul_point(Point *result, Point *pt1, Point *pt2);
 static inline void point_div_point(Point *result, Point *pt1, Point *pt2);
 static inline bool point_eq_point(Point *pt1, Point *pt2);
 static inline float8 point_dt(Point *pt1, Point *pt2);
 static inline float8 point_sl(Point *pt1, Point *pt2);
 static int	point_inside(Point *p, int npts, Point *plist);
 
 /* Routines for lines */
 static inline void line_construct(LINE *result, Point *pt, float8 m);
+static inline float8 line_sl(LINE *line);
 static inline float8 line_invsl(LINE *line);
 static bool	line_interpt_line(Point *result, LINE *l1, LINE *l2);
 static bool line_contain_point(LINE *line, Point *point);
 static float8 line_closept_point(Point *result, LINE *line, Point *pt);
 
 /* Routines for line segments */
 static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
 static inline float8 lseg_sl(LSEG *lseg);
 static inline float8 lseg_invsl(LSEG *lseg);
 static bool	lseg_interpt_line(Point *result, LSEG *lseg, LINE *line);
@@ -973,20 +974,25 @@ line_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LINE	   *line;
 
 	line = (LINE *) palloc(sizeof(LINE));
 
 	line->A = pq_getmsgfloat8(buf);
 	line->B = pq_getmsgfloat8(buf);
 	line->C = pq_getmsgfloat8(buf);
 
+	if (FPzero(line->A) && FPzero(line->B))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("invalid line specification: A and B cannot both be zero")));
+
 	PG_RETURN_LINE_P(line);
 }
 
 /*
  *		line_send			- converts line to binary format
  */
 Datum
 line_send(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -1030,20 +1036,25 @@ line_construct(LINE *result, Point *pt, float8 m)
 /* line_construct_pp()
  * two points
  */
 Datum
 line_construct_pp(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 	LINE	   *result = (LINE *) palloc(sizeof(LINE));
 
+	if (point_eq_point(pt1, pt2))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("invalid line specification: must be two distinct points")));
+
 	line_construct(result, pt1, point_sl(pt1, pt2));
 
 	PG_RETURN_LINE_P(result);
 }
 
 
 /*----------------------------------------------------------
  *	Relative position routines.
  *---------------------------------------------------------*/
 
@@ -1066,25 +1077,29 @@ line_parallel(PG_FUNCTION_ARGS)
 }
 
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
-	else if (FPzero(l1->B))
+	if (FPzero(l2->A))
+		PG_RETURN_BOOL(FPzero(l1->B));
+	if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
+	if (FPzero(l2->B))
+		PG_RETURN_BOOL(FPzero(l1->A));
 
-	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
-								   float8_mul(l1->B, l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->A),
+								   float8_mul(l1->B, l2->B)), -1.0));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
@@ -1125,20 +1140,34 @@ line_eq(PG_FUNCTION_ARGS)
 				   (float8_eq(l1->A, l2->A) &&
 					float8_eq(l1->B, l2->B) &&
 					float8_eq(l1->C, l2->C)));
 }
 
 
 /*----------------------------------------------------------
  *	Line arithmetic routines.
  *---------------------------------------------------------*/
 
+/*
+ * Return slope of the line
+ */
+static inline float8
+line_sl(LINE *line)
+{
+	if (FPzero(line->A))
+		return 0.0;
+	if (FPzero(line->B))
+		return DBL_MAX;
+	return float8_div(line->A, -line->B);
+}
+
+
 /*
  * Return inverse slope of the line
  */
 static inline float8
 line_invsl(LINE *line)
 {
 	if (FPzero(line->A))
 		return DBL_MAX;
 	if (FPzero(line->B))
 		return 0.0;
@@ -1147,30 +1176,35 @@ line_invsl(LINE *line)
 
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	float8		result;
-	Point		tmp;
+	float8		ratio;
 
 	if (line_interpt_line(NULL, l1, l2))	/* intersecting? */
 		PG_RETURN_FLOAT8(0.0);
-	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
-	point_construct(&tmp, 0.0, l1->C);
-	result = line_closept_point(NULL, l2, &tmp);
-	PG_RETURN_FLOAT8(result);
+
+	if (!FPzero(l1->A) && !isnan(l1->A) && !FPzero(l2->A) && !isnan(l2->A))
+		ratio = float8_div(l1->A, l2->A);
+	else if (!FPzero(l1->B) && !isnan(l1->B) && !FPzero(l2->B) && !isnan(l2->B))
+		ratio = float8_div(l1->B, l2->B);
+	else
+		ratio = 1.0;
+
+	PG_RETURN_FLOAT8(float8_div(fabs(float8_mi(l1->C,
+											   float8_mul(ratio, l2->C))),
+								HYPOT(l1->A, l1->B)));
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
@@ -1197,41 +1231,44 @@ line_interpt(PG_FUNCTION_ARGS)
  * If the lines have NaN constants, we will return true, and the intersection
  * point would have NaN coordinates.  We shouldn't return false in this case
  * because that would mean the lines are parallel.
  */
 static bool
 line_interpt_line(Point *result, LINE *l1, LINE *l2)
 {
 	float8		x,
 				y;
 
-	if (FPzero(l1->B))			/* l1 vertical? */
-	{
-		if (FPzero(l2->B))		/* l2 vertical? */
-			return false;
-
-		x = l1->C;
-		y = float8_pl(float8_mul(l2->A, x), l2->C);
-	}
-	else if (FPzero(l2->B))		/* l2 vertical? */
-	{
-		x = l2->C;
-		y = float8_pl(float8_mul(l1->A, x), l1->C);
-	}
-	else
+	if (!FPzero(l1->B))
 	{
 		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
 			return false;
 
-		x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
-		y = float8_pl(float8_mul(l1->A, x), l1->C);
+		x = float8_div(float8_mi(float8_mul(l1->B, l2->C),
+								 float8_mul(l2->B, l1->C)),
+					   float8_mi(float8_mul(l1->A, l2->B),
+								 float8_mul(l2->A, l1->B)));
+		y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
 	}
+	else if (!FPzero(l2->B))
+	{
+		if (FPeq(l1->A, float8_mul(l2->A, float8_div(l1->B, l2->B))))
+			return false;
+
+		x = float8_div(float8_mi(float8_mul(l2->B, l1->C),
+								 float8_mul(l1->B, l2->C)),
+					   float8_mi(float8_mul(l2->A, l1->B),
+								 float8_mul(l1->A, l2->B)));
+		y = float8_div(-float8_pl(float8_mul(l2->A, x), l2->C), l2->B);
+	}
+	else
+		return false;
 
 	if (result != NULL)
 		point_construct(result, x, y);
 
 	return true;
 }
 
 
 /***********************************************************************
  **
@@ -2337,30 +2374,22 @@ dist_pb(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
-	float8		result;
 
-	if (lseg_interpt_line(NULL, lseg, line))
-		result = 0.0;
-	else
-		/* XXX shouldn't we take the min not max? */
-		result = float8_max(line_closept_point(NULL, line, &lseg->p[0]),
-							line_closept_point(NULL, line, &lseg->p[1]));
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(lseg_closept_line(NULL, lseg, line));
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
@@ -2534,33 +2563,40 @@ lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
 /*
  *		The intersection point of a perpendicular of the line
  *		through the point.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 line_closept_point(Point *result, LINE *line, Point *point)
 {
-	bool		retval;
-	Point       closept;
+	Point		closept;
 	LINE		tmp;
 
-	/* We drop a perpendicular to find the intersection point. */
+	/*
+	 * We drop a perpendicular to find the intersection point.  Ordinarily
+	 * we should always find it, but that can fail in the presence of NaN
+	 * coordinates, and perhaps even from simple roundoff issues.
+	 */
 	line_construct(&tmp, point, line_invsl(line));
-	retval = line_interpt_line(&closept, line, &tmp);
-	Assert(retval);		/* XXX: We need something better. */
+	if (!line_interpt_line(&closept, &tmp, line))
+	{
+		if (result != NULL)
+			*result = *point;
+
+		return get_float8_nan();
+	}
 
 	if (result != NULL)
 		*result = closept;
 
-	/* Then we calculate the distance between the points. */
 	return point_dt(&closept, point);
 }
 
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
@@ -2620,52 +2656,66 @@ close_ps(PG_FUNCTION_ARGS)
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
 {
 	Point		point;
 	float8		dist,
 				d;
 
-	d = lseg_closept_point(NULL, l1, &l2->p[0]);
-	dist = d;
-	if (result != NULL)
-		*result = l2->p[0];
+	/* First, we handle the case when the line segments are intersecting. */
+	if (lseg_interpt_lseg(result, l1, l2))
+		return 0.0;
 
-	d = lseg_closept_point(NULL, l1, &l2->p[1]);
+	/*
+	 * Then, we find the closest points from the endpoints of the second
+	 * line segment, and keep the closest one.
+	 */
+	dist = lseg_closept_point(result, l1, &l2->p[0]);
+	d = lseg_closept_point(&point, l1, &l2->p[1]);
 	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
-			*result = l2->p[1];
+			*result = point;
 	}
 
-	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[0]), dist))
-		d = lseg_closept_point(result, l1, &point);
-
-	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[1]), dist))
-		d = lseg_closept_point(result, l1, &point);
-
+	/* The closest point can still be one of the endpoints, so we test them. */
+	d = lseg_closept_point(NULL, l2, &l1->p[0]);
 	if (float8_lt(d, dist))
+	{
 		dist = d;
+		if (result != NULL)
+			*result = l1->p[0];
+	}
+	d = lseg_closept_point(NULL, l2, &l1->p[1]);
+	if (float8_lt(d, dist))
+	{
+		dist = d;
+		if (result != NULL)
+			*result = l1->p[1];
+	}
 
 	return dist;
 }
 
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
+	if (lseg_sl(l1) == lseg_sl(l2))
+		PG_RETURN_NULL();
+
 	result = (Point *) palloc(sizeof(Point));
 
 	if (isnan(lseg_closept_lseg(result, l2, l1)))
 		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
@@ -2826,20 +2876,23 @@ lseg_closept_line(Point *result, LSEG *lseg, LINE *line)
 	}
 }
 
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
+	if (lseg_sl(lseg) == line_sl(line))
+		PG_RETURN_NULL();
+
 	result = (Point *) palloc(sizeof(Point));
 
 	if (isnan(lseg_closept_line(result, lseg, line)))
 		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
-- 
2.14.3 (Apple Git-98)

0005-float-zero-v07.patchapplication/octet-stream; name=0005-float-zero-v07.patchDownload
From 8cadeef784338f635f1f2dfa6d28b799fc92a822 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Thu, 2 Nov 2017 12:21:19 +0100
Subject: [PATCH 5/6] float-zero-v07

Check for float -0 after multiplications and divisions

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com
---
 src/include/utils/float.h | 26 ++++++++++++++++++++------
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/src/include/utils/float.h b/src/include/utils/float.h
index 0e8483c930..e359d8a3d4 100644
--- a/src/include/utils/float.h
+++ b/src/include/utils/float.h
@@ -209,69 +209,83 @@ float8_mi(const float8 val1, const float8 val2)
 
 	result = val1 - val2;
 	check_float8_val(result, isinf(val1) || isinf(val2), true);
 
 	return result;
 }
 
 static inline float4
 float4_mul(const float4 val1, const float4 val2)
 {
+	const bool	zero_is_valid = val1 == 0.0f || val2 == 0.0f;
 	float4		result;
 
 	result = val1 * val2;
-	check_float4_val(result, isinf(val1) || isinf(val2),
-					 val1 == 0.0f || val2 == 0.0f);
+	check_float4_val(result, isinf(val1) || isinf(val2), zero_is_valid);
+
+	if (zero_is_valid && unlikely(result == -0.0f))
+		result = 0.0f;
 
 	return result;
 }
 
 static inline float8
 float8_mul(const float8 val1, const float8 val2)
 {
+	const bool	zero_is_valid = val1 == 0.0 || val2 == 0.0;
 	float8		result;
 
 	result = val1 * val2;
-	check_float8_val(result, isinf(val1) || isinf(val2),
-					 val1 == 0.0 || val2 == 0.0);
+	check_float8_val(result, isinf(val1) || isinf(val2), zero_is_valid);
+
+	if (zero_is_valid && unlikely(result == -0.0))
+		result = 0.0;
 
 	return result;
 }
 
 static inline float4
 float4_div(const float4 val1, const float4 val2)
 {
+	const bool	zero_is_valid = val1 == 0.0f;
 	float4		result;
 
 	if (val2 == 0.0f)
 		ereport(ERROR,
 				(errcode(ERRCODE_DIVISION_BY_ZERO),
 				 errmsg("division by zero")));
 
 	result = val1 / val2;
-	check_float4_val(result, isinf(val1) || isinf(val2), val1 == 0.0f);
+	check_float4_val(result, isinf(val1) || isinf(val2), zero_is_valid);
+
+	if (zero_is_valid && unlikely(result == -0.0f))
+		result = 0.0f;
 
 	return result;
 }
 
 static inline float8
 float8_div(const float8 val1, const float8 val2)
 {
+	const bool	zero_is_valid = val1 == 0.0;
 	float8		result;
 
 	if (val2 == 0.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_DIVISION_BY_ZERO),
 				 errmsg("division by zero")));
 
 	result = val1 / val2;
-	check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
+	check_float8_val(result, isinf(val1) || isinf(val2), zero_is_valid);
+
+	if (zero_is_valid && unlikely(result == -0.0))
+		result = 0.0;
 
 	return result;
 }
 
 /*
  * Routines for NaN-aware comparisons
  *
  * We consider all NaNs to be equal and larger than any non-NaN. This is
  * somewhat arbitrary; the important thing is to have a consistent sort
  * order.
-- 
2.14.3 (Apple Git-98)

0006-geo-tests-v07.patchapplication/octet-stream; name=0006-geo-tests-v07.patchDownload
From 09c3cb5c9a9f8ef0c201b559bda2f30d804acff9 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Tue, 24 Oct 2017 11:28:21 +0200
Subject: [PATCH 6/6] geo-tests-v07

Improve test coverage of geometric types

The tests for the geometric functions and operators were in sad state.
This commit increases test coverage of geo_ops.c significantly.  It
removes the alternative results to expect -0 on some platforms.  We
better try to return the same results on different platforms, but if we
can't we can add them back using the results from build farm.

The tests are added to geometric.sql file.  It is not clear where to
put them as there are many cross datatype operators.  Organising them
on a single file sorted by the left hand side of the operators appear
to be a simple solution.  We may take this further and remove the other
tests later.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com
---
 src/test/regress/expected/box.out          |   44 +-
 src/test/regress/expected/circle.out       |   39 +-
 src/test/regress/expected/create_index.out |   73 +-
 src/test/regress/expected/geometry.out     | 4879 ++++++++++++++++++++++++++--
 src/test/regress/expected/geometry_1.out   | 4879 ++++++++++++++++++++++++++--
 src/test/regress/expected/geometry_2.out   |  563 ----
 src/test/regress/expected/line.out         |  272 +-
 src/test/regress/expected/lseg.out         |   24 +-
 src/test/regress/expected/path.out         |   49 +-
 src/test/regress/expected/point.out        |  358 +-
 src/test/regress/expected/polygon.out      |  200 +-
 src/test/regress/sql/box.sql               |    9 +
 src/test/regress/sql/circle.sql            |   10 +-
 src/test/regress/sql/geometry.sql          |  400 ++-
 src/test/regress/sql/line.sql              |   79 +-
 src/test/regress/sql/lseg.sql              |    9 +-
 src/test/regress/sql/path.sql              |   22 +-
 src/test/regress/sql/point.sql             |   10 +
 src/test/regress/sql/polygon.sql           |   91 +-
 19 files changed, 10086 insertions(+), 1924 deletions(-)
 delete mode 100644 src/test/regress/expected/geometry_2.out

diff --git a/src/test/regress/expected/box.out b/src/test/regress/expected/box.out
index 49af242c8c..998b52223c 100644
--- a/src/test/regress/expected/box.out
+++ b/src/test/regress/expected/box.out
@@ -11,92 +11,109 @@
 -- 1	| o-+-o
 --	|   |
 -- 0	+---+
 --
 --	0 1 2 3
 --
 -- boxes are specified by two points, given by four floats x1,y1,x2,y2
 CREATE TABLE BOX_TBL (f1 box);
 INSERT INTO BOX_TBL (f1) VALUES ('(2.0,2.0,0.0,0.0)');
 INSERT INTO BOX_TBL (f1) VALUES ('(1.0,1.0,3.0,3.0)');
+INSERT INTO BOX_TBL (f1) VALUES ('((-8, 2), (-2, -10))');
 -- degenerate cases where the box is a line or a point
 -- note that lines and points boxes all have zero area
 INSERT INTO BOX_TBL (f1) VALUES ('(2.5, 2.5, 2.5,3.5)');
 INSERT INTO BOX_TBL (f1) VALUES ('(3.0, 3.0,3.0,3.0)');
 -- badly formatted box inputs
 INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
 ERROR:  invalid input syntax for type box: "(2.3, 4.5)"
 LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
                                          ^
+INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+ERROR:  invalid input syntax for type box: "[1, 2, 3, 4)"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+                                         ^
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+ERROR:  invalid input syntax for type box: "(1, 2, 3, 4]"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+                                         ^
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+ERROR:  invalid input syntax for type box: "(1, 2, 3, 4) x"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+                                         ^
 INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
 ERROR:  invalid input syntax for type box: "asdfasdf(ad"
 LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
                                          ^
 SELECT '' AS four, * FROM BOX_TBL;
  four |         f1          
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
+      | (-2,2),(-8,-10)
       | (2.5,3.5),(2.5,2.5)
       | (3,3),(3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, b.*, area(b.f1) as barea
    FROM BOX_TBL b;
  four |         f1          | barea 
 ------+---------------------+-------
       | (2,2),(0,0)         |     4
       | (3,3),(1,1)         |     4
+      | (-2,2),(-8,-10)     |    72
       | (2.5,3.5),(2.5,2.5) |     0
       | (3,3),(3,3)         |     0
-(4 rows)
+(5 rows)
 
 -- overlap
 SELECT '' AS three, b.f1
    FROM BOX_TBL b
    WHERE b.f1 && box '(2.5,2.5,1.0,1.0)';
  three |         f1          
 -------+---------------------
        | (2,2),(0,0)
        | (3,3),(1,1)
        | (2.5,3.5),(2.5,2.5)
 (3 rows)
 
 -- left-or-overlap (x only)
 SELECT '' AS two, b1.*
    FROM BOX_TBL b1
    WHERE b1.f1 &< box '(2.0,2.0,2.5,2.5)';
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- right-or-overlap (x only)
 SELECT '' AS two, b1.*
    FROM BOX_TBL b1
    WHERE b1.f1 &> box '(2.0,2.0,2.5,2.5)';
  two |         f1          
 -----+---------------------
      | (2.5,3.5),(2.5,2.5)
      | (3,3),(3,3)
 (2 rows)
 
 -- left of
 SELECT '' AS two, b.f1
    FROM BOX_TBL b
    WHERE b.f1 << box '(3.0,3.0,5.0,5.0)';
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- area <=
 SELECT '' AS four, b.f1
    FROM BOX_TBL b
    WHERE b.f1 <= box '(3.0,3.0,5.0,5.0)';
  four |         f1          
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
       | (2.5,3.5),(2.5,2.5)
@@ -120,47 +137,50 @@ SELECT '' AS two, b.f1
  two |     f1      
 -----+-------------
      | (2,2),(0,0)
      | (3,3),(1,1)
 (2 rows)
 
 -- area >
 SELECT '' AS two, b.f1
    FROM BOX_TBL b				-- zero area
    WHERE b.f1 > box '(3.5,3.0,4.5,3.0)';
- two |     f1      
------+-------------
+ two |       f1        
+-----+-----------------
      | (2,2),(0,0)
      | (3,3),(1,1)
-(2 rows)
+     | (-2,2),(-8,-10)
+(3 rows)
 
 -- area >=
 SELECT '' AS four, b.f1
    FROM BOX_TBL b				-- zero area
    WHERE b.f1 >= box '(3.5,3.0,4.5,3.0)';
  four |         f1          
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
+      | (-2,2),(-8,-10)
       | (2.5,3.5),(2.5,2.5)
       | (3,3),(3,3)
-(4 rows)
+(5 rows)
 
 -- right of
 SELECT '' AS two, b.f1
    FROM BOX_TBL b
    WHERE box '(3.0,3.0,5.0,5.0)' >> b.f1;
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- contained in
 SELECT '' AS three, b.f1
    FROM BOX_TBL b
    WHERE b.f1 <@ box '(0,0,3,3)';
  three |     f1      
 -------+-------------
        | (2,2),(0,0)
        | (3,3),(1,1)
        | (3,3),(3,3)
@@ -186,41 +206,43 @@ SELECT '' AS one, b.f1
      | (3,3),(1,1)
 (1 row)
 
 -- center of box, left unary operator
 SELECT '' AS four, @@(b1.f1) AS p
    FROM BOX_TBL b1;
  four |    p    
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 -- wholly-contained
 SELECT '' AS one, b1.*, b2.*
    FROM BOX_TBL b1, BOX_TBL b2
    WHERE b1.f1 @> b2.f1 and not b1.f1 ~= b2.f1;
  one |     f1      |     f1      
 -----+-------------+-------------
      | (3,3),(1,1) | (3,3),(3,3)
 (1 row)
 
 SELECT '' AS four, height(f1), width(f1) FROM BOX_TBL;
  four | height | width 
 ------+--------+-------
       |      2 |     2
       |      2 |     2
+      |     12 |     6
       |      1 |     0
       |      0 |     0
-(4 rows)
+(5 rows)
 
 --
 -- Test the SP-GiST index
 --
 CREATE TEMPORARY TABLE box_temp (f1 box);
 INSERT INTO box_temp
 	SELECT box(point(i, i), point(i * 2, i * 2))
 	FROM generate_series(1, 50) AS i;
 CREATE INDEX box_spgist ON box_temp USING spgist (f1);
 INSERT INTO box_temp
diff --git a/src/test/regress/expected/circle.out b/src/test/regress/expected/circle.out
index 9ba4a0495d..2ed74cc6aa 100644
--- a/src/test/regress/expected/circle.out
+++ b/src/test/regress/expected/circle.out
@@ -1,99 +1,122 @@
 --
 -- CIRCLE
 --
 CREATE TABLE CIRCLE_TBL (f1 circle);
 INSERT INTO CIRCLE_TBL VALUES ('<(5,1),3>');
 INSERT INTO CIRCLE_TBL VALUES ('<(1,2),100>');
 INSERT INTO CIRCLE_TBL VALUES ('1,3,5');
 INSERT INTO CIRCLE_TBL VALUES ('((1,2),3)');
 INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10>');
-INSERT INTO CIRCLE_TBL VALUES ('<(100,1),115>');
+INSERT INTO CIRCLE_TBL VALUES (' < ( 100 , 1 ) , 115 > ');
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),0>');	-- Zero radius
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),NaN>');	-- NaN radius
 -- bad values
 INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
 ERROR:  invalid input syntax for type circle: "<(-100,0),-100>"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
                                        ^
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+ERROR:  invalid input syntax for type circle: "<(100,200),10"
+LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+                                       ^
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+ERROR:  invalid input syntax for type circle: "<(100,200),10> x"
+LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+                                       ^
 INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
 ERROR:  invalid input syntax for type circle: "1abc,3,5"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
                                        ^
 INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
 ERROR:  invalid input syntax for type circle: "(3,(1,2),3)"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
                                        ^
 SELECT * FROM CIRCLE_TBL;
        f1       
 ----------------
  <(5,1),3>
  <(1,2),100>
  <(1,3),5>
  <(1,2),3>
  <(100,200),10>
  <(100,1),115>
-(6 rows)
+ <(3,5),0>
+ <(3,5),NaN>
+(8 rows)
 
 SELECT '' AS six, center(f1) AS center
   FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS six, radius(f1) AS radius
   FROM CIRCLE_TBL;
  six | radius 
 -----+--------
      |      3
      |    100
      |      5
      |      3
      |     10
      |    115
-(6 rows)
+     |      0
+     |    NaN
+(8 rows)
 
 SELECT '' AS six, diameter(f1) AS diameter
   FROM CIRCLE_TBL;
  six | diameter 
 -----+----------
      |        6
      |      200
      |       10
      |        6
      |       20
      |      230
-(6 rows)
+     |        0
+     |      NaN
+(8 rows)
 
 SELECT '' AS two, f1 FROM CIRCLE_TBL WHERE radius(f1) < 5;
  two |    f1     
 -----+-----------
      | <(5,1),3>
      | <(1,2),3>
-(2 rows)
+     | <(3,5),0>
+(3 rows)
 
 SELECT '' AS four, f1 FROM CIRCLE_TBL WHERE diameter(f1) >= 10;
  four |       f1       
 ------+----------------
       | <(1,2),100>
       | <(1,3),5>
       | <(100,200),10>
       | <(100,1),115>
-(4 rows)
+      | <(3,5),NaN>
+(5 rows)
 
 SELECT '' as five, c1.f1 AS one, c2.f1 AS two, (c1.f1 <-> c2.f1) AS distance
   FROM CIRCLE_TBL c1, CIRCLE_TBL c2
   WHERE (c1.f1 < c2.f1) AND ((c1.f1 <-> c2.f1) > 0)
   ORDER BY distance, area(c1.f1), area(c2.f1);
  five |      one       |      two       |     distance     
 ------+----------------+----------------+------------------
+      | <(3,5),0>      | <(1,2),3>      | 0.60555127546399
+      | <(3,5),0>      | <(5,1),3>      | 1.47213595499958
       | <(100,200),10> | <(100,1),115>  |               74
       | <(100,200),10> | <(1,2),100>    | 111.370729772479
       | <(1,3),5>      | <(100,200),10> | 205.476756144497
       | <(5,1),3>      | <(100,200),10> |  207.51303816328
+      | <(3,5),0>      | <(100,200),10> | 207.793480159531
       | <(1,2),3>      | <(100,200),10> | 208.370729772479
-(5 rows)
+(8 rows)
 
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc81088d4b..4e5f573349 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -150,96 +150,103 @@ SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)';
 
 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
+     5
 (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
+     3
 (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
+     4
 (1 row)
 
 SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
  count 
 -------
      1
 (1 row)
 
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
  (-5,-12)
  (5.1,34.5)
+ (1e+300,Infinity)
+ (NaN,NaN)
  
-(7 rows)
+(10 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NULL;
  f1 
 ----
  
 (1 row)
 
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (1e-300,-1e-300)
  (0,0)
  (-3,4)
  (-10,0)
  (10,10)
  (-5,-12)
  (5.1,34.5)
-(6 rows)
+ (1e+300,Infinity)
+ (NaN,NaN)
+(9 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
  count 
 -------
      3
 (1 row)
 
 SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
  count 
 -------
@@ -567,21 +574,21 @@ SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,
                                        QUERY PLAN                                       
 ----------------------------------------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     4
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>';
                      QUERY PLAN                     
 ----------------------------------------------------
  Aggregate
    ->  Index Only Scan using gpointind on point_tbl
          Index Cond: (f1 <@ '<(50,50),50>'::circle)
 (3 rows)
@@ -612,21 +619,21 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     3
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl p WHERE p.f1 <^ '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only Scan using gpointind on point_tbl p
          Index Cond: (f1 <^ '(0,0)'::point)
 (3 rows)
@@ -642,21 +649,21 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 >^ '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     4
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only Scan using gpointind on point_tbl p
          Index Cond: (f1 ~= '(-5,-12)'::point)
 (3 rows)
@@ -669,30 +676,33 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
                   QUERY PLAN                  
 ----------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Order By: (f1 <-> '(0,1)'::point)
 (2 rows)
 
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (10,10)
+ (NaN,NaN)
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
- (10,10)
  (-5,-12)
  (5.1,34.5)
  
-(7 rows)
+ (1e+300,Infinity)
+(10 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 IS NULL;
                   QUERY PLAN                  
 ----------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Index Cond: (f1 IS NULL)
 (2 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NULL;
@@ -704,47 +714,51 @@ SELECT * FROM point_tbl WHERE f1 IS NULL;
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
                   QUERY PLAN                  
 ----------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Index Cond: (f1 IS NOT NULL)
    Order By: (f1 <-> '(0,1)'::point)
 (3 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (10,10)
+ (NaN,NaN)
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
- (10,10)
  (-5,-12)
  (5.1,34.5)
-(6 rows)
+ (1e+300,Infinity)
+(9 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
                    QUERY PLAN                   
 ------------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Index Cond: (f1 <@ '(10,10),(-10,-10)'::box)
    Order By: (f1 <-> '(0,1)'::point)
 (3 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
                         QUERY PLAN                         
 -----------------------------------------------------------
  Aggregate
    ->  Index Only Scan using sp_quad_ind on quad_point_tbl
          Index Cond: (p IS NULL)
 (3 rows)
 
@@ -1261,27 +1275,28 @@ SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0
 ------------------------------------------------------------
  Sort
    Sort Key: ((f1 <-> '(0,1)'::point))
    ->  Bitmap Heap Scan on point_tbl
          Recheck Cond: (f1 <@ '(10,10),(-10,-10)'::box)
          ->  Bitmap Index Scan on gpointind
                Index Cond: (f1 <@ '(10,10),(-10,-10)'::box)
 (6 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
                   QUERY PLAN                  
 ----------------------------------------------
  Aggregate
    ->  Bitmap Heap Scan on quad_point_tbl
          Recheck Cond: (p IS NULL)
          ->  Bitmap Index Scan on sp_quad_ind
                Index Cond: (p IS NULL)
diff --git a/src/test/regress/expected/geometry.out b/src/test/regress/expected/geometry.out
index e4c0039040..b4da3baa37 100644
--- a/src/test/regress/expected/geometry.out
+++ b/src/test/regress/expected/geometry.out
@@ -6,558 +6,4885 @@
 SET extra_float_digits TO -3;
 --
 -- Points
 --
 SELECT '' AS four, center(f1) AS center
    FROM BOX_TBL;
  four | center  
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, (@@ f1) AS center
    FROM BOX_TBL;
  four | center  
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS six, point(f1) AS center
    FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS six, (@@ f1) AS center
    FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS two, (@@ f1) AS center
    FROM POLYGON_TBL
    WHERE (# f1) > 2;
  two |            center             
 -----+-------------------------------
      | (1.33333333333,1.33333333333)
      | (2.33333333333,1.33333333333)
-(2 rows)
+     | (4,5)
+     | (4,5)
+     | (4,3)
+(5 rows)
 
 -- "is horizontal" function
 SELECT '' AS two, p1.f1
    FROM POINT_TBL p1
    WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 -- "is horizontal" operator
 SELECT '' AS two, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 -- "is vertical" function
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE isvertical(p1.f1, point '(5.1,34.5)');
  one |     f1     
 -----+------------
      | (5.1,34.5)
 (1 row)
 
 -- "is vertical" operator
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?| point '(5.1,34.5)';
  one |     f1     
 -----+------------
      | (5.1,34.5)
 (1 row)
 
+-- Slope
+SELECT p1.f1, p2.f1, slope(p1.f1, p2.f1) FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |       slope        
+-------------------+-------------------+--------------------
+ (0,0)             | (0,0)             | 1.79769313486e+308
+ (0,0)             | (-10,0)           |                  0
+ (0,0)             | (-3,4)            |     -1.33333333333
+ (0,0)             | (5.1,34.5)        |      6.76470588235
+ (0,0)             | (-5,-12)          |                2.4
+ (0,0)             | (1e-300,-1e-300)  | 1.79769313486e+308
+ (0,0)             | (1e+300,Infinity) |           Infinity
+ (0,0)             | (NaN,NaN)         |                NaN
+ (0,0)             | (10,10)           |                  1
+ (-10,0)           | (0,0)             |                  0
+ (-10,0)           | (-10,0)           | 1.79769313486e+308
+ (-10,0)           | (-3,4)            |     0.571428571429
+ (-10,0)           | (5.1,34.5)        |      2.28476821192
+ (-10,0)           | (-5,-12)          |               -2.4
+ (-10,0)           | (1e-300,-1e-300)  |                  0
+ (-10,0)           | (1e+300,Infinity) |           Infinity
+ (-10,0)           | (NaN,NaN)         |                NaN
+ (-10,0)           | (10,10)           |                0.5
+ (-3,4)            | (0,0)             |     -1.33333333333
+ (-3,4)            | (-10,0)           |     0.571428571429
+ (-3,4)            | (-3,4)            | 1.79769313486e+308
+ (-3,4)            | (5.1,34.5)        |      3.76543209877
+ (-3,4)            | (-5,-12)          |                  8
+ (-3,4)            | (1e-300,-1e-300)  |     -1.33333333333
+ (-3,4)            | (1e+300,Infinity) |           Infinity
+ (-3,4)            | (NaN,NaN)         |                NaN
+ (-3,4)            | (10,10)           |     0.461538461538
+ (5.1,34.5)        | (0,0)             |      6.76470588235
+ (5.1,34.5)        | (-10,0)           |      2.28476821192
+ (5.1,34.5)        | (-3,4)            |      3.76543209877
+ (5.1,34.5)        | (5.1,34.5)        | 1.79769313486e+308
+ (5.1,34.5)        | (-5,-12)          |      4.60396039604
+ (5.1,34.5)        | (1e-300,-1e-300)  |      6.76470588235
+ (5.1,34.5)        | (1e+300,Infinity) |           Infinity
+ (5.1,34.5)        | (NaN,NaN)         |                NaN
+ (5.1,34.5)        | (10,10)           |                 -5
+ (-5,-12)          | (0,0)             |                2.4
+ (-5,-12)          | (-10,0)           |               -2.4
+ (-5,-12)          | (-3,4)            |                  8
+ (-5,-12)          | (5.1,34.5)        |      4.60396039604
+ (-5,-12)          | (-5,-12)          | 1.79769313486e+308
+ (-5,-12)          | (1e-300,-1e-300)  |                2.4
+ (-5,-12)          | (1e+300,Infinity) |           Infinity
+ (-5,-12)          | (NaN,NaN)         |                NaN
+ (-5,-12)          | (10,10)           |      1.46666666667
+ (1e-300,-1e-300)  | (0,0)             | 1.79769313486e+308
+ (1e-300,-1e-300)  | (-10,0)           |                  0
+ (1e-300,-1e-300)  | (-3,4)            |     -1.33333333333
+ (1e-300,-1e-300)  | (5.1,34.5)        |      6.76470588235
+ (1e-300,-1e-300)  | (-5,-12)          |                2.4
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | 1.79769313486e+308
+ (1e-300,-1e-300)  | (1e+300,Infinity) |           Infinity
+ (1e-300,-1e-300)  | (NaN,NaN)         |                NaN
+ (1e-300,-1e-300)  | (10,10)           |                  1
+ (1e+300,Infinity) | (0,0)             |           Infinity
+ (1e+300,Infinity) | (-10,0)           |           Infinity
+ (1e+300,Infinity) | (-3,4)            |           Infinity
+ (1e+300,Infinity) | (5.1,34.5)        |           Infinity
+ (1e+300,Infinity) | (-5,-12)          |           Infinity
+ (1e+300,Infinity) | (1e-300,-1e-300)  |           Infinity
+ (1e+300,Infinity) | (1e+300,Infinity) | 1.79769313486e+308
+ (1e+300,Infinity) | (NaN,NaN)         |                NaN
+ (1e+300,Infinity) | (10,10)           |           Infinity
+ (NaN,NaN)         | (0,0)             |                NaN
+ (NaN,NaN)         | (-10,0)           |                NaN
+ (NaN,NaN)         | (-3,4)            |                NaN
+ (NaN,NaN)         | (5.1,34.5)        |                NaN
+ (NaN,NaN)         | (-5,-12)          |                NaN
+ (NaN,NaN)         | (1e-300,-1e-300)  |                NaN
+ (NaN,NaN)         | (1e+300,Infinity) |                NaN
+ (NaN,NaN)         | (NaN,NaN)         |                NaN
+ (NaN,NaN)         | (10,10)           |                NaN
+ (10,10)           | (0,0)             |                  1
+ (10,10)           | (-10,0)           |                0.5
+ (10,10)           | (-3,4)            |     0.461538461538
+ (10,10)           | (5.1,34.5)        |                 -5
+ (10,10)           | (-5,-12)          |      1.46666666667
+ (10,10)           | (1e-300,-1e-300)  |                  1
+ (10,10)           | (1e+300,Infinity) |           Infinity
+ (10,10)           | (NaN,NaN)         |                NaN
+ (10,10)           | (10,10)           | 1.79769313486e+308
+(81 rows)
+
+-- Add point
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |     ?column?      
+-------------------+-------------------+-------------------
+ (0,0)             | (0,0)             | (0,0)
+ (0,0)             | (-10,0)           | (-10,0)
+ (0,0)             | (-3,4)            | (-3,4)
+ (0,0)             | (5.1,34.5)        | (5.1,34.5)
+ (0,0)             | (-5,-12)          | (-5,-12)
+ (0,0)             | (1e-300,-1e-300)  | (1e-300,-1e-300)
+ (0,0)             | (1e+300,Infinity) | (1e+300,Infinity)
+ (0,0)             | (NaN,NaN)         | (NaN,NaN)
+ (0,0)             | (10,10)           | (10,10)
+ (-10,0)           | (0,0)             | (-10,0)
+ (-10,0)           | (-10,0)           | (-20,0)
+ (-10,0)           | (-3,4)            | (-13,4)
+ (-10,0)           | (5.1,34.5)        | (-4.9,34.5)
+ (-10,0)           | (-5,-12)          | (-15,-12)
+ (-10,0)           | (1e-300,-1e-300)  | (-10,-1e-300)
+ (-10,0)           | (1e+300,Infinity) | (1e+300,Infinity)
+ (-10,0)           | (NaN,NaN)         | (NaN,NaN)
+ (-10,0)           | (10,10)           | (0,10)
+ (-3,4)            | (0,0)             | (-3,4)
+ (-3,4)            | (-10,0)           | (-13,4)
+ (-3,4)            | (-3,4)            | (-6,8)
+ (-3,4)            | (5.1,34.5)        | (2.1,38.5)
+ (-3,4)            | (-5,-12)          | (-8,-8)
+ (-3,4)            | (1e-300,-1e-300)  | (-3,4)
+ (-3,4)            | (1e+300,Infinity) | (1e+300,Infinity)
+ (-3,4)            | (NaN,NaN)         | (NaN,NaN)
+ (-3,4)            | (10,10)           | (7,14)
+ (5.1,34.5)        | (0,0)             | (5.1,34.5)
+ (5.1,34.5)        | (-10,0)           | (-4.9,34.5)
+ (5.1,34.5)        | (-3,4)            | (2.1,38.5)
+ (5.1,34.5)        | (5.1,34.5)        | (10.2,69)
+ (5.1,34.5)        | (-5,-12)          | (0.1,22.5)
+ (5.1,34.5)        | (1e-300,-1e-300)  | (5.1,34.5)
+ (5.1,34.5)        | (1e+300,Infinity) | (1e+300,Infinity)
+ (5.1,34.5)        | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5)        | (10,10)           | (15.1,44.5)
+ (-5,-12)          | (0,0)             | (-5,-12)
+ (-5,-12)          | (-10,0)           | (-15,-12)
+ (-5,-12)          | (-3,4)            | (-8,-8)
+ (-5,-12)          | (5.1,34.5)        | (0.1,22.5)
+ (-5,-12)          | (-5,-12)          | (-10,-24)
+ (-5,-12)          | (1e-300,-1e-300)  | (-5,-12)
+ (-5,-12)          | (1e+300,Infinity) | (1e+300,Infinity)
+ (-5,-12)          | (NaN,NaN)         | (NaN,NaN)
+ (-5,-12)          | (10,10)           | (5,-2)
+ (1e-300,-1e-300)  | (0,0)             | (1e-300,-1e-300)
+ (1e-300,-1e-300)  | (-10,0)           | (-10,-1e-300)
+ (1e-300,-1e-300)  | (-3,4)            | (-3,4)
+ (1e-300,-1e-300)  | (5.1,34.5)        | (5.1,34.5)
+ (1e-300,-1e-300)  | (-5,-12)          | (-5,-12)
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | (2e-300,-2e-300)
+ (1e-300,-1e-300)  | (1e+300,Infinity) | (1e+300,Infinity)
+ (1e-300,-1e-300)  | (NaN,NaN)         | (NaN,NaN)
+ (1e-300,-1e-300)  | (10,10)           | (10,10)
+ (1e+300,Infinity) | (0,0)             | (1e+300,Infinity)
+ (1e+300,Infinity) | (-10,0)           | (1e+300,Infinity)
+ (1e+300,Infinity) | (-3,4)            | (1e+300,Infinity)
+ (1e+300,Infinity) | (5.1,34.5)        | (1e+300,Infinity)
+ (1e+300,Infinity) | (-5,-12)          | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e-300,-1e-300)  | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e+300,Infinity) | (2e+300,Infinity)
+ (1e+300,Infinity) | (NaN,NaN)         | (NaN,NaN)
+ (1e+300,Infinity) | (10,10)           | (1e+300,Infinity)
+ (NaN,NaN)         | (0,0)             | (NaN,NaN)
+ (NaN,NaN)         | (-10,0)           | (NaN,NaN)
+ (NaN,NaN)         | (-3,4)            | (NaN,NaN)
+ (NaN,NaN)         | (5.1,34.5)        | (NaN,NaN)
+ (NaN,NaN)         | (-5,-12)          | (NaN,NaN)
+ (NaN,NaN)         | (1e-300,-1e-300)  | (NaN,NaN)
+ (NaN,NaN)         | (1e+300,Infinity) | (NaN,NaN)
+ (NaN,NaN)         | (NaN,NaN)         | (NaN,NaN)
+ (NaN,NaN)         | (10,10)           | (NaN,NaN)
+ (10,10)           | (0,0)             | (10,10)
+ (10,10)           | (-10,0)           | (0,10)
+ (10,10)           | (-3,4)            | (7,14)
+ (10,10)           | (5.1,34.5)        | (15.1,44.5)
+ (10,10)           | (-5,-12)          | (5,-2)
+ (10,10)           | (1e-300,-1e-300)  | (10,10)
+ (10,10)           | (1e+300,Infinity) | (1e+300,Infinity)
+ (10,10)           | (NaN,NaN)         | (NaN,NaN)
+ (10,10)           | (10,10)           | (20,20)
+(81 rows)
+
+-- Subtract point
+SELECT p1.f1, p2.f1, p1.f1 - p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |      ?column?       
+-------------------+-------------------+---------------------
+ (0,0)             | (0,0)             | (0,0)
+ (0,0)             | (-10,0)           | (10,0)
+ (0,0)             | (-3,4)            | (3,-4)
+ (0,0)             | (5.1,34.5)        | (-5.1,-34.5)
+ (0,0)             | (-5,-12)          | (5,12)
+ (0,0)             | (1e-300,-1e-300)  | (-1e-300,1e-300)
+ (0,0)             | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (0,0)             | (NaN,NaN)         | (NaN,NaN)
+ (0,0)             | (10,10)           | (-10,-10)
+ (-10,0)           | (0,0)             | (-10,0)
+ (-10,0)           | (-10,0)           | (0,0)
+ (-10,0)           | (-3,4)            | (-7,-4)
+ (-10,0)           | (5.1,34.5)        | (-15.1,-34.5)
+ (-10,0)           | (-5,-12)          | (-5,12)
+ (-10,0)           | (1e-300,-1e-300)  | (-10,1e-300)
+ (-10,0)           | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-10,0)           | (NaN,NaN)         | (NaN,NaN)
+ (-10,0)           | (10,10)           | (-20,-10)
+ (-3,4)            | (0,0)             | (-3,4)
+ (-3,4)            | (-10,0)           | (7,4)
+ (-3,4)            | (-3,4)            | (0,0)
+ (-3,4)            | (5.1,34.5)        | (-8.1,-30.5)
+ (-3,4)            | (-5,-12)          | (2,16)
+ (-3,4)            | (1e-300,-1e-300)  | (-3,4)
+ (-3,4)            | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-3,4)            | (NaN,NaN)         | (NaN,NaN)
+ (-3,4)            | (10,10)           | (-13,-6)
+ (5.1,34.5)        | (0,0)             | (5.1,34.5)
+ (5.1,34.5)        | (-10,0)           | (15.1,34.5)
+ (5.1,34.5)        | (-3,4)            | (8.1,30.5)
+ (5.1,34.5)        | (5.1,34.5)        | (0,0)
+ (5.1,34.5)        | (-5,-12)          | (10.1,46.5)
+ (5.1,34.5)        | (1e-300,-1e-300)  | (5.1,34.5)
+ (5.1,34.5)        | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (5.1,34.5)        | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5)        | (10,10)           | (-4.9,24.5)
+ (-5,-12)          | (0,0)             | (-5,-12)
+ (-5,-12)          | (-10,0)           | (5,-12)
+ (-5,-12)          | (-3,4)            | (-2,-16)
+ (-5,-12)          | (5.1,34.5)        | (-10.1,-46.5)
+ (-5,-12)          | (-5,-12)          | (0,0)
+ (-5,-12)          | (1e-300,-1e-300)  | (-5,-12)
+ (-5,-12)          | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-5,-12)          | (NaN,NaN)         | (NaN,NaN)
+ (-5,-12)          | (10,10)           | (-15,-22)
+ (1e-300,-1e-300)  | (0,0)             | (1e-300,-1e-300)
+ (1e-300,-1e-300)  | (-10,0)           | (10,-1e-300)
+ (1e-300,-1e-300)  | (-3,4)            | (3,-4)
+ (1e-300,-1e-300)  | (5.1,34.5)        | (-5.1,-34.5)
+ (1e-300,-1e-300)  | (-5,-12)          | (5,12)
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | (0,0)
+ (1e-300,-1e-300)  | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (1e-300,-1e-300)  | (NaN,NaN)         | (NaN,NaN)
+ (1e-300,-1e-300)  | (10,10)           | (-10,-10)
+ (1e+300,Infinity) | (0,0)             | (1e+300,Infinity)
+ (1e+300,Infinity) | (-10,0)           | (1e+300,Infinity)
+ (1e+300,Infinity) | (-3,4)            | (1e+300,Infinity)
+ (1e+300,Infinity) | (5.1,34.5)        | (1e+300,Infinity)
+ (1e+300,Infinity) | (-5,-12)          | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e-300,-1e-300)  | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e+300,Infinity) | (0,NaN)
+ (1e+300,Infinity) | (NaN,NaN)         | (NaN,NaN)
+ (1e+300,Infinity) | (10,10)           | (1e+300,Infinity)
+ (NaN,NaN)         | (0,0)             | (NaN,NaN)
+ (NaN,NaN)         | (-10,0)           | (NaN,NaN)
+ (NaN,NaN)         | (-3,4)            | (NaN,NaN)
+ (NaN,NaN)         | (5.1,34.5)        | (NaN,NaN)
+ (NaN,NaN)         | (-5,-12)          | (NaN,NaN)
+ (NaN,NaN)         | (1e-300,-1e-300)  | (NaN,NaN)
+ (NaN,NaN)         | (1e+300,Infinity) | (NaN,NaN)
+ (NaN,NaN)         | (NaN,NaN)         | (NaN,NaN)
+ (NaN,NaN)         | (10,10)           | (NaN,NaN)
+ (10,10)           | (0,0)             | (10,10)
+ (10,10)           | (-10,0)           | (20,10)
+ (10,10)           | (-3,4)            | (13,6)
+ (10,10)           | (5.1,34.5)        | (4.9,-24.5)
+ (10,10)           | (-5,-12)          | (15,22)
+ (10,10)           | (1e-300,-1e-300)  | (10,10)
+ (10,10)           | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (10,10)           | (NaN,NaN)         | (NaN,NaN)
+ (10,10)           | (10,10)           | (0,0)
+(81 rows)
+
+-- Multiply with point
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+     f1     |        f1         |       ?column?        
+------------+-------------------+-----------------------
+ (5.1,34.5) | (0,0)             | (0,0)
+ (10,10)    | (0,0)             | (0,0)
+ (5.1,34.5) | (-10,0)           | (-51,-345)
+ (10,10)    | (-10,0)           | (-100,-100)
+ (5.1,34.5) | (-3,4)            | (-153.3,-83.1)
+ (10,10)    | (-3,4)            | (-70,10)
+ (5.1,34.5) | (5.1,34.5)        | (-1164.24,351.9)
+ (10,10)    | (5.1,34.5)        | (-294,396)
+ (5.1,34.5) | (-5,-12)          | (388.5,-233.7)
+ (10,10)    | (-5,-12)          | (70,-170)
+ (5.1,34.5) | (1e-300,-1e-300)  | (3.96e-299,2.94e-299)
+ (10,10)    | (1e-300,-1e-300)  | (2e-299,0)
+ (5.1,34.5) | (1e+300,Infinity) | (-Infinity,Infinity)
+ (10,10)    | (1e+300,Infinity) | (-Infinity,Infinity)
+ (5.1,34.5) | (NaN,NaN)         | (NaN,NaN)
+ (10,10)    | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5) | (10,10)           | (-294,396)
+ (10,10)    | (10,10)           | (0,200)
+(18 rows)
+
+-- Underflow error
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] < 1;
+ERROR:  value out of range: underflow
+-- Divide by point
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] BETWEEN 1 AND 1000;
+        f1         |     f1     |                 ?column?                  
+-------------------+------------+-------------------------------------------
+ (0,0)             | (5.1,34.5) | (0,0)
+ (0,0)             | (10,10)    | (0,0)
+ (-10,0)           | (5.1,34.5) | (-0.0419318237877,0.283656455034)
+ (-10,0)           | (10,10)    | (-0.5,0.5)
+ (-3,4)            | (5.1,34.5) | (0.100883034877,0.101869666025)
+ (-3,4)            | (10,10)    | (0.05,0.35)
+ (5.1,34.5)        | (5.1,34.5) | (1,0)
+ (5.1,34.5)        | (10,10)    | (1.98,1.47)
+ (-5,-12)          | (5.1,34.5) | (-0.361353657935,0.0915100389719)
+ (-5,-12)          | (10,10)    | (-0.85,-0.35)
+ (1e-300,-1e-300)  | (5.1,34.5) | (-2.41724631247e-302,-3.25588278822e-302)
+ (1e-300,-1e-300)  | (10,10)    | (0,-1e-301)
+ (1e+300,Infinity) | (5.1,34.5) | (Infinity,Infinity)
+ (1e+300,Infinity) | (10,10)    | (Infinity,Infinity)
+ (NaN,NaN)         | (5.1,34.5) | (NaN,NaN)
+ (NaN,NaN)         | (10,10)    | (NaN,NaN)
+ (10,10)           | (5.1,34.5) | (0.325588278822,-0.241724631247)
+ (10,10)           | (10,10)    | (1,0)
+(18 rows)
+
+-- Overflow error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] > 1000;
+ERROR:  value out of range: overflow
+-- Division by 0 error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to line
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LINE_TBL l;
+        f1         |                   s                   |      ?column?      
+-------------------+---------------------------------------+--------------------
+ (0,0)             | {0,-1,5}                              |                  5
+ (0,0)             | {1,0,5}                               |                  5
+ (0,0)             | {0,3,0}                               |                  0
+ (0,0)             | {1,-1,0}                              |                  0
+ (0,0)             | {-0.4,-1,-6}                          |      5.57086014531
+ (0,0)             | {-0.000184615384615,-1,15.3846153846} |      15.3846151224
+ (0,0)             | {3,NaN,5}                             |                NaN
+ (0,0)             | {NaN,NaN,NaN}                         |                NaN
+ (0,0)             | {0,-1,3}                              |                  3
+ (0,0)             | {-1,0,3}                              |                  3
+ (-10,0)           | {0,-1,5}                              |                  5
+ (-10,0)           | {1,0,5}                               |                  5
+ (-10,0)           | {0,3,0}                               |                  0
+ (-10,0)           | {1,-1,0}                              |      7.07106781187
+ (-10,0)           | {-0.4,-1,-6}                          |      1.85695338177
+ (-10,0)           | {-0.000184615384615,-1,15.3846153846} |      15.3864612763
+ (-10,0)           | {3,NaN,5}                             |                NaN
+ (-10,0)           | {NaN,NaN,NaN}                         |                NaN
+ (-10,0)           | {0,-1,3}                              |                  3
+ (-10,0)           | {-1,0,3}                              |                 13
+ (-3,4)            | {0,-1,5}                              |                  1
+ (-3,4)            | {1,0,5}                               |                  2
+ (-3,4)            | {0,3,0}                               |                  4
+ (-3,4)            | {1,-1,0}                              |      4.94974746831
+ (-3,4)            | {-0.4,-1,-6}                          |      8.17059487979
+ (-3,4)            | {-0.000184615384615,-1,15.3846153846} |      11.3851690368
+ (-3,4)            | {3,NaN,5}                             |                NaN
+ (-3,4)            | {NaN,NaN,NaN}                         |                NaN
+ (-3,4)            | {0,-1,3}                              |                  1
+ (-3,4)            | {-1,0,3}                              |                  6
+ (5.1,34.5)        | {0,-1,5}                              |               29.5
+ (5.1,34.5)        | {1,0,5}                               |               10.1
+ (5.1,34.5)        | {0,3,0}                               |               34.5
+ (5.1,34.5)        | {1,-1,0}                              |      20.7889393669
+ (5.1,34.5)        | {-0.4,-1,-6}                          |      39.4973984303
+ (5.1,34.5)        | {-0.000184615384615,-1,15.3846153846} |      19.1163258281
+ (5.1,34.5)        | {3,NaN,5}                             |                NaN
+ (5.1,34.5)        | {NaN,NaN,NaN}                         |                NaN
+ (5.1,34.5)        | {0,-1,3}                              |               31.5
+ (5.1,34.5)        | {-1,0,3}                              |                2.1
+ (-5,-12)          | {0,-1,5}                              |                 17
+ (-5,-12)          | {1,0,5}                               |                  0
+ (-5,-12)          | {0,3,0}                               |                 12
+ (-5,-12)          | {1,-1,0}                              |      4.94974746831
+ (-5,-12)          | {-0.4,-1,-6}                          |      7.42781352708
+ (-5,-12)          | {-0.000184615384615,-1,15.3846153846} |      27.3855379948
+ (-5,-12)          | {3,NaN,5}                             |                NaN
+ (-5,-12)          | {NaN,NaN,NaN}                         |                NaN
+ (-5,-12)          | {0,-1,3}                              |                 15
+ (-5,-12)          | {-1,0,3}                              |                  8
+ (1e-300,-1e-300)  | {0,-1,5}                              |                  5
+ (1e-300,-1e-300)  | {1,0,5}                               |                  5
+ (1e-300,-1e-300)  | {0,3,0}                               |             1e-300
+ (1e-300,-1e-300)  | {1,-1,0}                              | 1.41421356237e-300
+ (1e-300,-1e-300)  | {-0.4,-1,-6}                          |      5.57086014531
+ (1e-300,-1e-300)  | {-0.000184615384615,-1,15.3846153846} |      15.3846151224
+ (1e-300,-1e-300)  | {3,NaN,5}                             |                NaN
+ (1e-300,-1e-300)  | {NaN,NaN,NaN}                         |                NaN
+ (1e-300,-1e-300)  | {0,-1,3}                              |                  3
+ (1e-300,-1e-300)  | {-1,0,3}                              |                  3
+ (1e+300,Infinity) | {0,-1,5}                              |           Infinity
+ (1e+300,Infinity) | {1,0,5}                               |                NaN
+ (1e+300,Infinity) | {0,3,0}                               |           Infinity
+ (1e+300,Infinity) | {1,-1,0}                              |           Infinity
+ (1e+300,Infinity) | {-0.4,-1,-6}                          |           Infinity
+ (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} |           Infinity
+ (1e+300,Infinity) | {3,NaN,5}                             |                NaN
+ (1e+300,Infinity) | {NaN,NaN,NaN}                         |                NaN
+ (1e+300,Infinity) | {0,-1,3}                              |           Infinity
+ (1e+300,Infinity) | {-1,0,3}                              |                NaN
+ (NaN,NaN)         | {0,-1,5}                              |                NaN
+ (NaN,NaN)         | {1,0,5}                               |                NaN
+ (NaN,NaN)         | {0,3,0}                               |                NaN
+ (NaN,NaN)         | {1,-1,0}                              |                NaN
+ (NaN,NaN)         | {-0.4,-1,-6}                          |                NaN
+ (NaN,NaN)         | {-0.000184615384615,-1,15.3846153846} |                NaN
+ (NaN,NaN)         | {3,NaN,5}                             |                NaN
+ (NaN,NaN)         | {NaN,NaN,NaN}                         |                NaN
+ (NaN,NaN)         | {0,-1,3}                              |                NaN
+ (NaN,NaN)         | {-1,0,3}                              |                NaN
+ (10,10)           | {0,-1,5}                              |                  5
+ (10,10)           | {1,0,5}                               |                 15
+ (10,10)           | {0,3,0}                               |                 10
+ (10,10)           | {1,-1,0}                              |                  0
+ (10,10)           | {-0.4,-1,-6}                          |      18.5695338177
+ (10,10)           | {-0.000184615384615,-1,15.3846153846} |      5.38276913903
+ (10,10)           | {3,NaN,5}                             |                NaN
+ (10,10)           | {NaN,NaN,NaN}                         |                NaN
+ (10,10)           | {0,-1,3}                              |                  7
+ (10,10)           | {-1,0,3}                              |                  7
+(90 rows)
+
+-- Distance to line segment
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LSEG_TBL l;
+        f1         |               s               |      ?column?      
+-------------------+-------------------------------+--------------------
+ (0,0)             | [(1,2),(3,4)]                 |       2.2360679775
+ (0,0)             | [(0,0),(6,6)]                 |                  0
+ (0,0)             | [(10,-10),(-3,-4)]            |      4.88901207039
+ (0,0)             | [(-1000000,200),(300000,-40)] |      15.3846151224
+ (0,0)             | [(11,22),(33,44)]             |      24.5967477525
+ (0,0)             | [(-10,2),(-10,3)]             |      10.1980390272
+ (0,0)             | [(0,-20),(30,-20)]            |                 20
+ (0,0)             | [(NaN,1),(NaN,90)]            |                NaN
+ (-10,0)           | [(1,2),(3,4)]                 |      11.1803398875
+ (-10,0)           | [(0,0),(6,6)]                 |                 10
+ (-10,0)           | [(10,-10),(-3,-4)]            |       8.0622577483
+ (-10,0)           | [(-1000000,200),(300000,-40)] |      15.3864612763
+ (-10,0)           | [(11,22),(33,44)]             |      30.4138126515
+ (-10,0)           | [(-10,2),(-10,3)]             |                  2
+ (-10,0)           | [(0,-20),(30,-20)]            |       22.360679775
+ (-10,0)           | [(NaN,1),(NaN,90)]            |                NaN
+ (-3,4)            | [(1,2),(3,4)]                 |        4.472135955
+ (-3,4)            | [(0,0),(6,6)]                 |      4.94974746831
+ (-3,4)            | [(10,-10),(-3,-4)]            |                  8
+ (-3,4)            | [(-1000000,200),(300000,-40)] |      11.3851690367
+ (-3,4)            | [(11,22),(33,44)]             |       22.803508502
+ (-3,4)            | [(-10,2),(-10,3)]             |      7.07106781187
+ (-3,4)            | [(0,-20),(30,-20)]            |      24.1867732449
+ (-3,4)            | [(NaN,1),(NaN,90)]            |                NaN
+ (5.1,34.5)        | [(1,2),(3,4)]                 |      30.5722096028
+ (5.1,34.5)        | [(0,0),(6,6)]                 |      28.5142069853
+ (5.1,34.5)        | [(10,-10),(-3,-4)]            |      39.3428519556
+ (5.1,34.5)        | [(-1000000,200),(300000,-40)] |      19.1163258281
+ (5.1,34.5)        | [(11,22),(33,44)]             |      13.0107647738
+ (5.1,34.5)        | [(-10,2),(-10,3)]             |       34.932220084
+ (5.1,34.5)        | [(0,-20),(30,-20)]            |               54.5
+ (5.1,34.5)        | [(NaN,1),(NaN,90)]            |                NaN
+ (-5,-12)          | [(1,2),(3,4)]                 |      15.2315462117
+ (-5,-12)          | [(0,0),(6,6)]                 |                 13
+ (-5,-12)          | [(10,-10),(-3,-4)]            |      8.10179143093
+ (-5,-12)          | [(-1000000,200),(300000,-40)] |      27.3855379949
+ (-5,-12)          | [(11,22),(33,44)]             |      37.5765884561
+ (-5,-12)          | [(-10,2),(-10,3)]             |      14.8660687473
+ (-5,-12)          | [(0,-20),(30,-20)]            |      9.43398113206
+ (-5,-12)          | [(NaN,1),(NaN,90)]            |                NaN
+ (1e-300,-1e-300)  | [(1,2),(3,4)]                 |       2.2360679775
+ (1e-300,-1e-300)  | [(0,0),(6,6)]                 | 1.41421356237e-300
+ (1e-300,-1e-300)  | [(10,-10),(-3,-4)]            |      4.88901207039
+ (1e-300,-1e-300)  | [(-1000000,200),(300000,-40)] |      15.3846151224
+ (1e-300,-1e-300)  | [(11,22),(33,44)]             |      24.5967477525
+ (1e-300,-1e-300)  | [(-10,2),(-10,3)]             |      10.1980390272
+ (1e-300,-1e-300)  | [(0,-20),(30,-20)]            |                 20
+ (1e-300,-1e-300)  | [(NaN,1),(NaN,90)]            |                NaN
+ (1e+300,Infinity) | [(1,2),(3,4)]                 |           Infinity
+ (1e+300,Infinity) | [(0,0),(6,6)]                 |           Infinity
+ (1e+300,Infinity) | [(10,-10),(-3,-4)]            |           Infinity
+ (1e+300,Infinity) | [(-1000000,200),(300000,-40)] |           Infinity
+ (1e+300,Infinity) | [(11,22),(33,44)]             |           Infinity
+ (1e+300,Infinity) | [(-10,2),(-10,3)]             |           Infinity
+ (1e+300,Infinity) | [(0,-20),(30,-20)]            |           Infinity
+ (1e+300,Infinity) | [(NaN,1),(NaN,90)]            |           Infinity
+ (NaN,NaN)         | [(1,2),(3,4)]                 |                NaN
+ (NaN,NaN)         | [(0,0),(6,6)]                 |                NaN
+ (NaN,NaN)         | [(10,-10),(-3,-4)]            |                NaN
+ (NaN,NaN)         | [(-1000000,200),(300000,-40)] |                NaN
+ (NaN,NaN)         | [(11,22),(33,44)]             |                NaN
+ (NaN,NaN)         | [(-10,2),(-10,3)]             |                NaN
+ (NaN,NaN)         | [(0,-20),(30,-20)]            |                NaN
+ (NaN,NaN)         | [(NaN,1),(NaN,90)]            |                NaN
+ (10,10)           | [(1,2),(3,4)]                 |      9.21954445729
+ (10,10)           | [(0,0),(6,6)]                 |      5.65685424949
+ (10,10)           | [(10,-10),(-3,-4)]            |        18.15918769
+ (10,10)           | [(-1000000,200),(300000,-40)] |      5.38276913904
+ (10,10)           | [(11,22),(33,44)]             |      12.0415945788
+ (10,10)           | [(-10,2),(-10,3)]             |      21.1896201004
+ (10,10)           | [(0,-20),(30,-20)]            |                 30
+ (10,10)           | [(NaN,1),(NaN,90)]            |                NaN
+(72 rows)
+
+-- Distance to box
+SELECT p.f1, b.f1, p.f1 <-> b.f1 FROM POINT_TBL p, BOX_TBL b;
+        f1         |         f1          |      ?column?      
+-------------------+---------------------+--------------------
+ (0,0)             | (2,2),(0,0)         |                  0
+ (0,0)             | (3,3),(1,1)         |      1.41421356237
+ (0,0)             | (-2,2),(-8,-10)     |                  2
+ (0,0)             | (2.5,3.5),(2.5,2.5) |      3.53553390593
+ (0,0)             | (3,3),(3,3)         |      4.24264068712
+ (-10,0)           | (2,2),(0,0)         |                 10
+ (-10,0)           | (3,3),(1,1)         |      11.0453610172
+ (-10,0)           | (-2,2),(-8,-10)     |                  2
+ (-10,0)           | (2.5,3.5),(2.5,2.5) |       12.747548784
+ (-10,0)           | (3,3),(3,3)         |      13.3416640641
+ (-3,4)            | (2,2),(0,0)         |      3.60555127546
+ (-3,4)            | (3,3),(1,1)         |      4.12310562562
+ (-3,4)            | (-2,2),(-8,-10)     |                  2
+ (-3,4)            | (2.5,3.5),(2.5,2.5) |      5.52268050859
+ (-3,4)            | (3,3),(3,3)         |       6.0827625303
+ (5.1,34.5)        | (2,2),(0,0)         |      32.6475113906
+ (5.1,34.5)        | (3,3),(1,1)         |      31.5699223946
+ (5.1,34.5)        | (-2,2),(-8,-10)     |      33.2664996656
+ (5.1,34.5)        | (2.5,3.5),(2.5,2.5) |       31.108841187
+ (5.1,34.5)        | (3,3),(3,3)         |      31.5699223946
+ (-5,-12)          | (2,2),(0,0)         |                 13
+ (-5,-12)          | (3,3),(1,1)         |      14.3178210633
+ (-5,-12)          | (-2,2),(-8,-10)     |                  2
+ (-5,-12)          | (2.5,3.5),(2.5,2.5) |      16.3248277173
+ (-5,-12)          | (3,3),(3,3)         |                 17
+ (1e-300,-1e-300)  | (2,2),(0,0)         | 1.41421356237e-300
+ (1e-300,-1e-300)  | (3,3),(1,1)         |      1.41421356237
+ (1e-300,-1e-300)  | (-2,2),(-8,-10)     |                  2
+ (1e-300,-1e-300)  | (2.5,3.5),(2.5,2.5) |      3.53553390593
+ (1e-300,-1e-300)  | (3,3),(3,3)         |      4.24264068712
+ (1e+300,Infinity) | (2,2),(0,0)         |           Infinity
+ (1e+300,Infinity) | (3,3),(1,1)         |           Infinity
+ (1e+300,Infinity) | (-2,2),(-8,-10)     |           Infinity
+ (1e+300,Infinity) | (2.5,3.5),(2.5,2.5) |           Infinity
+ (1e+300,Infinity) | (3,3),(3,3)         |           Infinity
+ (NaN,NaN)         | (2,2),(0,0)         |                NaN
+ (NaN,NaN)         | (3,3),(1,1)         |                NaN
+ (NaN,NaN)         | (-2,2),(-8,-10)     |                NaN
+ (NaN,NaN)         | (2.5,3.5),(2.5,2.5) |                NaN
+ (NaN,NaN)         | (3,3),(3,3)         |                NaN
+ (10,10)           | (2,2),(0,0)         |       11.313708499
+ (10,10)           | (3,3),(1,1)         |      9.89949493661
+ (10,10)           | (-2,2),(-8,-10)     |      14.4222051019
+ (10,10)           | (2.5,3.5),(2.5,2.5) |      9.92471662064
+ (10,10)           | (3,3),(3,3)         |      9.89949493661
+(45 rows)
+
+-- Distance to path
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, PATH_TBL p1;
+        f1         |            f1             |      ?column?      
+-------------------+---------------------------+--------------------
+ (0,0)             | [(1,2),(3,4)]             |       2.2360679775
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | [(0,0),(3,0),(4,5),(1,6)] |                  0
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | [(1,2),(3,4)]             |       2.2360679775
+ (0,0)             | ((10,20))                 |       22.360679775
+ (0,0)             | [(11,12),(13,14)]         |      16.2788205961
+ (0,0)             | ((11,12),(13,14))         |      16.2788205961
+ (-10,0)           | [(1,2),(3,4)]             |      11.1803398875
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | [(0,0),(3,0),(4,5),(1,6)] |                 10
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | [(1,2),(3,4)]             |      11.1803398875
+ (-10,0)           | ((10,20))                 |      28.2842712475
+ (-10,0)           | [(11,12),(13,14)]         |      24.1867732449
+ (-10,0)           | ((11,12),(13,14))         |      24.1867732449
+ (-3,4)            | [(1,2),(3,4)]             |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | [(0,0),(3,0),(4,5),(1,6)] |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | [(1,2),(3,4)]             |        4.472135955
+ (-3,4)            | ((10,20))                 |      20.6155281281
+ (-3,4)            | [(11,12),(13,14)]         |      16.1245154966
+ (-3,4)            | ((11,12),(13,14))         |      16.1245154966
+ (5.1,34.5)        | [(1,2),(3,4)]             |      30.5722096028
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | [(0,0),(3,0),(4,5),(1,6)] |       28.793402022
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | [(1,2),(3,4)]             |      30.5722096028
+ (5.1,34.5)        | ((10,20))                 |      15.3055545473
+ (5.1,34.5)        | [(11,12),(13,14)]         |      21.9695243462
+ (5.1,34.5)        | ((11,12),(13,14))         |      21.9695243462
+ (-5,-12)          | [(1,2),(3,4)]             |      15.2315462117
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | [(0,0),(3,0),(4,5),(1,6)] |                 13
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | [(1,2),(3,4)]             |      15.2315462117
+ (-5,-12)          | ((10,20))                 |      35.3411940941
+ (-5,-12)          | [(11,12),(13,14)]         |      28.8444102037
+ (-5,-12)          | ((11,12),(13,14))         |      28.8444102037
+ (1e-300,-1e-300)  | [(1,2),(3,4)]             |       2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | [(0,0),(3,0),(4,5),(1,6)] | 1.41421356237e-300
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | [(1,2),(3,4)]             |       2.2360679775
+ (1e-300,-1e-300)  | ((10,20))                 |       22.360679775
+ (1e-300,-1e-300)  | [(11,12),(13,14)]         |      16.2788205961
+ (1e-300,-1e-300)  | ((11,12),(13,14))         |      16.2788205961
+ (1e+300,Infinity) | [(1,2),(3,4)]             |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | [(0,0),(3,0),(4,5),(1,6)] |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | [(1,2),(3,4)]             |           Infinity
+ (1e+300,Infinity) | ((10,20))                 |           Infinity
+ (1e+300,Infinity) | [(11,12),(13,14)]         |           Infinity
+ (1e+300,Infinity) | ((11,12),(13,14))         |           Infinity
+ (NaN,NaN)         | [(1,2),(3,4)]             |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | [(0,0),(3,0),(4,5),(1,6)] |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | [(1,2),(3,4)]             |                NaN
+ (NaN,NaN)         | ((10,20))                 |                NaN
+ (NaN,NaN)         | [(11,12),(13,14)]         |                NaN
+ (NaN,NaN)         | ((11,12),(13,14))         |                NaN
+ (10,10)           | [(1,2),(3,4)]             |      9.21954445729
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | [(0,0),(3,0),(4,5),(1,6)] |      7.81024967591
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | [(1,2),(3,4)]             |      9.21954445729
+ (10,10)           | ((10,20))                 |                 10
+ (10,10)           | [(11,12),(13,14)]         |       2.2360679775
+ (10,10)           | ((11,12),(13,14))         |       2.2360679775
+(81 rows)
+
+-- Distance to polygon
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, POLYGON_TBL p1;
+        f1         |             f1             |   ?column?    
+-------------------+----------------------------+---------------
+ (0,0)             | ((2,0),(2,4),(0,0))        |             0
+ (0,0)             | ((3,1),(3,3),(1,0))        |             1
+ (0,0)             | ((1,2),(3,4),(5,6),(7,8))  |  2.2360679775
+ (0,0)             | ((7,8),(5,6),(3,4),(1,2))  |  2.2360679775
+ (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | 1.58113883008
+ (0,0)             | ((0,0))                    |             0
+ (0,0)             | ((0,1),(0,1))              |             1
+ (-10,0)           | ((2,0),(2,4),(0,0))        |            10
+ (-10,0)           | ((3,1),(3,3),(1,0))        |            11
+ (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | 11.1803398875
+ (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | 11.1803398875
+ (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | 11.1803398875
+ (-10,0)           | ((0,0))                    |            10
+ (-10,0)           | ((0,1),(0,1))              | 10.0498756211
+ (-3,4)            | ((2,0),(2,4),(0,0))        |   4.472135955
+ (-3,4)            | ((3,1),(3,3),(1,0))        | 5.54700196225
+ (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  |   4.472135955
+ (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  |   4.472135955
+ (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) |   4.472135955
+ (-3,4)            | ((0,0))                    |             5
+ (-3,4)            | ((0,1),(0,1))              | 4.24264068712
+ (5.1,34.5)        | ((2,0),(2,4),(0,0))        | 30.6571362002
+ (5.1,34.5)        | ((3,1),(3,3),(1,0))        | 31.5699223946
+ (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | 26.5680258958
+ (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | 26.5680258958
+ (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | 26.5680258958
+ (5.1,34.5)        | ((0,0))                    | 34.8749193547
+ (5.1,34.5)        | ((0,1),(0,1))              | 33.8859853037
+ (-5,-12)          | ((2,0),(2,4),(0,0))        |            13
+ (-5,-12)          | ((3,1),(3,3),(1,0))        |  13.416407865
+ (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | 15.2315462117
+ (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | 15.2315462117
+ (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) |  11.313708499
+ (-5,-12)          | ((0,0))                    |            13
+ (-5,-12)          | ((0,1),(0,1))              | 13.9283882772
+ (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        |             0
+ (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        |             1
+ (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  |  2.2360679775
+ (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  |  2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | 1.58113883008
+ (1e-300,-1e-300)  | ((0,0))                    |             0
+ (1e-300,-1e-300)  | ((0,1),(0,1))              |             1
+ (1e+300,Infinity) | ((2,0),(2,4),(0,0))        |      Infinity
+ (1e+300,Infinity) | ((3,1),(3,3),(1,0))        |      Infinity
+ (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  |      Infinity
+ (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  |      Infinity
+ (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) |      Infinity
+ (1e+300,Infinity) | ((0,0))                    |      Infinity
+ (1e+300,Infinity) | ((0,1),(0,1))              |      Infinity
+ (NaN,NaN)         | ((2,0),(2,4),(0,0))        |             0
+ (NaN,NaN)         | ((3,1),(3,3),(1,0))        |             0
+ (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  |             0
+ (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  |             0
+ (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) |             0
+ (NaN,NaN)         | ((0,0))                    |             0
+ (NaN,NaN)         | ((0,1),(0,1))              |             0
+ (10,10)           | ((2,0),(2,4),(0,0))        |            10
+ (10,10)           | ((3,1),(3,3),(1,0))        | 9.89949493661
+ (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | 3.60555127546
+ (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | 3.60555127546
+ (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | 3.60555127546
+ (10,10)           | ((0,0))                    | 14.1421356237
+ (10,10)           | ((0,1),(0,1))              | 13.4536240471
+(63 rows)
+
+-- Closest point to line
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LINE_TBL l;
+        f1         |                   s                   |             ?column?             
+-------------------+---------------------------------------+----------------------------------
+ (0,0)             | {0,-1,5}                              | (0,5)
+ (0,0)             | {1,0,5}                               | (-5,0)
+ (0,0)             | {0,3,0}                               | (0,0)
+ (0,0)             | {1,-1,0}                              | (0,0)
+ (0,0)             | {-0.4,-1,-6}                          | (-2.06896551724,-5.1724137931)
+ (0,0)             | {-0.000184615384615,-1,15.3846153846} | (0.00284023658959,15.3846148603)
+ (0,0)             | {3,NaN,5}                             | 
+ (0,0)             | {NaN,NaN,NaN}                         | 
+ (0,0)             | {0,-1,3}                              | (0,3)
+ (0,0)             | {-1,0,3}                              | (3,0)
+ (-10,0)           | {0,-1,5}                              | (-10,5)
+ (-10,0)           | {1,0,5}                               | (-5,0)
+ (-10,0)           | {0,3,0}                               | (-10,0)
+ (-10,0)           | {1,-1,0}                              | (-5,-5)
+ (-10,0)           | {-0.4,-1,-6}                          | (-10.6896551724,-1.72413793103)
+ (-10,0)           | {-0.000184615384615,-1,15.3846153846} | (-9.99715942258,15.386461014)
+ (-10,0)           | {3,NaN,5}                             | 
+ (-10,0)           | {NaN,NaN,NaN}                         | 
+ (-10,0)           | {0,-1,3}                              | (-10,3)
+ (-10,0)           | {-1,0,3}                              | (3,0)
+ (-3,4)            | {0,-1,5}                              | (-3,5)
+ (-3,4)            | {1,0,5}                               | (-5,4)
+ (-3,4)            | {0,3,0}                               | (-3,0)
+ (-3,4)            | {1,-1,0}                              | (0.5,0.5)
+ (-3,4)            | {-0.4,-1,-6}                          | (-6.03448275862,-3.58620689655)
+ (-3,4)            | {-0.000184615384615,-1,15.3846153846} | (-2.99789812268,15.3851688427)
+ (-3,4)            | {3,NaN,5}                             | 
+ (-3,4)            | {NaN,NaN,NaN}                         | 
+ (-3,4)            | {0,-1,3}                              | (-3,3)
+ (-3,4)            | {-1,0,3}                              | (3,4)
+ (5.1,34.5)        | {0,-1,5}                              | (5.1,5)
+ (5.1,34.5)        | {1,0,5}                               | (-5,34.5)
+ (5.1,34.5)        | {0,3,0}                               | (5.1,0)
+ (5.1,34.5)        | {1,-1,0}                              | (19.8,19.8)
+ (5.1,34.5)        | {-0.4,-1,-6}                          | (-9.56896551724,-2.1724137931)
+ (5.1,34.5)        | {-0.000184615384615,-1,15.3846153846} | (5.09647083221,15.3836744977)
+ (5.1,34.5)        | {3,NaN,5}                             | 
+ (5.1,34.5)        | {NaN,NaN,NaN}                         | 
+ (5.1,34.5)        | {0,-1,3}                              | (5.1,3)
+ (5.1,34.5)        | {-1,0,3}                              | (3,34.5)
+ (-5,-12)          | {0,-1,5}                              | (-5,5)
+ (-5,-12)          | {1,0,5}                               | (-5,-12)
+ (-5,-12)          | {0,3,0}                               | (-5,0)
+ (-5,-12)          | {1,-1,0}                              | (-8.5,-8.5)
+ (-5,-12)          | {-0.4,-1,-6}                          | (-2.24137931034,-5.10344827586)
+ (-5,-12)          | {-0.000184615384615,-1,15.3846153846} | (-4.99494420846,15.3855375282)
+ (-5,-12)          | {3,NaN,5}                             | 
+ (-5,-12)          | {NaN,NaN,NaN}                         | 
+ (-5,-12)          | {0,-1,3}                              | (-5,3)
+ (-5,-12)          | {-1,0,3}                              | (3,-12)
+ (1e-300,-1e-300)  | {0,-1,5}                              | (1e-300,5)
+ (1e-300,-1e-300)  | {1,0,5}                               | (-5,-1e-300)
+ (1e-300,-1e-300)  | {0,3,0}                               | (1e-300,0)
+ (1e-300,-1e-300)  | {1,-1,0}                              | (0,0)
+ (1e-300,-1e-300)  | {-0.4,-1,-6}                          | (-2.06896551724,-5.1724137931)
+ (1e-300,-1e-300)  | {-0.000184615384615,-1,15.3846153846} | (0.00284023658959,15.3846148603)
+ (1e-300,-1e-300)  | {3,NaN,5}                             | 
+ (1e-300,-1e-300)  | {NaN,NaN,NaN}                         | 
+ (1e-300,-1e-300)  | {0,-1,3}                              | (1e-300,3)
+ (1e-300,-1e-300)  | {-1,0,3}                              | (3,-1e-300)
+ (1e+300,Infinity) | {0,-1,5}                              | (1e+300,5)
+ (1e+300,Infinity) | {1,0,5}                               | 
+ (1e+300,Infinity) | {0,3,0}                               | (1e+300,0)
+ (1e+300,Infinity) | {1,-1,0}                              | (Infinity,NaN)
+ (1e+300,Infinity) | {-0.4,-1,-6}                          | (-Infinity,NaN)
+ (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} | (-Infinity,NaN)
+ (1e+300,Infinity) | {3,NaN,5}                             | 
+ (1e+300,Infinity) | {NaN,NaN,NaN}                         | 
+ (1e+300,Infinity) | {0,-1,3}                              | (1e+300,3)
+ (1e+300,Infinity) | {-1,0,3}                              | 
+ (NaN,NaN)         | {0,-1,5}                              | 
+ (NaN,NaN)         | {1,0,5}                               | 
+ (NaN,NaN)         | {0,3,0}                               | 
+ (NaN,NaN)         | {1,-1,0}                              | 
+ (NaN,NaN)         | {-0.4,-1,-6}                          | 
+ (NaN,NaN)         | {-0.000184615384615,-1,15.3846153846} | 
+ (NaN,NaN)         | {3,NaN,5}                             | 
+ (NaN,NaN)         | {NaN,NaN,NaN}                         | 
+ (NaN,NaN)         | {0,-1,3}                              | 
+ (NaN,NaN)         | {-1,0,3}                              | 
+ (10,10)           | {0,-1,5}                              | (10,5)
+ (10,10)           | {1,0,5}                               | (-5,10)
+ (10,10)           | {0,3,0}                               | (10,0)
+ (10,10)           | {1,-1,0}                              | (10,10)
+ (10,10)           | {-0.4,-1,-6}                          | (3.10344827586,-7.24137931034)
+ (10,10)           | {-0.000184615384615,-1,15.3846153846} | (10.000993742,15.3827690473)
+ (10,10)           | {3,NaN,5}                             | 
+ (10,10)           | {NaN,NaN,NaN}                         | 
+ (10,10)           | {0,-1,3}                              | (10,3)
+ (10,10)           | {-1,0,3}                              | (3,10)
+(90 rows)
+
+-- Closest point to line segment
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LSEG_TBL l;
+        f1         |               s               |             ?column?             
+-------------------+-------------------------------+----------------------------------
+ (0,0)             | [(1,2),(3,4)]                 | (1,2)
+ (0,0)             | [(0,0),(6,6)]                 | (0,0)
+ (0,0)             | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ (0,0)             | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
+ (0,0)             | [(11,22),(33,44)]             | (11,22)
+ (0,0)             | [(-10,2),(-10,3)]             | (-10,2)
+ (0,0)             | [(0,-20),(30,-20)]            | (0,-20)
+ (0,0)             | [(NaN,1),(NaN,90)]            | 
+ (-10,0)           | [(1,2),(3,4)]                 | (1,2)
+ (-10,0)           | [(0,0),(6,6)]                 | (0,0)
+ (-10,0)           | [(10,-10),(-3,-4)]            | (-3,-4)
+ (-10,0)           | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
+ (-10,0)           | [(11,22),(33,44)]             | (11,22)
+ (-10,0)           | [(-10,2),(-10,3)]             | (-10,2)
+ (-10,0)           | [(0,-20),(30,-20)]            | (0,-20)
+ (-10,0)           | [(NaN,1),(NaN,90)]            | 
+ (-3,4)            | [(1,2),(3,4)]                 | (1,2)
+ (-3,4)            | [(0,0),(6,6)]                 | (0.5,0.5)
+ (-3,4)            | [(10,-10),(-3,-4)]            | (-3,-4)
+ (-3,4)            | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
+ (-3,4)            | [(11,22),(33,44)]             | (11,22)
+ (-3,4)            | [(-10,2),(-10,3)]             | (-10,3)
+ (-3,4)            | [(0,-20),(30,-20)]            | (0,-20)
+ (-3,4)            | [(NaN,1),(NaN,90)]            | 
+ (5.1,34.5)        | [(1,2),(3,4)]                 | (3,4)
+ (5.1,34.5)        | [(0,0),(6,6)]                 | (6,6)
+ (5.1,34.5)        | [(10,-10),(-3,-4)]            | (-3,-4)
+ (5.1,34.5)        | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
+ (5.1,34.5)        | [(11,22),(33,44)]             | (14.3,25.3)
+ (5.1,34.5)        | [(-10,2),(-10,3)]             | (-10,3)
+ (5.1,34.5)        | [(0,-20),(30,-20)]            | (5.1,-20)
+ (5.1,34.5)        | [(NaN,1),(NaN,90)]            | 
+ (-5,-12)          | [(1,2),(3,4)]                 | (1,2)
+ (-5,-12)          | [(0,0),(6,6)]                 | (0,0)
+ (-5,-12)          | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
+ (-5,-12)          | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
+ (-5,-12)          | [(11,22),(33,44)]             | (11,22)
+ (-5,-12)          | [(-10,2),(-10,3)]             | (-10,2)
+ (-5,-12)          | [(0,-20),(30,-20)]            | (0,-20)
+ (-5,-12)          | [(NaN,1),(NaN,90)]            | 
+ (1e-300,-1e-300)  | [(1,2),(3,4)]                 | (1,2)
+ (1e-300,-1e-300)  | [(0,0),(6,6)]                 | (0,0)
+ (1e-300,-1e-300)  | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ (1e-300,-1e-300)  | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
+ (1e-300,-1e-300)  | [(11,22),(33,44)]             | (11,22)
+ (1e-300,-1e-300)  | [(-10,2),(-10,3)]             | (-10,2)
+ (1e-300,-1e-300)  | [(0,-20),(30,-20)]            | (0,-20)
+ (1e-300,-1e-300)  | [(NaN,1),(NaN,90)]            | 
+ (1e+300,Infinity) | [(1,2),(3,4)]                 | (3,4)
+ (1e+300,Infinity) | [(0,0),(6,6)]                 | (6,6)
+ (1e+300,Infinity) | [(10,-10),(-3,-4)]            | (-3,-4)
+ (1e+300,Infinity) | [(-1000000,200),(300000,-40)] | (300000,-40)
+ (1e+300,Infinity) | [(11,22),(33,44)]             | (33,44)
+ (1e+300,Infinity) | [(-10,2),(-10,3)]             | (-10,3)
+ (1e+300,Infinity) | [(0,-20),(30,-20)]            | (30,-20)
+ (1e+300,Infinity) | [(NaN,1),(NaN,90)]            | (NaN,90)
+ (NaN,NaN)         | [(1,2),(3,4)]                 | 
+ (NaN,NaN)         | [(0,0),(6,6)]                 | 
+ (NaN,NaN)         | [(10,-10),(-3,-4)]            | 
+ (NaN,NaN)         | [(-1000000,200),(300000,-40)] | 
+ (NaN,NaN)         | [(11,22),(33,44)]             | 
+ (NaN,NaN)         | [(-10,2),(-10,3)]             | 
+ (NaN,NaN)         | [(0,-20),(30,-20)]            | 
+ (NaN,NaN)         | [(NaN,1),(NaN,90)]            | 
+ (10,10)           | [(1,2),(3,4)]                 | (3,4)
+ (10,10)           | [(0,0),(6,6)]                 | (6,6)
+ (10,10)           | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
+ (10,10)           | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
+ (10,10)           | [(11,22),(33,44)]             | (11,22)
+ (10,10)           | [(-10,2),(-10,3)]             | (-10,3)
+ (10,10)           | [(0,-20),(30,-20)]            | (10,-20)
+ (10,10)           | [(NaN,1),(NaN,90)]            | 
+(72 rows)
+
+-- Closest point to box
+SELECT p.f1, b.f1, p.f1 ## b.f1 FROM POINT_TBL p, BOX_TBL b;
+        f1         |         f1          |   ?column?   
+-------------------+---------------------+--------------
+ (0,0)             | (2,2),(0,0)         | (0,0)
+ (0,0)             | (3,3),(1,1)         | (1,1)
+ (0,0)             | (-2,2),(-8,-10)     | (-2,0)
+ (0,0)             | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (0,0)             | (3,3),(3,3)         | (3,3)
+ (-10,0)           | (2,2),(0,0)         | (0,0)
+ (-10,0)           | (3,3),(1,1)         | (1,1)
+ (-10,0)           | (-2,2),(-8,-10)     | (-8,0)
+ (-10,0)           | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (-10,0)           | (3,3),(3,3)         | (3,3)
+ (-3,4)            | (2,2),(0,0)         | (0,2)
+ (-3,4)            | (3,3),(1,1)         | (1,3)
+ (-3,4)            | (-2,2),(-8,-10)     | (-3,2)
+ (-3,4)            | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (-3,4)            | (3,3),(3,3)         | (3,3)
+ (5.1,34.5)        | (2,2),(0,0)         | (2,2)
+ (5.1,34.5)        | (3,3),(1,1)         | (3,3)
+ (5.1,34.5)        | (-2,2),(-8,-10)     | (-2,2)
+ (5.1,34.5)        | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (5.1,34.5)        | (3,3),(3,3)         | (3,3)
+ (-5,-12)          | (2,2),(0,0)         | (0,0)
+ (-5,-12)          | (3,3),(1,1)         | (1,1)
+ (-5,-12)          | (-2,2),(-8,-10)     | (-5,-10)
+ (-5,-12)          | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (-5,-12)          | (3,3),(3,3)         | (3,3)
+ (1e-300,-1e-300)  | (2,2),(0,0)         | (0,0)
+ (1e-300,-1e-300)  | (3,3),(1,1)         | (1,1)
+ (1e-300,-1e-300)  | (-2,2),(-8,-10)     | (-2,-1e-300)
+ (1e-300,-1e-300)  | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (1e-300,-1e-300)  | (3,3),(3,3)         | (3,3)
+ (1e+300,Infinity) | (2,2),(0,0)         | (0,2)
+ (1e+300,Infinity) | (3,3),(1,1)         | (1,3)
+ (1e+300,Infinity) | (-2,2),(-8,-10)     | (-8,2)
+ (1e+300,Infinity) | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (1e+300,Infinity) | (3,3),(3,3)         | (3,3)
+ (NaN,NaN)         | (2,2),(0,0)         | 
+ (NaN,NaN)         | (3,3),(1,1)         | 
+ (NaN,NaN)         | (-2,2),(-8,-10)     | 
+ (NaN,NaN)         | (2.5,3.5),(2.5,2.5) | 
+ (NaN,NaN)         | (3,3),(3,3)         | 
+ (10,10)           | (2,2),(0,0)         | (2,2)
+ (10,10)           | (3,3),(1,1)         | (3,3)
+ (10,10)           | (-2,2),(-8,-10)     | (-2,2)
+ (10,10)           | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (10,10)           | (3,3),(3,3)         | (3,3)
+(45 rows)
+
+-- On line
+SELECT p.f1, l.s FROM POINT_TBL p, LINE_TBL l WHERE p.f1 <@ l.s;
+        f1        |    s     
+------------------+----------
+ (0,0)            | {0,3,0}
+ (0,0)            | {1,-1,0}
+ (-10,0)          | {0,3,0}
+ (-5,-12)         | {1,0,5}
+ (1e-300,-1e-300) | {0,3,0}
+ (1e-300,-1e-300) | {1,-1,0}
+ (10,10)          | {1,-1,0}
+(7 rows)
+
+-- On line segment
+SELECT p.f1, l.s FROM POINT_TBL p, LSEG_TBL l WHERE p.f1 <@ l.s;
+        f1        |       s       
+------------------+---------------
+ (0,0)            | [(0,0),(6,6)]
+ (1e-300,-1e-300) | [(0,0),(6,6)]
+(2 rows)
+
+-- On path
+SELECT p.f1, p1.f1 FROM POINT_TBL p, PATH_TBL p1 WHERE p.f1 <@ p1.f1;
+        f1        |            f1             
+------------------+---------------------------
+ (0,0)            | [(0,0),(3,0),(4,5),(1,6)]
+ (1e-300,-1e-300) | [(0,0),(3,0),(4,5),(1,6)]
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((10,20))
+ (NaN,NaN)        | ((11,12),(13,14))
+(7 rows)
+
+--
+-- Lines
+--
+-- Vertical
+SELECT s FROM LINE_TBL WHERE ?| s;
+    s     
+----------
+ {1,0,5}
+ {-1,0,3}
+(2 rows)
+
+-- Horizontal
+SELECT s FROM LINE_TBL WHERE ?- s;
+    s     
+----------
+ {0,-1,5}
+ {0,3,0}
+ {0,-1,3}
+(3 rows)
+
+-- Same as line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s = l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {0,-1,5}
+ {1,0,5}                               | {1,0,5}
+ {0,3,0}                               | {0,3,0}
+ {1,-1,0}                              | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846}
+ {3,NaN,5}                             | {3,NaN,5}
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}
+ {0,-1,3}                              | {0,-1,3}
+ {-1,0,3}                              | {-1,0,3}
+(10 rows)
+
+-- Parallel to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?|| l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {0,-1,5}
+ {0,-1,5}                              | {0,3,0}
+ {0,-1,5}                              | {0,-1,3}
+ {1,0,5}                               | {1,0,5}
+ {1,0,5}                               | {-1,0,3}
+ {0,3,0}                               | {0,-1,5}
+ {0,3,0}                               | {0,3,0}
+ {0,3,0}                               | {0,-1,3}
+ {1,-1,0}                              | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,3}                              | {0,-1,5}
+ {0,-1,3}                              | {0,3,0}
+ {0,-1,3}                              | {0,-1,3}
+ {-1,0,3}                              | {1,0,5}
+ {-1,0,3}                              | {-1,0,3}
+(16 rows)
+
+-- Perpendicular to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?-| l2.s;
+    s     |    s     
+----------+----------
+ {0,-1,5} | {1,0,5}
+ {0,-1,5} | {-1,0,3}
+ {1,0,5}  | {0,-1,5}
+ {1,0,5}  | {0,3,0}
+ {1,0,5}  | {0,-1,3}
+ {0,3,0}  | {1,0,5}
+ {0,3,0}  | {-1,0,3}
+ {0,-1,3} | {1,0,5}
+ {0,-1,3} | {-1,0,3}
+ {-1,0,3} | {0,-1,5}
+ {-1,0,3} | {0,3,0}
+ {-1,0,3} | {0,-1,3}
+(12 rows)
+
+-- Distance to line
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2;
+                   s                   |                   s                   | ?column? 
+---------------------------------------+---------------------------------------+----------
+ {0,-1,5}                              | {0,-1,5}                              |        0
+ {0,-1,5}                              | {1,0,5}                               |        0
+ {0,-1,5}                              | {0,3,0}                               |        5
+ {0,-1,5}                              | {1,-1,0}                              |        0
+ {0,-1,5}                              | {-0.4,-1,-6}                          |        0
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,-1,5}                              | {3,NaN,5}                             |        0
+ {0,-1,5}                              | {NaN,NaN,NaN}                         |        0
+ {0,-1,5}                              | {0,-1,3}                              |        2
+ {0,-1,5}                              | {-1,0,3}                              |        0
+ {1,0,5}                               | {0,-1,5}                              |        0
+ {1,0,5}                               | {1,0,5}                               |        0
+ {1,0,5}                               | {0,3,0}                               |        0
+ {1,0,5}                               | {1,-1,0}                              |        0
+ {1,0,5}                               | {-0.4,-1,-6}                          |        0
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846} |        0
+ {1,0,5}                               | {3,NaN,5}                             |        0
+ {1,0,5}                               | {NaN,NaN,NaN}                         |        0
+ {1,0,5}                               | {0,-1,3}                              |        0
+ {1,0,5}                               | {-1,0,3}                              |        8
+ {0,3,0}                               | {0,-1,5}                              |        5
+ {0,3,0}                               | {1,0,5}                               |        0
+ {0,3,0}                               | {0,3,0}                               |        0
+ {0,3,0}                               | {1,-1,0}                              |        0
+ {0,3,0}                               | {-0.4,-1,-6}                          |        0
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,3,0}                               | {3,NaN,5}                             |        0
+ {0,3,0}                               | {NaN,NaN,NaN}                         |        0
+ {0,3,0}                               | {0,-1,3}                              |        3
+ {0,3,0}                               | {-1,0,3}                              |        0
+ {1,-1,0}                              | {0,-1,5}                              |        0
+ {1,-1,0}                              | {1,0,5}                               |        0
+ {1,-1,0}                              | {0,3,0}                               |        0
+ {1,-1,0}                              | {1,-1,0}                              |        0
+ {1,-1,0}                              | {-0.4,-1,-6}                          |        0
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {1,-1,0}                              | {3,NaN,5}                             |        0
+ {1,-1,0}                              | {NaN,NaN,NaN}                         |        0
+ {1,-1,0}                              | {0,-1,3}                              |        0
+ {1,-1,0}                              | {-1,0,3}                              |        0
+ {-0.4,-1,-6}                          | {0,-1,5}                              |        0
+ {-0.4,-1,-6}                          | {1,0,5}                               |        0
+ {-0.4,-1,-6}                          | {0,3,0}                               |        0
+ {-0.4,-1,-6}                          | {1,-1,0}                              |        0
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}                          |        0
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846} |        0
+ {-0.4,-1,-6}                          | {3,NaN,5}                             |        0
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}                         |        0
+ {-0.4,-1,-6}                          | {0,-1,3}                              |        0
+ {-0.4,-1,-6}                          | {-1,0,3}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}                               |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}                               |        0
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}                          |        0
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} |        0
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}                             |        0
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}                         |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}                              |        0
+ {3,NaN,5}                             | {0,-1,5}                              |        0
+ {3,NaN,5}                             | {1,0,5}                               |        0
+ {3,NaN,5}                             | {0,3,0}                               |        0
+ {3,NaN,5}                             | {1,-1,0}                              |        0
+ {3,NaN,5}                             | {-0.4,-1,-6}                          |        0
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846} |        0
+ {3,NaN,5}                             | {3,NaN,5}                             |        0
+ {3,NaN,5}                             | {NaN,NaN,NaN}                         |        0
+ {3,NaN,5}                             | {0,-1,3}                              |        0
+ {3,NaN,5}                             | {-1,0,3}                              |        0
+ {NaN,NaN,NaN}                         | {0,-1,5}                              |        0
+ {NaN,NaN,NaN}                         | {1,0,5}                               |        0
+ {NaN,NaN,NaN}                         | {0,3,0}                               |        0
+ {NaN,NaN,NaN}                         | {1,-1,0}                              |        0
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}                          |        0
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846} |        0
+ {NaN,NaN,NaN}                         | {3,NaN,5}                             |        0
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}                         |        0
+ {NaN,NaN,NaN}                         | {0,-1,3}                              |        0
+ {NaN,NaN,NaN}                         | {-1,0,3}                              |        0
+ {0,-1,3}                              | {0,-1,5}                              |        2
+ {0,-1,3}                              | {1,0,5}                               |        0
+ {0,-1,3}                              | {0,3,0}                               |        3
+ {0,-1,3}                              | {1,-1,0}                              |        0
+ {0,-1,3}                              | {-0.4,-1,-6}                          |        0
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,-1,3}                              | {3,NaN,5}                             |        0
+ {0,-1,3}                              | {NaN,NaN,NaN}                         |        0
+ {0,-1,3}                              | {0,-1,3}                              |        0
+ {0,-1,3}                              | {-1,0,3}                              |        0
+ {-1,0,3}                              | {0,-1,5}                              |        0
+ {-1,0,3}                              | {1,0,5}                               |        8
+ {-1,0,3}                              | {0,3,0}                               |        0
+ {-1,0,3}                              | {1,-1,0}                              |        0
+ {-1,0,3}                              | {-0.4,-1,-6}                          |        0
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {-1,0,3}                              | {3,NaN,5}                             |        0
+ {-1,0,3}                              | {NaN,NaN,NaN}                         |        0
+ {-1,0,3}                              | {0,-1,3}                              |        0
+ {-1,0,3}                              | {-1,0,3}                              |        0
+(100 rows)
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LINE_TBL l, BOX_TBL b;
+ERROR:  function "dist_lb" not implemented
+-- Intersect with line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?# l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {1,0,5}
+ {0,-1,5}                              | {1,-1,0}
+ {0,-1,5}                              | {-0.4,-1,-6}
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,5}                              | {3,NaN,5}
+ {0,-1,5}                              | {NaN,NaN,NaN}
+ {0,-1,5}                              | {-1,0,3}
+ {1,0,5}                               | {0,-1,5}
+ {1,0,5}                               | {0,3,0}
+ {1,0,5}                               | {1,-1,0}
+ {1,0,5}                               | {-0.4,-1,-6}
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846}
+ {1,0,5}                               | {3,NaN,5}
+ {1,0,5}                               | {NaN,NaN,NaN}
+ {1,0,5}                               | {0,-1,3}
+ {0,3,0}                               | {1,0,5}
+ {0,3,0}                               | {1,-1,0}
+ {0,3,0}                               | {-0.4,-1,-6}
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846}
+ {0,3,0}                               | {3,NaN,5}
+ {0,3,0}                               | {NaN,NaN,NaN}
+ {0,3,0}                               | {-1,0,3}
+ {1,-1,0}                              | {0,-1,5}
+ {1,-1,0}                              | {1,0,5}
+ {1,-1,0}                              | {0,3,0}
+ {1,-1,0}                              | {-0.4,-1,-6}
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846}
+ {1,-1,0}                              | {3,NaN,5}
+ {1,-1,0}                              | {NaN,NaN,NaN}
+ {1,-1,0}                              | {0,-1,3}
+ {1,-1,0}                              | {-1,0,3}
+ {-0.4,-1,-6}                          | {0,-1,5}
+ {-0.4,-1,-6}                          | {1,0,5}
+ {-0.4,-1,-6}                          | {0,3,0}
+ {-0.4,-1,-6}                          | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846}
+ {-0.4,-1,-6}                          | {3,NaN,5}
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}
+ {-0.4,-1,-6}                          | {0,-1,3}
+ {-0.4,-1,-6}                          | {-1,0,3}
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}
+ {3,NaN,5}                             | {0,-1,5}
+ {3,NaN,5}                             | {1,0,5}
+ {3,NaN,5}                             | {0,3,0}
+ {3,NaN,5}                             | {1,-1,0}
+ {3,NaN,5}                             | {-0.4,-1,-6}
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846}
+ {3,NaN,5}                             | {3,NaN,5}
+ {3,NaN,5}                             | {NaN,NaN,NaN}
+ {3,NaN,5}                             | {0,-1,3}
+ {3,NaN,5}                             | {-1,0,3}
+ {NaN,NaN,NaN}                         | {0,-1,5}
+ {NaN,NaN,NaN}                         | {1,0,5}
+ {NaN,NaN,NaN}                         | {0,3,0}
+ {NaN,NaN,NaN}                         | {1,-1,0}
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846}
+ {NaN,NaN,NaN}                         | {3,NaN,5}
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}
+ {NaN,NaN,NaN}                         | {0,-1,3}
+ {NaN,NaN,NaN}                         | {-1,0,3}
+ {0,-1,3}                              | {1,0,5}
+ {0,-1,3}                              | {1,-1,0}
+ {0,-1,3}                              | {-0.4,-1,-6}
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,3}                              | {3,NaN,5}
+ {0,-1,3}                              | {NaN,NaN,NaN}
+ {0,-1,3}                              | {-1,0,3}
+ {-1,0,3}                              | {0,-1,5}
+ {-1,0,3}                              | {0,3,0}
+ {-1,0,3}                              | {1,-1,0}
+ {-1,0,3}                              | {-0.4,-1,-6}
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846}
+ {-1,0,3}                              | {3,NaN,5}
+ {-1,0,3}                              | {NaN,NaN,NaN}
+ {-1,0,3}                              | {0,-1,3}
+(84 rows)
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LINE_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+      s       |         f1          
+--------------+---------------------
+ {1,0,5}      | (-2,2),(-8,-10)
+ {0,3,0}      | (2,2),(0,0)
+ {0,3,0}      | (-2,2),(-8,-10)
+ {1,-1,0}     | (2,2),(0,0)
+ {1,-1,0}     | (3,3),(1,1)
+ {1,-1,0}     | (-2,2),(-8,-10)
+ {1,-1,0}     | (2.5,3.5),(2.5,2.5)
+ {1,-1,0}     | (3,3),(3,3)
+ {-0.4,-1,-6} | (-2,2),(-8,-10)
+ {0,-1,3}     | (3,3),(1,1)
+ {0,-1,3}     | (2.5,3.5),(2.5,2.5)
+ {0,-1,3}     | (3,3),(3,3)
+ {-1,0,3}     | (3,3),(1,1)
+(13 rows)
+
+-- Intersection point with line
+SELECT l1.s, l2.s, l1.s # l2.s FROM LINE_TBL l1, LINE_TBL l2;
+                   s                   |                   s                   |             ?column?              
+---------------------------------------+---------------------------------------+-----------------------------------
+ {0,-1,5}                              | {0,-1,5}                              | 
+ {0,-1,5}                              | {1,0,5}                               | (-5,5)
+ {0,-1,5}                              | {0,3,0}                               | 
+ {0,-1,5}                              | {1,-1,0}                              | (5,5)
+ {0,-1,5}                              | {-0.4,-1,-6}                          | (-27.5,5)
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846} | (56250,5)
+ {0,-1,5}                              | {3,NaN,5}                             | (NaN,NaN)
+ {0,-1,5}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,-1,5}                              | {0,-1,3}                              | 
+ {0,-1,5}                              | {-1,0,3}                              | (3,5)
+ {1,0,5}                               | {0,-1,5}                              | (-5,5)
+ {1,0,5}                               | {1,0,5}                               | 
+ {1,0,5}                               | {0,3,0}                               | (-5,0)
+ {1,0,5}                               | {1,-1,0}                              | (-5,-5)
+ {1,0,5}                               | {-0.4,-1,-6}                          | (-5,-4)
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846} | (-5,15.3855384615)
+ {1,0,5}                               | {3,NaN,5}                             | (NaN,NaN)
+ {1,0,5}                               | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {1,0,5}                               | {0,-1,3}                              | (-5,3)
+ {1,0,5}                               | {-1,0,3}                              | 
+ {0,3,0}                               | {0,-1,5}                              | 
+ {0,3,0}                               | {1,0,5}                               | (-5,0)
+ {0,3,0}                               | {0,3,0}                               | 
+ {0,3,0}                               | {1,-1,0}                              | (0,0)
+ {0,3,0}                               | {-0.4,-1,-6}                          | (-15,0)
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846} | (83333.3333333,0)
+ {0,3,0}                               | {3,NaN,5}                             | (NaN,NaN)
+ {0,3,0}                               | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,3,0}                               | {0,-1,3}                              | 
+ {0,3,0}                               | {-1,0,3}                              | (3,0)
+ {1,-1,0}                              | {0,-1,5}                              | (5,5)
+ {1,-1,0}                              | {1,0,5}                               | (-5,-5)
+ {1,-1,0}                              | {0,3,0}                               | (0,0)
+ {1,-1,0}                              | {1,-1,0}                              | 
+ {1,-1,0}                              | {-0.4,-1,-6}                          | (-4.28571428571,-4.28571428571)
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846} | (15.3817756722,15.3817756722)
+ {1,-1,0}                              | {3,NaN,5}                             | (NaN,NaN)
+ {1,-1,0}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {1,-1,0}                              | {0,-1,3}                              | (3,3)
+ {1,-1,0}                              | {-1,0,3}                              | (3,3)
+ {-0.4,-1,-6}                          | {0,-1,5}                              | (-27.5,5)
+ {-0.4,-1,-6}                          | {1,0,5}                               | (-5,-4)
+ {-0.4,-1,-6}                          | {0,3,0}                               | (-15,0)
+ {-0.4,-1,-6}                          | {1,-1,0}                              | (-4.28571428571,-4.28571428571)
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}                          | 
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846} | (-53.4862244113,15.3944897645)
+ {-0.4,-1,-6}                          | {3,NaN,5}                             | (NaN,NaN)
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-0.4,-1,-6}                          | {0,-1,3}                              | (-22.5,3)
+ {-0.4,-1,-6}                          | {-1,0,3}                              | (3,-7.2)
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}                              | (56250,5)
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}                               | (-5,15.3855384615)
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}                               | (83333.3333333,-1.7763568394e-15)
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}                              | (15.3817756722,15.3817756722)
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}                          | (-53.4862244113,15.3944897645)
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} | 
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}                             | (NaN,NaN)
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}                              | (67083.3333333,3)
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}                              | (3,15.3840615385)
+ {3,NaN,5}                             | {0,-1,5}                              | (NaN,NaN)
+ {3,NaN,5}                             | {1,0,5}                               | (NaN,NaN)
+ {3,NaN,5}                             | {0,3,0}                               | (NaN,NaN)
+ {3,NaN,5}                             | {1,-1,0}                              | (NaN,NaN)
+ {3,NaN,5}                             | {-0.4,-1,-6}                          | (NaN,NaN)
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ {3,NaN,5}                             | {3,NaN,5}                             | (NaN,NaN)
+ {3,NaN,5}                             | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {3,NaN,5}                             | {0,-1,3}                              | (NaN,NaN)
+ {3,NaN,5}                             | {-1,0,3}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,-1,5}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {1,0,5}                               | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,3,0}                               | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {1,-1,0}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}                          | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {3,NaN,5}                             | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,-1,3}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-1,0,3}                              | (NaN,NaN)
+ {0,-1,3}                              | {0,-1,5}                              | 
+ {0,-1,3}                              | {1,0,5}                               | (-5,3)
+ {0,-1,3}                              | {0,3,0}                               | 
+ {0,-1,3}                              | {1,-1,0}                              | (3,3)
+ {0,-1,3}                              | {-0.4,-1,-6}                          | (-22.5,3)
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846} | (67083.3333333,3)
+ {0,-1,3}                              | {3,NaN,5}                             | (NaN,NaN)
+ {0,-1,3}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,-1,3}                              | {0,-1,3}                              | 
+ {0,-1,3}                              | {-1,0,3}                              | (3,3)
+ {-1,0,3}                              | {0,-1,5}                              | (3,5)
+ {-1,0,3}                              | {1,0,5}                               | 
+ {-1,0,3}                              | {0,3,0}                               | (3,0)
+ {-1,0,3}                              | {1,-1,0}                              | (3,3)
+ {-1,0,3}                              | {-0.4,-1,-6}                          | (3,-7.2)
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846} | (3,15.3840615385)
+ {-1,0,3}                              | {3,NaN,5}                             | (NaN,NaN)
+ {-1,0,3}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-1,0,3}                              | {0,-1,3}                              | (3,3)
+ {-1,0,3}                              | {-1,0,3}                              | 
+(100 rows)
+
+-- Closest point to line segment
+SELECT l.s, l1.s, l.s ## l1.s FROM LINE_TBL l, LSEG_TBL l1;
+                   s                   |               s               |             ?column?              
+---------------------------------------+-------------------------------+-----------------------------------
+ {0,-1,5}                              | [(1,2),(3,4)]                 | (3,4)
+ {0,-1,5}                              | [(0,0),(6,6)]                 | (5,5)
+ {0,-1,5}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,-1,5}                              | [(-1000000,200),(300000,-40)] | (56250,5)
+ {0,-1,5}                              | [(11,22),(33,44)]             | (11,22)
+ {0,-1,5}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {0,-1,5}                              | [(0,-20),(30,-20)]            | 
+ {0,-1,5}                              | [(NaN,1),(NaN,90)]            | 
+ {1,0,5}                               | [(1,2),(3,4)]                 | (1,2)
+ {1,0,5}                               | [(0,0),(6,6)]                 | (0,0)
+ {1,0,5}                               | [(10,-10),(-3,-4)]            | (-3,-4)
+ {1,0,5}                               | [(-1000000,200),(300000,-40)] | (-5,15.3855384615)
+ {1,0,5}                               | [(11,22),(33,44)]             | (11,22)
+ {1,0,5}                               | [(-10,2),(-10,3)]             | 
+ {1,0,5}                               | [(0,-20),(30,-20)]            | (0,-20)
+ {1,0,5}                               | [(NaN,1),(NaN,90)]            | 
+ {0,3,0}                               | [(1,2),(3,4)]                 | (1,2)
+ {0,3,0}                               | [(0,0),(6,6)]                 | (0,0)
+ {0,3,0}                               | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,3,0}                               | [(-1000000,200),(300000,-40)] | (83333.3333333,-1.7763568394e-15)
+ {0,3,0}                               | [(11,22),(33,44)]             | (11,22)
+ {0,3,0}                               | [(-10,2),(-10,3)]             | (-10,2)
+ {0,3,0}                               | [(0,-20),(30,-20)]            | 
+ {0,3,0}                               | [(NaN,1),(NaN,90)]            | 
+ {1,-1,0}                              | [(1,2),(3,4)]                 | 
+ {1,-1,0}                              | [(0,0),(6,6)]                 | 
+ {1,-1,0}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {1,-1,0}                              | [(-1000000,200),(300000,-40)] | (15.3817756722,15.3817756722)
+ {1,-1,0}                              | [(11,22),(33,44)]             | 
+ {1,-1,0}                              | [(-10,2),(-10,3)]             | (-10,2)
+ {1,-1,0}                              | [(0,-20),(30,-20)]            | (0,-20)
+ {1,-1,0}                              | [(NaN,1),(NaN,90)]            | 
+ {-0.4,-1,-6}                          | [(1,2),(3,4)]                 | (1,2)
+ {-0.4,-1,-6}                          | [(0,0),(6,6)]                 | (0,0)
+ {-0.4,-1,-6}                          | [(10,-10),(-3,-4)]            | (10,-10)
+ {-0.4,-1,-6}                          | [(-1000000,200),(300000,-40)] | (-53.4862244113,15.3944897645)
+ {-0.4,-1,-6}                          | [(11,22),(33,44)]             | (11,22)
+ {-0.4,-1,-6}                          | [(-10,2),(-10,3)]             | (-10,2)
+ {-0.4,-1,-6}                          | [(0,-20),(30,-20)]            | (30,-20)
+ {-0.4,-1,-6}                          | [(NaN,1),(NaN,90)]            | 
+ {-0.000184615384615,-1,15.3846153846} | [(1,2),(3,4)]                 | (3,4)
+ {-0.000184615384615,-1,15.3846153846} | [(0,0),(6,6)]                 | (6,6)
+ {-0.000184615384615,-1,15.3846153846} | [(10,-10),(-3,-4)]            | (-3,-4)
+ {-0.000184615384615,-1,15.3846153846} | [(-1000000,200),(300000,-40)] | 
+ {-0.000184615384615,-1,15.3846153846} | [(11,22),(33,44)]             | (11,22)
+ {-0.000184615384615,-1,15.3846153846} | [(-10,2),(-10,3)]             | (-10,3)
+ {-0.000184615384615,-1,15.3846153846} | [(0,-20),(30,-20)]            | (30,-20)
+ {-0.000184615384615,-1,15.3846153846} | [(NaN,1),(NaN,90)]            | 
+ {3,NaN,5}                             | [(1,2),(3,4)]                 | 
+ {3,NaN,5}                             | [(0,0),(6,6)]                 | 
+ {3,NaN,5}                             | [(10,-10),(-3,-4)]            | 
+ {3,NaN,5}                             | [(-1000000,200),(300000,-40)] | 
+ {3,NaN,5}                             | [(11,22),(33,44)]             | 
+ {3,NaN,5}                             | [(-10,2),(-10,3)]             | 
+ {3,NaN,5}                             | [(0,-20),(30,-20)]            | 
+ {3,NaN,5}                             | [(NaN,1),(NaN,90)]            | 
+ {NaN,NaN,NaN}                         | [(1,2),(3,4)]                 | 
+ {NaN,NaN,NaN}                         | [(0,0),(6,6)]                 | 
+ {NaN,NaN,NaN}                         | [(10,-10),(-3,-4)]            | 
+ {NaN,NaN,NaN}                         | [(-1000000,200),(300000,-40)] | 
+ {NaN,NaN,NaN}                         | [(11,22),(33,44)]             | 
+ {NaN,NaN,NaN}                         | [(-10,2),(-10,3)]             | 
+ {NaN,NaN,NaN}                         | [(0,-20),(30,-20)]            | 
+ {NaN,NaN,NaN}                         | [(NaN,1),(NaN,90)]            | 
+ {0,-1,3}                              | [(1,2),(3,4)]                 | (2,3)
+ {0,-1,3}                              | [(0,0),(6,6)]                 | (3,3)
+ {0,-1,3}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,-1,3}                              | [(-1000000,200),(300000,-40)] | (67083.3333333,3)
+ {0,-1,3}                              | [(11,22),(33,44)]             | (11,22)
+ {0,-1,3}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {0,-1,3}                              | [(0,-20),(30,-20)]            | 
+ {0,-1,3}                              | [(NaN,1),(NaN,90)]            | 
+ {-1,0,3}                              | [(1,2),(3,4)]                 | (3,4)
+ {-1,0,3}                              | [(0,0),(6,6)]                 | (3,3)
+ {-1,0,3}                              | [(10,-10),(-3,-4)]            | (3,-6.76923076923)
+ {-1,0,3}                              | [(-1000000,200),(300000,-40)] | (3,15.3840615385)
+ {-1,0,3}                              | [(11,22),(33,44)]             | (11,22)
+ {-1,0,3}                              | [(-10,2),(-10,3)]             | 
+ {-1,0,3}                              | [(0,-20),(30,-20)]            | (3,-20)
+ {-1,0,3}                              | [(NaN,1),(NaN,90)]            | 
+(80 rows)
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LINE_TBL l, BOX_TBL b;
+ERROR:  function "close_lb" not implemented
 --
 -- Line segments
 --
 -- intersection
 SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
    FROM LSEG_TBL l, POINT_TBL p;
 ERROR:  operator does not exist: lseg # point
 LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
                                            ^
 HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (-0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
+-- Length
+SELECT s, @-@ s FROM LSEG_TBL;
+               s               |   ?column?    
+-------------------------------+---------------
+ [(1,2),(3,4)]                 | 2.82842712475
+ [(0,0),(6,6)]                 | 8.48528137424
+ [(10,-10),(-3,-4)]            | 14.3178210633
+ [(-1000000,200),(300000,-40)] | 1300000.02215
+ [(11,22),(33,44)]             | 31.1126983722
+ [(-10,2),(-10,3)]             |             1
+ [(0,-20),(30,-20)]            |            30
+ [(NaN,1),(NaN,90)]            |           NaN
+(8 rows)
+
+-- Vertical
+SELECT s FROM LSEG_TBL WHERE ?| s;
+         s         
+-------------------
+ [(-10,2),(-10,3)]
+(1 row)
+
+-- Horizontal
+SELECT s FROM LSEG_TBL WHERE ?- s;
+         s          
+--------------------
+ [(0,-20),(30,-20)]
+(1 row)
+
+-- Center
+SELECT s, @@ s FROM LSEG_TBL;
+               s               |   ?column?   
+-------------------------------+--------------
+ [(1,2),(3,4)]                 | (2,3)
+ [(0,0),(6,6)]                 | (3,3)
+ [(10,-10),(-3,-4)]            | (3.5,-7)
+ [(-1000000,200),(300000,-40)] | (-350000,80)
+ [(11,22),(33,44)]             | (22,33)
+ [(-10,2),(-10,3)]             | (-10,2.5)
+ [(0,-20),(30,-20)]            | (15,-20)
+ [(NaN,1),(NaN,90)]            | (NaN,45.5)
+(8 rows)
+
+-- To point
+SELECT s, s::point FROM LSEG_TBL;
+               s               |      s       
+-------------------------------+--------------
+ [(1,2),(3,4)]                 | (2,3)
+ [(0,0),(6,6)]                 | (3,3)
+ [(10,-10),(-3,-4)]            | (3.5,-7)
+ [(-1000000,200),(300000,-40)] | (-350000,80)
+ [(11,22),(33,44)]             | (22,33)
+ [(-10,2),(-10,3)]             | (-10,2.5)
+ [(0,-20),(30,-20)]            | (15,-20)
+ [(NaN,1),(NaN,90)]            | (NaN,45.5)
+(8 rows)
+
+-- Has points less than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s < l2.s;
+         s          |               s               
+--------------------+-------------------------------
+ [(1,2),(3,4)]      | [(0,0),(6,6)]
+ [(1,2),(3,4)]      | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]      | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]      | [(11,22),(33,44)]
+ [(1,2),(3,4)]      | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]      | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]      | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]      | [(11,22),(33,44)]
+ [(0,0),(6,6)]      | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)] | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)] | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]  | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]  | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]  | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]  | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]  | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]  | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]  | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)] | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)] | [(11,22),(33,44)]
+(21 rows)
+
+-- Has points less than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s <= l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(28 rows)
+
+-- Has points equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s = l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]
+(8 rows)
+
+-- Has points greater than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s >= l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(28 rows)
+
+-- Has points greater than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s > l2.s;
+               s               |         s          
+-------------------------------+--------------------
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+(21 rows)
+
+-- Has points not equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s != l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)]
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]
+(56 rows)
+
+-- Parallel with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?|| l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(13 rows)
+
+-- Perpendicular with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?-| l2.s;
+         s          |         s          
+--------------------+--------------------
+ [(-10,2),(-10,3)]  | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)] | [(-10,2),(-10,3)]
+(2 rows)
+
+-- Distance to line
+SELECT l.s, l1.s, l.s <-> l1.s FROM LSEG_TBL l, LINE_TBL l1;
+               s               |                   s                   |    ?column?    
+-------------------------------+---------------------------------------+----------------
+ [(1,2),(3,4)]                 | {0,-1,5}                              |              1
+ [(0,0),(6,6)]                 | {0,-1,5}                              |              0
+ [(10,-10),(-3,-4)]            | {0,-1,5}                              |              9
+ [(-1000000,200),(300000,-40)] | {0,-1,5}                              |              0
+ [(11,22),(33,44)]             | {0,-1,5}                              |             17
+ [(-10,2),(-10,3)]             | {0,-1,5}                              |              2
+ [(0,-20),(30,-20)]            | {0,-1,5}                              |             25
+ [(NaN,1),(NaN,90)]            | {0,-1,5}                              |            NaN
+ [(1,2),(3,4)]                 | {1,0,5}                               |              6
+ [(0,0),(6,6)]                 | {1,0,5}                               |              5
+ [(10,-10),(-3,-4)]            | {1,0,5}                               |              2
+ [(-1000000,200),(300000,-40)] | {1,0,5}                               |              0
+ [(11,22),(33,44)]             | {1,0,5}                               |             16
+ [(-10,2),(-10,3)]             | {1,0,5}                               |              5
+ [(0,-20),(30,-20)]            | {1,0,5}                               |              5
+ [(NaN,1),(NaN,90)]            | {1,0,5}                               |            NaN
+ [(1,2),(3,4)]                 | {0,3,0}                               |              2
+ [(0,0),(6,6)]                 | {0,3,0}                               |              0
+ [(10,-10),(-3,-4)]            | {0,3,0}                               |              4
+ [(-1000000,200),(300000,-40)] | {0,3,0}                               |              0
+ [(11,22),(33,44)]             | {0,3,0}                               |             22
+ [(-10,2),(-10,3)]             | {0,3,0}                               |              2
+ [(0,-20),(30,-20)]            | {0,3,0}                               |             20
+ [(NaN,1),(NaN,90)]            | {0,3,0}                               |            NaN
+ [(1,2),(3,4)]                 | {1,-1,0}                              | 0.707106781187
+ [(0,0),(6,6)]                 | {1,-1,0}                              |              0
+ [(10,-10),(-3,-4)]            | {1,-1,0}                              | 0.707106781187
+ [(-1000000,200),(300000,-40)] | {1,-1,0}                              |              0
+ [(11,22),(33,44)]             | {1,-1,0}                              |  7.77817459305
+ [(-10,2),(-10,3)]             | {1,-1,0}                              |  8.48528137424
+ [(0,-20),(30,-20)]            | {1,-1,0}                              |  14.1421356237
+ [(NaN,1),(NaN,90)]            | {1,-1,0}                              |            NaN
+ [(1,2),(3,4)]                 | {-0.4,-1,-6}                          |  7.79920420344
+ [(0,0),(6,6)]                 | {-0.4,-1,-6}                          |  5.57086014531
+ [(10,-10),(-3,-4)]            | {-0.4,-1,-6}                          |              0
+ [(-1000000,200),(300000,-40)] | {-0.4,-1,-6}                          |              0
+ [(11,22),(33,44)]             | {-0.4,-1,-6}                          |  30.0826447847
+ [(-10,2),(-10,3)]             | {-0.4,-1,-6}                          |  3.71390676354
+ [(0,-20),(30,-20)]            | {-0.4,-1,-6}                          |  1.85695338177
+ [(NaN,1),(NaN,90)]            | {-0.4,-1,-6}                          |            NaN
+ [(1,2),(3,4)]                 | {-0.000184615384615,-1,15.3846153846} |  11.3840613445
+ [(0,0),(6,6)]                 | {-0.000184615384615,-1,15.3846153846} |   9.3835075324
+ [(10,-10),(-3,-4)]            | {-0.000184615384615,-1,15.3846153846} |  19.3851689004
+ [(-1000000,200),(300000,-40)] | {-0.000184615384615,-1,15.3846153846} |              0
+ [(11,22),(33,44)]             | {-0.000184615384615,-1,15.3846153846} |  6.61741527185
+ [(-10,2),(-10,3)]             | {-0.000184615384615,-1,15.3846153846} |  12.3864613274
+ [(0,-20),(30,-20)]            | {-0.000184615384615,-1,15.3846153846} |  35.3790763202
+ [(NaN,1),(NaN,90)]            | {-0.000184615384615,-1,15.3846153846} |            NaN
+ [(1,2),(3,4)]                 | {3,NaN,5}                             |            NaN
+ [(0,0),(6,6)]                 | {3,NaN,5}                             |            NaN
+ [(10,-10),(-3,-4)]            | {3,NaN,5}                             |            NaN
+ [(-1000000,200),(300000,-40)] | {3,NaN,5}                             |            NaN
+ [(11,22),(33,44)]             | {3,NaN,5}                             |            NaN
+ [(-10,2),(-10,3)]             | {3,NaN,5}                             |            NaN
+ [(0,-20),(30,-20)]            | {3,NaN,5}                             |            NaN
+ [(NaN,1),(NaN,90)]            | {3,NaN,5}                             |            NaN
+ [(1,2),(3,4)]                 | {NaN,NaN,NaN}                         |            NaN
+ [(0,0),(6,6)]                 | {NaN,NaN,NaN}                         |            NaN
+ [(10,-10),(-3,-4)]            | {NaN,NaN,NaN}                         |            NaN
+ [(-1000000,200),(300000,-40)] | {NaN,NaN,NaN}                         |            NaN
+ [(11,22),(33,44)]             | {NaN,NaN,NaN}                         |            NaN
+ [(-10,2),(-10,3)]             | {NaN,NaN,NaN}                         |            NaN
+ [(0,-20),(30,-20)]            | {NaN,NaN,NaN}                         |            NaN
+ [(NaN,1),(NaN,90)]            | {NaN,NaN,NaN}                         |            NaN
+ [(1,2),(3,4)]                 | {0,-1,3}                              |              0
+ [(0,0),(6,6)]                 | {0,-1,3}                              |              0
+ [(10,-10),(-3,-4)]            | {0,-1,3}                              |              7
+ [(-1000000,200),(300000,-40)] | {0,-1,3}                              |              0
+ [(11,22),(33,44)]             | {0,-1,3}                              |             19
+ [(-10,2),(-10,3)]             | {0,-1,3}                              |              0
+ [(0,-20),(30,-20)]            | {0,-1,3}                              |             23
+ [(NaN,1),(NaN,90)]            | {0,-1,3}                              |            NaN
+ [(1,2),(3,4)]                 | {-1,0,3}                              |              0
+ [(0,0),(6,6)]                 | {-1,0,3}                              |              0
+ [(10,-10),(-3,-4)]            | {-1,0,3}                              |              0
+ [(-1000000,200),(300000,-40)] | {-1,0,3}                              |              0
+ [(11,22),(33,44)]             | {-1,0,3}                              |              8
+ [(-10,2),(-10,3)]             | {-1,0,3}                              |             13
+ [(0,-20),(30,-20)]            | {-1,0,3}                              |              0
+ [(NaN,1),(NaN,90)]            | {-1,0,3}                              |            NaN
+(80 rows)
+
+-- Distance to line segment
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               |    ?column?    
+-------------------------------+-------------------------------+----------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 |              0
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 0.707106781187
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            |  7.12398901685
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] |  11.3840613445
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             |  19.6977156036
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             |             11
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            |             22
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            |            NaN
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 0.707106781187
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 |              0
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            |  4.88901207039
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] |   9.3835075324
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             |  16.7630546142
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             |  10.1980390272
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            |             20
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            |            NaN
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 |  7.12398901685
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 |  4.88901207039
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            |              0
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] |  19.3851689004
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             |  29.4737584815
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             |  9.21954445729
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            |             10
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            |            NaN
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 |  11.3840613445
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 |   9.3835075324
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            |  19.3851689004
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] |              0
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             |  6.61741527185
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             |  12.3864613274
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            |  35.3790763202
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            |            NaN
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 |  19.6977156036
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 |  16.7630546142
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            |  29.4737584815
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] |  6.61741527185
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             |              0
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             |   28.319604517
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            |             42
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            |            NaN
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 |             11
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 |  10.1980390272
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            |  9.21954445729
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] |  12.3864613274
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             |   28.319604517
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             |              0
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            |  24.1660919472
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            |            NaN
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 |             22
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 |             20
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            |             10
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] |  35.3790763202
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             |             42
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             |  24.1660919472
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            |              0
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 |            NaN
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 |            NaN
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] |            NaN
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             |            NaN
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             |            NaN
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            |            NaN
+(64 rows)
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LSEG_TBL l, BOX_TBL b;
+               s               |         f1          |    ?column?    
+-------------------------------+---------------------+----------------
+ [(1,2),(3,4)]                 | (2,2),(0,0)         |              0
+ [(1,2),(3,4)]                 | (3,3),(1,1)         |              0
+ [(1,2),(3,4)]                 | (-2,2),(-8,-10)     |              3
+ [(1,2),(3,4)]                 | (2.5,3.5),(2.5,2.5) |              0
+ [(1,2),(3,4)]                 | (3,3),(3,3)         | 0.707106781187
+ [(0,0),(6,6)]                 | (2,2),(0,0)         |              0
+ [(0,0),(6,6)]                 | (3,3),(1,1)         |              0
+ [(0,0),(6,6)]                 | (-2,2),(-8,-10)     |              2
+ [(0,0),(6,6)]                 | (2.5,3.5),(2.5,2.5) |              0
+ [(0,0),(6,6)]                 | (3,3),(3,3)         |              0
+ [(10,-10),(-3,-4)]            | (2,2),(0,0)         |  4.88901207039
+ [(10,-10),(-3,-4)]            | (3,3),(1,1)         |  6.21602963235
+ [(10,-10),(-3,-4)]            | (-2,2),(-8,-10)     |              0
+ [(10,-10),(-3,-4)]            | (2.5,3.5),(2.5,2.5) |  8.20655597529
+ [(10,-10),(-3,-4)]            | (3,3),(3,3)         |  8.87006475627
+ [(-1000000,200),(300000,-40)] | (2,2),(0,0)         |  13.3842459258
+ [(-1000000,200),(300000,-40)] | (3,3),(1,1)         |  12.3840613274
+ [(-1000000,200),(300000,-40)] | (-2,2),(-8,-10)     |  13.3849843873
+ [(-1000000,200),(300000,-40)] | (2.5,3.5),(2.5,2.5) |  11.8841536436
+ [(-1000000,200),(300000,-40)] | (3,3),(3,3)         |  12.3840613274
+ [(11,22),(33,44)]             | (2,2),(0,0)         |  21.9317121995
+ [(11,22),(33,44)]             | (3,3),(1,1)         |  20.6155281281
+ [(11,22),(33,44)]             | (-2,2),(-8,-10)     |  23.8537208838
+ [(11,22),(33,44)]             | (2.5,3.5),(2.5,2.5) |  20.3592730715
+ [(11,22),(33,44)]             | (3,3),(3,3)         |  20.6155281281
+ [(-10,2),(-10,3)]             | (2,2),(0,0)         |             10
+ [(-10,2),(-10,3)]             | (3,3),(1,1)         |             11
+ [(-10,2),(-10,3)]             | (-2,2),(-8,-10)     |              2
+ [(-10,2),(-10,3)]             | (2.5,3.5),(2.5,2.5) |           12.5
+ [(-10,2),(-10,3)]             | (3,3),(3,3)         |             13
+ [(0,-20),(30,-20)]            | (2,2),(0,0)         |             20
+ [(0,-20),(30,-20)]            | (3,3),(1,1)         |             21
+ [(0,-20),(30,-20)]            | (-2,2),(-8,-10)     |  10.1980390272
+ [(0,-20),(30,-20)]            | (2.5,3.5),(2.5,2.5) |           22.5
+ [(0,-20),(30,-20)]            | (3,3),(3,3)         |             23
+ [(NaN,1),(NaN,90)]            | (2,2),(0,0)         |            NaN
+ [(NaN,1),(NaN,90)]            | (3,3),(1,1)         |            NaN
+ [(NaN,1),(NaN,90)]            | (-2,2),(-8,-10)     |            NaN
+ [(NaN,1),(NaN,90)]            | (2.5,3.5),(2.5,2.5) |            NaN
+ [(NaN,1),(NaN,90)]            | (3,3),(3,3)         |            NaN
+(40 rows)
+
+-- Intersect with line segment
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s ?# l1.s;
+               s               |      s       
+-------------------------------+--------------
+ [(0,0),(6,6)]                 | {0,-1,5}
+ [(-1000000,200),(300000,-40)] | {0,-1,5}
+ [(-1000000,200),(300000,-40)] | {1,0,5}
+ [(0,0),(6,6)]                 | {0,3,0}
+ [(-1000000,200),(300000,-40)] | {0,3,0}
+ [(-1000000,200),(300000,-40)] | {1,-1,0}
+ [(10,-10),(-3,-4)]            | {-0.4,-1,-6}
+ [(-1000000,200),(300000,-40)] | {-0.4,-1,-6}
+ [(1,2),(3,4)]                 | {0,-1,3}
+ [(0,0),(6,6)]                 | {0,-1,3}
+ [(-1000000,200),(300000,-40)] | {0,-1,3}
+ [(-10,2),(-10,3)]             | {0,-1,3}
+ [(1,2),(3,4)]                 | {-1,0,3}
+ [(0,0),(6,6)]                 | {-1,0,3}
+ [(10,-10),(-3,-4)]            | {-1,0,3}
+ [(-1000000,200),(300000,-40)] | {-1,0,3}
+ [(0,-20),(30,-20)]            | {-1,0,3}
+(17 rows)
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+         s          |         f1          
+--------------------+---------------------
+ [(1,2),(3,4)]      | (2,2),(0,0)
+ [(1,2),(3,4)]      | (3,3),(1,1)
+ [(1,2),(3,4)]      | (2.5,3.5),(2.5,2.5)
+ [(0,0),(6,6)]      | (2,2),(0,0)
+ [(0,0),(6,6)]      | (3,3),(1,1)
+ [(0,0),(6,6)]      | (2.5,3.5),(2.5,2.5)
+ [(0,0),(6,6)]      | (3,3),(3,3)
+ [(10,-10),(-3,-4)] | (-2,2),(-8,-10)
+(8 rows)
+
+-- Intersection point with line segment
+SELECT l1.s, l2.s, l1.s # l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               | ?column? 
+-------------------------------+-------------------------------+----------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 | 
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            | 
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] | 
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             | 
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             | 
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            | 
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            | 
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 | 
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            | 
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] | 
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             | 
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             | 
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            | 
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            | 
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 | 
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 | 
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            | 
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] | 
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             | 
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             | 
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            | 
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            | 
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 | 
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 | 
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            | 
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] | 
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             | 
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             | 
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            | 
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            | 
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 | 
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 | 
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            | 
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] | 
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             | 
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             | 
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            | 
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            | 
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 | 
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 | 
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            | 
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] | 
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             | 
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             | 
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            | 
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            | 
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 | 
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 | 
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            | 
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] | 
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             | 
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             | 
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            | 
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            | 
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 | 
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 | 
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            | 
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] | 
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             | 
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             | 
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            | 
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            | 
+(64 rows)
+
+-- Closest point to line
+SELECT l.s, l1.s, l.s ## l1.s FROM LSEG_TBL l, LINE_TBL l1;
+ERROR:  function "close_sl" not implemented
+-- Closest point to line segment
+SELECT l1.s, l2.s, l1.s ## l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               |            ?column?             
+-------------------------------+-------------------------------+---------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 | 
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            | (-1.98536585366,-4.46829268293)
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] | (3.00210167283,15.3840611505)
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             | 
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             | (-10,2)
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            | (1,-20)
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            | 
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 | 
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] | (6.00173233982,15.3835073725)
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             | 
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             | (-10,2)
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            | (0,-20)
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            | 
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 | (1,2)
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 | (0,0)
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            | 
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] | (-2.99642119965,15.3851685701)
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             | (11,22)
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             | (-10,2)
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            | (10,-20)
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            | 
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 | (3,4)
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 | (6,6)
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            | (-3,-4)
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] | 
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             | (11,22)
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             | (-10,3)
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            | (30,-20)
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            | 
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 | 
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 | 
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            | (-1.3512195122,-4.76097560976)
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] | (10.9987783234,15.3825848409)
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             | 
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             | (-10,3)
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            | (11,-20)
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            | 
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 | (1,2)
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 | (0,0)
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            | (-3,-4)
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] | (-9.99771326872,15.3864611163)
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             | (11,22)
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             | 
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            | (0,-20)
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            | 
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 | (1,2)
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 | (0,0)
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            | (10,-10)
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] | (30.0065315217,15.3790757173)
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             | (11,22)
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             | (-10,2)
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            | 
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            | 
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 | 
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 | 
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            | 
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] | 
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             | 
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             | 
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            | 
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            | 
+(64 rows)
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LSEG_TBL l, BOX_TBL b;
+               s               |         f1          |  ?column?   
+-------------------------------+---------------------+-------------
+ [(1,2),(3,4)]                 | (2,2),(0,0)         | (1,2)
+ [(1,2),(3,4)]                 | (3,3),(1,1)         | (1.5,2.5)
+ [(1,2),(3,4)]                 | (-2,2),(-8,-10)     | (-2,2)
+ [(1,2),(3,4)]                 | (2.5,3.5),(2.5,2.5) | (2.25,3.25)
+ [(1,2),(3,4)]                 | (3,3),(3,3)         | (3,3)
+ [(0,0),(6,6)]                 | (2,2),(0,0)         | (1,1)
+ [(0,0),(6,6)]                 | (3,3),(1,1)         | (2,2)
+ [(0,0),(6,6)]                 | (-2,2),(-8,-10)     | (-2,0)
+ [(0,0),(6,6)]                 | (2.5,3.5),(2.5,2.5) | (2.75,2.75)
+ [(0,0),(6,6)]                 | (3,3),(3,3)         | (3,3)
+ [(10,-10),(-3,-4)]            | (2,2),(0,0)         | (0,0)
+ [(10,-10),(-3,-4)]            | (3,3),(1,1)         | (1,1)
+ [(10,-10),(-3,-4)]            | (-2,2),(-8,-10)     | (-3,-4)
+ [(10,-10),(-3,-4)]            | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ [(10,-10),(-3,-4)]            | (3,3),(3,3)         | (3,3)
+ [(-1000000,200),(300000,-40)] | (2,2),(0,0)         | (2,2)
+ [(-1000000,200),(300000,-40)] | (3,3),(1,1)         | (3,3)
+ [(-1000000,200),(300000,-40)] | (-2,2),(-8,-10)     | (-2,2)
+ [(-1000000,200),(300000,-40)] | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ [(-1000000,200),(300000,-40)] | (3,3),(3,3)         | (3,3)
+ [(11,22),(33,44)]             | (2,2),(0,0)         | (2,2)
+ [(11,22),(33,44)]             | (3,3),(1,1)         | (3,3)
+ [(11,22),(33,44)]             | (-2,2),(-8,-10)     | (-2,2)
+ [(11,22),(33,44)]             | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ [(11,22),(33,44)]             | (3,3),(3,3)         | (3,3)
+ [(-10,2),(-10,3)]             | (2,2),(0,0)         | (0,2)
+ [(-10,2),(-10,3)]             | (3,3),(1,1)         | (1,2)
+ [(-10,2),(-10,3)]             | (-2,2),(-8,-10)     | (-8,2)
+ [(-10,2),(-10,3)]             | (2.5,3.5),(2.5,2.5) | (2.5,3)
+ [(-10,2),(-10,3)]             | (3,3),(3,3)         | (3,3)
+ [(0,-20),(30,-20)]            | (2,2),(0,0)         | (0,0)
+ [(0,-20),(30,-20)]            | (3,3),(1,1)         | (1,1)
+ [(0,-20),(30,-20)]            | (-2,2),(-8,-10)     | (-2,-10)
+ [(0,-20),(30,-20)]            | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ [(0,-20),(30,-20)]            | (3,3),(3,3)         | (3,3)
+ [(NaN,1),(NaN,90)]            | (2,2),(0,0)         | 
+ [(NaN,1),(NaN,90)]            | (3,3),(1,1)         | 
+ [(NaN,1),(NaN,90)]            | (-2,2),(-8,-10)     | 
+ [(NaN,1),(NaN,90)]            | (2.5,3.5),(2.5,2.5) | 
+ [(NaN,1),(NaN,90)]            | (3,3),(3,3)         | 
+(40 rows)
+
+-- On line
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s <@ l1.s;
+               s               |                   s                   
+-------------------------------+---------------------------------------
+ [(0,0),(6,6)]                 | {1,-1,0}
+ [(-1000000,200),(300000,-40)] | {-0.000184615384615,-1,15.3846153846}
+(2 rows)
+
+-- On box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s <@ b.f1;
+ s | f1 
+---+----
+(0 rows)
 
 --
 -- Boxes
 --
 SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
  six |                              box                               
 -----+----------------------------------------------------------------
      | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
      | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
      | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
      | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
      | (107.071067812,207.071067812),(92.9289321881,192.928932188)
      | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
+     | (3,5),(3,5)
+     | (NaN,NaN),(NaN,NaN)
+(8 rows)
 
 -- translation
 SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
+ twentyfour |             translation             
+------------+-------------------------------------
             | (2,2),(0,0)
             | (3,3),(1,1)
+            | (-2,2),(-8,-10)
             | (2.5,3.5),(2.5,2.5)
             | (3,3),(3,3)
             | (-8,2),(-10,0)
             | (-7,3),(-9,1)
+            | (-12,2),(-18,-10)
             | (-7.5,3.5),(-7.5,2.5)
             | (-7,3),(-7,3)
             | (-1,6),(-3,4)
             | (0,7),(-2,5)
+            | (-5,6),(-11,-6)
             | (-0.5,7.5),(-0.5,6.5)
             | (0,7),(0,7)
             | (7.1,36.5),(5.1,34.5)
             | (8.1,37.5),(6.1,35.5)
+            | (3.1,36.5),(-2.9,24.5)
             | (7.6,38),(7.6,37)
             | (8.1,37.5),(8.1,37.5)
             | (-3,-10),(-5,-12)
             | (-2,-9),(-4,-11)
+            | (-7,-10),(-13,-22)
             | (-2.5,-8.5),(-2.5,-9.5)
             | (-2,-9),(-2,-9)
+            | (2,2),(1e-300,-1e-300)
+            | (3,3),(1,1)
+            | (-2,2),(-8,-10)
+            | (2.5,3.5),(2.5,2.5)
+            | (3,3),(3,3)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
             | (12,12),(10,10)
             | (13,13),(11,11)
+            | (8,12),(2,0)
             | (12.5,13.5),(12.5,12.5)
             | (13,13),(13,13)
-(24 rows)
+(45 rows)
 
 SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
+ twentyfour |               translation               
+------------+-----------------------------------------
             | (2,2),(0,0)
             | (3,3),(1,1)
+            | (-2,2),(-8,-10)
             | (2.5,3.5),(2.5,2.5)
             | (3,3),(3,3)
             | (12,2),(10,0)
             | (13,3),(11,1)
+            | (8,2),(2,-10)
             | (12.5,3.5),(12.5,2.5)
             | (13,3),(13,3)
             | (5,-2),(3,-4)
             | (6,-1),(4,-3)
+            | (1,-2),(-5,-14)
             | (5.5,-0.5),(5.5,-1.5)
             | (6,-1),(6,-1)
             | (-3.1,-32.5),(-5.1,-34.5)
             | (-2.1,-31.5),(-4.1,-33.5)
+            | (-7.1,-32.5),(-13.1,-44.5)
             | (-2.6,-31),(-2.6,-32)
             | (-2.1,-31.5),(-2.1,-31.5)
             | (7,14),(5,12)
             | (8,15),(6,13)
+            | (3,14),(-3,2)
             | (7.5,15.5),(7.5,14.5)
             | (8,15),(8,15)
+            | (2,2),(-1e-300,1e-300)
+            | (3,3),(1,1)
+            | (-2,2),(-8,-10)
+            | (2.5,3.5),(2.5,2.5)
+            | (3,3),(3,3)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
             | (-8,-8),(-10,-10)
             | (-7,-7),(-9,-9)
+            | (-12,-8),(-18,-20)
             | (-7.5,-6.5),(-7.5,-7.5)
             | (-7,-7),(-7,-7)
-(24 rows)
+(45 rows)
 
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (-0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (-0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,-0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
+-- Multiply with point
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+         f1          |     f1     |          ?column?           
+---------------------+------------+-----------------------------
+ (2,2),(0,0)         | (5.1,34.5) | (0,79.2),(-58.8,0)
+ (2,2),(0,0)         | (10,10)    | (0,40),(0,0)
+ (3,3),(1,1)         | (5.1,34.5) | (-29.4,118.8),(-88.2,39.6)
+ (3,3),(1,1)         | (10,10)    | (0,60),(0,20)
+ (-2,2),(-8,-10)     | (5.1,34.5) | (304.2,-58.8),(-79.2,-327)
+ (-2,2),(-8,-10)     | (10,10)    | (20,0),(-40,-180)
+ (2.5,3.5),(2.5,2.5) | (5.1,34.5) | (-73.5,104.1),(-108,99)
+ (2.5,3.5),(2.5,2.5) | (10,10)    | (0,60),(-10,50)
+ (3,3),(3,3)         | (5.1,34.5) | (-88.2,118.8),(-88.2,118.8)
+ (3,3),(3,3)         | (10,10)    | (0,60),(0,60)
+(10 rows)
 
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,-0),(-0.2,-0.2)
-        | (0.08,-0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (-0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
+-- Overflow error
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] > 1000;
+         f1          |        f1         |                  ?column?                  
+---------------------+-------------------+--------------------------------------------
+ (2,2),(0,0)         | (1e+300,Infinity) | (NaN,NaN),(-Infinity,Infinity)
+ (2,2),(0,0)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (3,3),(1,1)         | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (3,3),(1,1)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (-2,2),(-8,-10)     | (1e+300,Infinity) | (Infinity,-Infinity),(-Infinity,-Infinity)
+ (-2,2),(-8,-10)     | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (2.5,3.5),(2.5,2.5) | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (2.5,3.5),(2.5,2.5) | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (3,3),(3,3)         | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (3,3),(3,3)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+(10 rows)
 
+-- Divide by point
+SELECT b.f1, p.f1, b.f1 / p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+         f1          |     f1     |                               ?column?                               
+---------------------+------------+----------------------------------------------------------------------
+ (2,2),(0,0)         | (5.1,34.5) | (0.0651176557644,0),(0,-0.0483449262493)
+ (2,2),(0,0)         | (10,10)    | (0.2,0),(0,0)
+ (3,3),(1,1)         | (5.1,34.5) | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
+ (3,3),(1,1)         | (10,10)    | (0.3,0),(0.1,0)
+ (-2,2),(-8,-10)     | (5.1,34.5) | (0.0483449262493,0.18499334024),(-0.317201914064,0.0651176557644)
+ (-2,2),(-8,-10)     | (10,10)    | (0,0.2),(-0.9,-0.1)
+ (2.5,3.5),(2.5,2.5) | (5.1,34.5) | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
+ (2.5,3.5),(2.5,2.5) | (10,10)    | (0.3,0.05),(0.25,0)
+ (3,3),(3,3)         | (5.1,34.5) | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
+ (3,3),(3,3)         | (10,10)    | (0.3,0),(0.3,0)
+(10 rows)
+
+-- To box
 SELECT f1::box
 	FROM POINT_TBL;
-          f1           
------------------------
+                 f1                  
+-------------------------------------
  (0,0),(0,0)
  (-10,0),(-10,0)
  (-3,4),(-3,4)
  (5.1,34.5),(5.1,34.5)
  (-5,-12),(-5,-12)
+ (1e-300,-1e-300),(1e-300,-1e-300)
+ (1e+300,Infinity),(1e+300,Infinity)
+ (NaN,NaN),(NaN,NaN)
  (10,10),(10,10)
-(6 rows)
+(9 rows)
 
 SELECT bound_box(a.f1, b.f1)
 	FROM BOX_TBL a, BOX_TBL b;
       bound_box      
 ---------------------
  (2,2),(0,0)
  (3,3),(0,0)
+ (2,2),(-8,-10)
  (2.5,3.5),(0,0)
  (3,3),(0,0)
  (3,3),(0,0)
  (3,3),(1,1)
+ (3,3),(-8,-10)
  (3,3.5),(1,1)
  (3,3),(1,1)
+ (2,2),(-8,-10)
+ (3,3),(-8,-10)
+ (-2,2),(-8,-10)
+ (2.5,3.5),(-8,-10)
+ (3,3),(-8,-10)
  (2.5,3.5),(0,0)
  (3,3.5),(1,1)
+ (2.5,3.5),(-8,-10)
  (2.5,3.5),(2.5,2.5)
  (3,3.5),(2.5,2.5)
  (3,3),(0,0)
  (3,3),(1,1)
+ (3,3),(-8,-10)
  (3,3.5),(2.5,2.5)
  (3,3),(3,3)
-(16 rows)
+(25 rows)
+
+-- Below box
+SELECT b1.f1, b2.f1, b1.f1 <^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          | ?column? 
+---------------------+---------------------+----------
+ (2,2),(0,0)         | (2,2),(0,0)         | f
+ (2,2),(0,0)         | (3,3),(1,1)         | f
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | f
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | t
+ (2,2),(0,0)         | (3,3),(3,3)         | t
+ (3,3),(1,1)         | (2,2),(0,0)         | f
+ (3,3),(1,1)         | (3,3),(1,1)         | f
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | f
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(1,1)         | (3,3),(3,3)         | t
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | f
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | f
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | f
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | t
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | t
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | f
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | f
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | f
+ (3,3),(3,3)         | (2,2),(0,0)         | f
+ (3,3),(3,3)         | (3,3),(1,1)         | f
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | f
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(3,3)         | (3,3),(3,3)         | t
+(25 rows)
+
+-- Above box
+SELECT b1.f1, b2.f1, b1.f1 >^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          | ?column? 
+---------------------+---------------------+----------
+ (2,2),(0,0)         | (2,2),(0,0)         | f
+ (2,2),(0,0)         | (3,3),(1,1)         | f
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | f
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | f
+ (2,2),(0,0)         | (3,3),(3,3)         | f
+ (3,3),(1,1)         | (2,2),(0,0)         | f
+ (3,3),(1,1)         | (3,3),(1,1)         | f
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | f
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(1,1)         | (3,3),(3,3)         | f
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | f
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | f
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | f
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | f
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | f
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | t
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | f
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | t
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | f
+ (3,3),(3,3)         | (2,2),(0,0)         | t
+ (3,3),(3,3)         | (3,3),(1,1)         | t
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | t
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(3,3)         | (3,3),(3,3)         | t
+(25 rows)
+
+-- Intersection point with box
+SELECT b1.f1, b2.f1, b1.f1 # b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          |      ?column?       
+---------------------+---------------------+---------------------
+ (2,2),(0,0)         | (2,2),(0,0)         | (2,2),(0,0)
+ (2,2),(0,0)         | (3,3),(1,1)         | (2,2),(1,1)
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | 
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | 
+ (2,2),(0,0)         | (3,3),(3,3)         | 
+ (3,3),(1,1)         | (2,2),(0,0)         | (2,2),(1,1)
+ (3,3),(1,1)         | (3,3),(1,1)         | (3,3),(1,1)
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | 
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | (2.5,3),(2.5,2.5)
+ (3,3),(1,1)         | (3,3),(3,3)         | (3,3),(3,3)
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | 
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | 
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | (-2,2),(-8,-10)
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | 
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | 
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | 
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | (2.5,3),(2.5,2.5)
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | 
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5)
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | 
+ (3,3),(3,3)         | (2,2),(0,0)         | 
+ (3,3),(3,3)         | (3,3),(1,1)         | (3,3),(3,3)
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | 
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | 
+ (3,3),(3,3)         | (3,3),(3,3)         | (3,3),(3,3)
+(25 rows)
+
+-- Diagonal
+SELECT f1, diagonal(f1) FROM BOX_TBL;
+         f1          |       diagonal        
+---------------------+-----------------------
+ (2,2),(0,0)         | [(2,2),(0,0)]
+ (3,3),(1,1)         | [(3,3),(1,1)]
+ (-2,2),(-8,-10)     | [(-2,2),(-8,-10)]
+ (2.5,3.5),(2.5,2.5) | [(2.5,3.5),(2.5,2.5)]
+ (3,3),(3,3)         | [(3,3),(3,3)]
+(5 rows)
+
+-- Distance to box
+SELECT b1.f1, b2.f1, b1.f1 <-> b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          |   ?column?    
+---------------------+---------------------+---------------
+ (2,2),(0,0)         | (2,2),(0,0)         |             0
+ (2,2),(0,0)         | (3,3),(1,1)         | 1.41421356237
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | 7.81024967591
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) |           2.5
+ (2,2),(0,0)         | (3,3),(3,3)         | 2.82842712475
+ (3,3),(1,1)         | (2,2),(0,0)         | 1.41421356237
+ (3,3),(1,1)         | (3,3),(1,1)         |             0
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | 9.21954445729
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | 1.11803398875
+ (3,3),(1,1)         | (3,3),(3,3)         | 1.41421356237
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | 7.81024967591
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | 9.21954445729
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     |             0
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | 10.2591422643
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | 10.6301458127
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         |           2.5
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | 1.11803398875
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | 10.2591422643
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) |             0
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         |           0.5
+ (3,3),(3,3)         | (2,2),(0,0)         | 2.82842712475
+ (3,3),(3,3)         | (3,3),(1,1)         | 1.41421356237
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | 10.6301458127
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) |           0.5
+ (3,3),(3,3)         | (3,3),(3,3)         |             0
+(25 rows)
 
 --
 -- Paths
 --
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
+-- Points
+SELECT f1, npoints(f1) FROM PATH_TBL;
+            f1             | npoints 
+---------------------------+---------
+ [(1,2),(3,4)]             |       2
+ ((1,2),(3,4))             |       2
+ [(0,0),(3,0),(4,5),(1,6)] |       4
+ ((1,2),(3,4))             |       2
+ ((1,2),(3,4))             |       2
+ [(1,2),(3,4)]             |       2
+ ((10,20))                 |       1
+ [(11,12),(13,14)]         |       2
+ ((11,12),(13,14))         |       2
+(9 rows)
 
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
+-- Area
+SELECT f1, area(f1) FROM PATH_TBL;
+            f1             | area 
+---------------------------+------
+ [(1,2),(3,4)]             |     
+ ((1,2),(3,4))             |    0
+ [(0,0),(3,0),(4,5),(1,6)] |     
+ ((1,2),(3,4))             |    0
+ ((1,2),(3,4))             |    0
+ [(1,2),(3,4)]             |     
+ ((10,20))                 |    0
+ [(11,12),(13,14)]         |     
+ ((11,12),(13,14))         |    0
+(9 rows)
 
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
+-- Length
+SELECT f1, @-@ f1 FROM PATH_TBL;
+            f1             |   ?column?    
+---------------------------+---------------
+ [(1,2),(3,4)]             | 2.82842712475
+ ((1,2),(3,4))             | 5.65685424949
+ [(0,0),(3,0),(4,5),(1,6)] | 11.2612971738
+ ((1,2),(3,4))             | 5.65685424949
+ ((1,2),(3,4))             | 5.65685424949
+ [(1,2),(3,4)]             | 2.82842712475
+ ((10,20))                 |             0
+ [(11,12),(13,14)]         | 2.82842712475
+ ((11,12),(13,14))         | 5.65685424949
+(9 rows)
 
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
+-- Center
+SELECT f1, @@ f1 FROM PATH_TBL;
+ERROR:  function "path_center" not implemented
+-- To polygon
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isclosed(f1);
+        f1         |        f1         
+-------------------+-------------------
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((10,20))         | ((10,20))
+ ((11,12),(13,14)) | ((11,12),(13,14))
+(5 rows)
+
+-- Open path cannot be converted to polygon error
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isopen(f1);
+ERROR:  open path cannot be converted to polygon
+-- Has points less than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 < p2.f1;
+        f1         |            f1             
+-------------------+---------------------------
+ [(1,2),(3,4)]     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]     | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))         | [(1,2),(3,4)]
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | [(1,2),(3,4)]
+ ((10,20))         | [(11,12),(13,14)]
+ ((10,20))         | ((11,12),(13,14))
+ [(11,12),(13,14)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((11,12),(13,14)) | [(0,0),(3,0),(4,5),(1,6)]
+(15 rows)
+
+-- Has points less than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 <= p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | [(1,2),(3,4)]
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | [(1,2),(3,4)]
+ ((10,20))                 | ((10,20))
+ ((10,20))                 | [(11,12),(13,14)]
+ ((10,20))                 | ((11,12),(13,14))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(66 rows)
+
+-- Has points equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 = p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | ((10,20))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(51 rows)
+
+-- Has points greater than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 >= p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | ((10,20))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((10,20))
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((10,20))
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(66 rows)
+
+-- Has points greater than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 > p2.f1;
+            f1             |        f1         
+---------------------------+-------------------
+ [(1,2),(3,4)]             | ((10,20))
+ ((1,2),(3,4))             | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | ((10,20))
+ [(1,2),(3,4)]             | ((10,20))
+ [(11,12),(13,14)]         | ((10,20))
+ ((11,12),(13,14))         | ((10,20))
+(15 rows)
+
+-- Add path
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+            f1             |            f1             |                     ?column?                      
+---------------------------+---------------------------+---------------------------------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4),(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))                 | 
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         | [(1,2),(3,4),(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6),(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6),(0,0),(3,0),(4,5),(1,6)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6),(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))                 | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6),(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4),(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))                 | 
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         | [(1,2),(3,4),(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))         | 
+ ((10,20))                 | [(1,2),(3,4)]             | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | [(1,2),(3,4)]             | 
+ ((10,20))                 | ((10,20))                 | 
+ ((10,20))                 | [(11,12),(13,14)]         | 
+ ((10,20))                 | ((11,12),(13,14))         | 
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             | [(11,12),(13,14),(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14),(0,0),(3,0),(4,5),(1,6)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             | [(11,12),(13,14),(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((10,20))                 | 
+ [(11,12),(13,14)]         | [(11,12),(13,14)]         | [(11,12),(13,14),(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))         | 
+ ((11,12),(13,14))         | [(1,2),(3,4)]             | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | [(1,2),(3,4)]             | 
+ ((11,12),(13,14))         | ((10,20))                 | 
+ ((11,12),(13,14))         | [(11,12),(13,14)]         | 
+ ((11,12),(13,14))         | ((11,12),(13,14))         | 
+(81 rows)
+
+-- Add point
+SELECT p.f1, p1.f1, p.f1 + p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                                 ?column?                                  
+---------------------------+-------------------+---------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((10,20))                 | (0,0)             | ((10,20))
+ [(11,12),(13,14)]         | (0,0)             | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (0,0)             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (-10,0)           | [(-9,2),(-7,4)]
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(-10,0),(-7,0),(-6,5),(-9,6)]
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ [(1,2),(3,4)]             | (-10,0)           | [(-9,2),(-7,4)]
+ ((10,20))                 | (-10,0)           | ((0,20))
+ [(11,12),(13,14)]         | (-10,0)           | [(1,12),(3,14)]
+ ((11,12),(13,14))         | (-10,0)           | ((1,12),(3,14))
+ [(1,2),(3,4)]             | (-3,4)            | [(-2,6),(0,8)]
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(-3,4),(0,4),(1,9),(-2,10)]
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ [(1,2),(3,4)]             | (-3,4)            | [(-2,6),(0,8)]
+ ((10,20))                 | (-3,4)            | ((7,24))
+ [(11,12),(13,14)]         | (-3,4)            | [(8,16),(10,18)]
+ ((11,12),(13,14))         | (-3,4)            | ((8,16),(10,18))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(6.1,36.5),(8.1,38.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(5.1,34.5),(8.1,34.5),(9.1,39.5),(6.1,40.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(6.1,36.5),(8.1,38.5)]
+ ((10,20))                 | (5.1,34.5)        | ((15.1,54.5))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(16.1,46.5),(18.1,48.5)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((16.1,46.5),(18.1,48.5))
+ [(1,2),(3,4)]             | (-5,-12)          | [(-4,-10),(-2,-8)]
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(-5,-12),(-2,-12),(-1,-7),(-4,-6)]
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ [(1,2),(3,4)]             | (-5,-12)          | [(-4,-10),(-2,-8)]
+ ((10,20))                 | (-5,-12)          | ((5,8))
+ [(11,12),(13,14)]         | (-5,-12)          | [(6,0),(8,2)]
+ ((11,12),(13,14))         | (-5,-12)          | ((6,0),(8,2))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(1e-300,-1e-300),(3,-1e-300),(4,5),(1,6)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((10,20))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity),(1e+300,Infinity),(1e+300,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((1e+300,Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(11,12),(13,14)]
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(10,10),(13,10),(14,15),(11,16)]
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (10,10)           | [(11,12),(13,14)]
+ ((10,20))                 | (10,10)           | ((20,30))
+ [(11,12),(13,14)]         | (10,10)           | [(21,22),(23,24)]
+ ((11,12),(13,14))         | (10,10)           | ((21,22),(23,24))
+(81 rows)
+
+-- Subtract point
+SELECT p.f1, p1.f1, p.f1 - p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                                     ?column?                                      
+---------------------------+-------------------+-----------------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((10,20))                 | (0,0)             | ((10,20))
+ [(11,12),(13,14)]         | (0,0)             | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (0,0)             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (-10,0)           | [(11,2),(13,4)]
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(10,0),(13,0),(14,5),(11,6)]
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ [(1,2),(3,4)]             | (-10,0)           | [(11,2),(13,4)]
+ ((10,20))                 | (-10,0)           | ((20,20))
+ [(11,12),(13,14)]         | (-10,0)           | [(21,12),(23,14)]
+ ((11,12),(13,14))         | (-10,0)           | ((21,12),(23,14))
+ [(1,2),(3,4)]             | (-3,4)            | [(4,-2),(6,0)]
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(3,-4),(6,-4),(7,1),(4,2)]
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ [(1,2),(3,4)]             | (-3,4)            | [(4,-2),(6,0)]
+ ((10,20))                 | (-3,4)            | ((13,16))
+ [(11,12),(13,14)]         | (-3,4)            | [(14,8),(16,10)]
+ ((11,12),(13,14))         | (-3,4)            | ((14,8),(16,10))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-4.1,-32.5),(-2.1,-30.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(-5.1,-34.5),(-2.1,-34.5),(-1.1,-29.5),(-4.1,-28.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-4.1,-32.5),(-2.1,-30.5)]
+ ((10,20))                 | (5.1,34.5)        | ((4.9,-14.5))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(5.9,-22.5),(7.9,-20.5)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((5.9,-22.5),(7.9,-20.5))
+ [(1,2),(3,4)]             | (-5,-12)          | [(6,14),(8,16)]
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(5,12),(8,12),(9,17),(6,18)]
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ [(1,2),(3,4)]             | (-5,-12)          | [(6,14),(8,16)]
+ ((10,20))                 | (-5,-12)          | ((15,32))
+ [(11,12),(13,14)]         | (-5,-12)          | [(16,24),(18,26)]
+ ((11,12),(13,14))         | (-5,-12)          | ((16,24),(18,26))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(-1e-300,1e-300),(3,1e-300),(4,5),(1,6)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((10,20))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity),(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((-1e+300,-Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(-9,-8),(-7,-6)]
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(-10,-10),(-7,-10),(-6,-5),(-9,-4)]
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ [(1,2),(3,4)]             | (10,10)           | [(-9,-8),(-7,-6)]
+ ((10,20))                 | (10,10)           | ((0,10))
+ [(11,12),(13,14)]         | (10,10)           | [(1,2),(3,4)]
+ ((11,12),(13,14))         | (10,10)           | ((1,2),(3,4))
+(81 rows)
+
+-- Multiply with point
+SELECT p.f1, p1.f1, p.f1 * p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                               ?column?                               
+---------------------------+-------------------+----------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(0,0),(0,0)]
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(0,0),(0,0),(0,0)]
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ [(1,2),(3,4)]             | (0,0)             | [(0,0),(0,0)]
+ ((10,20))                 | (0,0)             | ((0,0))
+ [(11,12),(13,14)]         | (0,0)             | [(0,0),(0,0)]
+ ((11,12),(13,14))         | (0,0)             | ((0,0),(0,0))
+ [(1,2),(3,4)]             | (-10,0)           | [(-10,-20),(-30,-40)]
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(0,0),(-30,0),(-40,-50),(-10,-60)]
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ [(1,2),(3,4)]             | (-10,0)           | [(-10,-20),(-30,-40)]
+ ((10,20))                 | (-10,0)           | ((-100,-200))
+ [(11,12),(13,14)]         | (-10,0)           | [(-110,-120),(-130,-140)]
+ ((11,12),(13,14))         | (-10,0)           | ((-110,-120),(-130,-140))
+ [(1,2),(3,4)]             | (-3,4)            | [(-11,-2),(-25,0)]
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(0,0),(-9,12),(-32,1),(-27,-14)]
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ [(1,2),(3,4)]             | (-3,4)            | [(-11,-2),(-25,0)]
+ ((10,20))                 | (-3,4)            | ((-110,-20))
+ [(11,12),(13,14)]         | (-3,4)            | [(-81,8),(-95,10)]
+ ((11,12),(13,14))         | (-3,4)            | ((-81,8),(-95,10))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-63.9,44.7),(-122.7,123.9)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(0,0),(15.3,103.5),(-152.1,163.5),(-201.9,65.1)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-63.9,44.7),(-122.7,123.9)]
+ ((10,20))                 | (5.1,34.5)        | ((-639,447))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(-357.9,440.7),(-416.7,519.9)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((-357.9,440.7),(-416.7,519.9))
+ [(1,2),(3,4)]             | (-5,-12)          | [(19,-22),(33,-56)]
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(0,0),(-15,-36),(40,-73),(67,-42)]
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ [(1,2),(3,4)]             | (-5,-12)          | [(19,-22),(33,-56)]
+ ((10,20))                 | (-5,-12)          | ((190,-220))
+ [(11,12),(13,14)]         | (-5,-12)          | [(89,-192),(103,-226)]
+ ((11,12),(13,14))         | (-5,-12)          | ((89,-192),(103,-226))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(3e-300,1e-300),(7e-300,1e-300)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(0,0),(3e-300,-3e-300),(9e-300,1e-300),(7e-300,5e-300)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(3e-300,1e-300),(7e-300,1e-300)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((3e-299,1e-299))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(2.3e-299,1e-300),(2.7e-299,1e-300)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((2.3e-299,1e-300),(2.7e-299,1e-300))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(NaN,NaN),(NaN,Infinity),(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((-Infinity,Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(-10,30),(-10,70)]
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(0,0),(30,30),(-10,90),(-50,70)]
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ [(1,2),(3,4)]             | (10,10)           | [(-10,30),(-10,70)]
+ ((10,20))                 | (10,10)           | ((-100,300))
+ [(11,12),(13,14)]         | (10,10)           | [(-10,230),(-10,270)]
+ ((11,12),(13,14))         | (10,10)           | ((-10,230),(-10,270))
+(81 rows)
+
+-- Divide by point
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+            f1             |     f1     |                                                    ?column?                                                     
+---------------------------+------------+-----------------------------------------------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (5.1,34.5) | [(0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952)]
+ [(1,2),(3,4)]             | (10,10)    | [(0.15,0.05),(0.35,0.05)]
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5) | [(0,0),(0.0125795471363,-0.0850969365103),(0.158600957032,-0.0924966701199),(0.174387055399,-0.00320655123082)]
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)    | [(0,0),(0.15,-0.15),(0.45,0.05),(0.35,0.25)]
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ [(1,2),(3,4)]             | (5.1,34.5) | [(0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952)]
+ [(1,2),(3,4)]             | (10,10)    | [(0.15,0.05),(0.35,0.05)]
+ ((10,20))                 | (5.1,34.5) | ((0.609244733856,-0.199792807459))
+ ((10,20))                 | (10,10)    | ((1.5,0.5))
+ [(11,12),(13,14)]         | (5.1,34.5) | [(0.386512752208,-0.261703911993),(0.451630407972,-0.310048838242)]
+ [(11,12),(13,14)]         | (10,10)    | [(1.15,0.05),(1.35,0.05)]
+ ((11,12),(13,14))         | (5.1,34.5) | ((0.386512752208,-0.261703911993),(0.451630407972,-0.310048838242))
+ ((11,12),(13,14))         | (10,10)    | ((1.15,0.05),(1.35,0.05))
+(18 rows)
+
+-- Division by 0 error
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to path
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+            f1             |            f1             |    ?column?    
+---------------------------+---------------------------+----------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((10,20))                 |  17.4642491966
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         |   11.313708499
+ [(1,2),(3,4)]             | ((11,12),(13,14))         |   11.313708499
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)] |              0
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))                 |  16.1554944214
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]         |  9.89949493661
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))         |  9.89949493661
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((10,20))                 |  17.4642491966
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         |   11.313708499
+ [(1,2),(3,4)]             | ((11,12),(13,14))         |   11.313708499
+ ((10,20))                 | [(1,2),(3,4)]             |  17.4642491966
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)] |  16.1554944214
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | [(1,2),(3,4)]             |  17.4642491966
+ ((10,20))                 | ((10,20))                 |              0
+ ((10,20))                 | [(11,12),(13,14)]         |   6.7082039325
+ ((10,20))                 | ((11,12),(13,14))         |   6.7082039325
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             |   11.313708499
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)] |  9.89949493661
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             |   11.313708499
+ [(11,12),(13,14)]         | ((10,20))                 |   6.7082039325
+ [(11,12),(13,14)]         | [(11,12),(13,14)]         |              0
+ [(11,12),(13,14)]         | ((11,12),(13,14))         |              0
+ ((11,12),(13,14))         | [(1,2),(3,4)]             |   11.313708499
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)] |  9.89949493661
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | [(1,2),(3,4)]             |   11.313708499
+ ((11,12),(13,14))         | ((10,20))                 |   6.7082039325
+ ((11,12),(13,14))         | [(11,12),(13,14)]         |              0
+ ((11,12),(13,14))         | ((11,12),(13,14))         |              0
+(81 rows)
 
 --
 -- Polygons
 --
 -- containment
 SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
    FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
+ twentyfour |        f1         |             f1             | contains 
+------------+-------------------+----------------------------+----------
+            | (0,0)             | ((2,0),(2,4),(0,0))        | t
+            | (0,0)             | ((3,1),(3,3),(1,0))        | f
+            | (0,0)             | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (0,0)             | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (0,0)             | ((0,0))                    | t
+            | (0,0)             | ((0,1),(0,1))              | f
+            | (-10,0)           | ((2,0),(2,4),(0,0))        | f
+            | (-10,0)           | ((3,1),(3,3),(1,0))        | f
+            | (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-10,0)           | ((0,0))                    | f
+            | (-10,0)           | ((0,1),(0,1))              | f
+            | (-3,4)            | ((2,0),(2,4),(0,0))        | f
+            | (-3,4)            | ((3,1),(3,3),(1,0))        | f
+            | (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-3,4)            | ((0,0))                    | f
+            | (-3,4)            | ((0,1),(0,1))              | f
+            | (5.1,34.5)        | ((2,0),(2,4),(0,0))        | f
+            | (5.1,34.5)        | ((3,1),(3,3),(1,0))        | f
+            | (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (5.1,34.5)        | ((0,0))                    | f
+            | (5.1,34.5)        | ((0,1),(0,1))              | f
+            | (-5,-12)          | ((2,0),(2,4),(0,0))        | f
+            | (-5,-12)          | ((3,1),(3,3),(1,0))        | f
+            | (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-5,-12)          | ((0,0))                    | f
+            | (-5,-12)          | ((0,1),(0,1))              | f
+            | (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        | t
+            | (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        | f
+            | (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e-300,-1e-300)  | ((0,0))                    | t
+            | (1e-300,-1e-300)  | ((0,1),(0,1))              | f
+            | (1e+300,Infinity) | ((2,0),(2,4),(0,0))        | f
+            | (1e+300,Infinity) | ((3,1),(3,3),(1,0))        | f
+            | (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e+300,Infinity) | ((0,0))                    | f
+            | (1e+300,Infinity) | ((0,1),(0,1))              | f
+            | (NaN,NaN)         | ((2,0),(2,4),(0,0))        | t
+            | (NaN,NaN)         | ((3,1),(3,3),(1,0))        | t
+            | (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  | t
+            | (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  | t
+            | (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) | t
+            | (NaN,NaN)         | ((0,0))                    | t
+            | (NaN,NaN)         | ((0,1),(0,1))              | t
+            | (10,10)           | ((2,0),(2,4),(0,0))        | f
+            | (10,10)           | ((3,1),(3,3),(1,0))        | f
+            | (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (10,10)           | ((0,0))                    | f
+            | (10,10)           | ((0,1),(0,1))              | f
+(63 rows)
 
 SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
    FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
+ twentyfour |        f1         |             f1             | contained 
+------------+-------------------+----------------------------+-----------
+            | (0,0)             | ((2,0),(2,4),(0,0))        | t
+            | (0,0)             | ((3,1),(3,3),(1,0))        | f
+            | (0,0)             | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (0,0)             | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (0,0)             | ((0,0))                    | t
+            | (0,0)             | ((0,1),(0,1))              | f
+            | (-10,0)           | ((2,0),(2,4),(0,0))        | f
+            | (-10,0)           | ((3,1),(3,3),(1,0))        | f
+            | (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-10,0)           | ((0,0))                    | f
+            | (-10,0)           | ((0,1),(0,1))              | f
+            | (-3,4)            | ((2,0),(2,4),(0,0))        | f
+            | (-3,4)            | ((3,1),(3,3),(1,0))        | f
+            | (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-3,4)            | ((0,0))                    | f
+            | (-3,4)            | ((0,1),(0,1))              | f
+            | (5.1,34.5)        | ((2,0),(2,4),(0,0))        | f
+            | (5.1,34.5)        | ((3,1),(3,3),(1,0))        | f
+            | (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (5.1,34.5)        | ((0,0))                    | f
+            | (5.1,34.5)        | ((0,1),(0,1))              | f
+            | (-5,-12)          | ((2,0),(2,4),(0,0))        | f
+            | (-5,-12)          | ((3,1),(3,3),(1,0))        | f
+            | (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-5,-12)          | ((0,0))                    | f
+            | (-5,-12)          | ((0,1),(0,1))              | f
+            | (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        | t
+            | (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        | f
+            | (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e-300,-1e-300)  | ((0,0))                    | t
+            | (1e-300,-1e-300)  | ((0,1),(0,1))              | f
+            | (1e+300,Infinity) | ((2,0),(2,4),(0,0))        | f
+            | (1e+300,Infinity) | ((3,1),(3,3),(1,0))        | f
+            | (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e+300,Infinity) | ((0,0))                    | f
+            | (1e+300,Infinity) | ((0,1),(0,1))              | f
+            | (NaN,NaN)         | ((2,0),(2,4),(0,0))        | t
+            | (NaN,NaN)         | ((3,1),(3,3),(1,0))        | t
+            | (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  | t
+            | (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  | t
+            | (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) | t
+            | (NaN,NaN)         | ((0,0))                    | t
+            | (NaN,NaN)         | ((0,1),(0,1))              | t
+            | (10,10)           | ((2,0),(2,4),(0,0))        | f
+            | (10,10)           | ((3,1),(3,3),(1,0))        | f
+            | (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (10,10)           | ((0,0))                    | f
+            | (10,10)           | ((0,1),(0,1))              | f
+(63 rows)
 
 SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
    FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
+ four | npoints |          polygon           
+------+---------+----------------------------
       |       3 | ((2,0),(2,4),(0,0))
       |       3 | ((3,1),(3,3),(1,0))
+      |       4 | ((1,2),(3,4),(5,6),(7,8))
+      |       4 | ((7,8),(5,6),(3,4),(1,2))
+      |       4 | ((1,2),(7,8),(5,6),(3,-4))
       |       1 | ((0,0))
       |       2 | ((0,1),(0,1))
-(4 rows)
+(7 rows)
 
 SELECT '' AS four, polygon(f1)
    FROM BOX_TBL;
  four |                  polygon                  
 ------+-------------------------------------------
       | ((0,0),(0,2),(2,2),(2,0))
       | ((1,1),(1,3),(3,3),(3,1))
+      | ((-8,-10),(-8,2),(-2,2),(-2,-10))
       | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
       | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, polygon(f1)
    FROM PATH_TBL WHERE isclosed(f1);
  four |      polygon      
 ------+-------------------
       | ((1,2),(3,4))
       | ((1,2),(3,4))
       | ((1,2),(3,4))
+      | ((10,20))
       | ((11,12),(13,14))
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
    FROM PATH_TBL
    WHERE isopen(f1);
  four |         open_path         |          polygon          
 ------+---------------------------+---------------------------
       | [(1,2),(3,4)]             | ((1,2),(3,4))
       | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
       | [(1,2),(3,4)]             | ((1,2),(3,4))
       | [(11,12),(13,14)]         | ((11,12),(13,14))
 (4 rows)
 
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
+-- To box
+SELECT f1, f1::box FROM POLYGON_TBL;
+             f1             |      f1      
+----------------------------+--------------
+ ((2,0),(2,4),(0,0))        | (2,4),(0,0)
+ ((3,1),(3,3),(1,0))        | (3,3),(1,0)
+ ((1,2),(3,4),(5,6),(7,8))  | (7,8),(1,2)
+ ((7,8),(5,6),(3,4),(1,2))  | (7,8),(1,2)
+ ((1,2),(7,8),(5,6),(3,-4)) | (7,8),(1,-4)
+ ((0,0))                    | (0,0),(0,0)
+ ((0,1),(0,1))              | (0,1),(0,1)
+(7 rows)
 
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
+-- To path
+SELECT f1, f1::path FROM POLYGON_TBL;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(7 rows)
 
+-- Same as polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 ~= p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(9 rows)
+
+-- Contained by polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <@ p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(12 rows)
+
+-- Contains polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 @> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(12 rows)
+
+-- Overlap with polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 && p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(25 rows)
+
+-- Left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 << p2.f1;
+      f1       |             f1             
+---------------+----------------------------
+ ((0,0))       | ((3,1),(3,3),(1,0))
+ ((0,0))       | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))       | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))       | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1)) | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1)) | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1)) | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1)) | ((1,2),(7,8),(5,6),(3,-4))
+(8 rows)
+
+-- Overlap of left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &< p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))                    | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1))              | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(32 rows)
+
+-- Right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 >> p2.f1;
+             f1             |      f1       
+----------------------------+---------------
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((0,1),(0,1))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1))
+(8 rows)
+
+-- Overlap of right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((2,0),(2,4),(0,0))        | ((0,1),(0,1))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((0,1),(0,1))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((3,1),(3,3),(1,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(37 rows)
+
+-- Below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <<| p2.f1;
+      f1       |            f1             
+---------------+---------------------------
+ ((0,0))       | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))       | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))       | ((0,1),(0,1))
+ ((0,1),(0,1)) | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1)) | ((7,8),(5,6),(3,4),(1,2))
+(5 rows)
+
+-- Overlap or below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &<| p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))                    | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1))              | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(31 rows)
+
+-- Above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |>> p2.f1;
+            f1             |      f1       
+---------------------------+---------------
+ ((1,2),(3,4),(5,6),(7,8)) | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8)) | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2)) | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2)) | ((0,1),(0,1))
+ ((0,1),(0,1))             | ((0,0))
+(5 rows)
+
+-- Overlap or above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |&> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((3,1),(3,3),(1,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(32 rows)
+
+-- Distance to polygon
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2;
+ERROR:  function "poly_distance" not implemented
 --
 -- Circles
 --
 SELECT '' AS six, circle(f1, 50.0)
    FROM POINT_TBL;
- six |     circle      
------+-----------------
+ six |         circle         
+-----+------------------------
      | <(0,0),50>
      | <(-10,0),50>
      | <(-3,4),50>
      | <(5.1,34.5),50>
      | <(-5,-12),50>
+     | <(1e-300,-1e-300),50>
+     | <(1e+300,Infinity),50>
+     | <(NaN,NaN),50>
      | <(10,10),50>
-(6 rows)
+(9 rows)
 
 SELECT '' AS four, circle(f1)
    FROM BOX_TBL;
- four |        circle         
-------+-----------------------
+ four |         circle         
+------+------------------------
       | <(1,1),1.41421356237>
       | <(2,2),1.41421356237>
+      | <(-5,-4),6.7082039325>
       | <(2.5,3),0.5>
       | <(3,3),0>
-(4 rows)
+(5 rows)
 
 SELECT '' AS two, circle(f1)
    FROM POLYGON_TBL
    WHERE (# f1) >= 3;
  two |                    circle                     
 -----+-----------------------------------------------
      | <(1.33333333333,1.33333333333),2.04168905064>
      | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
+     | <(4,5),2.82842712475>
+     | <(4,5),2.82842712475>
+     | <(4,3),4.80664375676>
+(5 rows)
 
 SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
    FROM CIRCLE_TBL c1, POINT_TBL p1
    WHERE (p1.f1 <-> c1.f1) > 0
    ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
+ twentyfour |     circle     |       point       |   distance    
+------------+----------------+-------------------+---------------
+            | <(1,2),3>      | (-3,4)            |   1.472135955
+            | <(5,1),3>      | (0,0)             | 2.09901951359
+            | <(5,1),3>      | (1e-300,-1e-300)  | 2.09901951359
+            | <(5,1),3>      | (-3,4)            | 5.54400374532
+            | <(3,5),0>      | (0,0)             | 5.83095189485
+            | <(3,5),0>      | (1e-300,-1e-300)  | 5.83095189485
+            | <(3,5),0>      | (-3,4)            |  6.0827625303
+            | <(1,3),5>      | (-10,0)           | 6.40175425099
+            | <(1,3),5>      | (10,10)           | 6.40175425099
+            | <(5,1),3>      | (10,10)           | 7.29563014099
+            | <(1,2),3>      | (-10,0)           |  8.1803398875
+            | <(3,5),0>      | (10,10)           | 8.60232526704
+            | <(1,2),3>      | (10,10)           | 9.04159457879
+            | <(1,3),5>      | (-5,-12)          | 11.1554944214
+            | <(5,1),3>      | (-10,0)           | 12.0332963784
+            | <(1,2),3>      | (-5,-12)          | 12.2315462117
+            | <(5,1),3>      | (-5,-12)          | 13.4012194669
+            | <(3,5),0>      | (-10,0)           | 13.9283882772
+            | <(3,5),0>      | (-5,-12)          | 18.7882942281
+            | <(1,3),5>      | (5.1,34.5)        | 26.7657047773
+            | <(3,5),0>      | (5.1,34.5)        | 29.5746513082
+            | <(1,2),3>      | (5.1,34.5)        | 29.7575945393
+            | <(5,1),3>      | (5.1,34.5)        | 30.5001492534
+            | <(100,200),10> | (5.1,34.5)        | 180.778038568
+            | <(100,200),10> | (10,10)           | 200.237960416
+            | <(100,200),10> | (-3,4)            | 211.415898255
+            | <(100,200),10> | (0,0)             |  213.60679775
+            | <(100,200),10> | (1e-300,-1e-300)  |  213.60679775
+            | <(100,200),10> | (-10,0)           |  218.25424421
+            | <(100,200),10> | (-5,-12)          | 226.577682802
+            | <(3,5),0>      | (1e+300,Infinity) |      Infinity
+            | <(1,2),3>      | (1e+300,Infinity) |      Infinity
+            | <(5,1),3>      | (1e+300,Infinity) |      Infinity
+            | <(1,3),5>      | (1e+300,Infinity) |      Infinity
+            | <(100,200),10> | (1e+300,Infinity) |      Infinity
+            | <(1,2),100>    | (1e+300,Infinity) |      Infinity
+            | <(100,1),115>  | (1e+300,Infinity) |      Infinity
+            | <(3,5),0>      | (NaN,NaN)         |           NaN
+            | <(1,2),3>      | (NaN,NaN)         |           NaN
+            | <(5,1),3>      | (NaN,NaN)         |           NaN
+            | <(1,3),5>      | (NaN,NaN)         |           NaN
+            | <(100,200),10> | (NaN,NaN)         |           NaN
+            | <(1,2),100>    | (NaN,NaN)         |           NaN
+            | <(100,1),115>  | (NaN,NaN)         |           NaN
+            | <(3,5),NaN>    | (-10,0)           |           NaN
+            | <(3,5),NaN>    | (-5,-12)          |           NaN
+            | <(3,5),NaN>    | (-3,4)            |           NaN
+            | <(3,5),NaN>    | (0,0)             |           NaN
+            | <(3,5),NaN>    | (1e-300,-1e-300)  |           NaN
+            | <(3,5),NaN>    | (5.1,34.5)        |           NaN
+            | <(3,5),NaN>    | (10,10)           |           NaN
+            | <(3,5),NaN>    | (1e+300,Infinity) |           NaN
+            | <(3,5),NaN>    | (NaN,NaN)         |           NaN
+(53 rows)
+
+-- To polygon
+SELECT f1, f1::polygon FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+       f1       |                                                                                                          f1                                                                                                          
+----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ <(5,1),3>      | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
+ <(1,2),100>    | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
+ <(1,3),5>      | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
+ <(1,2),3>      | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
+ <(100,200),10> | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
+ <(100,1),115>  | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
+(6 rows)
+
+-- To polygon with less points
+SELECT f1, polygon(8, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+       f1       |                                                                             polygon                                                                              
+----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ <(5,1),3>      | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
+ <(1,2),100>    | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
+ <(1,3),5>      | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
+ <(1,2),3>      | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
+ <(100,200),10> | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
+ <(100,1),115>  | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
+(6 rows)
+
+-- Too less points error
+SELECT f1, polygon(1, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+ERROR:  must request at least 2 points
+-- Zero radius error
+SELECT f1, polygon(10, f1) FROM CIRCLE_TBL WHERE f1 < '<(0,0),1>';
+ERROR:  cannot convert circle with radius zero to polygon
+-- Same as circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 ~= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+ <(3,5),NaN>    | <(3,5),0>
+ <(3,5),NaN>    | <(3,5),NaN>
+(9 rows)
+
+-- Overlap with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 && c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,1),115>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(100,1),115>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(33 rows)
+
+-- Overlap or left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &< c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(28 rows)
+
+-- Left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 << c2.f1;
+    f1     |       f1       
+-----------+----------------
+ <(5,1),3> | <(100,200),10>
+ <(1,3),5> | <(100,200),10>
+ <(1,2),3> | <(100,200),10>
+ <(3,5),0> | <(100,200),10>
+(4 rows)
+
+-- Right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >> c2.f1;
+       f1       |    f1     
+----------------+-----------
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(3,5),0>
+(4 rows)
+
+-- Overlap or right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(28 rows)
+
+-- Contained by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <@ c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(17 rows)
+
+-- Contain by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 @> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(3,5),0>
+(17 rows)
+
+-- Below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <<| c2.f1;
+      f1       |       f1       
+---------------+----------------
+ <(5,1),3>     | <(100,200),10>
+ <(5,1),3>     | <(3,5),0>
+ <(1,2),100>   | <(100,200),10>
+ <(1,3),5>     | <(100,200),10>
+ <(1,2),3>     | <(100,200),10>
+ <(100,1),115> | <(100,200),10>
+ <(3,5),0>     | <(100,200),10>
+(7 rows)
+
+-- Above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |>> c2.f1;
+       f1       |      f1       
+----------------+---------------
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(3,5),0>      | <(5,1),3>
+(7 rows)
+
+-- Overlap or below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &<| c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Overlap or above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |&> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 = c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(9 rows)
+
+-- Area not equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 != c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(40 rows)
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 > c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(3,5),0>
+(20 rows)
+
+-- Area less than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area greater than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Add point
+SELECT c.f1, p.f1, c.f1 + p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |        ?column?         
+----------------+-------------------+-------------------------
+ <(5,1),3>      | (0,0)             | <(5,1),3>
+ <(1,2),100>    | (0,0)             | <(1,2),100>
+ <(1,3),5>      | (0,0)             | <(1,3),5>
+ <(1,2),3>      | (0,0)             | <(1,2),3>
+ <(100,200),10> | (0,0)             | <(100,200),10>
+ <(100,1),115>  | (0,0)             | <(100,1),115>
+ <(3,5),0>      | (0,0)             | <(3,5),0>
+ <(3,5),NaN>    | (0,0)             | <(3,5),NaN>
+ <(5,1),3>      | (-10,0)           | <(-5,1),3>
+ <(1,2),100>    | (-10,0)           | <(-9,2),100>
+ <(1,3),5>      | (-10,0)           | <(-9,3),5>
+ <(1,2),3>      | (-10,0)           | <(-9,2),3>
+ <(100,200),10> | (-10,0)           | <(90,200),10>
+ <(100,1),115>  | (-10,0)           | <(90,1),115>
+ <(3,5),0>      | (-10,0)           | <(-7,5),0>
+ <(3,5),NaN>    | (-10,0)           | <(-7,5),NaN>
+ <(5,1),3>      | (-3,4)            | <(2,5),3>
+ <(1,2),100>    | (-3,4)            | <(-2,6),100>
+ <(1,3),5>      | (-3,4)            | <(-2,7),5>
+ <(1,2),3>      | (-3,4)            | <(-2,6),3>
+ <(100,200),10> | (-3,4)            | <(97,204),10>
+ <(100,1),115>  | (-3,4)            | <(97,5),115>
+ <(3,5),0>      | (-3,4)            | <(0,9),0>
+ <(3,5),NaN>    | (-3,4)            | <(0,9),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(10.1,35.5),3>
+ <(1,2),100>    | (5.1,34.5)        | <(6.1,36.5),100>
+ <(1,3),5>      | (5.1,34.5)        | <(6.1,37.5),5>
+ <(1,2),3>      | (5.1,34.5)        | <(6.1,36.5),3>
+ <(100,200),10> | (5.1,34.5)        | <(105.1,234.5),10>
+ <(100,1),115>  | (5.1,34.5)        | <(105.1,35.5),115>
+ <(3,5),0>      | (5.1,34.5)        | <(8.1,39.5),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(8.1,39.5),NaN>
+ <(5,1),3>      | (-5,-12)          | <(0,-11),3>
+ <(1,2),100>    | (-5,-12)          | <(-4,-10),100>
+ <(1,3),5>      | (-5,-12)          | <(-4,-9),5>
+ <(1,2),3>      | (-5,-12)          | <(-4,-10),3>
+ <(100,200),10> | (-5,-12)          | <(95,188),10>
+ <(100,1),115>  | (-5,-12)          | <(95,-11),115>
+ <(3,5),0>      | (-5,-12)          | <(-2,-7),0>
+ <(3,5),NaN>    | (-5,-12)          | <(-2,-7),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(5,1),3>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(1,2),100>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(1,3),5>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(1,2),3>
+ <(100,200),10> | (1e-300,-1e-300)  | <(100,200),10>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(100,1),115>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(3,5),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(3,5),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(1e+300,Infinity),3>
+ <(1,2),100>    | (1e+300,Infinity) | <(1e+300,Infinity),100>
+ <(1,3),5>      | (1e+300,Infinity) | <(1e+300,Infinity),5>
+ <(1,2),3>      | (1e+300,Infinity) | <(1e+300,Infinity),3>
+ <(100,200),10> | (1e+300,Infinity) | <(1e+300,Infinity),10>
+ <(100,1),115>  | (1e+300,Infinity) | <(1e+300,Infinity),115>
+ <(3,5),0>      | (1e+300,Infinity) | <(1e+300,Infinity),0>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(1e+300,Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),100>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),5>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),10>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),115>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),0>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(15,11),3>
+ <(1,2),100>    | (10,10)           | <(11,12),100>
+ <(1,3),5>      | (10,10)           | <(11,13),5>
+ <(1,2),3>      | (10,10)           | <(11,12),3>
+ <(100,200),10> | (10,10)           | <(110,210),10>
+ <(100,1),115>  | (10,10)           | <(110,11),115>
+ <(3,5),0>      | (10,10)           | <(13,15),0>
+ <(3,5),NaN>    | (10,10)           | <(13,15),NaN>
+(72 rows)
+
+-- Subtract point
+SELECT c.f1, p.f1, c.f1 - p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |         ?column?          
+----------------+-------------------+---------------------------
+ <(5,1),3>      | (0,0)             | <(5,1),3>
+ <(1,2),100>    | (0,0)             | <(1,2),100>
+ <(1,3),5>      | (0,0)             | <(1,3),5>
+ <(1,2),3>      | (0,0)             | <(1,2),3>
+ <(100,200),10> | (0,0)             | <(100,200),10>
+ <(100,1),115>  | (0,0)             | <(100,1),115>
+ <(3,5),0>      | (0,0)             | <(3,5),0>
+ <(3,5),NaN>    | (0,0)             | <(3,5),NaN>
+ <(5,1),3>      | (-10,0)           | <(15,1),3>
+ <(1,2),100>    | (-10,0)           | <(11,2),100>
+ <(1,3),5>      | (-10,0)           | <(11,3),5>
+ <(1,2),3>      | (-10,0)           | <(11,2),3>
+ <(100,200),10> | (-10,0)           | <(110,200),10>
+ <(100,1),115>  | (-10,0)           | <(110,1),115>
+ <(3,5),0>      | (-10,0)           | <(13,5),0>
+ <(3,5),NaN>    | (-10,0)           | <(13,5),NaN>
+ <(5,1),3>      | (-3,4)            | <(8,-3),3>
+ <(1,2),100>    | (-3,4)            | <(4,-2),100>
+ <(1,3),5>      | (-3,4)            | <(4,-1),5>
+ <(1,2),3>      | (-3,4)            | <(4,-2),3>
+ <(100,200),10> | (-3,4)            | <(103,196),10>
+ <(100,1),115>  | (-3,4)            | <(103,-3),115>
+ <(3,5),0>      | (-3,4)            | <(6,1),0>
+ <(3,5),NaN>    | (-3,4)            | <(6,1),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(-0.1,-33.5),3>
+ <(1,2),100>    | (5.1,34.5)        | <(-4.1,-32.5),100>
+ <(1,3),5>      | (5.1,34.5)        | <(-4.1,-31.5),5>
+ <(1,2),3>      | (5.1,34.5)        | <(-4.1,-32.5),3>
+ <(100,200),10> | (5.1,34.5)        | <(94.9,165.5),10>
+ <(100,1),115>  | (5.1,34.5)        | <(94.9,-33.5),115>
+ <(3,5),0>      | (5.1,34.5)        | <(-2.1,-29.5),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(-2.1,-29.5),NaN>
+ <(5,1),3>      | (-5,-12)          | <(10,13),3>
+ <(1,2),100>    | (-5,-12)          | <(6,14),100>
+ <(1,3),5>      | (-5,-12)          | <(6,15),5>
+ <(1,2),3>      | (-5,-12)          | <(6,14),3>
+ <(100,200),10> | (-5,-12)          | <(105,212),10>
+ <(100,1),115>  | (-5,-12)          | <(105,13),115>
+ <(3,5),0>      | (-5,-12)          | <(8,17),0>
+ <(3,5),NaN>    | (-5,-12)          | <(8,17),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(5,1),3>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(1,2),100>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(1,3),5>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(1,2),3>
+ <(100,200),10> | (1e-300,-1e-300)  | <(100,200),10>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(100,1),115>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(3,5),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(3,5),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(-1e+300,-Infinity),3>
+ <(1,2),100>    | (1e+300,Infinity) | <(-1e+300,-Infinity),100>
+ <(1,3),5>      | (1e+300,Infinity) | <(-1e+300,-Infinity),5>
+ <(1,2),3>      | (1e+300,Infinity) | <(-1e+300,-Infinity),3>
+ <(100,200),10> | (1e+300,Infinity) | <(-1e+300,-Infinity),10>
+ <(100,1),115>  | (1e+300,Infinity) | <(-1e+300,-Infinity),115>
+ <(3,5),0>      | (1e+300,Infinity) | <(-1e+300,-Infinity),0>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(-1e+300,-Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),100>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),5>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),10>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),115>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),0>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(-5,-9),3>
+ <(1,2),100>    | (10,10)           | <(-9,-8),100>
+ <(1,3),5>      | (10,10)           | <(-9,-7),5>
+ <(1,2),3>      | (10,10)           | <(-9,-8),3>
+ <(100,200),10> | (10,10)           | <(90,190),10>
+ <(100,1),115>  | (10,10)           | <(90,-9),115>
+ <(3,5),0>      | (10,10)           | <(-7,-5),0>
+ <(3,5),NaN>    | (10,10)           | <(-7,-5),NaN>
+(72 rows)
+
+-- Multiply with point
+SELECT c.f1, p.f1, c.f1 * p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |                  ?column?                  
+----------------+-------------------+--------------------------------------------
+ <(5,1),3>      | (0,0)             | <(0,0),0>
+ <(1,2),100>    | (0,0)             | <(0,0),0>
+ <(1,3),5>      | (0,0)             | <(0,0),0>
+ <(1,2),3>      | (0,0)             | <(0,0),0>
+ <(100,200),10> | (0,0)             | <(0,0),0>
+ <(100,1),115>  | (0,0)             | <(0,0),0>
+ <(3,5),0>      | (0,0)             | <(0,0),0>
+ <(3,5),NaN>    | (0,0)             | <(0,0),NaN>
+ <(5,1),3>      | (-10,0)           | <(-50,-10),30>
+ <(1,2),100>    | (-10,0)           | <(-10,-20),1000>
+ <(1,3),5>      | (-10,0)           | <(-10,-30),50>
+ <(1,2),3>      | (-10,0)           | <(-10,-20),30>
+ <(100,200),10> | (-10,0)           | <(-1000,-2000),100>
+ <(100,1),115>  | (-10,0)           | <(-1000,-10),1150>
+ <(3,5),0>      | (-10,0)           | <(-30,-50),0>
+ <(3,5),NaN>    | (-10,0)           | <(-30,-50),NaN>
+ <(5,1),3>      | (-3,4)            | <(-19,17),15>
+ <(1,2),100>    | (-3,4)            | <(-11,-2),500>
+ <(1,3),5>      | (-3,4)            | <(-15,-5),25>
+ <(1,2),3>      | (-3,4)            | <(-11,-2),15>
+ <(100,200),10> | (-3,4)            | <(-1100,-200),50>
+ <(100,1),115>  | (-3,4)            | <(-304,397),575>
+ <(3,5),0>      | (-3,4)            | <(-29,-3),0>
+ <(3,5),NaN>    | (-3,4)            | <(-29,-3),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(-9,177.6),104.624758064>
+ <(1,2),100>    | (5.1,34.5)        | <(-63.9,44.7),3487.49193547>
+ <(1,3),5>      | (5.1,34.5)        | <(-98.4,49.8),174.374596774>
+ <(1,2),3>      | (5.1,34.5)        | <(-63.9,44.7),104.624758064>
+ <(100,200),10> | (5.1,34.5)        | <(-6390,4470),348.749193547>
+ <(100,1),115>  | (5.1,34.5)        | <(475.5,3455.1),4010.6157258>
+ <(3,5),0>      | (5.1,34.5)        | <(-157.2,129),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(-157.2,129),NaN>
+ <(5,1),3>      | (-5,-12)          | <(-13,-65),39>
+ <(1,2),100>    | (-5,-12)          | <(19,-22),1300>
+ <(1,3),5>      | (-5,-12)          | <(31,-27),65>
+ <(1,2),3>      | (-5,-12)          | <(19,-22),39>
+ <(100,200),10> | (-5,-12)          | <(1900,-2200),130>
+ <(100,1),115>  | (-5,-12)          | <(-488,-1205),1495>
+ <(3,5),0>      | (-5,-12)          | <(45,-61),0>
+ <(3,5),NaN>    | (-5,-12)          | <(45,-61),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(6e-300,-4e-300),4.24264068712e-300>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(3e-300,1e-300),1.41421356237e-298>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(4e-300,2e-300),7.07106781187e-300>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(3e-300,1e-300),4.24264068712e-300>
+ <(100,200),10> | (1e-300,-1e-300)  | <(3e-298,1e-298),1.41421356237e-299>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(1.01e-298,-9.9e-299),1.62634559673e-298>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(8e-300,2e-300),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(8e-300,2e-300),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,2),100>    | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,3),5>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,2),3>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(100,200),10> | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(100,1),115>  | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(3,5),0>      | (1e+300,Infinity) | <(-Infinity,Infinity),NaN>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(-Infinity,Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(40,60),42.4264068712>
+ <(1,2),100>    | (10,10)           | <(-10,30),1414.21356237>
+ <(1,3),5>      | (10,10)           | <(-20,40),70.7106781187>
+ <(1,2),3>      | (10,10)           | <(-10,30),42.4264068712>
+ <(100,200),10> | (10,10)           | <(-1000,3000),141.421356237>
+ <(100,1),115>  | (10,10)           | <(990,1010),1626.34559673>
+ <(3,5),0>      | (10,10)           | <(-20,80),0>
+ <(3,5),NaN>    | (10,10)           | <(-20,80),NaN>
+(72 rows)
+
+-- Divide by point
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+       f1       |     f1     |                       ?column?                       
+----------------+------------+------------------------------------------------------
+ <(5,1),3>      | (5.1,34.5) | <(0.0493315573973,-0.137635045138),0.0860217042937>
+ <(5,1),3>      | (10,10)    | <(0.3,-0.2),0.212132034356>
+ <(1,2),100>    | (5.1,34.5) | <(0.0609244733856,-0.0199792807459),2.86739014312>
+ <(1,2),100>    | (10,10)    | <(0.15,0.05),7.07106781187>
+ <(1,3),5>      | (5.1,34.5) | <(0.0892901188891,-0.0157860983671),0.143369507156>
+ <(1,3),5>      | (10,10)    | <(0.2,0.1),0.353553390593>
+ <(1,2),3>      | (5.1,34.5) | <(0.0609244733856,-0.0199792807459),0.0860217042937>
+ <(1,2),3>      | (10,10)    | <(0.15,0.05),0.212132034356>
+ <(100,200),10> | (5.1,34.5) | <(6.09244733856,-1.99792807459),0.286739014312>
+ <(100,200),10> | (10,10)    | <(15,5),0.707106781187>
+ <(100,1),115>  | (5.1,34.5) | <(0.44768388338,-2.83237136796),3.29749866459>
+ <(100,1),115>  | (10,10)    | <(5.05,-4.95),8.13172798365>
+ <(3,5),0>      | (5.1,34.5) | <(0.154407774653,-0.0641310246164),0>
+ <(3,5),0>      | (10,10)    | <(0.4,0.1),0>
+ <(3,5),NaN>    | (5.1,34.5) | <(0.154407774653,-0.0641310246164),NaN>
+ <(3,5),NaN>    | (10,10)    | <(0.4,0.1),NaN>
+(16 rows)
+
+-- Overflow error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] > 1000;
+ERROR:  value out of range: overflow
+-- Division by 0 error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to polygon
+SELECT c.f1, p.f1, c.f1 <-> p.f1 FROM CIRCLE_TBL c, POLYGON_TBL p;
+       f1       |             f1             |    ?column?    
+----------------+----------------------------+----------------
+ <(5,1),3>      | ((2,0),(2,4),(0,0))        |              0
+ <(5,1),3>      | ((3,1),(3,3),(1,0))        |              0
+ <(5,1),3>      | ((1,2),(3,4),(5,6),(7,8))  | 0.535533905933
+ <(5,1),3>      | ((7,8),(5,6),(3,4),(1,2))  | 0.535533905933
+ <(5,1),3>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(5,1),3>      | ((0,0))                    |  2.09901951359
+ <(5,1),3>      | ((0,1),(0,1))              |              2
+ <(1,2),100>    | ((2,0),(2,4),(0,0))        |              0
+ <(1,2),100>    | ((3,1),(3,3),(1,0))        |              0
+ <(1,2),100>    | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,2),100>    | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,2),100>    | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,2),100>    | ((0,0))                    |              0
+ <(1,2),100>    | ((0,1),(0,1))              |              0
+ <(1,3),5>      | ((2,0),(2,4),(0,0))        |              0
+ <(1,3),5>      | ((3,1),(3,3),(1,0))        |              0
+ <(1,3),5>      | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,3),5>      | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,3),5>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,3),5>      | ((0,0))                    |              0
+ <(1,3),5>      | ((0,1),(0,1))              |              0
+ <(1,2),3>      | ((2,0),(2,4),(0,0))        |              0
+ <(1,2),3>      | ((3,1),(3,3),(1,0))        |              0
+ <(1,2),3>      | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,2),3>      | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,2),3>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,2),3>      | ((0,0))                    |              0
+ <(1,2),3>      | ((0,1),(0,1))              |              0
+ <(100,200),10> | ((2,0),(2,4),(0,0))        |  209.134661795
+ <(100,200),10> | ((3,1),(3,3),(1,0))        |  209.585974051
+ <(100,200),10> | ((1,2),(3,4),(5,6),(7,8))  |  203.337760371
+ <(100,200),10> | ((7,8),(5,6),(3,4),(1,2))  |  203.337760371
+ <(100,200),10> | ((1,2),(7,8),(5,6),(3,-4)) |  203.337760371
+ <(100,200),10> | ((0,0))                    |   213.60679775
+ <(100,200),10> | ((0,1),(0,1))              |  212.712819568
+ <(100,1),115>  | ((2,0),(2,4),(0,0))        |              0
+ <(100,1),115>  | ((3,1),(3,3),(1,0))        |              0
+ <(100,1),115>  | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(100,1),115>  | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(100,1),115>  | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(100,1),115>  | ((0,0))                    |              0
+ <(100,1),115>  | ((0,1),(0,1))              |              0
+ <(3,5),0>      | ((2,0),(2,4),(0,0))        |  1.41421356237
+ <(3,5),0>      | ((3,1),(3,3),(1,0))        |              2
+ <(3,5),0>      | ((1,2),(3,4),(5,6),(7,8))  | 0.707106781187
+ <(3,5),0>      | ((7,8),(5,6),(3,4),(1,2))  | 0.707106781187
+ <(3,5),0>      | ((1,2),(7,8),(5,6),(3,-4)) | 0.707106781187
+ <(3,5),0>      | ((0,0))                    |  5.83095189485
+ <(3,5),0>      | ((0,1),(0,1))              |              5
+ <(3,5),NaN>    | ((2,0),(2,4),(0,0))        |            NaN
+ <(3,5),NaN>    | ((3,1),(3,3),(1,0))        |            NaN
+ <(3,5),NaN>    | ((1,2),(3,4),(5,6),(7,8))  |            NaN
+ <(3,5),NaN>    | ((7,8),(5,6),(3,4),(1,2))  |            NaN
+ <(3,5),NaN>    | ((1,2),(7,8),(5,6),(3,-4)) |            NaN
+ <(3,5),NaN>    | ((0,0))                    |            NaN
+ <(3,5),NaN>    | ((0,1),(0,1))              |            NaN
+(56 rows)
 
diff --git a/src/test/regress/expected/geometry_1.out b/src/test/regress/expected/geometry_1.out
index 3b92e23059..48f4aa8638 100644
--- a/src/test/regress/expected/geometry_1.out
+++ b/src/test/regress/expected/geometry_1.out
@@ -6,558 +6,4885 @@
 SET extra_float_digits TO -3;
 --
 -- Points
 --
 SELECT '' AS four, center(f1) AS center
    FROM BOX_TBL;
  four | center  
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, (@@ f1) AS center
    FROM BOX_TBL;
  four | center  
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS six, point(f1) AS center
    FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS six, (@@ f1) AS center
    FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS two, (@@ f1) AS center
    FROM POLYGON_TBL
    WHERE (# f1) > 2;
  two |            center             
 -----+-------------------------------
      | (1.33333333333,1.33333333333)
      | (2.33333333333,1.33333333333)
-(2 rows)
+     | (4,5)
+     | (4,5)
+     | (4,3)
+(5 rows)
 
 -- "is horizontal" function
 SELECT '' AS two, p1.f1
    FROM POINT_TBL p1
    WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 -- "is horizontal" operator
 SELECT '' AS two, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 -- "is vertical" function
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE isvertical(p1.f1, point '(5.1,34.5)');
  one |     f1     
 -----+------------
      | (5.1,34.5)
 (1 row)
 
 -- "is vertical" operator
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?| point '(5.1,34.5)';
  one |     f1     
 -----+------------
      | (5.1,34.5)
 (1 row)
 
+-- Slope
+SELECT p1.f1, p2.f1, slope(p1.f1, p2.f1) FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |       slope        
+-------------------+-------------------+--------------------
+ (0,0)             | (0,0)             | 1.79769313486e+308
+ (0,0)             | (-10,0)           |                  0
+ (0,0)             | (-3,4)            |     -1.33333333333
+ (0,0)             | (5.1,34.5)        |      6.76470588235
+ (0,0)             | (-5,-12)          |                2.4
+ (0,0)             | (1e-300,-1e-300)  | 1.79769313486e+308
+ (0,0)             | (1e+300,Infinity) |           Infinity
+ (0,0)             | (NaN,NaN)         |                NaN
+ (0,0)             | (10,10)           |                  1
+ (-10,0)           | (0,0)             |                  0
+ (-10,0)           | (-10,0)           | 1.79769313486e+308
+ (-10,0)           | (-3,4)            |     0.571428571429
+ (-10,0)           | (5.1,34.5)        |      2.28476821192
+ (-10,0)           | (-5,-12)          |               -2.4
+ (-10,0)           | (1e-300,-1e-300)  |                  0
+ (-10,0)           | (1e+300,Infinity) |           Infinity
+ (-10,0)           | (NaN,NaN)         |                NaN
+ (-10,0)           | (10,10)           |                0.5
+ (-3,4)            | (0,0)             |     -1.33333333333
+ (-3,4)            | (-10,0)           |     0.571428571429
+ (-3,4)            | (-3,4)            | 1.79769313486e+308
+ (-3,4)            | (5.1,34.5)        |      3.76543209877
+ (-3,4)            | (-5,-12)          |                  8
+ (-3,4)            | (1e-300,-1e-300)  |     -1.33333333333
+ (-3,4)            | (1e+300,Infinity) |           Infinity
+ (-3,4)            | (NaN,NaN)         |                NaN
+ (-3,4)            | (10,10)           |     0.461538461538
+ (5.1,34.5)        | (0,0)             |      6.76470588235
+ (5.1,34.5)        | (-10,0)           |      2.28476821192
+ (5.1,34.5)        | (-3,4)            |      3.76543209877
+ (5.1,34.5)        | (5.1,34.5)        | 1.79769313486e+308
+ (5.1,34.5)        | (-5,-12)          |      4.60396039604
+ (5.1,34.5)        | (1e-300,-1e-300)  |      6.76470588235
+ (5.1,34.5)        | (1e+300,Infinity) |           Infinity
+ (5.1,34.5)        | (NaN,NaN)         |                NaN
+ (5.1,34.5)        | (10,10)           |                 -5
+ (-5,-12)          | (0,0)             |                2.4
+ (-5,-12)          | (-10,0)           |               -2.4
+ (-5,-12)          | (-3,4)            |                  8
+ (-5,-12)          | (5.1,34.5)        |      4.60396039604
+ (-5,-12)          | (-5,-12)          | 1.79769313486e+308
+ (-5,-12)          | (1e-300,-1e-300)  |                2.4
+ (-5,-12)          | (1e+300,Infinity) |           Infinity
+ (-5,-12)          | (NaN,NaN)         |                NaN
+ (-5,-12)          | (10,10)           |      1.46666666667
+ (1e-300,-1e-300)  | (0,0)             | 1.79769313486e+308
+ (1e-300,-1e-300)  | (-10,0)           |                  0
+ (1e-300,-1e-300)  | (-3,4)            |     -1.33333333333
+ (1e-300,-1e-300)  | (5.1,34.5)        |      6.76470588235
+ (1e-300,-1e-300)  | (-5,-12)          |                2.4
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | 1.79769313486e+308
+ (1e-300,-1e-300)  | (1e+300,Infinity) |           Infinity
+ (1e-300,-1e-300)  | (NaN,NaN)         |                NaN
+ (1e-300,-1e-300)  | (10,10)           |                  1
+ (1e+300,Infinity) | (0,0)             |           Infinity
+ (1e+300,Infinity) | (-10,0)           |           Infinity
+ (1e+300,Infinity) | (-3,4)            |           Infinity
+ (1e+300,Infinity) | (5.1,34.5)        |           Infinity
+ (1e+300,Infinity) | (-5,-12)          |           Infinity
+ (1e+300,Infinity) | (1e-300,-1e-300)  |           Infinity
+ (1e+300,Infinity) | (1e+300,Infinity) | 1.79769313486e+308
+ (1e+300,Infinity) | (NaN,NaN)         |                NaN
+ (1e+300,Infinity) | (10,10)           |           Infinity
+ (NaN,NaN)         | (0,0)             |                NaN
+ (NaN,NaN)         | (-10,0)           |                NaN
+ (NaN,NaN)         | (-3,4)            |                NaN
+ (NaN,NaN)         | (5.1,34.5)        |                NaN
+ (NaN,NaN)         | (-5,-12)          |                NaN
+ (NaN,NaN)         | (1e-300,-1e-300)  |                NaN
+ (NaN,NaN)         | (1e+300,Infinity) |                NaN
+ (NaN,NaN)         | (NaN,NaN)         |                NaN
+ (NaN,NaN)         | (10,10)           |                NaN
+ (10,10)           | (0,0)             |                  1
+ (10,10)           | (-10,0)           |                0.5
+ (10,10)           | (-3,4)            |     0.461538461538
+ (10,10)           | (5.1,34.5)        |                 -5
+ (10,10)           | (-5,-12)          |      1.46666666667
+ (10,10)           | (1e-300,-1e-300)  |                  1
+ (10,10)           | (1e+300,Infinity) |           Infinity
+ (10,10)           | (NaN,NaN)         |                NaN
+ (10,10)           | (10,10)           | 1.79769313486e+308
+(81 rows)
+
+-- Add point
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |     ?column?      
+-------------------+-------------------+-------------------
+ (0,0)             | (0,0)             | (0,0)
+ (0,0)             | (-10,0)           | (-10,0)
+ (0,0)             | (-3,4)            | (-3,4)
+ (0,0)             | (5.1,34.5)        | (5.1,34.5)
+ (0,0)             | (-5,-12)          | (-5,-12)
+ (0,0)             | (1e-300,-1e-300)  | (1e-300,-1e-300)
+ (0,0)             | (1e+300,Infinity) | (1e+300,Infinity)
+ (0,0)             | (NaN,NaN)         | (NaN,NaN)
+ (0,0)             | (10,10)           | (10,10)
+ (-10,0)           | (0,0)             | (-10,0)
+ (-10,0)           | (-10,0)           | (-20,0)
+ (-10,0)           | (-3,4)            | (-13,4)
+ (-10,0)           | (5.1,34.5)        | (-4.9,34.5)
+ (-10,0)           | (-5,-12)          | (-15,-12)
+ (-10,0)           | (1e-300,-1e-300)  | (-10,-1e-300)
+ (-10,0)           | (1e+300,Infinity) | (1e+300,Infinity)
+ (-10,0)           | (NaN,NaN)         | (NaN,NaN)
+ (-10,0)           | (10,10)           | (0,10)
+ (-3,4)            | (0,0)             | (-3,4)
+ (-3,4)            | (-10,0)           | (-13,4)
+ (-3,4)            | (-3,4)            | (-6,8)
+ (-3,4)            | (5.1,34.5)        | (2.1,38.5)
+ (-3,4)            | (-5,-12)          | (-8,-8)
+ (-3,4)            | (1e-300,-1e-300)  | (-3,4)
+ (-3,4)            | (1e+300,Infinity) | (1e+300,Infinity)
+ (-3,4)            | (NaN,NaN)         | (NaN,NaN)
+ (-3,4)            | (10,10)           | (7,14)
+ (5.1,34.5)        | (0,0)             | (5.1,34.5)
+ (5.1,34.5)        | (-10,0)           | (-4.9,34.5)
+ (5.1,34.5)        | (-3,4)            | (2.1,38.5)
+ (5.1,34.5)        | (5.1,34.5)        | (10.2,69)
+ (5.1,34.5)        | (-5,-12)          | (0.1,22.5)
+ (5.1,34.5)        | (1e-300,-1e-300)  | (5.1,34.5)
+ (5.1,34.5)        | (1e+300,Infinity) | (1e+300,Infinity)
+ (5.1,34.5)        | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5)        | (10,10)           | (15.1,44.5)
+ (-5,-12)          | (0,0)             | (-5,-12)
+ (-5,-12)          | (-10,0)           | (-15,-12)
+ (-5,-12)          | (-3,4)            | (-8,-8)
+ (-5,-12)          | (5.1,34.5)        | (0.1,22.5)
+ (-5,-12)          | (-5,-12)          | (-10,-24)
+ (-5,-12)          | (1e-300,-1e-300)  | (-5,-12)
+ (-5,-12)          | (1e+300,Infinity) | (1e+300,Infinity)
+ (-5,-12)          | (NaN,NaN)         | (NaN,NaN)
+ (-5,-12)          | (10,10)           | (5,-2)
+ (1e-300,-1e-300)  | (0,0)             | (1e-300,-1e-300)
+ (1e-300,-1e-300)  | (-10,0)           | (-10,-1e-300)
+ (1e-300,-1e-300)  | (-3,4)            | (-3,4)
+ (1e-300,-1e-300)  | (5.1,34.5)        | (5.1,34.5)
+ (1e-300,-1e-300)  | (-5,-12)          | (-5,-12)
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | (2e-300,-2e-300)
+ (1e-300,-1e-300)  | (1e+300,Infinity) | (1e+300,Infinity)
+ (1e-300,-1e-300)  | (NaN,NaN)         | (NaN,NaN)
+ (1e-300,-1e-300)  | (10,10)           | (10,10)
+ (1e+300,Infinity) | (0,0)             | (1e+300,Infinity)
+ (1e+300,Infinity) | (-10,0)           | (1e+300,Infinity)
+ (1e+300,Infinity) | (-3,4)            | (1e+300,Infinity)
+ (1e+300,Infinity) | (5.1,34.5)        | (1e+300,Infinity)
+ (1e+300,Infinity) | (-5,-12)          | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e-300,-1e-300)  | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e+300,Infinity) | (2e+300,Infinity)
+ (1e+300,Infinity) | (NaN,NaN)         | (NaN,NaN)
+ (1e+300,Infinity) | (10,10)           | (1e+300,Infinity)
+ (NaN,NaN)         | (0,0)             | (NaN,NaN)
+ (NaN,NaN)         | (-10,0)           | (NaN,NaN)
+ (NaN,NaN)         | (-3,4)            | (NaN,NaN)
+ (NaN,NaN)         | (5.1,34.5)        | (NaN,NaN)
+ (NaN,NaN)         | (-5,-12)          | (NaN,NaN)
+ (NaN,NaN)         | (1e-300,-1e-300)  | (NaN,NaN)
+ (NaN,NaN)         | (1e+300,Infinity) | (NaN,NaN)
+ (NaN,NaN)         | (NaN,NaN)         | (NaN,NaN)
+ (NaN,NaN)         | (10,10)           | (NaN,NaN)
+ (10,10)           | (0,0)             | (10,10)
+ (10,10)           | (-10,0)           | (0,10)
+ (10,10)           | (-3,4)            | (7,14)
+ (10,10)           | (5.1,34.5)        | (15.1,44.5)
+ (10,10)           | (-5,-12)          | (5,-2)
+ (10,10)           | (1e-300,-1e-300)  | (10,10)
+ (10,10)           | (1e+300,Infinity) | (1e+300,Infinity)
+ (10,10)           | (NaN,NaN)         | (NaN,NaN)
+ (10,10)           | (10,10)           | (20,20)
+(81 rows)
+
+-- Subtract point
+SELECT p1.f1, p2.f1, p1.f1 - p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |      ?column?       
+-------------------+-------------------+---------------------
+ (0,0)             | (0,0)             | (0,0)
+ (0,0)             | (-10,0)           | (10,0)
+ (0,0)             | (-3,4)            | (3,-4)
+ (0,0)             | (5.1,34.5)        | (-5.1,-34.5)
+ (0,0)             | (-5,-12)          | (5,12)
+ (0,0)             | (1e-300,-1e-300)  | (-1e-300,1e-300)
+ (0,0)             | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (0,0)             | (NaN,NaN)         | (NaN,NaN)
+ (0,0)             | (10,10)           | (-10,-10)
+ (-10,0)           | (0,0)             | (-10,0)
+ (-10,0)           | (-10,0)           | (0,0)
+ (-10,0)           | (-3,4)            | (-7,-4)
+ (-10,0)           | (5.1,34.5)        | (-15.1,-34.5)
+ (-10,0)           | (-5,-12)          | (-5,12)
+ (-10,0)           | (1e-300,-1e-300)  | (-10,1e-300)
+ (-10,0)           | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-10,0)           | (NaN,NaN)         | (NaN,NaN)
+ (-10,0)           | (10,10)           | (-20,-10)
+ (-3,4)            | (0,0)             | (-3,4)
+ (-3,4)            | (-10,0)           | (7,4)
+ (-3,4)            | (-3,4)            | (0,0)
+ (-3,4)            | (5.1,34.5)        | (-8.1,-30.5)
+ (-3,4)            | (-5,-12)          | (2,16)
+ (-3,4)            | (1e-300,-1e-300)  | (-3,4)
+ (-3,4)            | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-3,4)            | (NaN,NaN)         | (NaN,NaN)
+ (-3,4)            | (10,10)           | (-13,-6)
+ (5.1,34.5)        | (0,0)             | (5.1,34.5)
+ (5.1,34.5)        | (-10,0)           | (15.1,34.5)
+ (5.1,34.5)        | (-3,4)            | (8.1,30.5)
+ (5.1,34.5)        | (5.1,34.5)        | (0,0)
+ (5.1,34.5)        | (-5,-12)          | (10.1,46.5)
+ (5.1,34.5)        | (1e-300,-1e-300)  | (5.1,34.5)
+ (5.1,34.5)        | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (5.1,34.5)        | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5)        | (10,10)           | (-4.9,24.5)
+ (-5,-12)          | (0,0)             | (-5,-12)
+ (-5,-12)          | (-10,0)           | (5,-12)
+ (-5,-12)          | (-3,4)            | (-2,-16)
+ (-5,-12)          | (5.1,34.5)        | (-10.1,-46.5)
+ (-5,-12)          | (-5,-12)          | (0,0)
+ (-5,-12)          | (1e-300,-1e-300)  | (-5,-12)
+ (-5,-12)          | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-5,-12)          | (NaN,NaN)         | (NaN,NaN)
+ (-5,-12)          | (10,10)           | (-15,-22)
+ (1e-300,-1e-300)  | (0,0)             | (1e-300,-1e-300)
+ (1e-300,-1e-300)  | (-10,0)           | (10,-1e-300)
+ (1e-300,-1e-300)  | (-3,4)            | (3,-4)
+ (1e-300,-1e-300)  | (5.1,34.5)        | (-5.1,-34.5)
+ (1e-300,-1e-300)  | (-5,-12)          | (5,12)
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | (0,0)
+ (1e-300,-1e-300)  | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (1e-300,-1e-300)  | (NaN,NaN)         | (NaN,NaN)
+ (1e-300,-1e-300)  | (10,10)           | (-10,-10)
+ (1e+300,Infinity) | (0,0)             | (1e+300,Infinity)
+ (1e+300,Infinity) | (-10,0)           | (1e+300,Infinity)
+ (1e+300,Infinity) | (-3,4)            | (1e+300,Infinity)
+ (1e+300,Infinity) | (5.1,34.5)        | (1e+300,Infinity)
+ (1e+300,Infinity) | (-5,-12)          | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e-300,-1e-300)  | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e+300,Infinity) | (0,NaN)
+ (1e+300,Infinity) | (NaN,NaN)         | (NaN,NaN)
+ (1e+300,Infinity) | (10,10)           | (1e+300,Infinity)
+ (NaN,NaN)         | (0,0)             | (NaN,NaN)
+ (NaN,NaN)         | (-10,0)           | (NaN,NaN)
+ (NaN,NaN)         | (-3,4)            | (NaN,NaN)
+ (NaN,NaN)         | (5.1,34.5)        | (NaN,NaN)
+ (NaN,NaN)         | (-5,-12)          | (NaN,NaN)
+ (NaN,NaN)         | (1e-300,-1e-300)  | (NaN,NaN)
+ (NaN,NaN)         | (1e+300,Infinity) | (NaN,NaN)
+ (NaN,NaN)         | (NaN,NaN)         | (NaN,NaN)
+ (NaN,NaN)         | (10,10)           | (NaN,NaN)
+ (10,10)           | (0,0)             | (10,10)
+ (10,10)           | (-10,0)           | (20,10)
+ (10,10)           | (-3,4)            | (13,6)
+ (10,10)           | (5.1,34.5)        | (4.9,-24.5)
+ (10,10)           | (-5,-12)          | (15,22)
+ (10,10)           | (1e-300,-1e-300)  | (10,10)
+ (10,10)           | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (10,10)           | (NaN,NaN)         | (NaN,NaN)
+ (10,10)           | (10,10)           | (0,0)
+(81 rows)
+
+-- Multiply with point
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+     f1     |        f1         |       ?column?        
+------------+-------------------+-----------------------
+ (5.1,34.5) | (0,0)             | (0,0)
+ (10,10)    | (0,0)             | (0,0)
+ (5.1,34.5) | (-10,0)           | (-51,-345)
+ (10,10)    | (-10,0)           | (-100,-100)
+ (5.1,34.5) | (-3,4)            | (-153.3,-83.1)
+ (10,10)    | (-3,4)            | (-70,10)
+ (5.1,34.5) | (5.1,34.5)        | (-1164.24,351.9)
+ (10,10)    | (5.1,34.5)        | (-294,396)
+ (5.1,34.5) | (-5,-12)          | (388.5,-233.7)
+ (10,10)    | (-5,-12)          | (70,-170)
+ (5.1,34.5) | (1e-300,-1e-300)  | (3.96e-299,2.94e-299)
+ (10,10)    | (1e-300,-1e-300)  | (2e-299,0)
+ (5.1,34.5) | (1e+300,Infinity) | (-Infinity,Infinity)
+ (10,10)    | (1e+300,Infinity) | (-Infinity,Infinity)
+ (5.1,34.5) | (NaN,NaN)         | (NaN,NaN)
+ (10,10)    | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5) | (10,10)           | (-294,396)
+ (10,10)    | (10,10)           | (0,200)
+(18 rows)
+
+-- Underflow error
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] < 1;
+ERROR:  value out of range: underflow
+-- Divide by point
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] BETWEEN 1 AND 1000;
+        f1         |     f1     |                 ?column?                  
+-------------------+------------+-------------------------------------------
+ (0,0)             | (5.1,34.5) | (0,0)
+ (0,0)             | (10,10)    | (0,0)
+ (-10,0)           | (5.1,34.5) | (-0.0419318237877,0.283656455034)
+ (-10,0)           | (10,10)    | (-0.5,0.5)
+ (-3,4)            | (5.1,34.5) | (0.100883034877,0.101869666025)
+ (-3,4)            | (10,10)    | (0.05,0.35)
+ (5.1,34.5)        | (5.1,34.5) | (1,0)
+ (5.1,34.5)        | (10,10)    | (1.98,1.47)
+ (-5,-12)          | (5.1,34.5) | (-0.361353657935,0.0915100389719)
+ (-5,-12)          | (10,10)    | (-0.85,-0.35)
+ (1e-300,-1e-300)  | (5.1,34.5) | (-2.41724631247e-302,-3.25588278822e-302)
+ (1e-300,-1e-300)  | (10,10)    | (0,-1e-301)
+ (1e+300,Infinity) | (5.1,34.5) | (Infinity,Infinity)
+ (1e+300,Infinity) | (10,10)    | (Infinity,Infinity)
+ (NaN,NaN)         | (5.1,34.5) | (NaN,NaN)
+ (NaN,NaN)         | (10,10)    | (NaN,NaN)
+ (10,10)           | (5.1,34.5) | (0.325588278822,-0.241724631247)
+ (10,10)           | (10,10)    | (1,0)
+(18 rows)
+
+-- Overflow error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] > 1000;
+ERROR:  value out of range: overflow
+-- Division by 0 error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to line
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LINE_TBL l;
+        f1         |                   s                   |      ?column?      
+-------------------+---------------------------------------+--------------------
+ (0,0)             | {0,-1,5}                              |                  5
+ (0,0)             | {1,0,5}                               |                  5
+ (0,0)             | {0,3,0}                               |                  0
+ (0,0)             | {1,-1,0}                              |                  0
+ (0,0)             | {-0.4,-1,-6}                          |      5.57086014531
+ (0,0)             | {-0.000184615384615,-1,15.3846153846} |      15.3846151224
+ (0,0)             | {3,NaN,5}                             |                NaN
+ (0,0)             | {NaN,NaN,NaN}                         |                NaN
+ (0,0)             | {0,-1,3}                              |                  3
+ (0,0)             | {-1,0,3}                              |                  3
+ (-10,0)           | {0,-1,5}                              |                  5
+ (-10,0)           | {1,0,5}                               |                  5
+ (-10,0)           | {0,3,0}                               |                  0
+ (-10,0)           | {1,-1,0}                              |      7.07106781187
+ (-10,0)           | {-0.4,-1,-6}                          |      1.85695338177
+ (-10,0)           | {-0.000184615384615,-1,15.3846153846} |      15.3864612763
+ (-10,0)           | {3,NaN,5}                             |                NaN
+ (-10,0)           | {NaN,NaN,NaN}                         |                NaN
+ (-10,0)           | {0,-1,3}                              |                  3
+ (-10,0)           | {-1,0,3}                              |                 13
+ (-3,4)            | {0,-1,5}                              |                  1
+ (-3,4)            | {1,0,5}                               |                  2
+ (-3,4)            | {0,3,0}                               |                  4
+ (-3,4)            | {1,-1,0}                              |      4.94974746831
+ (-3,4)            | {-0.4,-1,-6}                          |      8.17059487979
+ (-3,4)            | {-0.000184615384615,-1,15.3846153846} |      11.3851690368
+ (-3,4)            | {3,NaN,5}                             |                NaN
+ (-3,4)            | {NaN,NaN,NaN}                         |                NaN
+ (-3,4)            | {0,-1,3}                              |                  1
+ (-3,4)            | {-1,0,3}                              |                  6
+ (5.1,34.5)        | {0,-1,5}                              |               29.5
+ (5.1,34.5)        | {1,0,5}                               |               10.1
+ (5.1,34.5)        | {0,3,0}                               |               34.5
+ (5.1,34.5)        | {1,-1,0}                              |      20.7889393669
+ (5.1,34.5)        | {-0.4,-1,-6}                          |      39.4973984303
+ (5.1,34.5)        | {-0.000184615384615,-1,15.3846153846} |      19.1163258281
+ (5.1,34.5)        | {3,NaN,5}                             |                NaN
+ (5.1,34.5)        | {NaN,NaN,NaN}                         |                NaN
+ (5.1,34.5)        | {0,-1,3}                              |               31.5
+ (5.1,34.5)        | {-1,0,3}                              |                2.1
+ (-5,-12)          | {0,-1,5}                              |                 17
+ (-5,-12)          | {1,0,5}                               |                  0
+ (-5,-12)          | {0,3,0}                               |                 12
+ (-5,-12)          | {1,-1,0}                              |      4.94974746831
+ (-5,-12)          | {-0.4,-1,-6}                          |      7.42781352708
+ (-5,-12)          | {-0.000184615384615,-1,15.3846153846} |      27.3855379948
+ (-5,-12)          | {3,NaN,5}                             |                NaN
+ (-5,-12)          | {NaN,NaN,NaN}                         |                NaN
+ (-5,-12)          | {0,-1,3}                              |                 15
+ (-5,-12)          | {-1,0,3}                              |                  8
+ (1e-300,-1e-300)  | {0,-1,5}                              |                  5
+ (1e-300,-1e-300)  | {1,0,5}                               |                  5
+ (1e-300,-1e-300)  | {0,3,0}                               |             1e-300
+ (1e-300,-1e-300)  | {1,-1,0}                              | 1.41421356237e-300
+ (1e-300,-1e-300)  | {-0.4,-1,-6}                          |      5.57086014531
+ (1e-300,-1e-300)  | {-0.000184615384615,-1,15.3846153846} |      15.3846151224
+ (1e-300,-1e-300)  | {3,NaN,5}                             |                NaN
+ (1e-300,-1e-300)  | {NaN,NaN,NaN}                         |                NaN
+ (1e-300,-1e-300)  | {0,-1,3}                              |                  3
+ (1e-300,-1e-300)  | {-1,0,3}                              |                  3
+ (1e+300,Infinity) | {0,-1,5}                              |           Infinity
+ (1e+300,Infinity) | {1,0,5}                               |                NaN
+ (1e+300,Infinity) | {0,3,0}                               |           Infinity
+ (1e+300,Infinity) | {1,-1,0}                              |           Infinity
+ (1e+300,Infinity) | {-0.4,-1,-6}                          |           Infinity
+ (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} |           Infinity
+ (1e+300,Infinity) | {3,NaN,5}                             |                NaN
+ (1e+300,Infinity) | {NaN,NaN,NaN}                         |                NaN
+ (1e+300,Infinity) | {0,-1,3}                              |           Infinity
+ (1e+300,Infinity) | {-1,0,3}                              |                NaN
+ (NaN,NaN)         | {0,-1,5}                              |                NaN
+ (NaN,NaN)         | {1,0,5}                               |                NaN
+ (NaN,NaN)         | {0,3,0}                               |                NaN
+ (NaN,NaN)         | {1,-1,0}                              |                NaN
+ (NaN,NaN)         | {-0.4,-1,-6}                          |                NaN
+ (NaN,NaN)         | {-0.000184615384615,-1,15.3846153846} |                NaN
+ (NaN,NaN)         | {3,NaN,5}                             |                NaN
+ (NaN,NaN)         | {NaN,NaN,NaN}                         |                NaN
+ (NaN,NaN)         | {0,-1,3}                              |                NaN
+ (NaN,NaN)         | {-1,0,3}                              |                NaN
+ (10,10)           | {0,-1,5}                              |                  5
+ (10,10)           | {1,0,5}                               |                 15
+ (10,10)           | {0,3,0}                               |                 10
+ (10,10)           | {1,-1,0}                              |                  0
+ (10,10)           | {-0.4,-1,-6}                          |      18.5695338177
+ (10,10)           | {-0.000184615384615,-1,15.3846153846} |      5.38276913903
+ (10,10)           | {3,NaN,5}                             |                NaN
+ (10,10)           | {NaN,NaN,NaN}                         |                NaN
+ (10,10)           | {0,-1,3}                              |                  7
+ (10,10)           | {-1,0,3}                              |                  7
+(90 rows)
+
+-- Distance to line segment
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LSEG_TBL l;
+        f1         |               s               |      ?column?      
+-------------------+-------------------------------+--------------------
+ (0,0)             | [(1,2),(3,4)]                 |       2.2360679775
+ (0,0)             | [(0,0),(6,6)]                 |                  0
+ (0,0)             | [(10,-10),(-3,-4)]            |      4.88901207039
+ (0,0)             | [(-1000000,200),(300000,-40)] |      15.3846151224
+ (0,0)             | [(11,22),(33,44)]             |      24.5967477525
+ (0,0)             | [(-10,2),(-10,3)]             |      10.1980390272
+ (0,0)             | [(0,-20),(30,-20)]            |                 20
+ (0,0)             | [(NaN,1),(NaN,90)]            |                NaN
+ (-10,0)           | [(1,2),(3,4)]                 |      11.1803398875
+ (-10,0)           | [(0,0),(6,6)]                 |                 10
+ (-10,0)           | [(10,-10),(-3,-4)]            |       8.0622577483
+ (-10,0)           | [(-1000000,200),(300000,-40)] |      15.3864612763
+ (-10,0)           | [(11,22),(33,44)]             |      30.4138126515
+ (-10,0)           | [(-10,2),(-10,3)]             |                  2
+ (-10,0)           | [(0,-20),(30,-20)]            |       22.360679775
+ (-10,0)           | [(NaN,1),(NaN,90)]            |                NaN
+ (-3,4)            | [(1,2),(3,4)]                 |        4.472135955
+ (-3,4)            | [(0,0),(6,6)]                 |      4.94974746831
+ (-3,4)            | [(10,-10),(-3,-4)]            |                  8
+ (-3,4)            | [(-1000000,200),(300000,-40)] |      11.3851690367
+ (-3,4)            | [(11,22),(33,44)]             |       22.803508502
+ (-3,4)            | [(-10,2),(-10,3)]             |      7.07106781187
+ (-3,4)            | [(0,-20),(30,-20)]            |      24.1867732449
+ (-3,4)            | [(NaN,1),(NaN,90)]            |                NaN
+ (5.1,34.5)        | [(1,2),(3,4)]                 |      30.5722096028
+ (5.1,34.5)        | [(0,0),(6,6)]                 |      28.5142069853
+ (5.1,34.5)        | [(10,-10),(-3,-4)]            |      39.3428519556
+ (5.1,34.5)        | [(-1000000,200),(300000,-40)] |      19.1163258281
+ (5.1,34.5)        | [(11,22),(33,44)]             |      13.0107647738
+ (5.1,34.5)        | [(-10,2),(-10,3)]             |       34.932220084
+ (5.1,34.5)        | [(0,-20),(30,-20)]            |               54.5
+ (5.1,34.5)        | [(NaN,1),(NaN,90)]            |                NaN
+ (-5,-12)          | [(1,2),(3,4)]                 |      15.2315462117
+ (-5,-12)          | [(0,0),(6,6)]                 |                 13
+ (-5,-12)          | [(10,-10),(-3,-4)]            |      8.10179143093
+ (-5,-12)          | [(-1000000,200),(300000,-40)] |      27.3855379949
+ (-5,-12)          | [(11,22),(33,44)]             |      37.5765884561
+ (-5,-12)          | [(-10,2),(-10,3)]             |      14.8660687473
+ (-5,-12)          | [(0,-20),(30,-20)]            |      9.43398113206
+ (-5,-12)          | [(NaN,1),(NaN,90)]            |                NaN
+ (1e-300,-1e-300)  | [(1,2),(3,4)]                 |       2.2360679775
+ (1e-300,-1e-300)  | [(0,0),(6,6)]                 | 1.41421356237e-300
+ (1e-300,-1e-300)  | [(10,-10),(-3,-4)]            |      4.88901207039
+ (1e-300,-1e-300)  | [(-1000000,200),(300000,-40)] |      15.3846151224
+ (1e-300,-1e-300)  | [(11,22),(33,44)]             |      24.5967477525
+ (1e-300,-1e-300)  | [(-10,2),(-10,3)]             |      10.1980390272
+ (1e-300,-1e-300)  | [(0,-20),(30,-20)]            |                 20
+ (1e-300,-1e-300)  | [(NaN,1),(NaN,90)]            |                NaN
+ (1e+300,Infinity) | [(1,2),(3,4)]                 |           Infinity
+ (1e+300,Infinity) | [(0,0),(6,6)]                 |           Infinity
+ (1e+300,Infinity) | [(10,-10),(-3,-4)]            |           Infinity
+ (1e+300,Infinity) | [(-1000000,200),(300000,-40)] |           Infinity
+ (1e+300,Infinity) | [(11,22),(33,44)]             |           Infinity
+ (1e+300,Infinity) | [(-10,2),(-10,3)]             |           Infinity
+ (1e+300,Infinity) | [(0,-20),(30,-20)]            |           Infinity
+ (1e+300,Infinity) | [(NaN,1),(NaN,90)]            |           Infinity
+ (NaN,NaN)         | [(1,2),(3,4)]                 |                NaN
+ (NaN,NaN)         | [(0,0),(6,6)]                 |                NaN
+ (NaN,NaN)         | [(10,-10),(-3,-4)]            |                NaN
+ (NaN,NaN)         | [(-1000000,200),(300000,-40)] |                NaN
+ (NaN,NaN)         | [(11,22),(33,44)]             |                NaN
+ (NaN,NaN)         | [(-10,2),(-10,3)]             |                NaN
+ (NaN,NaN)         | [(0,-20),(30,-20)]            |                NaN
+ (NaN,NaN)         | [(NaN,1),(NaN,90)]            |                NaN
+ (10,10)           | [(1,2),(3,4)]                 |      9.21954445729
+ (10,10)           | [(0,0),(6,6)]                 |      5.65685424949
+ (10,10)           | [(10,-10),(-3,-4)]            |        18.15918769
+ (10,10)           | [(-1000000,200),(300000,-40)] |      5.38276913904
+ (10,10)           | [(11,22),(33,44)]             |      12.0415945788
+ (10,10)           | [(-10,2),(-10,3)]             |      21.1896201004
+ (10,10)           | [(0,-20),(30,-20)]            |                 30
+ (10,10)           | [(NaN,1),(NaN,90)]            |                NaN
+(72 rows)
+
+-- Distance to box
+SELECT p.f1, b.f1, p.f1 <-> b.f1 FROM POINT_TBL p, BOX_TBL b;
+        f1         |         f1          |      ?column?      
+-------------------+---------------------+--------------------
+ (0,0)             | (2,2),(0,0)         |                  0
+ (0,0)             | (3,3),(1,1)         |      1.41421356237
+ (0,0)             | (-2,2),(-8,-10)     |                  2
+ (0,0)             | (2.5,3.5),(2.5,2.5) |      3.53553390593
+ (0,0)             | (3,3),(3,3)         |      4.24264068712
+ (-10,0)           | (2,2),(0,0)         |                 10
+ (-10,0)           | (3,3),(1,1)         |      11.0453610172
+ (-10,0)           | (-2,2),(-8,-10)     |                  2
+ (-10,0)           | (2.5,3.5),(2.5,2.5) |       12.747548784
+ (-10,0)           | (3,3),(3,3)         |      13.3416640641
+ (-3,4)            | (2,2),(0,0)         |      3.60555127546
+ (-3,4)            | (3,3),(1,1)         |      4.12310562562
+ (-3,4)            | (-2,2),(-8,-10)     |                  2
+ (-3,4)            | (2.5,3.5),(2.5,2.5) |      5.52268050859
+ (-3,4)            | (3,3),(3,3)         |       6.0827625303
+ (5.1,34.5)        | (2,2),(0,0)         |      32.6475113906
+ (5.1,34.5)        | (3,3),(1,1)         |      31.5699223946
+ (5.1,34.5)        | (-2,2),(-8,-10)     |      33.2664996656
+ (5.1,34.5)        | (2.5,3.5),(2.5,2.5) |       31.108841187
+ (5.1,34.5)        | (3,3),(3,3)         |      31.5699223946
+ (-5,-12)          | (2,2),(0,0)         |                 13
+ (-5,-12)          | (3,3),(1,1)         |      14.3178210633
+ (-5,-12)          | (-2,2),(-8,-10)     |                  2
+ (-5,-12)          | (2.5,3.5),(2.5,2.5) |      16.3248277173
+ (-5,-12)          | (3,3),(3,3)         |                 17
+ (1e-300,-1e-300)  | (2,2),(0,0)         | 1.41421356237e-300
+ (1e-300,-1e-300)  | (3,3),(1,1)         |      1.41421356237
+ (1e-300,-1e-300)  | (-2,2),(-8,-10)     |                  2
+ (1e-300,-1e-300)  | (2.5,3.5),(2.5,2.5) |      3.53553390593
+ (1e-300,-1e-300)  | (3,3),(3,3)         |      4.24264068712
+ (1e+300,Infinity) | (2,2),(0,0)         |           Infinity
+ (1e+300,Infinity) | (3,3),(1,1)         |           Infinity
+ (1e+300,Infinity) | (-2,2),(-8,-10)     |           Infinity
+ (1e+300,Infinity) | (2.5,3.5),(2.5,2.5) |           Infinity
+ (1e+300,Infinity) | (3,3),(3,3)         |           Infinity
+ (NaN,NaN)         | (2,2),(0,0)         |                NaN
+ (NaN,NaN)         | (3,3),(1,1)         |                NaN
+ (NaN,NaN)         | (-2,2),(-8,-10)     |                NaN
+ (NaN,NaN)         | (2.5,3.5),(2.5,2.5) |                NaN
+ (NaN,NaN)         | (3,3),(3,3)         |                NaN
+ (10,10)           | (2,2),(0,0)         |       11.313708499
+ (10,10)           | (3,3),(1,1)         |      9.89949493661
+ (10,10)           | (-2,2),(-8,-10)     |      14.4222051019
+ (10,10)           | (2.5,3.5),(2.5,2.5) |      9.92471662064
+ (10,10)           | (3,3),(3,3)         |      9.89949493661
+(45 rows)
+
+-- Distance to path
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, PATH_TBL p1;
+        f1         |            f1             |      ?column?      
+-------------------+---------------------------+--------------------
+ (0,0)             | [(1,2),(3,4)]             |       2.2360679775
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | [(0,0),(3,0),(4,5),(1,6)] |                  0
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | [(1,2),(3,4)]             |       2.2360679775
+ (0,0)             | ((10,20))                 |       22.360679775
+ (0,0)             | [(11,12),(13,14)]         |      16.2788205961
+ (0,0)             | ((11,12),(13,14))         |      16.2788205961
+ (-10,0)           | [(1,2),(3,4)]             |      11.1803398875
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | [(0,0),(3,0),(4,5),(1,6)] |                 10
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | [(1,2),(3,4)]             |      11.1803398875
+ (-10,0)           | ((10,20))                 |      28.2842712475
+ (-10,0)           | [(11,12),(13,14)]         |      24.1867732449
+ (-10,0)           | ((11,12),(13,14))         |      24.1867732449
+ (-3,4)            | [(1,2),(3,4)]             |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | [(0,0),(3,0),(4,5),(1,6)] |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | [(1,2),(3,4)]             |        4.472135955
+ (-3,4)            | ((10,20))                 |      20.6155281281
+ (-3,4)            | [(11,12),(13,14)]         |      16.1245154966
+ (-3,4)            | ((11,12),(13,14))         |      16.1245154966
+ (5.1,34.5)        | [(1,2),(3,4)]             |      30.5722096028
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | [(0,0),(3,0),(4,5),(1,6)] |       28.793402022
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | [(1,2),(3,4)]             |      30.5722096028
+ (5.1,34.5)        | ((10,20))                 |      15.3055545473
+ (5.1,34.5)        | [(11,12),(13,14)]         |      21.9695243462
+ (5.1,34.5)        | ((11,12),(13,14))         |      21.9695243462
+ (-5,-12)          | [(1,2),(3,4)]             |      15.2315462117
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | [(0,0),(3,0),(4,5),(1,6)] |                 13
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | [(1,2),(3,4)]             |      15.2315462117
+ (-5,-12)          | ((10,20))                 |      35.3411940941
+ (-5,-12)          | [(11,12),(13,14)]         |      28.8444102037
+ (-5,-12)          | ((11,12),(13,14))         |      28.8444102037
+ (1e-300,-1e-300)  | [(1,2),(3,4)]             |       2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | [(0,0),(3,0),(4,5),(1,6)] | 1.41421356237e-300
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | [(1,2),(3,4)]             |       2.2360679775
+ (1e-300,-1e-300)  | ((10,20))                 |       22.360679775
+ (1e-300,-1e-300)  | [(11,12),(13,14)]         |      16.2788205961
+ (1e-300,-1e-300)  | ((11,12),(13,14))         |      16.2788205961
+ (1e+300,Infinity) | [(1,2),(3,4)]             |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | [(0,0),(3,0),(4,5),(1,6)] |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | [(1,2),(3,4)]             |           Infinity
+ (1e+300,Infinity) | ((10,20))                 |           Infinity
+ (1e+300,Infinity) | [(11,12),(13,14)]         |           Infinity
+ (1e+300,Infinity) | ((11,12),(13,14))         |           Infinity
+ (NaN,NaN)         | [(1,2),(3,4)]             |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | [(0,0),(3,0),(4,5),(1,6)] |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | [(1,2),(3,4)]             |                NaN
+ (NaN,NaN)         | ((10,20))                 |                NaN
+ (NaN,NaN)         | [(11,12),(13,14)]         |                NaN
+ (NaN,NaN)         | ((11,12),(13,14))         |                NaN
+ (10,10)           | [(1,2),(3,4)]             |      9.21954445729
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | [(0,0),(3,0),(4,5),(1,6)] |      7.81024967591
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | [(1,2),(3,4)]             |      9.21954445729
+ (10,10)           | ((10,20))                 |                 10
+ (10,10)           | [(11,12),(13,14)]         |       2.2360679775
+ (10,10)           | ((11,12),(13,14))         |       2.2360679775
+(81 rows)
+
+-- Distance to polygon
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, POLYGON_TBL p1;
+        f1         |             f1             |   ?column?    
+-------------------+----------------------------+---------------
+ (0,0)             | ((2,0),(2,4),(0,0))        |             0
+ (0,0)             | ((3,1),(3,3),(1,0))        |             1
+ (0,0)             | ((1,2),(3,4),(5,6),(7,8))  |  2.2360679775
+ (0,0)             | ((7,8),(5,6),(3,4),(1,2))  |  2.2360679775
+ (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | 1.58113883008
+ (0,0)             | ((0,0))                    |             0
+ (0,0)             | ((0,1),(0,1))              |             1
+ (-10,0)           | ((2,0),(2,4),(0,0))        |            10
+ (-10,0)           | ((3,1),(3,3),(1,0))        |            11
+ (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | 11.1803398875
+ (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | 11.1803398875
+ (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | 11.1803398875
+ (-10,0)           | ((0,0))                    |            10
+ (-10,0)           | ((0,1),(0,1))              | 10.0498756211
+ (-3,4)            | ((2,0),(2,4),(0,0))        |   4.472135955
+ (-3,4)            | ((3,1),(3,3),(1,0))        | 5.54700196225
+ (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  |   4.472135955
+ (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  |   4.472135955
+ (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) |   4.472135955
+ (-3,4)            | ((0,0))                    |             5
+ (-3,4)            | ((0,1),(0,1))              | 4.24264068712
+ (5.1,34.5)        | ((2,0),(2,4),(0,0))        | 30.6571362002
+ (5.1,34.5)        | ((3,1),(3,3),(1,0))        | 31.5699223946
+ (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | 26.5680258958
+ (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | 26.5680258958
+ (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | 26.5680258958
+ (5.1,34.5)        | ((0,0))                    | 34.8749193547
+ (5.1,34.5)        | ((0,1),(0,1))              | 33.8859853037
+ (-5,-12)          | ((2,0),(2,4),(0,0))        |            13
+ (-5,-12)          | ((3,1),(3,3),(1,0))        |  13.416407865
+ (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | 15.2315462117
+ (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | 15.2315462117
+ (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) |  11.313708499
+ (-5,-12)          | ((0,0))                    |            13
+ (-5,-12)          | ((0,1),(0,1))              | 13.9283882772
+ (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        |             0
+ (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        |             1
+ (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  |  2.2360679775
+ (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  |  2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | 1.58113883008
+ (1e-300,-1e-300)  | ((0,0))                    |             0
+ (1e-300,-1e-300)  | ((0,1),(0,1))              |             1
+ (1e+300,Infinity) | ((2,0),(2,4),(0,0))        |      Infinity
+ (1e+300,Infinity) | ((3,1),(3,3),(1,0))        |      Infinity
+ (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  |      Infinity
+ (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  |      Infinity
+ (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) |      Infinity
+ (1e+300,Infinity) | ((0,0))                    |      Infinity
+ (1e+300,Infinity) | ((0,1),(0,1))              |      Infinity
+ (NaN,NaN)         | ((2,0),(2,4),(0,0))        |             0
+ (NaN,NaN)         | ((3,1),(3,3),(1,0))        |             0
+ (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  |             0
+ (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  |             0
+ (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) |             0
+ (NaN,NaN)         | ((0,0))                    |             0
+ (NaN,NaN)         | ((0,1),(0,1))              |             0
+ (10,10)           | ((2,0),(2,4),(0,0))        |            10
+ (10,10)           | ((3,1),(3,3),(1,0))        | 9.89949493661
+ (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | 3.60555127546
+ (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | 3.60555127546
+ (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | 3.60555127546
+ (10,10)           | ((0,0))                    | 14.1421356237
+ (10,10)           | ((0,1),(0,1))              | 13.4536240471
+(63 rows)
+
+-- Closest point to line
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LINE_TBL l;
+        f1         |                   s                   |             ?column?             
+-------------------+---------------------------------------+----------------------------------
+ (0,0)             | {0,-1,5}                              | (0,5)
+ (0,0)             | {1,0,5}                               | (-5,0)
+ (0,0)             | {0,3,0}                               | (0,0)
+ (0,0)             | {1,-1,0}                              | (0,0)
+ (0,0)             | {-0.4,-1,-6}                          | (-2.06896551724,-5.1724137931)
+ (0,0)             | {-0.000184615384615,-1,15.3846153846} | (0.00284023658959,15.3846148603)
+ (0,0)             | {3,NaN,5}                             | 
+ (0,0)             | {NaN,NaN,NaN}                         | 
+ (0,0)             | {0,-1,3}                              | (0,3)
+ (0,0)             | {-1,0,3}                              | (3,0)
+ (-10,0)           | {0,-1,5}                              | (-10,5)
+ (-10,0)           | {1,0,5}                               | (-5,0)
+ (-10,0)           | {0,3,0}                               | (-10,0)
+ (-10,0)           | {1,-1,0}                              | (-5,-5)
+ (-10,0)           | {-0.4,-1,-6}                          | (-10.6896551724,-1.72413793103)
+ (-10,0)           | {-0.000184615384615,-1,15.3846153846} | (-9.99715942258,15.386461014)
+ (-10,0)           | {3,NaN,5}                             | 
+ (-10,0)           | {NaN,NaN,NaN}                         | 
+ (-10,0)           | {0,-1,3}                              | (-10,3)
+ (-10,0)           | {-1,0,3}                              | (3,0)
+ (-3,4)            | {0,-1,5}                              | (-3,5)
+ (-3,4)            | {1,0,5}                               | (-5,4)
+ (-3,4)            | {0,3,0}                               | (-3,0)
+ (-3,4)            | {1,-1,0}                              | (0.5,0.5)
+ (-3,4)            | {-0.4,-1,-6}                          | (-6.03448275862,-3.58620689655)
+ (-3,4)            | {-0.000184615384615,-1,15.3846153846} | (-2.99789812268,15.3851688427)
+ (-3,4)            | {3,NaN,5}                             | 
+ (-3,4)            | {NaN,NaN,NaN}                         | 
+ (-3,4)            | {0,-1,3}                              | (-3,3)
+ (-3,4)            | {-1,0,3}                              | (3,4)
+ (5.1,34.5)        | {0,-1,5}                              | (5.1,5)
+ (5.1,34.5)        | {1,0,5}                               | (-5,34.5)
+ (5.1,34.5)        | {0,3,0}                               | (5.1,0)
+ (5.1,34.5)        | {1,-1,0}                              | (19.8,19.8)
+ (5.1,34.5)        | {-0.4,-1,-6}                          | (-9.56896551724,-2.1724137931)
+ (5.1,34.5)        | {-0.000184615384615,-1,15.3846153846} | (5.09647083221,15.3836744977)
+ (5.1,34.5)        | {3,NaN,5}                             | 
+ (5.1,34.5)        | {NaN,NaN,NaN}                         | 
+ (5.1,34.5)        | {0,-1,3}                              | (5.1,3)
+ (5.1,34.5)        | {-1,0,3}                              | (3,34.5)
+ (-5,-12)          | {0,-1,5}                              | (-5,5)
+ (-5,-12)          | {1,0,5}                               | (-5,-12)
+ (-5,-12)          | {0,3,0}                               | (-5,0)
+ (-5,-12)          | {1,-1,0}                              | (-8.5,-8.5)
+ (-5,-12)          | {-0.4,-1,-6}                          | (-2.24137931034,-5.10344827586)
+ (-5,-12)          | {-0.000184615384615,-1,15.3846153846} | (-4.99494420846,15.3855375282)
+ (-5,-12)          | {3,NaN,5}                             | 
+ (-5,-12)          | {NaN,NaN,NaN}                         | 
+ (-5,-12)          | {0,-1,3}                              | (-5,3)
+ (-5,-12)          | {-1,0,3}                              | (3,-12)
+ (1e-300,-1e-300)  | {0,-1,5}                              | (1e-300,5)
+ (1e-300,-1e-300)  | {1,0,5}                               | (-5,-1e-300)
+ (1e-300,-1e-300)  | {0,3,0}                               | (1e-300,0)
+ (1e-300,-1e-300)  | {1,-1,0}                              | (0,0)
+ (1e-300,-1e-300)  | {-0.4,-1,-6}                          | (-2.06896551724,-5.1724137931)
+ (1e-300,-1e-300)  | {-0.000184615384615,-1,15.3846153846} | (0.00284023658959,15.3846148603)
+ (1e-300,-1e-300)  | {3,NaN,5}                             | 
+ (1e-300,-1e-300)  | {NaN,NaN,NaN}                         | 
+ (1e-300,-1e-300)  | {0,-1,3}                              | (1e-300,3)
+ (1e-300,-1e-300)  | {-1,0,3}                              | (3,-1e-300)
+ (1e+300,Infinity) | {0,-1,5}                              | (1e+300,5)
+ (1e+300,Infinity) | {1,0,5}                               | 
+ (1e+300,Infinity) | {0,3,0}                               | (1e+300,0)
+ (1e+300,Infinity) | {1,-1,0}                              | (Infinity,NaN)
+ (1e+300,Infinity) | {-0.4,-1,-6}                          | (-Infinity,NaN)
+ (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} | (-Infinity,NaN)
+ (1e+300,Infinity) | {3,NaN,5}                             | 
+ (1e+300,Infinity) | {NaN,NaN,NaN}                         | 
+ (1e+300,Infinity) | {0,-1,3}                              | (1e+300,3)
+ (1e+300,Infinity) | {-1,0,3}                              | 
+ (NaN,NaN)         | {0,-1,5}                              | 
+ (NaN,NaN)         | {1,0,5}                               | 
+ (NaN,NaN)         | {0,3,0}                               | 
+ (NaN,NaN)         | {1,-1,0}                              | 
+ (NaN,NaN)         | {-0.4,-1,-6}                          | 
+ (NaN,NaN)         | {-0.000184615384615,-1,15.3846153846} | 
+ (NaN,NaN)         | {3,NaN,5}                             | 
+ (NaN,NaN)         | {NaN,NaN,NaN}                         | 
+ (NaN,NaN)         | {0,-1,3}                              | 
+ (NaN,NaN)         | {-1,0,3}                              | 
+ (10,10)           | {0,-1,5}                              | (10,5)
+ (10,10)           | {1,0,5}                               | (-5,10)
+ (10,10)           | {0,3,0}                               | (10,0)
+ (10,10)           | {1,-1,0}                              | (10,10)
+ (10,10)           | {-0.4,-1,-6}                          | (3.10344827586,-7.24137931034)
+ (10,10)           | {-0.000184615384615,-1,15.3846153846} | (10.000993742,15.3827690473)
+ (10,10)           | {3,NaN,5}                             | 
+ (10,10)           | {NaN,NaN,NaN}                         | 
+ (10,10)           | {0,-1,3}                              | (10,3)
+ (10,10)           | {-1,0,3}                              | (3,10)
+(90 rows)
+
+-- Closest point to line segment
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LSEG_TBL l;
+        f1         |               s               |             ?column?             
+-------------------+-------------------------------+----------------------------------
+ (0,0)             | [(1,2),(3,4)]                 | (1,2)
+ (0,0)             | [(0,0),(6,6)]                 | (0,0)
+ (0,0)             | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ (0,0)             | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
+ (0,0)             | [(11,22),(33,44)]             | (11,22)
+ (0,0)             | [(-10,2),(-10,3)]             | (-10,2)
+ (0,0)             | [(0,-20),(30,-20)]            | (0,-20)
+ (0,0)             | [(NaN,1),(NaN,90)]            | 
+ (-10,0)           | [(1,2),(3,4)]                 | (1,2)
+ (-10,0)           | [(0,0),(6,6)]                 | (0,0)
+ (-10,0)           | [(10,-10),(-3,-4)]            | (-3,-4)
+ (-10,0)           | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
+ (-10,0)           | [(11,22),(33,44)]             | (11,22)
+ (-10,0)           | [(-10,2),(-10,3)]             | (-10,2)
+ (-10,0)           | [(0,-20),(30,-20)]            | (0,-20)
+ (-10,0)           | [(NaN,1),(NaN,90)]            | 
+ (-3,4)            | [(1,2),(3,4)]                 | (1,2)
+ (-3,4)            | [(0,0),(6,6)]                 | (0.5,0.5)
+ (-3,4)            | [(10,-10),(-3,-4)]            | (-3,-4)
+ (-3,4)            | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
+ (-3,4)            | [(11,22),(33,44)]             | (11,22)
+ (-3,4)            | [(-10,2),(-10,3)]             | (-10,3)
+ (-3,4)            | [(0,-20),(30,-20)]            | (0,-20)
+ (-3,4)            | [(NaN,1),(NaN,90)]            | 
+ (5.1,34.5)        | [(1,2),(3,4)]                 | (3,4)
+ (5.1,34.5)        | [(0,0),(6,6)]                 | (6,6)
+ (5.1,34.5)        | [(10,-10),(-3,-4)]            | (-3,-4)
+ (5.1,34.5)        | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
+ (5.1,34.5)        | [(11,22),(33,44)]             | (14.3,25.3)
+ (5.1,34.5)        | [(-10,2),(-10,3)]             | (-10,3)
+ (5.1,34.5)        | [(0,-20),(30,-20)]            | (5.1,-20)
+ (5.1,34.5)        | [(NaN,1),(NaN,90)]            | 
+ (-5,-12)          | [(1,2),(3,4)]                 | (1,2)
+ (-5,-12)          | [(0,0),(6,6)]                 | (0,0)
+ (-5,-12)          | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
+ (-5,-12)          | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
+ (-5,-12)          | [(11,22),(33,44)]             | (11,22)
+ (-5,-12)          | [(-10,2),(-10,3)]             | (-10,2)
+ (-5,-12)          | [(0,-20),(30,-20)]            | (0,-20)
+ (-5,-12)          | [(NaN,1),(NaN,90)]            | 
+ (1e-300,-1e-300)  | [(1,2),(3,4)]                 | (1,2)
+ (1e-300,-1e-300)  | [(0,0),(6,6)]                 | (0,0)
+ (1e-300,-1e-300)  | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ (1e-300,-1e-300)  | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
+ (1e-300,-1e-300)  | [(11,22),(33,44)]             | (11,22)
+ (1e-300,-1e-300)  | [(-10,2),(-10,3)]             | (-10,2)
+ (1e-300,-1e-300)  | [(0,-20),(30,-20)]            | (0,-20)
+ (1e-300,-1e-300)  | [(NaN,1),(NaN,90)]            | 
+ (1e+300,Infinity) | [(1,2),(3,4)]                 | (3,4)
+ (1e+300,Infinity) | [(0,0),(6,6)]                 | (6,6)
+ (1e+300,Infinity) | [(10,-10),(-3,-4)]            | (-3,-4)
+ (1e+300,Infinity) | [(-1000000,200),(300000,-40)] | (300000,-40)
+ (1e+300,Infinity) | [(11,22),(33,44)]             | (33,44)
+ (1e+300,Infinity) | [(-10,2),(-10,3)]             | (-10,3)
+ (1e+300,Infinity) | [(0,-20),(30,-20)]            | (30,-20)
+ (1e+300,Infinity) | [(NaN,1),(NaN,90)]            | (NaN,90)
+ (NaN,NaN)         | [(1,2),(3,4)]                 | 
+ (NaN,NaN)         | [(0,0),(6,6)]                 | 
+ (NaN,NaN)         | [(10,-10),(-3,-4)]            | 
+ (NaN,NaN)         | [(-1000000,200),(300000,-40)] | 
+ (NaN,NaN)         | [(11,22),(33,44)]             | 
+ (NaN,NaN)         | [(-10,2),(-10,3)]             | 
+ (NaN,NaN)         | [(0,-20),(30,-20)]            | 
+ (NaN,NaN)         | [(NaN,1),(NaN,90)]            | 
+ (10,10)           | [(1,2),(3,4)]                 | (3,4)
+ (10,10)           | [(0,0),(6,6)]                 | (6,6)
+ (10,10)           | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
+ (10,10)           | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
+ (10,10)           | [(11,22),(33,44)]             | (11,22)
+ (10,10)           | [(-10,2),(-10,3)]             | (-10,3)
+ (10,10)           | [(0,-20),(30,-20)]            | (10,-20)
+ (10,10)           | [(NaN,1),(NaN,90)]            | 
+(72 rows)
+
+-- Closest point to box
+SELECT p.f1, b.f1, p.f1 ## b.f1 FROM POINT_TBL p, BOX_TBL b;
+        f1         |         f1          |   ?column?   
+-------------------+---------------------+--------------
+ (0,0)             | (2,2),(0,0)         | (0,0)
+ (0,0)             | (3,3),(1,1)         | (1,1)
+ (0,0)             | (-2,2),(-8,-10)     | (-2,0)
+ (0,0)             | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (0,0)             | (3,3),(3,3)         | (3,3)
+ (-10,0)           | (2,2),(0,0)         | (0,0)
+ (-10,0)           | (3,3),(1,1)         | (1,1)
+ (-10,0)           | (-2,2),(-8,-10)     | (-8,0)
+ (-10,0)           | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (-10,0)           | (3,3),(3,3)         | (3,3)
+ (-3,4)            | (2,2),(0,0)         | (0,2)
+ (-3,4)            | (3,3),(1,1)         | (1,3)
+ (-3,4)            | (-2,2),(-8,-10)     | (-3,2)
+ (-3,4)            | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (-3,4)            | (3,3),(3,3)         | (3,3)
+ (5.1,34.5)        | (2,2),(0,0)         | (2,2)
+ (5.1,34.5)        | (3,3),(1,1)         | (3,3)
+ (5.1,34.5)        | (-2,2),(-8,-10)     | (-2,2)
+ (5.1,34.5)        | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (5.1,34.5)        | (3,3),(3,3)         | (3,3)
+ (-5,-12)          | (2,2),(0,0)         | (0,0)
+ (-5,-12)          | (3,3),(1,1)         | (1,1)
+ (-5,-12)          | (-2,2),(-8,-10)     | (-5,-10)
+ (-5,-12)          | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (-5,-12)          | (3,3),(3,3)         | (3,3)
+ (1e-300,-1e-300)  | (2,2),(0,0)         | (0,0)
+ (1e-300,-1e-300)  | (3,3),(1,1)         | (1,1)
+ (1e-300,-1e-300)  | (-2,2),(-8,-10)     | (-2,-1e-300)
+ (1e-300,-1e-300)  | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (1e-300,-1e-300)  | (3,3),(3,3)         | (3,3)
+ (1e+300,Infinity) | (2,2),(0,0)         | (0,2)
+ (1e+300,Infinity) | (3,3),(1,1)         | (1,3)
+ (1e+300,Infinity) | (-2,2),(-8,-10)     | (-8,2)
+ (1e+300,Infinity) | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (1e+300,Infinity) | (3,3),(3,3)         | (3,3)
+ (NaN,NaN)         | (2,2),(0,0)         | 
+ (NaN,NaN)         | (3,3),(1,1)         | 
+ (NaN,NaN)         | (-2,2),(-8,-10)     | 
+ (NaN,NaN)         | (2.5,3.5),(2.5,2.5) | 
+ (NaN,NaN)         | (3,3),(3,3)         | 
+ (10,10)           | (2,2),(0,0)         | (2,2)
+ (10,10)           | (3,3),(1,1)         | (3,3)
+ (10,10)           | (-2,2),(-8,-10)     | (-2,2)
+ (10,10)           | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (10,10)           | (3,3),(3,3)         | (3,3)
+(45 rows)
+
+-- On line
+SELECT p.f1, l.s FROM POINT_TBL p, LINE_TBL l WHERE p.f1 <@ l.s;
+        f1        |    s     
+------------------+----------
+ (0,0)            | {0,3,0}
+ (0,0)            | {1,-1,0}
+ (-10,0)          | {0,3,0}
+ (-5,-12)         | {1,0,5}
+ (1e-300,-1e-300) | {0,3,0}
+ (1e-300,-1e-300) | {1,-1,0}
+ (10,10)          | {1,-1,0}
+(7 rows)
+
+-- On line segment
+SELECT p.f1, l.s FROM POINT_TBL p, LSEG_TBL l WHERE p.f1 <@ l.s;
+        f1        |       s       
+------------------+---------------
+ (0,0)            | [(0,0),(6,6)]
+ (1e-300,-1e-300) | [(0,0),(6,6)]
+(2 rows)
+
+-- On path
+SELECT p.f1, p1.f1 FROM POINT_TBL p, PATH_TBL p1 WHERE p.f1 <@ p1.f1;
+        f1        |            f1             
+------------------+---------------------------
+ (0,0)            | [(0,0),(3,0),(4,5),(1,6)]
+ (1e-300,-1e-300) | [(0,0),(3,0),(4,5),(1,6)]
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((10,20))
+ (NaN,NaN)        | ((11,12),(13,14))
+(7 rows)
+
+--
+-- Lines
+--
+-- Vertical
+SELECT s FROM LINE_TBL WHERE ?| s;
+    s     
+----------
+ {1,0,5}
+ {-1,0,3}
+(2 rows)
+
+-- Horizontal
+SELECT s FROM LINE_TBL WHERE ?- s;
+    s     
+----------
+ {0,-1,5}
+ {0,3,0}
+ {0,-1,3}
+(3 rows)
+
+-- Same as line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s = l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {0,-1,5}
+ {1,0,5}                               | {1,0,5}
+ {0,3,0}                               | {0,3,0}
+ {1,-1,0}                              | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846}
+ {3,NaN,5}                             | {3,NaN,5}
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}
+ {0,-1,3}                              | {0,-1,3}
+ {-1,0,3}                              | {-1,0,3}
+(10 rows)
+
+-- Parallel to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?|| l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {0,-1,5}
+ {0,-1,5}                              | {0,3,0}
+ {0,-1,5}                              | {0,-1,3}
+ {1,0,5}                               | {1,0,5}
+ {1,0,5}                               | {-1,0,3}
+ {0,3,0}                               | {0,-1,5}
+ {0,3,0}                               | {0,3,0}
+ {0,3,0}                               | {0,-1,3}
+ {1,-1,0}                              | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,3}                              | {0,-1,5}
+ {0,-1,3}                              | {0,3,0}
+ {0,-1,3}                              | {0,-1,3}
+ {-1,0,3}                              | {1,0,5}
+ {-1,0,3}                              | {-1,0,3}
+(16 rows)
+
+-- Perpendicular to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?-| l2.s;
+    s     |    s     
+----------+----------
+ {0,-1,5} | {1,0,5}
+ {0,-1,5} | {-1,0,3}
+ {1,0,5}  | {0,-1,5}
+ {1,0,5}  | {0,3,0}
+ {1,0,5}  | {0,-1,3}
+ {0,3,0}  | {1,0,5}
+ {0,3,0}  | {-1,0,3}
+ {0,-1,3} | {1,0,5}
+ {0,-1,3} | {-1,0,3}
+ {-1,0,3} | {0,-1,5}
+ {-1,0,3} | {0,3,0}
+ {-1,0,3} | {0,-1,3}
+(12 rows)
+
+-- Distance to line
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2;
+                   s                   |                   s                   | ?column? 
+---------------------------------------+---------------------------------------+----------
+ {0,-1,5}                              | {0,-1,5}                              |        0
+ {0,-1,5}                              | {1,0,5}                               |        0
+ {0,-1,5}                              | {0,3,0}                               |        5
+ {0,-1,5}                              | {1,-1,0}                              |        0
+ {0,-1,5}                              | {-0.4,-1,-6}                          |        0
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,-1,5}                              | {3,NaN,5}                             |        0
+ {0,-1,5}                              | {NaN,NaN,NaN}                         |        0
+ {0,-1,5}                              | {0,-1,3}                              |        2
+ {0,-1,5}                              | {-1,0,3}                              |        0
+ {1,0,5}                               | {0,-1,5}                              |        0
+ {1,0,5}                               | {1,0,5}                               |        0
+ {1,0,5}                               | {0,3,0}                               |        0
+ {1,0,5}                               | {1,-1,0}                              |        0
+ {1,0,5}                               | {-0.4,-1,-6}                          |        0
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846} |        0
+ {1,0,5}                               | {3,NaN,5}                             |        0
+ {1,0,5}                               | {NaN,NaN,NaN}                         |        0
+ {1,0,5}                               | {0,-1,3}                              |        0
+ {1,0,5}                               | {-1,0,3}                              |        8
+ {0,3,0}                               | {0,-1,5}                              |        5
+ {0,3,0}                               | {1,0,5}                               |        0
+ {0,3,0}                               | {0,3,0}                               |        0
+ {0,3,0}                               | {1,-1,0}                              |        0
+ {0,3,0}                               | {-0.4,-1,-6}                          |        0
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,3,0}                               | {3,NaN,5}                             |        0
+ {0,3,0}                               | {NaN,NaN,NaN}                         |        0
+ {0,3,0}                               | {0,-1,3}                              |        3
+ {0,3,0}                               | {-1,0,3}                              |        0
+ {1,-1,0}                              | {0,-1,5}                              |        0
+ {1,-1,0}                              | {1,0,5}                               |        0
+ {1,-1,0}                              | {0,3,0}                               |        0
+ {1,-1,0}                              | {1,-1,0}                              |        0
+ {1,-1,0}                              | {-0.4,-1,-6}                          |        0
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {1,-1,0}                              | {3,NaN,5}                             |        0
+ {1,-1,0}                              | {NaN,NaN,NaN}                         |        0
+ {1,-1,0}                              | {0,-1,3}                              |        0
+ {1,-1,0}                              | {-1,0,3}                              |        0
+ {-0.4,-1,-6}                          | {0,-1,5}                              |        0
+ {-0.4,-1,-6}                          | {1,0,5}                               |        0
+ {-0.4,-1,-6}                          | {0,3,0}                               |        0
+ {-0.4,-1,-6}                          | {1,-1,0}                              |        0
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}                          |        0
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846} |        0
+ {-0.4,-1,-6}                          | {3,NaN,5}                             |        0
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}                         |        0
+ {-0.4,-1,-6}                          | {0,-1,3}                              |        0
+ {-0.4,-1,-6}                          | {-1,0,3}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}                               |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}                               |        0
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}                          |        0
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} |        0
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}                             |        0
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}                         |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}                              |        0
+ {3,NaN,5}                             | {0,-1,5}                              |        0
+ {3,NaN,5}                             | {1,0,5}                               |        0
+ {3,NaN,5}                             | {0,3,0}                               |        0
+ {3,NaN,5}                             | {1,-1,0}                              |        0
+ {3,NaN,5}                             | {-0.4,-1,-6}                          |        0
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846} |        0
+ {3,NaN,5}                             | {3,NaN,5}                             |        0
+ {3,NaN,5}                             | {NaN,NaN,NaN}                         |        0
+ {3,NaN,5}                             | {0,-1,3}                              |        0
+ {3,NaN,5}                             | {-1,0,3}                              |        0
+ {NaN,NaN,NaN}                         | {0,-1,5}                              |        0
+ {NaN,NaN,NaN}                         | {1,0,5}                               |        0
+ {NaN,NaN,NaN}                         | {0,3,0}                               |        0
+ {NaN,NaN,NaN}                         | {1,-1,0}                              |        0
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}                          |        0
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846} |        0
+ {NaN,NaN,NaN}                         | {3,NaN,5}                             |        0
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}                         |        0
+ {NaN,NaN,NaN}                         | {0,-1,3}                              |        0
+ {NaN,NaN,NaN}                         | {-1,0,3}                              |        0
+ {0,-1,3}                              | {0,-1,5}                              |        2
+ {0,-1,3}                              | {1,0,5}                               |        0
+ {0,-1,3}                              | {0,3,0}                               |        3
+ {0,-1,3}                              | {1,-1,0}                              |        0
+ {0,-1,3}                              | {-0.4,-1,-6}                          |        0
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,-1,3}                              | {3,NaN,5}                             |        0
+ {0,-1,3}                              | {NaN,NaN,NaN}                         |        0
+ {0,-1,3}                              | {0,-1,3}                              |        0
+ {0,-1,3}                              | {-1,0,3}                              |        0
+ {-1,0,3}                              | {0,-1,5}                              |        0
+ {-1,0,3}                              | {1,0,5}                               |        8
+ {-1,0,3}                              | {0,3,0}                               |        0
+ {-1,0,3}                              | {1,-1,0}                              |        0
+ {-1,0,3}                              | {-0.4,-1,-6}                          |        0
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {-1,0,3}                              | {3,NaN,5}                             |        0
+ {-1,0,3}                              | {NaN,NaN,NaN}                         |        0
+ {-1,0,3}                              | {0,-1,3}                              |        0
+ {-1,0,3}                              | {-1,0,3}                              |        0
+(100 rows)
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LINE_TBL l, BOX_TBL b;
+ERROR:  function "dist_lb" not implemented
+-- Intersect with line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?# l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {1,0,5}
+ {0,-1,5}                              | {1,-1,0}
+ {0,-1,5}                              | {-0.4,-1,-6}
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,5}                              | {3,NaN,5}
+ {0,-1,5}                              | {NaN,NaN,NaN}
+ {0,-1,5}                              | {-1,0,3}
+ {1,0,5}                               | {0,-1,5}
+ {1,0,5}                               | {0,3,0}
+ {1,0,5}                               | {1,-1,0}
+ {1,0,5}                               | {-0.4,-1,-6}
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846}
+ {1,0,5}                               | {3,NaN,5}
+ {1,0,5}                               | {NaN,NaN,NaN}
+ {1,0,5}                               | {0,-1,3}
+ {0,3,0}                               | {1,0,5}
+ {0,3,0}                               | {1,-1,0}
+ {0,3,0}                               | {-0.4,-1,-6}
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846}
+ {0,3,0}                               | {3,NaN,5}
+ {0,3,0}                               | {NaN,NaN,NaN}
+ {0,3,0}                               | {-1,0,3}
+ {1,-1,0}                              | {0,-1,5}
+ {1,-1,0}                              | {1,0,5}
+ {1,-1,0}                              | {0,3,0}
+ {1,-1,0}                              | {-0.4,-1,-6}
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846}
+ {1,-1,0}                              | {3,NaN,5}
+ {1,-1,0}                              | {NaN,NaN,NaN}
+ {1,-1,0}                              | {0,-1,3}
+ {1,-1,0}                              | {-1,0,3}
+ {-0.4,-1,-6}                          | {0,-1,5}
+ {-0.4,-1,-6}                          | {1,0,5}
+ {-0.4,-1,-6}                          | {0,3,0}
+ {-0.4,-1,-6}                          | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846}
+ {-0.4,-1,-6}                          | {3,NaN,5}
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}
+ {-0.4,-1,-6}                          | {0,-1,3}
+ {-0.4,-1,-6}                          | {-1,0,3}
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}
+ {3,NaN,5}                             | {0,-1,5}
+ {3,NaN,5}                             | {1,0,5}
+ {3,NaN,5}                             | {0,3,0}
+ {3,NaN,5}                             | {1,-1,0}
+ {3,NaN,5}                             | {-0.4,-1,-6}
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846}
+ {3,NaN,5}                             | {3,NaN,5}
+ {3,NaN,5}                             | {NaN,NaN,NaN}
+ {3,NaN,5}                             | {0,-1,3}
+ {3,NaN,5}                             | {-1,0,3}
+ {NaN,NaN,NaN}                         | {0,-1,5}
+ {NaN,NaN,NaN}                         | {1,0,5}
+ {NaN,NaN,NaN}                         | {0,3,0}
+ {NaN,NaN,NaN}                         | {1,-1,0}
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846}
+ {NaN,NaN,NaN}                         | {3,NaN,5}
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}
+ {NaN,NaN,NaN}                         | {0,-1,3}
+ {NaN,NaN,NaN}                         | {-1,0,3}
+ {0,-1,3}                              | {1,0,5}
+ {0,-1,3}                              | {1,-1,0}
+ {0,-1,3}                              | {-0.4,-1,-6}
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,3}                              | {3,NaN,5}
+ {0,-1,3}                              | {NaN,NaN,NaN}
+ {0,-1,3}                              | {-1,0,3}
+ {-1,0,3}                              | {0,-1,5}
+ {-1,0,3}                              | {0,3,0}
+ {-1,0,3}                              | {1,-1,0}
+ {-1,0,3}                              | {-0.4,-1,-6}
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846}
+ {-1,0,3}                              | {3,NaN,5}
+ {-1,0,3}                              | {NaN,NaN,NaN}
+ {-1,0,3}                              | {0,-1,3}
+(84 rows)
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LINE_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+      s       |         f1          
+--------------+---------------------
+ {1,0,5}      | (-2,2),(-8,-10)
+ {0,3,0}      | (2,2),(0,0)
+ {0,3,0}      | (-2,2),(-8,-10)
+ {1,-1,0}     | (2,2),(0,0)
+ {1,-1,0}     | (3,3),(1,1)
+ {1,-1,0}     | (-2,2),(-8,-10)
+ {1,-1,0}     | (2.5,3.5),(2.5,2.5)
+ {1,-1,0}     | (3,3),(3,3)
+ {-0.4,-1,-6} | (-2,2),(-8,-10)
+ {0,-1,3}     | (3,3),(1,1)
+ {0,-1,3}     | (2.5,3.5),(2.5,2.5)
+ {0,-1,3}     | (3,3),(3,3)
+ {-1,0,3}     | (3,3),(1,1)
+(13 rows)
+
+-- Intersection point with line
+SELECT l1.s, l2.s, l1.s # l2.s FROM LINE_TBL l1, LINE_TBL l2;
+                   s                   |                   s                   |             ?column?              
+---------------------------------------+---------------------------------------+------------------------------------
+ {0,-1,5}                              | {0,-1,5}                              | 
+ {0,-1,5}                              | {1,0,5}                               | (-5,5)
+ {0,-1,5}                              | {0,3,0}                               | 
+ {0,-1,5}                              | {1,-1,0}                              | (5,5)
+ {0,-1,5}                              | {-0.4,-1,-6}                          | (-27.5,5)
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846} | (56250,5)
+ {0,-1,5}                              | {3,NaN,5}                             | (NaN,NaN)
+ {0,-1,5}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,-1,5}                              | {0,-1,3}                              | 
+ {0,-1,5}                              | {-1,0,3}                              | (3,5)
+ {1,0,5}                               | {0,-1,5}                              | (-5,5)
+ {1,0,5}                               | {1,0,5}                               | 
+ {1,0,5}                               | {0,3,0}                               | (-5,0)
+ {1,0,5}                               | {1,-1,0}                              | (-5,-5)
+ {1,0,5}                               | {-0.4,-1,-6}                          | (-5,-4)
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846} | (-5,15.3855384615)
+ {1,0,5}                               | {3,NaN,5}                             | (NaN,NaN)
+ {1,0,5}                               | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {1,0,5}                               | {0,-1,3}                              | (-5,3)
+ {1,0,5}                               | {-1,0,3}                              | 
+ {0,3,0}                               | {0,-1,5}                              | 
+ {0,3,0}                               | {1,0,5}                               | (-5,0)
+ {0,3,0}                               | {0,3,0}                               | 
+ {0,3,0}                               | {1,-1,0}                              | (0,0)
+ {0,3,0}                               | {-0.4,-1,-6}                          | (-15,0)
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846} | (83333.3333333,0)
+ {0,3,0}                               | {3,NaN,5}                             | (NaN,NaN)
+ {0,3,0}                               | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,3,0}                               | {0,-1,3}                              | 
+ {0,3,0}                               | {-1,0,3}                              | (3,0)
+ {1,-1,0}                              | {0,-1,5}                              | (5,5)
+ {1,-1,0}                              | {1,0,5}                               | (-5,-5)
+ {1,-1,0}                              | {0,3,0}                               | (0,0)
+ {1,-1,0}                              | {1,-1,0}                              | 
+ {1,-1,0}                              | {-0.4,-1,-6}                          | (-4.28571428571,-4.28571428571)
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846} | (15.3817756722,15.3817756722)
+ {1,-1,0}                              | {3,NaN,5}                             | (NaN,NaN)
+ {1,-1,0}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {1,-1,0}                              | {0,-1,3}                              | (3,3)
+ {1,-1,0}                              | {-1,0,3}                              | (3,3)
+ {-0.4,-1,-6}                          | {0,-1,5}                              | (-27.5,5)
+ {-0.4,-1,-6}                          | {1,0,5}                               | (-5,-4)
+ {-0.4,-1,-6}                          | {0,3,0}                               | (-15,0)
+ {-0.4,-1,-6}                          | {1,-1,0}                              | (-4.28571428571,-4.28571428571)
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}                          | 
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846} | (-53.4862244113,15.3944897645)
+ {-0.4,-1,-6}                          | {3,NaN,5}                             | (NaN,NaN)
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-0.4,-1,-6}                          | {0,-1,3}                              | (-22.5,3)
+ {-0.4,-1,-6}                          | {-1,0,3}                              | (3,-7.2)
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}                              | (56250,5)
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}                               | (-5,15.3855384615)
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}                               | (83333.3333333,-1.7763568394e-015)
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}                              | (15.3817756722,15.3817756722)
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}                          | (-53.4862244113,15.3944897645)
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} | 
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}                             | (NaN,NaN)
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}                              | (67083.3333333,3)
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}                              | (3,15.3840615385)
+ {3,NaN,5}                             | {0,-1,5}                              | (NaN,NaN)
+ {3,NaN,5}                             | {1,0,5}                               | (NaN,NaN)
+ {3,NaN,5}                             | {0,3,0}                               | (NaN,NaN)
+ {3,NaN,5}                             | {1,-1,0}                              | (NaN,NaN)
+ {3,NaN,5}                             | {-0.4,-1,-6}                          | (NaN,NaN)
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ {3,NaN,5}                             | {3,NaN,5}                             | (NaN,NaN)
+ {3,NaN,5}                             | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {3,NaN,5}                             | {0,-1,3}                              | (NaN,NaN)
+ {3,NaN,5}                             | {-1,0,3}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,-1,5}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {1,0,5}                               | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,3,0}                               | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {1,-1,0}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}                          | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {3,NaN,5}                             | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,-1,3}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-1,0,3}                              | (NaN,NaN)
+ {0,-1,3}                              | {0,-1,5}                              | 
+ {0,-1,3}                              | {1,0,5}                               | (-5,3)
+ {0,-1,3}                              | {0,3,0}                               | 
+ {0,-1,3}                              | {1,-1,0}                              | (3,3)
+ {0,-1,3}                              | {-0.4,-1,-6}                          | (-22.5,3)
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846} | (67083.3333333,3)
+ {0,-1,3}                              | {3,NaN,5}                             | (NaN,NaN)
+ {0,-1,3}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,-1,3}                              | {0,-1,3}                              | 
+ {0,-1,3}                              | {-1,0,3}                              | (3,3)
+ {-1,0,3}                              | {0,-1,5}                              | (3,5)
+ {-1,0,3}                              | {1,0,5}                               | 
+ {-1,0,3}                              | {0,3,0}                               | (3,0)
+ {-1,0,3}                              | {1,-1,0}                              | (3,3)
+ {-1,0,3}                              | {-0.4,-1,-6}                          | (3,-7.2)
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846} | (3,15.3840615385)
+ {-1,0,3}                              | {3,NaN,5}                             | (NaN,NaN)
+ {-1,0,3}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-1,0,3}                              | {0,-1,3}                              | (3,3)
+ {-1,0,3}                              | {-1,0,3}                              | 
+(100 rows)
+
+-- Closest point to line segment
+SELECT l.s, l1.s, l.s ## l1.s FROM LINE_TBL l, LSEG_TBL l1;
+                   s                   |               s               |             ?column?              
+---------------------------------------+-------------------------------+------------------------------------
+ {0,-1,5}                              | [(1,2),(3,4)]                 | (3,4)
+ {0,-1,5}                              | [(0,0),(6,6)]                 | (5,5)
+ {0,-1,5}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,-1,5}                              | [(-1000000,200),(300000,-40)] | (56250,5)
+ {0,-1,5}                              | [(11,22),(33,44)]             | (11,22)
+ {0,-1,5}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {0,-1,5}                              | [(0,-20),(30,-20)]            | 
+ {0,-1,5}                              | [(NaN,1),(NaN,90)]            | 
+ {1,0,5}                               | [(1,2),(3,4)]                 | (1,2)
+ {1,0,5}                               | [(0,0),(6,6)]                 | (0,0)
+ {1,0,5}                               | [(10,-10),(-3,-4)]            | (-3,-4)
+ {1,0,5}                               | [(-1000000,200),(300000,-40)] | (-5,15.3855384615)
+ {1,0,5}                               | [(11,22),(33,44)]             | (11,22)
+ {1,0,5}                               | [(-10,2),(-10,3)]             | 
+ {1,0,5}                               | [(0,-20),(30,-20)]            | (0,-20)
+ {1,0,5}                               | [(NaN,1),(NaN,90)]            | 
+ {0,3,0}                               | [(1,2),(3,4)]                 | (1,2)
+ {0,3,0}                               | [(0,0),(6,6)]                 | (0,0)
+ {0,3,0}                               | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,3,0}                               | [(-1000000,200),(300000,-40)] | (83333.3333333,-1.7763568394e-015)
+ {0,3,0}                               | [(11,22),(33,44)]             | (11,22)
+ {0,3,0}                               | [(-10,2),(-10,3)]             | (-10,2)
+ {0,3,0}                               | [(0,-20),(30,-20)]            | 
+ {0,3,0}                               | [(NaN,1),(NaN,90)]            | 
+ {1,-1,0}                              | [(1,2),(3,4)]                 | 
+ {1,-1,0}                              | [(0,0),(6,6)]                 | 
+ {1,-1,0}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {1,-1,0}                              | [(-1000000,200),(300000,-40)] | (15.3817756722,15.3817756722)
+ {1,-1,0}                              | [(11,22),(33,44)]             | 
+ {1,-1,0}                              | [(-10,2),(-10,3)]             | (-10,2)
+ {1,-1,0}                              | [(0,-20),(30,-20)]            | (0,-20)
+ {1,-1,0}                              | [(NaN,1),(NaN,90)]            | 
+ {-0.4,-1,-6}                          | [(1,2),(3,4)]                 | (1,2)
+ {-0.4,-1,-6}                          | [(0,0),(6,6)]                 | (0,0)
+ {-0.4,-1,-6}                          | [(10,-10),(-3,-4)]            | (10,-10)
+ {-0.4,-1,-6}                          | [(-1000000,200),(300000,-40)] | (-53.4862244113,15.3944897645)
+ {-0.4,-1,-6}                          | [(11,22),(33,44)]             | (11,22)
+ {-0.4,-1,-6}                          | [(-10,2),(-10,3)]             | (-10,2)
+ {-0.4,-1,-6}                          | [(0,-20),(30,-20)]            | (30,-20)
+ {-0.4,-1,-6}                          | [(NaN,1),(NaN,90)]            | 
+ {-0.000184615384615,-1,15.3846153846} | [(1,2),(3,4)]                 | (3,4)
+ {-0.000184615384615,-1,15.3846153846} | [(0,0),(6,6)]                 | (6,6)
+ {-0.000184615384615,-1,15.3846153846} | [(10,-10),(-3,-4)]            | (-3,-4)
+ {-0.000184615384615,-1,15.3846153846} | [(-1000000,200),(300000,-40)] | 
+ {-0.000184615384615,-1,15.3846153846} | [(11,22),(33,44)]             | (11,22)
+ {-0.000184615384615,-1,15.3846153846} | [(-10,2),(-10,3)]             | (-10,3)
+ {-0.000184615384615,-1,15.3846153846} | [(0,-20),(30,-20)]            | (30,-20)
+ {-0.000184615384615,-1,15.3846153846} | [(NaN,1),(NaN,90)]            | 
+ {3,NaN,5}                             | [(1,2),(3,4)]                 | 
+ {3,NaN,5}                             | [(0,0),(6,6)]                 | 
+ {3,NaN,5}                             | [(10,-10),(-3,-4)]            | 
+ {3,NaN,5}                             | [(-1000000,200),(300000,-40)] | 
+ {3,NaN,5}                             | [(11,22),(33,44)]             | 
+ {3,NaN,5}                             | [(-10,2),(-10,3)]             | 
+ {3,NaN,5}                             | [(0,-20),(30,-20)]            | 
+ {3,NaN,5}                             | [(NaN,1),(NaN,90)]            | 
+ {NaN,NaN,NaN}                         | [(1,2),(3,4)]                 | 
+ {NaN,NaN,NaN}                         | [(0,0),(6,6)]                 | 
+ {NaN,NaN,NaN}                         | [(10,-10),(-3,-4)]            | 
+ {NaN,NaN,NaN}                         | [(-1000000,200),(300000,-40)] | 
+ {NaN,NaN,NaN}                         | [(11,22),(33,44)]             | 
+ {NaN,NaN,NaN}                         | [(-10,2),(-10,3)]             | 
+ {NaN,NaN,NaN}                         | [(0,-20),(30,-20)]            | 
+ {NaN,NaN,NaN}                         | [(NaN,1),(NaN,90)]            | 
+ {0,-1,3}                              | [(1,2),(3,4)]                 | (2,3)
+ {0,-1,3}                              | [(0,0),(6,6)]                 | (3,3)
+ {0,-1,3}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,-1,3}                              | [(-1000000,200),(300000,-40)] | (67083.3333333,3)
+ {0,-1,3}                              | [(11,22),(33,44)]             | (11,22)
+ {0,-1,3}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {0,-1,3}                              | [(0,-20),(30,-20)]            | 
+ {0,-1,3}                              | [(NaN,1),(NaN,90)]            | 
+ {-1,0,3}                              | [(1,2),(3,4)]                 | (3,4)
+ {-1,0,3}                              | [(0,0),(6,6)]                 | (3,3)
+ {-1,0,3}                              | [(10,-10),(-3,-4)]            | (3,-6.76923076923)
+ {-1,0,3}                              | [(-1000000,200),(300000,-40)] | (3,15.3840615385)
+ {-1,0,3}                              | [(11,22),(33,44)]             | (11,22)
+ {-1,0,3}                              | [(-10,2),(-10,3)]             | 
+ {-1,0,3}                              | [(0,-20),(30,-20)]            | (3,-20)
+ {-1,0,3}                              | [(NaN,1),(NaN,90)]            | 
+(80 rows)
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LINE_TBL l, BOX_TBL b;
+ERROR:  function "close_lb" not implemented
 --
 -- Line segments
 --
 -- intersection
 SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
    FROM LSEG_TBL l, POINT_TBL p;
 ERROR:  operator does not exist: lseg # point
 LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
                                            ^
 HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
+-- Length
+SELECT s, @-@ s FROM LSEG_TBL;
+               s               |   ?column?    
+-------------------------------+---------------
+ [(1,2),(3,4)]                 | 2.82842712475
+ [(0,0),(6,6)]                 | 8.48528137424
+ [(10,-10),(-3,-4)]            | 14.3178210633
+ [(-1000000,200),(300000,-40)] | 1300000.02215
+ [(11,22),(33,44)]             | 31.1126983722
+ [(-10,2),(-10,3)]             |             1
+ [(0,-20),(30,-20)]            |            30
+ [(NaN,1),(NaN,90)]            |           NaN
+(8 rows)
+
+-- Vertical
+SELECT s FROM LSEG_TBL WHERE ?| s;
+         s         
+-------------------
+ [(-10,2),(-10,3)]
+(1 row)
+
+-- Horizontal
+SELECT s FROM LSEG_TBL WHERE ?- s;
+         s          
+--------------------
+ [(0,-20),(30,-20)]
+(1 row)
+
+-- Center
+SELECT s, @@ s FROM LSEG_TBL;
+               s               |   ?column?   
+-------------------------------+--------------
+ [(1,2),(3,4)]                 | (2,3)
+ [(0,0),(6,6)]                 | (3,3)
+ [(10,-10),(-3,-4)]            | (3.5,-7)
+ [(-1000000,200),(300000,-40)] | (-350000,80)
+ [(11,22),(33,44)]             | (22,33)
+ [(-10,2),(-10,3)]             | (-10,2.5)
+ [(0,-20),(30,-20)]            | (15,-20)
+ [(NaN,1),(NaN,90)]            | (NaN,45.5)
+(8 rows)
+
+-- To point
+SELECT s, s::point FROM LSEG_TBL;
+               s               |      s       
+-------------------------------+--------------
+ [(1,2),(3,4)]                 | (2,3)
+ [(0,0),(6,6)]                 | (3,3)
+ [(10,-10),(-3,-4)]            | (3.5,-7)
+ [(-1000000,200),(300000,-40)] | (-350000,80)
+ [(11,22),(33,44)]             | (22,33)
+ [(-10,2),(-10,3)]             | (-10,2.5)
+ [(0,-20),(30,-20)]            | (15,-20)
+ [(NaN,1),(NaN,90)]            | (NaN,45.5)
+(8 rows)
+
+-- Has points less than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s < l2.s;
+         s          |               s               
+--------------------+-------------------------------
+ [(1,2),(3,4)]      | [(0,0),(6,6)]
+ [(1,2),(3,4)]      | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]      | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]      | [(11,22),(33,44)]
+ [(1,2),(3,4)]      | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]      | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]      | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]      | [(11,22),(33,44)]
+ [(0,0),(6,6)]      | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)] | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)] | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]  | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]  | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]  | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]  | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]  | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]  | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]  | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)] | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)] | [(11,22),(33,44)]
+(21 rows)
+
+-- Has points less than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s <= l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(28 rows)
+
+-- Has points equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s = l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]
+(8 rows)
+
+-- Has points greater than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s >= l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(28 rows)
+
+-- Has points greater than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s > l2.s;
+               s               |         s          
+-------------------------------+--------------------
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+(21 rows)
+
+-- Has points not equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s != l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)]
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]
+(56 rows)
+
+-- Parallel with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?|| l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(13 rows)
+
+-- Perpendicular with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?-| l2.s;
+         s          |         s          
+--------------------+--------------------
+ [(-10,2),(-10,3)]  | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)] | [(-10,2),(-10,3)]
+(2 rows)
+
+-- Distance to line
+SELECT l.s, l1.s, l.s <-> l1.s FROM LSEG_TBL l, LINE_TBL l1;
+               s               |                   s                   |    ?column?    
+-------------------------------+---------------------------------------+----------------
+ [(1,2),(3,4)]                 | {0,-1,5}                              |              1
+ [(0,0),(6,6)]                 | {0,-1,5}                              |              0
+ [(10,-10),(-3,-4)]            | {0,-1,5}                              |              9
+ [(-1000000,200),(300000,-40)] | {0,-1,5}                              |              0
+ [(11,22),(33,44)]             | {0,-1,5}                              |             17
+ [(-10,2),(-10,3)]             | {0,-1,5}                              |              2
+ [(0,-20),(30,-20)]            | {0,-1,5}                              |             25
+ [(NaN,1),(NaN,90)]            | {0,-1,5}                              |            NaN
+ [(1,2),(3,4)]                 | {1,0,5}                               |              6
+ [(0,0),(6,6)]                 | {1,0,5}                               |              5
+ [(10,-10),(-3,-4)]            | {1,0,5}                               |              2
+ [(-1000000,200),(300000,-40)] | {1,0,5}                               |              0
+ [(11,22),(33,44)]             | {1,0,5}                               |             16
+ [(-10,2),(-10,3)]             | {1,0,5}                               |              5
+ [(0,-20),(30,-20)]            | {1,0,5}                               |              5
+ [(NaN,1),(NaN,90)]            | {1,0,5}                               |            NaN
+ [(1,2),(3,4)]                 | {0,3,0}                               |              2
+ [(0,0),(6,6)]                 | {0,3,0}                               |              0
+ [(10,-10),(-3,-4)]            | {0,3,0}                               |              4
+ [(-1000000,200),(300000,-40)] | {0,3,0}                               |              0
+ [(11,22),(33,44)]             | {0,3,0}                               |             22
+ [(-10,2),(-10,3)]             | {0,3,0}                               |              2
+ [(0,-20),(30,-20)]            | {0,3,0}                               |             20
+ [(NaN,1),(NaN,90)]            | {0,3,0}                               |            NaN
+ [(1,2),(3,4)]                 | {1,-1,0}                              | 0.707106781187
+ [(0,0),(6,6)]                 | {1,-1,0}                              |              0
+ [(10,-10),(-3,-4)]            | {1,-1,0}                              | 0.707106781187
+ [(-1000000,200),(300000,-40)] | {1,-1,0}                              |              0
+ [(11,22),(33,44)]             | {1,-1,0}                              |  7.77817459305
+ [(-10,2),(-10,3)]             | {1,-1,0}                              |  8.48528137424
+ [(0,-20),(30,-20)]            | {1,-1,0}                              |  14.1421356237
+ [(NaN,1),(NaN,90)]            | {1,-1,0}                              |            NaN
+ [(1,2),(3,4)]                 | {-0.4,-1,-6}                          |  7.79920420344
+ [(0,0),(6,6)]                 | {-0.4,-1,-6}                          |  5.57086014531
+ [(10,-10),(-3,-4)]            | {-0.4,-1,-6}                          |              0
+ [(-1000000,200),(300000,-40)] | {-0.4,-1,-6}                          |              0
+ [(11,22),(33,44)]             | {-0.4,-1,-6}                          |  30.0826447847
+ [(-10,2),(-10,3)]             | {-0.4,-1,-6}                          |  3.71390676354
+ [(0,-20),(30,-20)]            | {-0.4,-1,-6}                          |  1.85695338177
+ [(NaN,1),(NaN,90)]            | {-0.4,-1,-6}                          |            NaN
+ [(1,2),(3,4)]                 | {-0.000184615384615,-1,15.3846153846} |  11.3840613445
+ [(0,0),(6,6)]                 | {-0.000184615384615,-1,15.3846153846} |   9.3835075324
+ [(10,-10),(-3,-4)]            | {-0.000184615384615,-1,15.3846153846} |  19.3851689004
+ [(-1000000,200),(300000,-40)] | {-0.000184615384615,-1,15.3846153846} |              0
+ [(11,22),(33,44)]             | {-0.000184615384615,-1,15.3846153846} |  6.61741527185
+ [(-10,2),(-10,3)]             | {-0.000184615384615,-1,15.3846153846} |  12.3864613274
+ [(0,-20),(30,-20)]            | {-0.000184615384615,-1,15.3846153846} |  35.3790763202
+ [(NaN,1),(NaN,90)]            | {-0.000184615384615,-1,15.3846153846} |            NaN
+ [(1,2),(3,4)]                 | {3,NaN,5}                             |            NaN
+ [(0,0),(6,6)]                 | {3,NaN,5}                             |            NaN
+ [(10,-10),(-3,-4)]            | {3,NaN,5}                             |            NaN
+ [(-1000000,200),(300000,-40)] | {3,NaN,5}                             |            NaN
+ [(11,22),(33,44)]             | {3,NaN,5}                             |            NaN
+ [(-10,2),(-10,3)]             | {3,NaN,5}                             |            NaN
+ [(0,-20),(30,-20)]            | {3,NaN,5}                             |            NaN
+ [(NaN,1),(NaN,90)]            | {3,NaN,5}                             |            NaN
+ [(1,2),(3,4)]                 | {NaN,NaN,NaN}                         |            NaN
+ [(0,0),(6,6)]                 | {NaN,NaN,NaN}                         |            NaN
+ [(10,-10),(-3,-4)]            | {NaN,NaN,NaN}                         |            NaN
+ [(-1000000,200),(300000,-40)] | {NaN,NaN,NaN}                         |            NaN
+ [(11,22),(33,44)]             | {NaN,NaN,NaN}                         |            NaN
+ [(-10,2),(-10,3)]             | {NaN,NaN,NaN}                         |            NaN
+ [(0,-20),(30,-20)]            | {NaN,NaN,NaN}                         |            NaN
+ [(NaN,1),(NaN,90)]            | {NaN,NaN,NaN}                         |            NaN
+ [(1,2),(3,4)]                 | {0,-1,3}                              |              0
+ [(0,0),(6,6)]                 | {0,-1,3}                              |              0
+ [(10,-10),(-3,-4)]            | {0,-1,3}                              |              7
+ [(-1000000,200),(300000,-40)] | {0,-1,3}                              |              0
+ [(11,22),(33,44)]             | {0,-1,3}                              |             19
+ [(-10,2),(-10,3)]             | {0,-1,3}                              |              0
+ [(0,-20),(30,-20)]            | {0,-1,3}                              |             23
+ [(NaN,1),(NaN,90)]            | {0,-1,3}                              |            NaN
+ [(1,2),(3,4)]                 | {-1,0,3}                              |              0
+ [(0,0),(6,6)]                 | {-1,0,3}                              |              0
+ [(10,-10),(-3,-4)]            | {-1,0,3}                              |              0
+ [(-1000000,200),(300000,-40)] | {-1,0,3}                              |              0
+ [(11,22),(33,44)]             | {-1,0,3}                              |              8
+ [(-10,2),(-10,3)]             | {-1,0,3}                              |             13
+ [(0,-20),(30,-20)]            | {-1,0,3}                              |              0
+ [(NaN,1),(NaN,90)]            | {-1,0,3}                              |            NaN
+(80 rows)
+
+-- Distance to line segment
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               |    ?column?    
+-------------------------------+-------------------------------+----------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 |              0
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 0.707106781187
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            |  7.12398901685
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] |  11.3840613445
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             |  19.6977156036
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             |             11
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            |             22
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            |            NaN
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 0.707106781187
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 |              0
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            |  4.88901207039
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] |   9.3835075324
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             |  16.7630546142
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             |  10.1980390272
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            |             20
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            |            NaN
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 |  7.12398901685
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 |  4.88901207039
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            |              0
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] |  19.3851689004
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             |  29.4737584815
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             |  9.21954445729
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            |             10
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            |            NaN
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 |  11.3840613445
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 |   9.3835075324
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            |  19.3851689004
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] |              0
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             |  6.61741527185
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             |  12.3864613274
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            |  35.3790763202
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            |            NaN
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 |  19.6977156036
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 |  16.7630546142
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            |  29.4737584815
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] |  6.61741527185
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             |              0
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             |   28.319604517
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            |             42
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            |            NaN
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 |             11
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 |  10.1980390272
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            |  9.21954445729
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] |  12.3864613274
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             |   28.319604517
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             |              0
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            |  24.1660919472
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            |            NaN
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 |             22
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 |             20
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            |             10
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] |  35.3790763202
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             |             42
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             |  24.1660919472
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            |              0
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 |            NaN
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 |            NaN
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] |            NaN
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             |            NaN
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             |            NaN
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            |            NaN
+(64 rows)
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LSEG_TBL l, BOX_TBL b;
+               s               |         f1          |    ?column?    
+-------------------------------+---------------------+----------------
+ [(1,2),(3,4)]                 | (2,2),(0,0)         |              0
+ [(1,2),(3,4)]                 | (3,3),(1,1)         |              0
+ [(1,2),(3,4)]                 | (-2,2),(-8,-10)     |              3
+ [(1,2),(3,4)]                 | (2.5,3.5),(2.5,2.5) |              0
+ [(1,2),(3,4)]                 | (3,3),(3,3)         | 0.707106781187
+ [(0,0),(6,6)]                 | (2,2),(0,0)         |              0
+ [(0,0),(6,6)]                 | (3,3),(1,1)         |              0
+ [(0,0),(6,6)]                 | (-2,2),(-8,-10)     |              2
+ [(0,0),(6,6)]                 | (2.5,3.5),(2.5,2.5) |              0
+ [(0,0),(6,6)]                 | (3,3),(3,3)         |              0
+ [(10,-10),(-3,-4)]            | (2,2),(0,0)         |  4.88901207039
+ [(10,-10),(-3,-4)]            | (3,3),(1,1)         |  6.21602963235
+ [(10,-10),(-3,-4)]            | (-2,2),(-8,-10)     |              0
+ [(10,-10),(-3,-4)]            | (2.5,3.5),(2.5,2.5) |  8.20655597529
+ [(10,-10),(-3,-4)]            | (3,3),(3,3)         |  8.87006475627
+ [(-1000000,200),(300000,-40)] | (2,2),(0,0)         |  13.3842459258
+ [(-1000000,200),(300000,-40)] | (3,3),(1,1)         |  12.3840613274
+ [(-1000000,200),(300000,-40)] | (-2,2),(-8,-10)     |  13.3849843873
+ [(-1000000,200),(300000,-40)] | (2.5,3.5),(2.5,2.5) |  11.8841536436
+ [(-1000000,200),(300000,-40)] | (3,3),(3,3)         |  12.3840613274
+ [(11,22),(33,44)]             | (2,2),(0,0)         |  21.9317121995
+ [(11,22),(33,44)]             | (3,3),(1,1)         |  20.6155281281
+ [(11,22),(33,44)]             | (-2,2),(-8,-10)     |  23.8537208838
+ [(11,22),(33,44)]             | (2.5,3.5),(2.5,2.5) |  20.3592730715
+ [(11,22),(33,44)]             | (3,3),(3,3)         |  20.6155281281
+ [(-10,2),(-10,3)]             | (2,2),(0,0)         |             10
+ [(-10,2),(-10,3)]             | (3,3),(1,1)         |             11
+ [(-10,2),(-10,3)]             | (-2,2),(-8,-10)     |              2
+ [(-10,2),(-10,3)]             | (2.5,3.5),(2.5,2.5) |           12.5
+ [(-10,2),(-10,3)]             | (3,3),(3,3)         |             13
+ [(0,-20),(30,-20)]            | (2,2),(0,0)         |             20
+ [(0,-20),(30,-20)]            | (3,3),(1,1)         |             21
+ [(0,-20),(30,-20)]            | (-2,2),(-8,-10)     |  10.1980390272
+ [(0,-20),(30,-20)]            | (2.5,3.5),(2.5,2.5) |           22.5
+ [(0,-20),(30,-20)]            | (3,3),(3,3)         |             23
+ [(NaN,1),(NaN,90)]            | (2,2),(0,0)         |            NaN
+ [(NaN,1),(NaN,90)]            | (3,3),(1,1)         |            NaN
+ [(NaN,1),(NaN,90)]            | (-2,2),(-8,-10)     |            NaN
+ [(NaN,1),(NaN,90)]            | (2.5,3.5),(2.5,2.5) |            NaN
+ [(NaN,1),(NaN,90)]            | (3,3),(3,3)         |            NaN
+(40 rows)
+
+-- Intersect with line segment
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s ?# l1.s;
+               s               |      s       
+-------------------------------+--------------
+ [(0,0),(6,6)]                 | {0,-1,5}
+ [(-1000000,200),(300000,-40)] | {0,-1,5}
+ [(-1000000,200),(300000,-40)] | {1,0,5}
+ [(0,0),(6,6)]                 | {0,3,0}
+ [(-1000000,200),(300000,-40)] | {0,3,0}
+ [(-1000000,200),(300000,-40)] | {1,-1,0}
+ [(10,-10),(-3,-4)]            | {-0.4,-1,-6}
+ [(-1000000,200),(300000,-40)] | {-0.4,-1,-6}
+ [(1,2),(3,4)]                 | {0,-1,3}
+ [(0,0),(6,6)]                 | {0,-1,3}
+ [(-1000000,200),(300000,-40)] | {0,-1,3}
+ [(-10,2),(-10,3)]             | {0,-1,3}
+ [(1,2),(3,4)]                 | {-1,0,3}
+ [(0,0),(6,6)]                 | {-1,0,3}
+ [(10,-10),(-3,-4)]            | {-1,0,3}
+ [(-1000000,200),(300000,-40)] | {-1,0,3}
+ [(0,-20),(30,-20)]            | {-1,0,3}
+(17 rows)
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+         s          |         f1          
+--------------------+---------------------
+ [(1,2),(3,4)]      | (2,2),(0,0)
+ [(1,2),(3,4)]      | (3,3),(1,1)
+ [(1,2),(3,4)]      | (2.5,3.5),(2.5,2.5)
+ [(0,0),(6,6)]      | (2,2),(0,0)
+ [(0,0),(6,6)]      | (3,3),(1,1)
+ [(0,0),(6,6)]      | (2.5,3.5),(2.5,2.5)
+ [(0,0),(6,6)]      | (3,3),(3,3)
+ [(10,-10),(-3,-4)] | (-2,2),(-8,-10)
+(8 rows)
+
+-- Intersection point with line segment
+SELECT l1.s, l2.s, l1.s # l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               | ?column? 
+-------------------------------+-------------------------------+----------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 | 
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            | 
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] | 
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             | 
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             | 
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            | 
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            | 
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 | 
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            | 
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] | 
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             | 
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             | 
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            | 
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            | 
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 | 
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 | 
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            | 
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] | 
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             | 
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             | 
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            | 
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            | 
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 | 
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 | 
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            | 
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] | 
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             | 
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             | 
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            | 
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            | 
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 | 
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 | 
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            | 
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] | 
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             | 
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             | 
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            | 
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            | 
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 | 
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 | 
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            | 
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] | 
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             | 
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             | 
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            | 
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            | 
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 | 
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 | 
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            | 
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] | 
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             | 
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             | 
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            | 
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            | 
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 | 
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 | 
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            | 
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] | 
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             | 
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             | 
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            | 
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            | 
+(64 rows)
+
+-- Closest point to line
+SELECT l.s, l1.s, l.s ## l1.s FROM LSEG_TBL l, LINE_TBL l1;
+ERROR:  function "close_sl" not implemented
+-- Closest point to line segment
+SELECT l1.s, l2.s, l1.s ## l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               |            ?column?             
+-------------------------------+-------------------------------+---------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 | 
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            | (-1.98536585366,-4.46829268293)
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] | (3.00210167283,15.3840611505)
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             | 
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             | (-10,2)
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            | (1,-20)
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            | 
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 | 
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] | (6.00173233982,15.3835073725)
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             | 
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             | (-10,2)
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            | (0,-20)
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            | 
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 | (1,2)
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 | (0,0)
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            | 
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] | (-2.99642119965,15.3851685701)
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             | (11,22)
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             | (-10,2)
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            | (10,-20)
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            | 
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 | (3,4)
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 | (6,6)
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            | (-3,-4)
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] | 
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             | (11,22)
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             | (-10,3)
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            | (30,-20)
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            | 
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 | 
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 | 
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            | (-1.3512195122,-4.76097560976)
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] | (10.9987783234,15.3825848409)
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             | 
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             | (-10,3)
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            | (11,-20)
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            | 
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 | (1,2)
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 | (0,0)
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            | (-3,-4)
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] | (-9.99771326872,15.3864611163)
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             | (11,22)
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             | 
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            | (0,-20)
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            | 
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 | (1,2)
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 | (0,0)
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            | (10,-10)
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] | (30.0065315217,15.3790757173)
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             | (11,22)
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             | (-10,2)
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            | 
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            | 
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 | 
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 | 
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            | 
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] | 
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             | 
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             | 
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            | 
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            | 
+(64 rows)
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LSEG_TBL l, BOX_TBL b;
+               s               |         f1          |  ?column?   
+-------------------------------+---------------------+-------------
+ [(1,2),(3,4)]                 | (2,2),(0,0)         | (1,2)
+ [(1,2),(3,4)]                 | (3,3),(1,1)         | (1.5,2.5)
+ [(1,2),(3,4)]                 | (-2,2),(-8,-10)     | (-2,2)
+ [(1,2),(3,4)]                 | (2.5,3.5),(2.5,2.5) | (2.25,3.25)
+ [(1,2),(3,4)]                 | (3,3),(3,3)         | (3,3)
+ [(0,0),(6,6)]                 | (2,2),(0,0)         | (1,1)
+ [(0,0),(6,6)]                 | (3,3),(1,1)         | (2,2)
+ [(0,0),(6,6)]                 | (-2,2),(-8,-10)     | (-2,0)
+ [(0,0),(6,6)]                 | (2.5,3.5),(2.5,2.5) | (2.75,2.75)
+ [(0,0),(6,6)]                 | (3,3),(3,3)         | (3,3)
+ [(10,-10),(-3,-4)]            | (2,2),(0,0)         | (0,0)
+ [(10,-10),(-3,-4)]            | (3,3),(1,1)         | (1,1)
+ [(10,-10),(-3,-4)]            | (-2,2),(-8,-10)     | (-3,-4)
+ [(10,-10),(-3,-4)]            | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ [(10,-10),(-3,-4)]            | (3,3),(3,3)         | (3,3)
+ [(-1000000,200),(300000,-40)] | (2,2),(0,0)         | (2,2)
+ [(-1000000,200),(300000,-40)] | (3,3),(1,1)         | (3,3)
+ [(-1000000,200),(300000,-40)] | (-2,2),(-8,-10)     | (-2,2)
+ [(-1000000,200),(300000,-40)] | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ [(-1000000,200),(300000,-40)] | (3,3),(3,3)         | (3,3)
+ [(11,22),(33,44)]             | (2,2),(0,0)         | (2,2)
+ [(11,22),(33,44)]             | (3,3),(1,1)         | (3,3)
+ [(11,22),(33,44)]             | (-2,2),(-8,-10)     | (-2,2)
+ [(11,22),(33,44)]             | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ [(11,22),(33,44)]             | (3,3),(3,3)         | (3,3)
+ [(-10,2),(-10,3)]             | (2,2),(0,0)         | (0,2)
+ [(-10,2),(-10,3)]             | (3,3),(1,1)         | (1,2)
+ [(-10,2),(-10,3)]             | (-2,2),(-8,-10)     | (-8,2)
+ [(-10,2),(-10,3)]             | (2.5,3.5),(2.5,2.5) | (2.5,3)
+ [(-10,2),(-10,3)]             | (3,3),(3,3)         | (3,3)
+ [(0,-20),(30,-20)]            | (2,2),(0,0)         | (0,0)
+ [(0,-20),(30,-20)]            | (3,3),(1,1)         | (1,1)
+ [(0,-20),(30,-20)]            | (-2,2),(-8,-10)     | (-2,-10)
+ [(0,-20),(30,-20)]            | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ [(0,-20),(30,-20)]            | (3,3),(3,3)         | (3,3)
+ [(NaN,1),(NaN,90)]            | (2,2),(0,0)         | 
+ [(NaN,1),(NaN,90)]            | (3,3),(1,1)         | 
+ [(NaN,1),(NaN,90)]            | (-2,2),(-8,-10)     | 
+ [(NaN,1),(NaN,90)]            | (2.5,3.5),(2.5,2.5) | 
+ [(NaN,1),(NaN,90)]            | (3,3),(3,3)         | 
+(40 rows)
+
+-- On line
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s <@ l1.s;
+               s               |                   s                   
+-------------------------------+---------------------------------------
+ [(0,0),(6,6)]                 | {1,-1,0}
+ [(-1000000,200),(300000,-40)] | {-0.000184615384615,-1,15.3846153846}
+(2 rows)
+
+-- On box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s <@ b.f1;
+ s | f1 
+---+----
+(0 rows)
 
 --
 -- Boxes
 --
 SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
  six |                              box                               
 -----+----------------------------------------------------------------
      | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
      | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
      | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
      | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
      | (107.071067812,207.071067812),(92.9289321881,192.928932188)
      | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
+     | (3,5),(3,5)
+     | (NaN,NaN),(NaN,NaN)
+(8 rows)
 
 -- translation
 SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
+ twentyfour |             translation             
+------------+-------------------------------------
             | (2,2),(0,0)
             | (3,3),(1,1)
+            | (-2,2),(-8,-10)
             | (2.5,3.5),(2.5,2.5)
             | (3,3),(3,3)
             | (-8,2),(-10,0)
             | (-7,3),(-9,1)
+            | (-12,2),(-18,-10)
             | (-7.5,3.5),(-7.5,2.5)
             | (-7,3),(-7,3)
             | (-1,6),(-3,4)
             | (0,7),(-2,5)
+            | (-5,6),(-11,-6)
             | (-0.5,7.5),(-0.5,6.5)
             | (0,7),(0,7)
             | (7.1,36.5),(5.1,34.5)
             | (8.1,37.5),(6.1,35.5)
+            | (3.1,36.5),(-2.9,24.5)
             | (7.6,38),(7.6,37)
             | (8.1,37.5),(8.1,37.5)
             | (-3,-10),(-5,-12)
             | (-2,-9),(-4,-11)
+            | (-7,-10),(-13,-22)
             | (-2.5,-8.5),(-2.5,-9.5)
             | (-2,-9),(-2,-9)
+            | (2,2),(1e-300,-1e-300)
+            | (3,3),(1,1)
+            | (-2,2),(-8,-10)
+            | (2.5,3.5),(2.5,2.5)
+            | (3,3),(3,3)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
             | (12,12),(10,10)
             | (13,13),(11,11)
+            | (8,12),(2,0)
             | (12.5,13.5),(12.5,12.5)
             | (13,13),(13,13)
-(24 rows)
+(45 rows)
 
 SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
+ twentyfour |               translation               
+------------+-----------------------------------------
             | (2,2),(0,0)
             | (3,3),(1,1)
+            | (-2,2),(-8,-10)
             | (2.5,3.5),(2.5,2.5)
             | (3,3),(3,3)
             | (12,2),(10,0)
             | (13,3),(11,1)
+            | (8,2),(2,-10)
             | (12.5,3.5),(12.5,2.5)
             | (13,3),(13,3)
             | (5,-2),(3,-4)
             | (6,-1),(4,-3)
+            | (1,-2),(-5,-14)
             | (5.5,-0.5),(5.5,-1.5)
             | (6,-1),(6,-1)
             | (-3.1,-32.5),(-5.1,-34.5)
             | (-2.1,-31.5),(-4.1,-33.5)
+            | (-7.1,-32.5),(-13.1,-44.5)
             | (-2.6,-31),(-2.6,-32)
             | (-2.1,-31.5),(-2.1,-31.5)
             | (7,14),(5,12)
             | (8,15),(6,13)
+            | (3,14),(-3,2)
             | (7.5,15.5),(7.5,14.5)
             | (8,15),(8,15)
+            | (2,2),(-1e-300,1e-300)
+            | (3,3),(1,1)
+            | (-2,2),(-8,-10)
+            | (2.5,3.5),(2.5,2.5)
+            | (3,3),(3,3)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
             | (-8,-8),(-10,-10)
             | (-7,-7),(-9,-9)
+            | (-12,-8),(-18,-20)
             | (-7.5,-6.5),(-7.5,-7.5)
             | (-7,-7),(-7,-7)
-(24 rows)
+(45 rows)
 
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
+-- Multiply with point
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+         f1          |     f1     |          ?column?           
+---------------------+------------+-----------------------------
+ (2,2),(0,0)         | (5.1,34.5) | (0,79.2),(-58.8,0)
+ (2,2),(0,0)         | (10,10)    | (0,40),(0,0)
+ (3,3),(1,1)         | (5.1,34.5) | (-29.4,118.8),(-88.2,39.6)
+ (3,3),(1,1)         | (10,10)    | (0,60),(0,20)
+ (-2,2),(-8,-10)     | (5.1,34.5) | (304.2,-58.8),(-79.2,-327)
+ (-2,2),(-8,-10)     | (10,10)    | (20,0),(-40,-180)
+ (2.5,3.5),(2.5,2.5) | (5.1,34.5) | (-73.5,104.1),(-108,99)
+ (2.5,3.5),(2.5,2.5) | (10,10)    | (0,60),(-10,50)
+ (3,3),(3,3)         | (5.1,34.5) | (-88.2,118.8),(-88.2,118.8)
+ (3,3),(3,3)         | (10,10)    | (0,60),(0,60)
+(10 rows)
 
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,0),(-0.2,-0.2)
-        | (0.08,0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
+-- Overflow error
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] > 1000;
+         f1          |        f1         |                  ?column?                  
+---------------------+-------------------+--------------------------------------------
+ (2,2),(0,0)         | (1e+300,Infinity) | (NaN,NaN),(-Infinity,Infinity)
+ (2,2),(0,0)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (3,3),(1,1)         | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (3,3),(1,1)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (-2,2),(-8,-10)     | (1e+300,Infinity) | (Infinity,-Infinity),(-Infinity,-Infinity)
+ (-2,2),(-8,-10)     | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (2.5,3.5),(2.5,2.5) | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (2.5,3.5),(2.5,2.5) | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (3,3),(3,3)         | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (3,3),(3,3)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+(10 rows)
 
+-- Divide by point
+SELECT b.f1, p.f1, b.f1 / p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+         f1          |     f1     |                               ?column?                               
+---------------------+------------+----------------------------------------------------------------------
+ (2,2),(0,0)         | (5.1,34.5) | (0.0651176557644,0),(0,-0.0483449262493)
+ (2,2),(0,0)         | (10,10)    | (0.2,0),(0,0)
+ (3,3),(1,1)         | (5.1,34.5) | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
+ (3,3),(1,1)         | (10,10)    | (0.3,0),(0.1,0)
+ (-2,2),(-8,-10)     | (5.1,34.5) | (0.0483449262493,0.18499334024),(-0.317201914064,0.0651176557644)
+ (-2,2),(-8,-10)     | (10,10)    | (0,0.2),(-0.9,-0.1)
+ (2.5,3.5),(2.5,2.5) | (5.1,34.5) | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
+ (2.5,3.5),(2.5,2.5) | (10,10)    | (0.3,0.05),(0.25,0)
+ (3,3),(3,3)         | (5.1,34.5) | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
+ (3,3),(3,3)         | (10,10)    | (0.3,0),(0.3,0)
+(10 rows)
+
+-- To box
 SELECT f1::box
 	FROM POINT_TBL;
-          f1           
------------------------
+                 f1                  
+-------------------------------------
  (0,0),(0,0)
  (-10,0),(-10,0)
  (-3,4),(-3,4)
  (5.1,34.5),(5.1,34.5)
  (-5,-12),(-5,-12)
+ (1e-300,-1e-300),(1e-300,-1e-300)
+ (1e+300,Infinity),(1e+300,Infinity)
+ (NaN,NaN),(NaN,NaN)
  (10,10),(10,10)
-(6 rows)
+(9 rows)
 
 SELECT bound_box(a.f1, b.f1)
 	FROM BOX_TBL a, BOX_TBL b;
       bound_box      
 ---------------------
  (2,2),(0,0)
  (3,3),(0,0)
+ (2,2),(-8,-10)
  (2.5,3.5),(0,0)
  (3,3),(0,0)
  (3,3),(0,0)
  (3,3),(1,1)
+ (3,3),(-8,-10)
  (3,3.5),(1,1)
  (3,3),(1,1)
+ (2,2),(-8,-10)
+ (3,3),(-8,-10)
+ (-2,2),(-8,-10)
+ (2.5,3.5),(-8,-10)
+ (3,3),(-8,-10)
  (2.5,3.5),(0,0)
  (3,3.5),(1,1)
+ (2.5,3.5),(-8,-10)
  (2.5,3.5),(2.5,2.5)
  (3,3.5),(2.5,2.5)
  (3,3),(0,0)
  (3,3),(1,1)
+ (3,3),(-8,-10)
  (3,3.5),(2.5,2.5)
  (3,3),(3,3)
-(16 rows)
+(25 rows)
+
+-- Below box
+SELECT b1.f1, b2.f1, b1.f1 <^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          | ?column? 
+---------------------+---------------------+----------
+ (2,2),(0,0)         | (2,2),(0,0)         | f
+ (2,2),(0,0)         | (3,3),(1,1)         | f
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | f
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | t
+ (2,2),(0,0)         | (3,3),(3,3)         | t
+ (3,3),(1,1)         | (2,2),(0,0)         | f
+ (3,3),(1,1)         | (3,3),(1,1)         | f
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | f
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(1,1)         | (3,3),(3,3)         | t
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | f
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | f
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | f
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | t
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | t
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | f
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | f
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | f
+ (3,3),(3,3)         | (2,2),(0,0)         | f
+ (3,3),(3,3)         | (3,3),(1,1)         | f
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | f
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(3,3)         | (3,3),(3,3)         | t
+(25 rows)
+
+-- Above box
+SELECT b1.f1, b2.f1, b1.f1 >^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          | ?column? 
+---------------------+---------------------+----------
+ (2,2),(0,0)         | (2,2),(0,0)         | f
+ (2,2),(0,0)         | (3,3),(1,1)         | f
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | f
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | f
+ (2,2),(0,0)         | (3,3),(3,3)         | f
+ (3,3),(1,1)         | (2,2),(0,0)         | f
+ (3,3),(1,1)         | (3,3),(1,1)         | f
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | f
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(1,1)         | (3,3),(3,3)         | f
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | f
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | f
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | f
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | f
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | f
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | t
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | f
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | t
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | f
+ (3,3),(3,3)         | (2,2),(0,0)         | t
+ (3,3),(3,3)         | (3,3),(1,1)         | t
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | t
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(3,3)         | (3,3),(3,3)         | t
+(25 rows)
+
+-- Intersection point with box
+SELECT b1.f1, b2.f1, b1.f1 # b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          |      ?column?       
+---------------------+---------------------+---------------------
+ (2,2),(0,0)         | (2,2),(0,0)         | (2,2),(0,0)
+ (2,2),(0,0)         | (3,3),(1,1)         | (2,2),(1,1)
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | 
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | 
+ (2,2),(0,0)         | (3,3),(3,3)         | 
+ (3,3),(1,1)         | (2,2),(0,0)         | (2,2),(1,1)
+ (3,3),(1,1)         | (3,3),(1,1)         | (3,3),(1,1)
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | 
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | (2.5,3),(2.5,2.5)
+ (3,3),(1,1)         | (3,3),(3,3)         | (3,3),(3,3)
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | 
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | 
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | (-2,2),(-8,-10)
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | 
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | 
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | 
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | (2.5,3),(2.5,2.5)
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | 
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5)
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | 
+ (3,3),(3,3)         | (2,2),(0,0)         | 
+ (3,3),(3,3)         | (3,3),(1,1)         | (3,3),(3,3)
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | 
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | 
+ (3,3),(3,3)         | (3,3),(3,3)         | (3,3),(3,3)
+(25 rows)
+
+-- Diagonal
+SELECT f1, diagonal(f1) FROM BOX_TBL;
+         f1          |       diagonal        
+---------------------+-----------------------
+ (2,2),(0,0)         | [(2,2),(0,0)]
+ (3,3),(1,1)         | [(3,3),(1,1)]
+ (-2,2),(-8,-10)     | [(-2,2),(-8,-10)]
+ (2.5,3.5),(2.5,2.5) | [(2.5,3.5),(2.5,2.5)]
+ (3,3),(3,3)         | [(3,3),(3,3)]
+(5 rows)
+
+-- Distance to box
+SELECT b1.f1, b2.f1, b1.f1 <-> b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          |   ?column?    
+---------------------+---------------------+---------------
+ (2,2),(0,0)         | (2,2),(0,0)         |             0
+ (2,2),(0,0)         | (3,3),(1,1)         | 1.41421356237
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | 7.81024967591
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) |           2.5
+ (2,2),(0,0)         | (3,3),(3,3)         | 2.82842712475
+ (3,3),(1,1)         | (2,2),(0,0)         | 1.41421356237
+ (3,3),(1,1)         | (3,3),(1,1)         |             0
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | 9.21954445729
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | 1.11803398875
+ (3,3),(1,1)         | (3,3),(3,3)         | 1.41421356237
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | 7.81024967591
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | 9.21954445729
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     |             0
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | 10.2591422643
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | 10.6301458127
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         |           2.5
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | 1.11803398875
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | 10.2591422643
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) |             0
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         |           0.5
+ (3,3),(3,3)         | (2,2),(0,0)         | 2.82842712475
+ (3,3),(3,3)         | (3,3),(1,1)         | 1.41421356237
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | 10.6301458127
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) |           0.5
+ (3,3),(3,3)         | (3,3),(3,3)         |             0
+(25 rows)
 
 --
 -- Paths
 --
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
+-- Points
+SELECT f1, npoints(f1) FROM PATH_TBL;
+            f1             | npoints 
+---------------------------+---------
+ [(1,2),(3,4)]             |       2
+ ((1,2),(3,4))             |       2
+ [(0,0),(3,0),(4,5),(1,6)] |       4
+ ((1,2),(3,4))             |       2
+ ((1,2),(3,4))             |       2
+ [(1,2),(3,4)]             |       2
+ ((10,20))                 |       1
+ [(11,12),(13,14)]         |       2
+ ((11,12),(13,14))         |       2
+(9 rows)
 
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
+-- Area
+SELECT f1, area(f1) FROM PATH_TBL;
+            f1             | area 
+---------------------------+------
+ [(1,2),(3,4)]             |     
+ ((1,2),(3,4))             |    0
+ [(0,0),(3,0),(4,5),(1,6)] |     
+ ((1,2),(3,4))             |    0
+ ((1,2),(3,4))             |    0
+ [(1,2),(3,4)]             |     
+ ((10,20))                 |    0
+ [(11,12),(13,14)]         |     
+ ((11,12),(13,14))         |    0
+(9 rows)
 
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
+-- Length
+SELECT f1, @-@ f1 FROM PATH_TBL;
+            f1             |   ?column?    
+---------------------------+---------------
+ [(1,2),(3,4)]             | 2.82842712475
+ ((1,2),(3,4))             | 5.65685424949
+ [(0,0),(3,0),(4,5),(1,6)] | 11.2612971738
+ ((1,2),(3,4))             | 5.65685424949
+ ((1,2),(3,4))             | 5.65685424949
+ [(1,2),(3,4)]             | 2.82842712475
+ ((10,20))                 |             0
+ [(11,12),(13,14)]         | 2.82842712475
+ ((11,12),(13,14))         | 5.65685424949
+(9 rows)
 
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
+-- Center
+SELECT f1, @@ f1 FROM PATH_TBL;
+ERROR:  function "path_center" not implemented
+-- To polygon
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isclosed(f1);
+        f1         |        f1         
+-------------------+-------------------
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((10,20))         | ((10,20))
+ ((11,12),(13,14)) | ((11,12),(13,14))
+(5 rows)
+
+-- Open path cannot be converted to polygon error
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isopen(f1);
+ERROR:  open path cannot be converted to polygon
+-- Has points less than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 < p2.f1;
+        f1         |            f1             
+-------------------+---------------------------
+ [(1,2),(3,4)]     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]     | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))         | [(1,2),(3,4)]
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | [(1,2),(3,4)]
+ ((10,20))         | [(11,12),(13,14)]
+ ((10,20))         | ((11,12),(13,14))
+ [(11,12),(13,14)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((11,12),(13,14)) | [(0,0),(3,0),(4,5),(1,6)]
+(15 rows)
+
+-- Has points less than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 <= p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | [(1,2),(3,4)]
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | [(1,2),(3,4)]
+ ((10,20))                 | ((10,20))
+ ((10,20))                 | [(11,12),(13,14)]
+ ((10,20))                 | ((11,12),(13,14))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(66 rows)
+
+-- Has points equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 = p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | ((10,20))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(51 rows)
+
+-- Has points greater than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 >= p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | ((10,20))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((10,20))
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((10,20))
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(66 rows)
+
+-- Has points greater than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 > p2.f1;
+            f1             |        f1         
+---------------------------+-------------------
+ [(1,2),(3,4)]             | ((10,20))
+ ((1,2),(3,4))             | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | ((10,20))
+ [(1,2),(3,4)]             | ((10,20))
+ [(11,12),(13,14)]         | ((10,20))
+ ((11,12),(13,14))         | ((10,20))
+(15 rows)
+
+-- Add path
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+            f1             |            f1             |                     ?column?                      
+---------------------------+---------------------------+---------------------------------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4),(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))                 | 
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         | [(1,2),(3,4),(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6),(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6),(0,0),(3,0),(4,5),(1,6)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6),(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))                 | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6),(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4),(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))                 | 
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         | [(1,2),(3,4),(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))         | 
+ ((10,20))                 | [(1,2),(3,4)]             | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | [(1,2),(3,4)]             | 
+ ((10,20))                 | ((10,20))                 | 
+ ((10,20))                 | [(11,12),(13,14)]         | 
+ ((10,20))                 | ((11,12),(13,14))         | 
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             | [(11,12),(13,14),(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14),(0,0),(3,0),(4,5),(1,6)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             | [(11,12),(13,14),(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((10,20))                 | 
+ [(11,12),(13,14)]         | [(11,12),(13,14)]         | [(11,12),(13,14),(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))         | 
+ ((11,12),(13,14))         | [(1,2),(3,4)]             | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | [(1,2),(3,4)]             | 
+ ((11,12),(13,14))         | ((10,20))                 | 
+ ((11,12),(13,14))         | [(11,12),(13,14)]         | 
+ ((11,12),(13,14))         | ((11,12),(13,14))         | 
+(81 rows)
+
+-- Add point
+SELECT p.f1, p1.f1, p.f1 + p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                                 ?column?                                  
+---------------------------+-------------------+---------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((10,20))                 | (0,0)             | ((10,20))
+ [(11,12),(13,14)]         | (0,0)             | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (0,0)             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (-10,0)           | [(-9,2),(-7,4)]
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(-10,0),(-7,0),(-6,5),(-9,6)]
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ [(1,2),(3,4)]             | (-10,0)           | [(-9,2),(-7,4)]
+ ((10,20))                 | (-10,0)           | ((0,20))
+ [(11,12),(13,14)]         | (-10,0)           | [(1,12),(3,14)]
+ ((11,12),(13,14))         | (-10,0)           | ((1,12),(3,14))
+ [(1,2),(3,4)]             | (-3,4)            | [(-2,6),(0,8)]
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(-3,4),(0,4),(1,9),(-2,10)]
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ [(1,2),(3,4)]             | (-3,4)            | [(-2,6),(0,8)]
+ ((10,20))                 | (-3,4)            | ((7,24))
+ [(11,12),(13,14)]         | (-3,4)            | [(8,16),(10,18)]
+ ((11,12),(13,14))         | (-3,4)            | ((8,16),(10,18))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(6.1,36.5),(8.1,38.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(5.1,34.5),(8.1,34.5),(9.1,39.5),(6.1,40.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(6.1,36.5),(8.1,38.5)]
+ ((10,20))                 | (5.1,34.5)        | ((15.1,54.5))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(16.1,46.5),(18.1,48.5)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((16.1,46.5),(18.1,48.5))
+ [(1,2),(3,4)]             | (-5,-12)          | [(-4,-10),(-2,-8)]
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(-5,-12),(-2,-12),(-1,-7),(-4,-6)]
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ [(1,2),(3,4)]             | (-5,-12)          | [(-4,-10),(-2,-8)]
+ ((10,20))                 | (-5,-12)          | ((5,8))
+ [(11,12),(13,14)]         | (-5,-12)          | [(6,0),(8,2)]
+ ((11,12),(13,14))         | (-5,-12)          | ((6,0),(8,2))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(1e-300,-1e-300),(3,-1e-300),(4,5),(1,6)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((10,20))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity),(1e+300,Infinity),(1e+300,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((1e+300,Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(11,12),(13,14)]
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(10,10),(13,10),(14,15),(11,16)]
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (10,10)           | [(11,12),(13,14)]
+ ((10,20))                 | (10,10)           | ((20,30))
+ [(11,12),(13,14)]         | (10,10)           | [(21,22),(23,24)]
+ ((11,12),(13,14))         | (10,10)           | ((21,22),(23,24))
+(81 rows)
+
+-- Subtract point
+SELECT p.f1, p1.f1, p.f1 - p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                                     ?column?                                      
+---------------------------+-------------------+-----------------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((10,20))                 | (0,0)             | ((10,20))
+ [(11,12),(13,14)]         | (0,0)             | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (0,0)             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (-10,0)           | [(11,2),(13,4)]
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(10,0),(13,0),(14,5),(11,6)]
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ [(1,2),(3,4)]             | (-10,0)           | [(11,2),(13,4)]
+ ((10,20))                 | (-10,0)           | ((20,20))
+ [(11,12),(13,14)]         | (-10,0)           | [(21,12),(23,14)]
+ ((11,12),(13,14))         | (-10,0)           | ((21,12),(23,14))
+ [(1,2),(3,4)]             | (-3,4)            | [(4,-2),(6,0)]
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(3,-4),(6,-4),(7,1),(4,2)]
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ [(1,2),(3,4)]             | (-3,4)            | [(4,-2),(6,0)]
+ ((10,20))                 | (-3,4)            | ((13,16))
+ [(11,12),(13,14)]         | (-3,4)            | [(14,8),(16,10)]
+ ((11,12),(13,14))         | (-3,4)            | ((14,8),(16,10))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-4.1,-32.5),(-2.1,-30.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(-5.1,-34.5),(-2.1,-34.5),(-1.1,-29.5),(-4.1,-28.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-4.1,-32.5),(-2.1,-30.5)]
+ ((10,20))                 | (5.1,34.5)        | ((4.9,-14.5))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(5.9,-22.5),(7.9,-20.5)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((5.9,-22.5),(7.9,-20.5))
+ [(1,2),(3,4)]             | (-5,-12)          | [(6,14),(8,16)]
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(5,12),(8,12),(9,17),(6,18)]
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ [(1,2),(3,4)]             | (-5,-12)          | [(6,14),(8,16)]
+ ((10,20))                 | (-5,-12)          | ((15,32))
+ [(11,12),(13,14)]         | (-5,-12)          | [(16,24),(18,26)]
+ ((11,12),(13,14))         | (-5,-12)          | ((16,24),(18,26))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(-1e-300,1e-300),(3,1e-300),(4,5),(1,6)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((10,20))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity),(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((-1e+300,-Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(-9,-8),(-7,-6)]
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(-10,-10),(-7,-10),(-6,-5),(-9,-4)]
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ [(1,2),(3,4)]             | (10,10)           | [(-9,-8),(-7,-6)]
+ ((10,20))                 | (10,10)           | ((0,10))
+ [(11,12),(13,14)]         | (10,10)           | [(1,2),(3,4)]
+ ((11,12),(13,14))         | (10,10)           | ((1,2),(3,4))
+(81 rows)
+
+-- Multiply with point
+SELECT p.f1, p1.f1, p.f1 * p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                               ?column?                               
+---------------------------+-------------------+----------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(0,0),(0,0)]
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(0,0),(0,0),(0,0)]
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ [(1,2),(3,4)]             | (0,0)             | [(0,0),(0,0)]
+ ((10,20))                 | (0,0)             | ((0,0))
+ [(11,12),(13,14)]         | (0,0)             | [(0,0),(0,0)]
+ ((11,12),(13,14))         | (0,0)             | ((0,0),(0,0))
+ [(1,2),(3,4)]             | (-10,0)           | [(-10,-20),(-30,-40)]
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(0,0),(-30,0),(-40,-50),(-10,-60)]
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ [(1,2),(3,4)]             | (-10,0)           | [(-10,-20),(-30,-40)]
+ ((10,20))                 | (-10,0)           | ((-100,-200))
+ [(11,12),(13,14)]         | (-10,0)           | [(-110,-120),(-130,-140)]
+ ((11,12),(13,14))         | (-10,0)           | ((-110,-120),(-130,-140))
+ [(1,2),(3,4)]             | (-3,4)            | [(-11,-2),(-25,0)]
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(0,0),(-9,12),(-32,1),(-27,-14)]
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ [(1,2),(3,4)]             | (-3,4)            | [(-11,-2),(-25,0)]
+ ((10,20))                 | (-3,4)            | ((-110,-20))
+ [(11,12),(13,14)]         | (-3,4)            | [(-81,8),(-95,10)]
+ ((11,12),(13,14))         | (-3,4)            | ((-81,8),(-95,10))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-63.9,44.7),(-122.7,123.9)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(0,0),(15.3,103.5),(-152.1,163.5),(-201.9,65.1)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-63.9,44.7),(-122.7,123.9)]
+ ((10,20))                 | (5.1,34.5)        | ((-639,447))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(-357.9,440.7),(-416.7,519.9)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((-357.9,440.7),(-416.7,519.9))
+ [(1,2),(3,4)]             | (-5,-12)          | [(19,-22),(33,-56)]
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(0,0),(-15,-36),(40,-73),(67,-42)]
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ [(1,2),(3,4)]             | (-5,-12)          | [(19,-22),(33,-56)]
+ ((10,20))                 | (-5,-12)          | ((190,-220))
+ [(11,12),(13,14)]         | (-5,-12)          | [(89,-192),(103,-226)]
+ ((11,12),(13,14))         | (-5,-12)          | ((89,-192),(103,-226))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(3e-300,1e-300),(7e-300,1e-300)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(0,0),(3e-300,-3e-300),(9e-300,1e-300),(7e-300,5e-300)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(3e-300,1e-300),(7e-300,1e-300)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((3e-299,1e-299))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(2.3e-299,1e-300),(2.7e-299,1e-300)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((2.3e-299,1e-300),(2.7e-299,1e-300))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(NaN,NaN),(NaN,Infinity),(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((-Infinity,Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(-10,30),(-10,70)]
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(0,0),(30,30),(-10,90),(-50,70)]
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ [(1,2),(3,4)]             | (10,10)           | [(-10,30),(-10,70)]
+ ((10,20))                 | (10,10)           | ((-100,300))
+ [(11,12),(13,14)]         | (10,10)           | [(-10,230),(-10,270)]
+ ((11,12),(13,14))         | (10,10)           | ((-10,230),(-10,270))
+(81 rows)
+
+-- Divide by point
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+            f1             |     f1     |                                                    ?column?                                                     
+---------------------------+------------+-----------------------------------------------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (5.1,34.5) | [(0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952)]
+ [(1,2),(3,4)]             | (10,10)    | [(0.15,0.05),(0.35,0.05)]
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5) | [(0,0),(0.0125795471363,-0.0850969365103),(0.158600957032,-0.0924966701199),(0.174387055399,-0.00320655123082)]
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)    | [(0,0),(0.15,-0.15),(0.45,0.05),(0.35,0.25)]
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ [(1,2),(3,4)]             | (5.1,34.5) | [(0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952)]
+ [(1,2),(3,4)]             | (10,10)    | [(0.15,0.05),(0.35,0.05)]
+ ((10,20))                 | (5.1,34.5) | ((0.609244733856,-0.199792807459))
+ ((10,20))                 | (10,10)    | ((1.5,0.5))
+ [(11,12),(13,14)]         | (5.1,34.5) | [(0.386512752208,-0.261703911993),(0.451630407972,-0.310048838242)]
+ [(11,12),(13,14)]         | (10,10)    | [(1.15,0.05),(1.35,0.05)]
+ ((11,12),(13,14))         | (5.1,34.5) | ((0.386512752208,-0.261703911993),(0.451630407972,-0.310048838242))
+ ((11,12),(13,14))         | (10,10)    | ((1.15,0.05),(1.35,0.05))
+(18 rows)
+
+-- Division by 0 error
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to path
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+            f1             |            f1             |    ?column?    
+---------------------------+---------------------------+----------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((10,20))                 |  17.4642491966
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         |   11.313708499
+ [(1,2),(3,4)]             | ((11,12),(13,14))         |   11.313708499
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)] |              0
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))                 |  16.1554944214
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]         |  9.89949493661
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))         |  9.89949493661
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((10,20))                 |  17.4642491966
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         |   11.313708499
+ [(1,2),(3,4)]             | ((11,12),(13,14))         |   11.313708499
+ ((10,20))                 | [(1,2),(3,4)]             |  17.4642491966
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)] |  16.1554944214
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | [(1,2),(3,4)]             |  17.4642491966
+ ((10,20))                 | ((10,20))                 |              0
+ ((10,20))                 | [(11,12),(13,14)]         |   6.7082039325
+ ((10,20))                 | ((11,12),(13,14))         |   6.7082039325
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             |   11.313708499
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)] |  9.89949493661
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             |   11.313708499
+ [(11,12),(13,14)]         | ((10,20))                 |   6.7082039325
+ [(11,12),(13,14)]         | [(11,12),(13,14)]         |              0
+ [(11,12),(13,14)]         | ((11,12),(13,14))         |              0
+ ((11,12),(13,14))         | [(1,2),(3,4)]             |   11.313708499
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)] |  9.89949493661
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | [(1,2),(3,4)]             |   11.313708499
+ ((11,12),(13,14))         | ((10,20))                 |   6.7082039325
+ ((11,12),(13,14))         | [(11,12),(13,14)]         |              0
+ ((11,12),(13,14))         | ((11,12),(13,14))         |              0
+(81 rows)
 
 --
 -- Polygons
 --
 -- containment
 SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
    FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
+ twentyfour |        f1         |             f1             | contains 
+------------+-------------------+----------------------------+----------
+            | (0,0)             | ((2,0),(2,4),(0,0))        | t
+            | (0,0)             | ((3,1),(3,3),(1,0))        | f
+            | (0,0)             | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (0,0)             | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (0,0)             | ((0,0))                    | t
+            | (0,0)             | ((0,1),(0,1))              | f
+            | (-10,0)           | ((2,0),(2,4),(0,0))        | f
+            | (-10,0)           | ((3,1),(3,3),(1,0))        | f
+            | (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-10,0)           | ((0,0))                    | f
+            | (-10,0)           | ((0,1),(0,1))              | f
+            | (-3,4)            | ((2,0),(2,4),(0,0))        | f
+            | (-3,4)            | ((3,1),(3,3),(1,0))        | f
+            | (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-3,4)            | ((0,0))                    | f
+            | (-3,4)            | ((0,1),(0,1))              | f
+            | (5.1,34.5)        | ((2,0),(2,4),(0,0))        | f
+            | (5.1,34.5)        | ((3,1),(3,3),(1,0))        | f
+            | (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (5.1,34.5)        | ((0,0))                    | f
+            | (5.1,34.5)        | ((0,1),(0,1))              | f
+            | (-5,-12)          | ((2,0),(2,4),(0,0))        | f
+            | (-5,-12)          | ((3,1),(3,3),(1,0))        | f
+            | (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-5,-12)          | ((0,0))                    | f
+            | (-5,-12)          | ((0,1),(0,1))              | f
+            | (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        | t
+            | (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        | f
+            | (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e-300,-1e-300)  | ((0,0))                    | t
+            | (1e-300,-1e-300)  | ((0,1),(0,1))              | f
+            | (1e+300,Infinity) | ((2,0),(2,4),(0,0))        | f
+            | (1e+300,Infinity) | ((3,1),(3,3),(1,0))        | f
+            | (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e+300,Infinity) | ((0,0))                    | f
+            | (1e+300,Infinity) | ((0,1),(0,1))              | f
+            | (NaN,NaN)         | ((2,0),(2,4),(0,0))        | t
+            | (NaN,NaN)         | ((3,1),(3,3),(1,0))        | t
+            | (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  | t
+            | (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  | t
+            | (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) | t
+            | (NaN,NaN)         | ((0,0))                    | t
+            | (NaN,NaN)         | ((0,1),(0,1))              | t
+            | (10,10)           | ((2,0),(2,4),(0,0))        | f
+            | (10,10)           | ((3,1),(3,3),(1,0))        | f
+            | (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (10,10)           | ((0,0))                    | f
+            | (10,10)           | ((0,1),(0,1))              | f
+(63 rows)
 
 SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
    FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
+ twentyfour |        f1         |             f1             | contained 
+------------+-------------------+----------------------------+-----------
+            | (0,0)             | ((2,0),(2,4),(0,0))        | t
+            | (0,0)             | ((3,1),(3,3),(1,0))        | f
+            | (0,0)             | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (0,0)             | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (0,0)             | ((0,0))                    | t
+            | (0,0)             | ((0,1),(0,1))              | f
+            | (-10,0)           | ((2,0),(2,4),(0,0))        | f
+            | (-10,0)           | ((3,1),(3,3),(1,0))        | f
+            | (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-10,0)           | ((0,0))                    | f
+            | (-10,0)           | ((0,1),(0,1))              | f
+            | (-3,4)            | ((2,0),(2,4),(0,0))        | f
+            | (-3,4)            | ((3,1),(3,3),(1,0))        | f
+            | (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-3,4)            | ((0,0))                    | f
+            | (-3,4)            | ((0,1),(0,1))              | f
+            | (5.1,34.5)        | ((2,0),(2,4),(0,0))        | f
+            | (5.1,34.5)        | ((3,1),(3,3),(1,0))        | f
+            | (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (5.1,34.5)        | ((0,0))                    | f
+            | (5.1,34.5)        | ((0,1),(0,1))              | f
+            | (-5,-12)          | ((2,0),(2,4),(0,0))        | f
+            | (-5,-12)          | ((3,1),(3,3),(1,0))        | f
+            | (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-5,-12)          | ((0,0))                    | f
+            | (-5,-12)          | ((0,1),(0,1))              | f
+            | (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        | t
+            | (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        | f
+            | (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e-300,-1e-300)  | ((0,0))                    | t
+            | (1e-300,-1e-300)  | ((0,1),(0,1))              | f
+            | (1e+300,Infinity) | ((2,0),(2,4),(0,0))        | f
+            | (1e+300,Infinity) | ((3,1),(3,3),(1,0))        | f
+            | (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e+300,Infinity) | ((0,0))                    | f
+            | (1e+300,Infinity) | ((0,1),(0,1))              | f
+            | (NaN,NaN)         | ((2,0),(2,4),(0,0))        | t
+            | (NaN,NaN)         | ((3,1),(3,3),(1,0))        | t
+            | (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  | t
+            | (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  | t
+            | (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) | t
+            | (NaN,NaN)         | ((0,0))                    | t
+            | (NaN,NaN)         | ((0,1),(0,1))              | t
+            | (10,10)           | ((2,0),(2,4),(0,0))        | f
+            | (10,10)           | ((3,1),(3,3),(1,0))        | f
+            | (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (10,10)           | ((0,0))                    | f
+            | (10,10)           | ((0,1),(0,1))              | f
+(63 rows)
 
 SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
    FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
+ four | npoints |          polygon           
+------+---------+----------------------------
       |       3 | ((2,0),(2,4),(0,0))
       |       3 | ((3,1),(3,3),(1,0))
+      |       4 | ((1,2),(3,4),(5,6),(7,8))
+      |       4 | ((7,8),(5,6),(3,4),(1,2))
+      |       4 | ((1,2),(7,8),(5,6),(3,-4))
       |       1 | ((0,0))
       |       2 | ((0,1),(0,1))
-(4 rows)
+(7 rows)
 
 SELECT '' AS four, polygon(f1)
    FROM BOX_TBL;
  four |                  polygon                  
 ------+-------------------------------------------
       | ((0,0),(0,2),(2,2),(2,0))
       | ((1,1),(1,3),(3,3),(3,1))
+      | ((-8,-10),(-8,2),(-2,2),(-2,-10))
       | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
       | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, polygon(f1)
    FROM PATH_TBL WHERE isclosed(f1);
  four |      polygon      
 ------+-------------------
       | ((1,2),(3,4))
       | ((1,2),(3,4))
       | ((1,2),(3,4))
+      | ((10,20))
       | ((11,12),(13,14))
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
    FROM PATH_TBL
    WHERE isopen(f1);
  four |         open_path         |          polygon          
 ------+---------------------------+---------------------------
       | [(1,2),(3,4)]             | ((1,2),(3,4))
       | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
       | [(1,2),(3,4)]             | ((1,2),(3,4))
       | [(11,12),(13,14)]         | ((11,12),(13,14))
 (4 rows)
 
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
+-- To box
+SELECT f1, f1::box FROM POLYGON_TBL;
+             f1             |      f1      
+----------------------------+--------------
+ ((2,0),(2,4),(0,0))        | (2,4),(0,0)
+ ((3,1),(3,3),(1,0))        | (3,3),(1,0)
+ ((1,2),(3,4),(5,6),(7,8))  | (7,8),(1,2)
+ ((7,8),(5,6),(3,4),(1,2))  | (7,8),(1,2)
+ ((1,2),(7,8),(5,6),(3,-4)) | (7,8),(1,-4)
+ ((0,0))                    | (0,0),(0,0)
+ ((0,1),(0,1))              | (0,1),(0,1)
+(7 rows)
 
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
+-- To path
+SELECT f1, f1::path FROM POLYGON_TBL;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(7 rows)
 
+-- Same as polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 ~= p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(9 rows)
+
+-- Contained by polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <@ p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(12 rows)
+
+-- Contains polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 @> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(12 rows)
+
+-- Overlap with polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 && p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(25 rows)
+
+-- Left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 << p2.f1;
+      f1       |             f1             
+---------------+----------------------------
+ ((0,0))       | ((3,1),(3,3),(1,0))
+ ((0,0))       | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))       | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))       | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1)) | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1)) | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1)) | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1)) | ((1,2),(7,8),(5,6),(3,-4))
+(8 rows)
+
+-- Overlap of left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &< p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))                    | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1))              | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(32 rows)
+
+-- Right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 >> p2.f1;
+             f1             |      f1       
+----------------------------+---------------
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((0,1),(0,1))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1))
+(8 rows)
+
+-- Overlap of right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((2,0),(2,4),(0,0))        | ((0,1),(0,1))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((0,1),(0,1))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((3,1),(3,3),(1,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(37 rows)
+
+-- Below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <<| p2.f1;
+      f1       |            f1             
+---------------+---------------------------
+ ((0,0))       | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))       | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))       | ((0,1),(0,1))
+ ((0,1),(0,1)) | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1)) | ((7,8),(5,6),(3,4),(1,2))
+(5 rows)
+
+-- Overlap or below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &<| p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))                    | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1))              | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(31 rows)
+
+-- Above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |>> p2.f1;
+            f1             |      f1       
+---------------------------+---------------
+ ((1,2),(3,4),(5,6),(7,8)) | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8)) | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2)) | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2)) | ((0,1),(0,1))
+ ((0,1),(0,1))             | ((0,0))
+(5 rows)
+
+-- Overlap or above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |&> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((3,1),(3,3),(1,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(32 rows)
+
+-- Distance to polygon
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2;
+ERROR:  function "poly_distance" not implemented
 --
 -- Circles
 --
 SELECT '' AS six, circle(f1, 50.0)
    FROM POINT_TBL;
- six |     circle      
------+-----------------
+ six |         circle         
+-----+------------------------
      | <(0,0),50>
      | <(-10,0),50>
      | <(-3,4),50>
      | <(5.1,34.5),50>
      | <(-5,-12),50>
+     | <(1e-300,-1e-300),50>
+     | <(1e+300,Infinity),50>
+     | <(NaN,NaN),50>
      | <(10,10),50>
-(6 rows)
+(9 rows)
 
 SELECT '' AS four, circle(f1)
    FROM BOX_TBL;
- four |        circle         
-------+-----------------------
+ four |         circle         
+------+------------------------
       | <(1,1),1.41421356237>
       | <(2,2),1.41421356237>
+      | <(-5,-4),6.7082039325>
       | <(2.5,3),0.5>
       | <(3,3),0>
-(4 rows)
+(5 rows)
 
 SELECT '' AS two, circle(f1)
    FROM POLYGON_TBL
    WHERE (# f1) >= 3;
  two |                    circle                     
 -----+-----------------------------------------------
      | <(1.33333333333,1.33333333333),2.04168905064>
      | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
+     | <(4,5),2.82842712475>
+     | <(4,5),2.82842712475>
+     | <(4,3),4.80664375676>
+(5 rows)
 
 SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
    FROM CIRCLE_TBL c1, POINT_TBL p1
    WHERE (p1.f1 <-> c1.f1) > 0
    ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
+ twentyfour |     circle     |       point       |   distance    
+------------+----------------+-------------------+---------------
+            | <(1,2),3>      | (-3,4)            |   1.472135955
+            | <(5,1),3>      | (0,0)             | 2.09901951359
+            | <(5,1),3>      | (1e-300,-1e-300)  | 2.09901951359
+            | <(5,1),3>      | (-3,4)            | 5.54400374532
+            | <(3,5),0>      | (0,0)             | 5.83095189485
+            | <(3,5),0>      | (1e-300,-1e-300)  | 5.83095189485
+            | <(3,5),0>      | (-3,4)            |  6.0827625303
+            | <(1,3),5>      | (-10,0)           | 6.40175425099
+            | <(1,3),5>      | (10,10)           | 6.40175425099
+            | <(5,1),3>      | (10,10)           | 7.29563014099
+            | <(1,2),3>      | (-10,0)           |  8.1803398875
+            | <(3,5),0>      | (10,10)           | 8.60232526704
+            | <(1,2),3>      | (10,10)           | 9.04159457879
+            | <(1,3),5>      | (-5,-12)          | 11.1554944214
+            | <(5,1),3>      | (-10,0)           | 12.0332963784
+            | <(1,2),3>      | (-5,-12)          | 12.2315462117
+            | <(5,1),3>      | (-5,-12)          | 13.4012194669
+            | <(3,5),0>      | (-10,0)           | 13.9283882772
+            | <(3,5),0>      | (-5,-12)          | 18.7882942281
+            | <(1,3),5>      | (5.1,34.5)        | 26.7657047773
+            | <(3,5),0>      | (5.1,34.5)        | 29.5746513082
+            | <(1,2),3>      | (5.1,34.5)        | 29.7575945393
+            | <(5,1),3>      | (5.1,34.5)        | 30.5001492534
+            | <(100,200),10> | (5.1,34.5)        | 180.778038568
+            | <(100,200),10> | (10,10)           | 200.237960416
+            | <(100,200),10> | (-3,4)            | 211.415898255
+            | <(100,200),10> | (0,0)             |  213.60679775
+            | <(100,200),10> | (1e-300,-1e-300)  |  213.60679775
+            | <(100,200),10> | (-10,0)           |  218.25424421
+            | <(100,200),10> | (-5,-12)          | 226.577682802
+            | <(3,5),0>      | (1e+300,Infinity) |      Infinity
+            | <(1,2),3>      | (1e+300,Infinity) |      Infinity
+            | <(5,1),3>      | (1e+300,Infinity) |      Infinity
+            | <(1,3),5>      | (1e+300,Infinity) |      Infinity
+            | <(100,200),10> | (1e+300,Infinity) |      Infinity
+            | <(1,2),100>    | (1e+300,Infinity) |      Infinity
+            | <(100,1),115>  | (1e+300,Infinity) |      Infinity
+            | <(3,5),0>      | (NaN,NaN)         |           NaN
+            | <(1,2),3>      | (NaN,NaN)         |           NaN
+            | <(5,1),3>      | (NaN,NaN)         |           NaN
+            | <(1,3),5>      | (NaN,NaN)         |           NaN
+            | <(100,200),10> | (NaN,NaN)         |           NaN
+            | <(1,2),100>    | (NaN,NaN)         |           NaN
+            | <(100,1),115>  | (NaN,NaN)         |           NaN
+            | <(3,5),NaN>    | (-10,0)           |           NaN
+            | <(3,5),NaN>    | (-5,-12)          |           NaN
+            | <(3,5),NaN>    | (-3,4)            |           NaN
+            | <(3,5),NaN>    | (0,0)             |           NaN
+            | <(3,5),NaN>    | (1e-300,-1e-300)  |           NaN
+            | <(3,5),NaN>    | (5.1,34.5)        |           NaN
+            | <(3,5),NaN>    | (10,10)           |           NaN
+            | <(3,5),NaN>    | (1e+300,Infinity) |           NaN
+            | <(3,5),NaN>    | (NaN,NaN)         |           NaN
+(53 rows)
+
+-- To polygon
+SELECT f1, f1::polygon FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+       f1       |                                                                                                          f1                                                                                                          
+----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ <(5,1),3>      | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
+ <(1,2),100>    | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
+ <(1,3),5>      | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
+ <(1,2),3>      | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
+ <(100,200),10> | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
+ <(100,1),115>  | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
+(6 rows)
+
+-- To polygon with less points
+SELECT f1, polygon(8, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+       f1       |                                                                             polygon                                                                              
+----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ <(5,1),3>      | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
+ <(1,2),100>    | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
+ <(1,3),5>      | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
+ <(1,2),3>      | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
+ <(100,200),10> | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
+ <(100,1),115>  | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
+(6 rows)
+
+-- Too less points error
+SELECT f1, polygon(1, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+ERROR:  must request at least 2 points
+-- Zero radius error
+SELECT f1, polygon(10, f1) FROM CIRCLE_TBL WHERE f1 < '<(0,0),1>';
+ERROR:  cannot convert circle with radius zero to polygon
+-- Same as circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 ~= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+ <(3,5),NaN>    | <(3,5),0>
+ <(3,5),NaN>    | <(3,5),NaN>
+(9 rows)
+
+-- Overlap with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 && c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,1),115>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(100,1),115>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(33 rows)
+
+-- Overlap or left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &< c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(28 rows)
+
+-- Left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 << c2.f1;
+    f1     |       f1       
+-----------+----------------
+ <(5,1),3> | <(100,200),10>
+ <(1,3),5> | <(100,200),10>
+ <(1,2),3> | <(100,200),10>
+ <(3,5),0> | <(100,200),10>
+(4 rows)
+
+-- Right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >> c2.f1;
+       f1       |    f1     
+----------------+-----------
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(3,5),0>
+(4 rows)
+
+-- Overlap or right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(28 rows)
+
+-- Contained by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <@ c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(17 rows)
+
+-- Contain by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 @> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(3,5),0>
+(17 rows)
+
+-- Below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <<| c2.f1;
+      f1       |       f1       
+---------------+----------------
+ <(5,1),3>     | <(100,200),10>
+ <(5,1),3>     | <(3,5),0>
+ <(1,2),100>   | <(100,200),10>
+ <(1,3),5>     | <(100,200),10>
+ <(1,2),3>     | <(100,200),10>
+ <(100,1),115> | <(100,200),10>
+ <(3,5),0>     | <(100,200),10>
+(7 rows)
+
+-- Above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |>> c2.f1;
+       f1       |      f1       
+----------------+---------------
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(3,5),0>      | <(5,1),3>
+(7 rows)
+
+-- Overlap or below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &<| c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Overlap or above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |&> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 = c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(9 rows)
+
+-- Area not equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 != c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(40 rows)
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 > c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(3,5),0>
+(20 rows)
+
+-- Area less than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area greater than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Add point
+SELECT c.f1, p.f1, c.f1 + p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |        ?column?         
+----------------+-------------------+-------------------------
+ <(5,1),3>      | (0,0)             | <(5,1),3>
+ <(1,2),100>    | (0,0)             | <(1,2),100>
+ <(1,3),5>      | (0,0)             | <(1,3),5>
+ <(1,2),3>      | (0,0)             | <(1,2),3>
+ <(100,200),10> | (0,0)             | <(100,200),10>
+ <(100,1),115>  | (0,0)             | <(100,1),115>
+ <(3,5),0>      | (0,0)             | <(3,5),0>
+ <(3,5),NaN>    | (0,0)             | <(3,5),NaN>
+ <(5,1),3>      | (-10,0)           | <(-5,1),3>
+ <(1,2),100>    | (-10,0)           | <(-9,2),100>
+ <(1,3),5>      | (-10,0)           | <(-9,3),5>
+ <(1,2),3>      | (-10,0)           | <(-9,2),3>
+ <(100,200),10> | (-10,0)           | <(90,200),10>
+ <(100,1),115>  | (-10,0)           | <(90,1),115>
+ <(3,5),0>      | (-10,0)           | <(-7,5),0>
+ <(3,5),NaN>    | (-10,0)           | <(-7,5),NaN>
+ <(5,1),3>      | (-3,4)            | <(2,5),3>
+ <(1,2),100>    | (-3,4)            | <(-2,6),100>
+ <(1,3),5>      | (-3,4)            | <(-2,7),5>
+ <(1,2),3>      | (-3,4)            | <(-2,6),3>
+ <(100,200),10> | (-3,4)            | <(97,204),10>
+ <(100,1),115>  | (-3,4)            | <(97,5),115>
+ <(3,5),0>      | (-3,4)            | <(0,9),0>
+ <(3,5),NaN>    | (-3,4)            | <(0,9),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(10.1,35.5),3>
+ <(1,2),100>    | (5.1,34.5)        | <(6.1,36.5),100>
+ <(1,3),5>      | (5.1,34.5)        | <(6.1,37.5),5>
+ <(1,2),3>      | (5.1,34.5)        | <(6.1,36.5),3>
+ <(100,200),10> | (5.1,34.5)        | <(105.1,234.5),10>
+ <(100,1),115>  | (5.1,34.5)        | <(105.1,35.5),115>
+ <(3,5),0>      | (5.1,34.5)        | <(8.1,39.5),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(8.1,39.5),NaN>
+ <(5,1),3>      | (-5,-12)          | <(0,-11),3>
+ <(1,2),100>    | (-5,-12)          | <(-4,-10),100>
+ <(1,3),5>      | (-5,-12)          | <(-4,-9),5>
+ <(1,2),3>      | (-5,-12)          | <(-4,-10),3>
+ <(100,200),10> | (-5,-12)          | <(95,188),10>
+ <(100,1),115>  | (-5,-12)          | <(95,-11),115>
+ <(3,5),0>      | (-5,-12)          | <(-2,-7),0>
+ <(3,5),NaN>    | (-5,-12)          | <(-2,-7),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(5,1),3>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(1,2),100>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(1,3),5>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(1,2),3>
+ <(100,200),10> | (1e-300,-1e-300)  | <(100,200),10>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(100,1),115>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(3,5),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(3,5),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(1e+300,Infinity),3>
+ <(1,2),100>    | (1e+300,Infinity) | <(1e+300,Infinity),100>
+ <(1,3),5>      | (1e+300,Infinity) | <(1e+300,Infinity),5>
+ <(1,2),3>      | (1e+300,Infinity) | <(1e+300,Infinity),3>
+ <(100,200),10> | (1e+300,Infinity) | <(1e+300,Infinity),10>
+ <(100,1),115>  | (1e+300,Infinity) | <(1e+300,Infinity),115>
+ <(3,5),0>      | (1e+300,Infinity) | <(1e+300,Infinity),0>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(1e+300,Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),100>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),5>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),10>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),115>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),0>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(15,11),3>
+ <(1,2),100>    | (10,10)           | <(11,12),100>
+ <(1,3),5>      | (10,10)           | <(11,13),5>
+ <(1,2),3>      | (10,10)           | <(11,12),3>
+ <(100,200),10> | (10,10)           | <(110,210),10>
+ <(100,1),115>  | (10,10)           | <(110,11),115>
+ <(3,5),0>      | (10,10)           | <(13,15),0>
+ <(3,5),NaN>    | (10,10)           | <(13,15),NaN>
+(72 rows)
+
+-- Subtract point
+SELECT c.f1, p.f1, c.f1 - p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |         ?column?          
+----------------+-------------------+---------------------------
+ <(5,1),3>      | (0,0)             | <(5,1),3>
+ <(1,2),100>    | (0,0)             | <(1,2),100>
+ <(1,3),5>      | (0,0)             | <(1,3),5>
+ <(1,2),3>      | (0,0)             | <(1,2),3>
+ <(100,200),10> | (0,0)             | <(100,200),10>
+ <(100,1),115>  | (0,0)             | <(100,1),115>
+ <(3,5),0>      | (0,0)             | <(3,5),0>
+ <(3,5),NaN>    | (0,0)             | <(3,5),NaN>
+ <(5,1),3>      | (-10,0)           | <(15,1),3>
+ <(1,2),100>    | (-10,0)           | <(11,2),100>
+ <(1,3),5>      | (-10,0)           | <(11,3),5>
+ <(1,2),3>      | (-10,0)           | <(11,2),3>
+ <(100,200),10> | (-10,0)           | <(110,200),10>
+ <(100,1),115>  | (-10,0)           | <(110,1),115>
+ <(3,5),0>      | (-10,0)           | <(13,5),0>
+ <(3,5),NaN>    | (-10,0)           | <(13,5),NaN>
+ <(5,1),3>      | (-3,4)            | <(8,-3),3>
+ <(1,2),100>    | (-3,4)            | <(4,-2),100>
+ <(1,3),5>      | (-3,4)            | <(4,-1),5>
+ <(1,2),3>      | (-3,4)            | <(4,-2),3>
+ <(100,200),10> | (-3,4)            | <(103,196),10>
+ <(100,1),115>  | (-3,4)            | <(103,-3),115>
+ <(3,5),0>      | (-3,4)            | <(6,1),0>
+ <(3,5),NaN>    | (-3,4)            | <(6,1),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(-0.1,-33.5),3>
+ <(1,2),100>    | (5.1,34.5)        | <(-4.1,-32.5),100>
+ <(1,3),5>      | (5.1,34.5)        | <(-4.1,-31.5),5>
+ <(1,2),3>      | (5.1,34.5)        | <(-4.1,-32.5),3>
+ <(100,200),10> | (5.1,34.5)        | <(94.9,165.5),10>
+ <(100,1),115>  | (5.1,34.5)        | <(94.9,-33.5),115>
+ <(3,5),0>      | (5.1,34.5)        | <(-2.1,-29.5),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(-2.1,-29.5),NaN>
+ <(5,1),3>      | (-5,-12)          | <(10,13),3>
+ <(1,2),100>    | (-5,-12)          | <(6,14),100>
+ <(1,3),5>      | (-5,-12)          | <(6,15),5>
+ <(1,2),3>      | (-5,-12)          | <(6,14),3>
+ <(100,200),10> | (-5,-12)          | <(105,212),10>
+ <(100,1),115>  | (-5,-12)          | <(105,13),115>
+ <(3,5),0>      | (-5,-12)          | <(8,17),0>
+ <(3,5),NaN>    | (-5,-12)          | <(8,17),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(5,1),3>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(1,2),100>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(1,3),5>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(1,2),3>
+ <(100,200),10> | (1e-300,-1e-300)  | <(100,200),10>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(100,1),115>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(3,5),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(3,5),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(-1e+300,-Infinity),3>
+ <(1,2),100>    | (1e+300,Infinity) | <(-1e+300,-Infinity),100>
+ <(1,3),5>      | (1e+300,Infinity) | <(-1e+300,-Infinity),5>
+ <(1,2),3>      | (1e+300,Infinity) | <(-1e+300,-Infinity),3>
+ <(100,200),10> | (1e+300,Infinity) | <(-1e+300,-Infinity),10>
+ <(100,1),115>  | (1e+300,Infinity) | <(-1e+300,-Infinity),115>
+ <(3,5),0>      | (1e+300,Infinity) | <(-1e+300,-Infinity),0>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(-1e+300,-Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),100>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),5>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),10>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),115>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),0>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(-5,-9),3>
+ <(1,2),100>    | (10,10)           | <(-9,-8),100>
+ <(1,3),5>      | (10,10)           | <(-9,-7),5>
+ <(1,2),3>      | (10,10)           | <(-9,-8),3>
+ <(100,200),10> | (10,10)           | <(90,190),10>
+ <(100,1),115>  | (10,10)           | <(90,-9),115>
+ <(3,5),0>      | (10,10)           | <(-7,-5),0>
+ <(3,5),NaN>    | (10,10)           | <(-7,-5),NaN>
+(72 rows)
+
+-- Multiply with point
+SELECT c.f1, p.f1, c.f1 * p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |                  ?column?                  
+----------------+-------------------+--------------------------------------------
+ <(5,1),3>      | (0,0)             | <(0,0),0>
+ <(1,2),100>    | (0,0)             | <(0,0),0>
+ <(1,3),5>      | (0,0)             | <(0,0),0>
+ <(1,2),3>      | (0,0)             | <(0,0),0>
+ <(100,200),10> | (0,0)             | <(0,0),0>
+ <(100,1),115>  | (0,0)             | <(0,0),0>
+ <(3,5),0>      | (0,0)             | <(0,0),0>
+ <(3,5),NaN>    | (0,0)             | <(0,0),NaN>
+ <(5,1),3>      | (-10,0)           | <(-50,-10),30>
+ <(1,2),100>    | (-10,0)           | <(-10,-20),1000>
+ <(1,3),5>      | (-10,0)           | <(-10,-30),50>
+ <(1,2),3>      | (-10,0)           | <(-10,-20),30>
+ <(100,200),10> | (-10,0)           | <(-1000,-2000),100>
+ <(100,1),115>  | (-10,0)           | <(-1000,-10),1150>
+ <(3,5),0>      | (-10,0)           | <(-30,-50),0>
+ <(3,5),NaN>    | (-10,0)           | <(-30,-50),NaN>
+ <(5,1),3>      | (-3,4)            | <(-19,17),15>
+ <(1,2),100>    | (-3,4)            | <(-11,-2),500>
+ <(1,3),5>      | (-3,4)            | <(-15,-5),25>
+ <(1,2),3>      | (-3,4)            | <(-11,-2),15>
+ <(100,200),10> | (-3,4)            | <(-1100,-200),50>
+ <(100,1),115>  | (-3,4)            | <(-304,397),575>
+ <(3,5),0>      | (-3,4)            | <(-29,-3),0>
+ <(3,5),NaN>    | (-3,4)            | <(-29,-3),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(-9,177.6),104.624758064>
+ <(1,2),100>    | (5.1,34.5)        | <(-63.9,44.7),3487.49193547>
+ <(1,3),5>      | (5.1,34.5)        | <(-98.4,49.8),174.374596774>
+ <(1,2),3>      | (5.1,34.5)        | <(-63.9,44.7),104.624758064>
+ <(100,200),10> | (5.1,34.5)        | <(-6390,4470),348.749193547>
+ <(100,1),115>  | (5.1,34.5)        | <(475.5,3455.1),4010.6157258>
+ <(3,5),0>      | (5.1,34.5)        | <(-157.2,129),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(-157.2,129),NaN>
+ <(5,1),3>      | (-5,-12)          | <(-13,-65),39>
+ <(1,2),100>    | (-5,-12)          | <(19,-22),1300>
+ <(1,3),5>      | (-5,-12)          | <(31,-27),65>
+ <(1,2),3>      | (-5,-12)          | <(19,-22),39>
+ <(100,200),10> | (-5,-12)          | <(1900,-2200),130>
+ <(100,1),115>  | (-5,-12)          | <(-488,-1205),1495>
+ <(3,5),0>      | (-5,-12)          | <(45,-61),0>
+ <(3,5),NaN>    | (-5,-12)          | <(45,-61),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(6e-300,-4e-300),4.24264068712e-300>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(3e-300,1e-300),1.41421356237e-298>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(4e-300,2e-300),7.07106781187e-300>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(3e-300,1e-300),4.24264068712e-300>
+ <(100,200),10> | (1e-300,-1e-300)  | <(3e-298,1e-298),1.41421356237e-299>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(1.01e-298,-9.9e-299),1.62634559673e-298>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(8e-300,2e-300),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(8e-300,2e-300),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,2),100>    | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,3),5>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,2),3>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(100,200),10> | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(100,1),115>  | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(3,5),0>      | (1e+300,Infinity) | <(-Infinity,Infinity),NaN>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(-Infinity,Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(40,60),42.4264068712>
+ <(1,2),100>    | (10,10)           | <(-10,30),1414.21356237>
+ <(1,3),5>      | (10,10)           | <(-20,40),70.7106781187>
+ <(1,2),3>      | (10,10)           | <(-10,30),42.4264068712>
+ <(100,200),10> | (10,10)           | <(-1000,3000),141.421356237>
+ <(100,1),115>  | (10,10)           | <(990,1010),1626.34559673>
+ <(3,5),0>      | (10,10)           | <(-20,80),0>
+ <(3,5),NaN>    | (10,10)           | <(-20,80),NaN>
+(72 rows)
+
+-- Divide by point
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+       f1       |     f1     |                       ?column?                       
+----------------+------------+------------------------------------------------------
+ <(5,1),3>      | (5.1,34.5) | <(0.0493315573973,-0.137635045138),0.0860217042937>
+ <(5,1),3>      | (10,10)    | <(0.3,-0.2),0.212132034356>
+ <(1,2),100>    | (5.1,34.5) | <(0.0609244733856,-0.0199792807459),2.86739014312>
+ <(1,2),100>    | (10,10)    | <(0.15,0.05),7.07106781187>
+ <(1,3),5>      | (5.1,34.5) | <(0.0892901188891,-0.0157860983671),0.143369507156>
+ <(1,3),5>      | (10,10)    | <(0.2,0.1),0.353553390593>
+ <(1,2),3>      | (5.1,34.5) | <(0.0609244733856,-0.0199792807459),0.0860217042937>
+ <(1,2),3>      | (10,10)    | <(0.15,0.05),0.212132034356>
+ <(100,200),10> | (5.1,34.5) | <(6.09244733856,-1.99792807459),0.286739014312>
+ <(100,200),10> | (10,10)    | <(15,5),0.707106781187>
+ <(100,1),115>  | (5.1,34.5) | <(0.44768388338,-2.83237136796),3.29749866459>
+ <(100,1),115>  | (10,10)    | <(5.05,-4.95),8.13172798365>
+ <(3,5),0>      | (5.1,34.5) | <(0.154407774653,-0.0641310246164),0>
+ <(3,5),0>      | (10,10)    | <(0.4,0.1),0>
+ <(3,5),NaN>    | (5.1,34.5) | <(0.154407774653,-0.0641310246164),NaN>
+ <(3,5),NaN>    | (10,10)    | <(0.4,0.1),NaN>
+(16 rows)
+
+-- Overflow error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] > 1000;
+ERROR:  value out of range: overflow
+-- Division by 0 error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to polygon
+SELECT c.f1, p.f1, c.f1 <-> p.f1 FROM CIRCLE_TBL c, POLYGON_TBL p;
+       f1       |             f1             |    ?column?    
+----------------+----------------------------+----------------
+ <(5,1),3>      | ((2,0),(2,4),(0,0))        |              0
+ <(5,1),3>      | ((3,1),(3,3),(1,0))        |              0
+ <(5,1),3>      | ((1,2),(3,4),(5,6),(7,8))  | 0.535533905933
+ <(5,1),3>      | ((7,8),(5,6),(3,4),(1,2))  | 0.535533905933
+ <(5,1),3>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(5,1),3>      | ((0,0))                    |  2.09901951359
+ <(5,1),3>      | ((0,1),(0,1))              |              2
+ <(1,2),100>    | ((2,0),(2,4),(0,0))        |              0
+ <(1,2),100>    | ((3,1),(3,3),(1,0))        |              0
+ <(1,2),100>    | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,2),100>    | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,2),100>    | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,2),100>    | ((0,0))                    |              0
+ <(1,2),100>    | ((0,1),(0,1))              |              0
+ <(1,3),5>      | ((2,0),(2,4),(0,0))        |              0
+ <(1,3),5>      | ((3,1),(3,3),(1,0))        |              0
+ <(1,3),5>      | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,3),5>      | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,3),5>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,3),5>      | ((0,0))                    |              0
+ <(1,3),5>      | ((0,1),(0,1))              |              0
+ <(1,2),3>      | ((2,0),(2,4),(0,0))        |              0
+ <(1,2),3>      | ((3,1),(3,3),(1,0))        |              0
+ <(1,2),3>      | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,2),3>      | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,2),3>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,2),3>      | ((0,0))                    |              0
+ <(1,2),3>      | ((0,1),(0,1))              |              0
+ <(100,200),10> | ((2,0),(2,4),(0,0))        |  209.134661795
+ <(100,200),10> | ((3,1),(3,3),(1,0))        |  209.585974051
+ <(100,200),10> | ((1,2),(3,4),(5,6),(7,8))  |  203.337760371
+ <(100,200),10> | ((7,8),(5,6),(3,4),(1,2))  |  203.337760371
+ <(100,200),10> | ((1,2),(7,8),(5,6),(3,-4)) |  203.337760371
+ <(100,200),10> | ((0,0))                    |   213.60679775
+ <(100,200),10> | ((0,1),(0,1))              |  212.712819568
+ <(100,1),115>  | ((2,0),(2,4),(0,0))        |              0
+ <(100,1),115>  | ((3,1),(3,3),(1,0))        |              0
+ <(100,1),115>  | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(100,1),115>  | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(100,1),115>  | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(100,1),115>  | ((0,0))                    |              0
+ <(100,1),115>  | ((0,1),(0,1))              |              0
+ <(3,5),0>      | ((2,0),(2,4),(0,0))        |  1.41421356237
+ <(3,5),0>      | ((3,1),(3,3),(1,0))        |              2
+ <(3,5),0>      | ((1,2),(3,4),(5,6),(7,8))  | 0.707106781187
+ <(3,5),0>      | ((7,8),(5,6),(3,4),(1,2))  | 0.707106781187
+ <(3,5),0>      | ((1,2),(7,8),(5,6),(3,-4)) | 0.707106781187
+ <(3,5),0>      | ((0,0))                    |  5.83095189485
+ <(3,5),0>      | ((0,1),(0,1))              |              5
+ <(3,5),NaN>    | ((2,0),(2,4),(0,0))        |            NaN
+ <(3,5),NaN>    | ((3,1),(3,3),(1,0))        |            NaN
+ <(3,5),NaN>    | ((1,2),(3,4),(5,6),(7,8))  |            NaN
+ <(3,5),NaN>    | ((7,8),(5,6),(3,4),(1,2))  |            NaN
+ <(3,5),NaN>    | ((1,2),(7,8),(5,6),(3,-4)) |            NaN
+ <(3,5),NaN>    | ((0,0))                    |            NaN
+ <(3,5),NaN>    | ((0,1),(0,1))              |            NaN
+(56 rows)
 
diff --git a/src/test/regress/expected/geometry_2.out b/src/test/regress/expected/geometry_2.out
deleted file mode 100644
index 5a922bcd3f..0000000000
--- a/src/test/regress/expected/geometry_2.out
+++ /dev/null
@@ -1,563 +0,0 @@
---
--- GEOMETRY
---
--- Back off displayed precision a little bit to reduce platform-to-platform
--- variation in results.
-SET extra_float_digits TO -3;
---
--- Points
---
-SELECT '' AS four, center(f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS four, (@@ f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS six, point(f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS six, (@@ f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS two, (@@ f1) AS center
-   FROM POLYGON_TBL
-   WHERE (# f1) > 2;
- two |            center             
------+-------------------------------
-     | (1.33333333333,1.33333333333)
-     | (2.33333333333,1.33333333333)
-(2 rows)
-
--- "is horizontal" function
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is horizontal" operator
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is vertical" function
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE isvertical(p1.f1, point '(5.1,34.5)');
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
--- "is vertical" operator
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?| point '(5.1,34.5)';
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
---
--- Line segments
---
--- intersection
-SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-   FROM LSEG_TBL l, POINT_TBL p;
-ERROR:  operator does not exist: lseg # point
-LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-                                           ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
-
---
--- Boxes
---
-SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
- six |                              box                               
------+----------------------------------------------------------------
-     | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
-     | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
-     | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
-     | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
-     | (107.071067812,207.071067812),(92.9289321881,192.928932188)
-     | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
-
--- translation
-SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (-8,2),(-10,0)
-            | (-7,3),(-9,1)
-            | (-7.5,3.5),(-7.5,2.5)
-            | (-7,3),(-7,3)
-            | (-1,6),(-3,4)
-            | (0,7),(-2,5)
-            | (-0.5,7.5),(-0.5,6.5)
-            | (0,7),(0,7)
-            | (7.1,36.5),(5.1,34.5)
-            | (8.1,37.5),(6.1,35.5)
-            | (7.6,38),(7.6,37)
-            | (8.1,37.5),(8.1,37.5)
-            | (-3,-10),(-5,-12)
-            | (-2,-9),(-4,-11)
-            | (-2.5,-8.5),(-2.5,-9.5)
-            | (-2,-9),(-2,-9)
-            | (12,12),(10,10)
-            | (13,13),(11,11)
-            | (12.5,13.5),(12.5,12.5)
-            | (13,13),(13,13)
-(24 rows)
-
-SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (12,2),(10,0)
-            | (13,3),(11,1)
-            | (12.5,3.5),(12.5,2.5)
-            | (13,3),(13,3)
-            | (5,-2),(3,-4)
-            | (6,-1),(4,-3)
-            | (5.5,-0.5),(5.5,-1.5)
-            | (6,-1),(6,-1)
-            | (-3.1,-32.5),(-5.1,-34.5)
-            | (-2.1,-31.5),(-4.1,-33.5)
-            | (-2.6,-31),(-2.6,-32)
-            | (-2.1,-31.5),(-2.1,-31.5)
-            | (7,14),(5,12)
-            | (8,15),(6,13)
-            | (7.5,15.5),(7.5,14.5)
-            | (8,15),(8,15)
-            | (-8,-8),(-10,-10)
-            | (-7,-7),(-9,-9)
-            | (-7.5,-6.5),(-7.5,-7.5)
-            | (-7,-7),(-7,-7)
-(24 rows)
-
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (-0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (-0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,-0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
-
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,-0),(-0.2,-0.2)
-        | (0.08,-0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (-0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
-
-SELECT f1::box
-	FROM POINT_TBL;
-          f1           
------------------------
- (0,0),(0,0)
- (-10,0),(-10,0)
- (-3,4),(-3,4)
- (5.1,34.5),(5.1,34.5)
- (-5,-12),(-5,-12)
- (10,10),(10,10)
-(6 rows)
-
-SELECT bound_box(a.f1, b.f1)
-	FROM BOX_TBL a, BOX_TBL b;
-      bound_box      
----------------------
- (2,2),(0,0)
- (3,3),(0,0)
- (2.5,3.5),(0,0)
- (3,3),(0,0)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(1,1)
- (3,3),(1,1)
- (2.5,3.5),(0,0)
- (3,3.5),(1,1)
- (2.5,3.5),(2.5,2.5)
- (3,3.5),(2.5,2.5)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(2.5,2.5)
- (3,3),(3,3)
-(16 rows)
-
---
--- Paths
---
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
-
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
-
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
-
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
-
---
--- Polygons
---
--- containment
-SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
-   FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
-      |       3 | ((2,0),(2,4),(0,0))
-      |       3 | ((3,1),(3,3),(1,0))
-      |       1 | ((0,0))
-      |       2 | ((0,1),(0,1))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM BOX_TBL;
- four |                  polygon                  
-------+-------------------------------------------
-      | ((0,0),(0,2),(2,2),(2,0))
-      | ((1,1),(1,3),(3,3),(3,1))
-      | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
-      | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM PATH_TBL WHERE isclosed(f1);
- four |      polygon      
-------+-------------------
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((11,12),(13,14))
-(4 rows)
-
-SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
-   FROM PATH_TBL
-   WHERE isopen(f1);
- four |         open_path         |          polygon          
-------+---------------------------+---------------------------
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(11,12),(13,14)]         | ((11,12),(13,14))
-(4 rows)
-
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
-
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
-
---
--- Circles
---
-SELECT '' AS six, circle(f1, 50.0)
-   FROM POINT_TBL;
- six |     circle      
------+-----------------
-     | <(0,0),50>
-     | <(-10,0),50>
-     | <(-3,4),50>
-     | <(5.1,34.5),50>
-     | <(-5,-12),50>
-     | <(10,10),50>
-(6 rows)
-
-SELECT '' AS four, circle(f1)
-   FROM BOX_TBL;
- four |        circle         
-------+-----------------------
-      | <(1,1),1.41421356237>
-      | <(2,2),1.41421356237>
-      | <(2.5,3),0.5>
-      | <(3,3),0>
-(4 rows)
-
-SELECT '' AS two, circle(f1)
-   FROM POLYGON_TBL
-   WHERE (# f1) >= 3;
- two |                    circle                     
------+-----------------------------------------------
-     | <(1.33333333333,1.33333333333),2.04168905064>
-     | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
-
-SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
-   FROM CIRCLE_TBL c1, POINT_TBL p1
-   WHERE (p1.f1 <-> c1.f1) > 0
-   ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
-
diff --git a/src/test/regress/expected/line.out b/src/test/regress/expected/line.out
index f20abdc430..bf780daa2c 100644
--- a/src/test/regress/expected/line.out
+++ b/src/test/regress/expected/line.out
@@ -1,271 +1,87 @@
 --
 -- LINE
 -- Infinite lines
 --
 --DROP TABLE LINE_TBL;
 CREATE TABLE LINE_TBL (s line);
-INSERT INTO LINE_TBL VALUES ('{1,-1,1}');
-INSERT INTO LINE_TBL VALUES ('(0,0),(6,6)');
+INSERT INTO LINE_TBL VALUES ('{0,-1,5}');	-- A == 0
+INSERT INTO LINE_TBL VALUES ('{1,0,5}');	-- B == 0
+INSERT INTO LINE_TBL VALUES ('{0,3,0}');	-- A == C == 0
+INSERT INTO LINE_TBL VALUES (' (0,0), (6,6)');
 INSERT INTO LINE_TBL VALUES ('10,-10 ,-5,-4');
 INSERT INTO LINE_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LINE_TBL VALUES ('(11,22,33,44)');
-INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
-ERROR:  invalid line specification: must be two distinct points
-LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
-                                     ^
+INSERT INTO LINE_TBL VALUES ('{3,NaN,5}');
+INSERT INTO LINE_TBL VALUES ('{NaN,NaN,NaN}');
 -- horizontal
 INSERT INTO LINE_TBL VALUES ('[(1,3),(2,3)]');
 -- vertical
-INSERT INTO LINE_TBL VALUES ('[(3,1),(3,2)]');
+INSERT INTO LINE_TBL VALUES (line(point '(3,1)', point '(3,2)'));
 -- bad values for parser testing
+INSERT INTO LINE_TBL VALUES ('{}');
+ERROR:  invalid input syntax for type line: "{}"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{}');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0');
+ERROR:  invalid input syntax for type line: "{0"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0,0}');
+ERROR:  invalid input syntax for type line: "{0,0}"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0}');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0,0,1');
+ERROR:  invalid input syntax for type line: "{0,0,1"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1');
+                                     ^
 INSERT INTO LINE_TBL VALUES ('{0,0,1}');
 ERROR:  invalid line specification: A and B cannot both be zero
 LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1}');
                                      ^
+INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
+ERROR:  invalid input syntax for type line: "{0,0,1} x"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
+                                     ^
 INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
 ERROR:  invalid input syntax for type line: "(3asdf,2 ,3,4r2)"
 LINE 1: INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
                                      ^
 INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
 ERROR:  invalid input syntax for type line: "[1,2,3, 4"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
                                      ^
 INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
 ERROR:  invalid input syntax for type line: "[(,2),(3,4)]"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
                                      ^
 INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
 ERROR:  invalid input syntax for type line: "[(1,2),(3,4)"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
                                      ^
+INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
+ERROR:  invalid line specification: must be two distinct points
+LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
+                                     ^
+INSERT INTO LINE_TBL VALUES (line(point '(1,0)', point '(1,0)'));
+ERROR:  invalid line specification: must be two distinct points
 select * from LINE_TBL;
                       s                      
 ---------------------------------------------
- {1,-1,1}
+ {0,-1,5}
+ {1,0,5}
+ {0,3,0}
  {1,-1,0}
  {-0.4,-1,-6}
  {-0.000184615384615385,-1,15.3846153846154}
- {1,-1,11}
+ {3,NaN,5}
+ {NaN,NaN,NaN}
  {0,-1,3}
  {-1,0,3}
-(7 rows)
+(10 rows)
 
--- functions and operators
-SELECT * FROM LINE_TBL WHERE (s <-> line '[(1,2),(3,4)]') < 10;
-                      s                      
----------------------------------------------
- {1,-1,1}
- {1,-1,0}
- {-0.4,-1,-6}
- {-0.000184615384615385,-1,15.3846153846154}
- {1,-1,11}
- {0,-1,3}
- {-1,0,3}
-(7 rows)
-
-SELECT * FROM LINE_TBL WHERE (point '(0.1,0.1)' <-> s) < 1;
-    s     
-----------
- {1,-1,1}
- {1,-1,0}
-(2 rows)
-
-SELECT * FROM LINE_TBL WHERE (lseg '[(0.1,0.1),(0.2,0.2)]' <-> s) < 1;
-    s     
-----------
- {1,-1,1}
- {1,-1,0}
-(2 rows)
-
-SELECT line '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
- ?column? 
-----------
-        2
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
- ?column? 
-----------
-        2
-(1 row)
-
-SELECT point '(-1,1)' <-> line '[(-3,0),(-4,0)]';
- ?column? 
-----------
-        1
-(1 row)
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(2,0),(0,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# box '(0,0,2,2)';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(3,0),(4,1)]' ?# box '(0,0,2,2)';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(1,1)' <@ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT point '(1,1)' <@ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(1,1)' @ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT point '(1,1)' @ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT lseg '[(1,1),(2,2)]' <@ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' <@ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT lseg '[(1,1),(2,2)]' @ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' @ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(0,1)' ## line '[(0,0),(1,1)]';
- ?column?  
------------
- (0.5,0.5)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ## lseg '[(1,0),(2,0)]';
- ?column? 
-----------
- (1,0)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(2,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(1,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(2,1)]';
- ?column? 
-----------
- 
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(1,1)]';
- ?column? 
-----------
- (1,1)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(2,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,0)]' ?-| line '[(0,0),(0,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?-| line '[(1,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT ?- line '[(0,0),(1,0)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT ?- line '[(0,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT ?| line '[(0,0),(0,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT ?| line '[(0,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line(point '(1,2)', point '(3,4)');
-   line   
-----------
- {1,-1,1}
-(1 row)
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,5)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,4)]';  -- false
- ?column? 
-----------
- f
+select '{nan, 1, nan}'::line = '{nan, 1, nan}'::line as true,
+	   '{nan, 1, nan}'::line = '{nan, 2, nan}'::line as false;
+ true | false 
+------+-------
+ t    | f
 (1 row)
 
diff --git a/src/test/regress/expected/lseg.out b/src/test/regress/expected/lseg.out
index bba1f3ee80..7e878b5577 100644
--- a/src/test/regress/expected/lseg.out
+++ b/src/test/regress/expected/lseg.out
@@ -1,21 +1,24 @@
 --
 -- LSEG
 -- Line segments
 --
 --DROP TABLE LSEG_TBL;
 CREATE TABLE LSEG_TBL (s lseg);
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('(0,0),(6,6)');
 INSERT INTO LSEG_TBL VALUES ('10,-10 ,-3,-4');
 INSERT INTO LSEG_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LSEG_TBL VALUES ('(11,22,33,44)');
+INSERT INTO LSEG_TBL VALUES (lseg(point(11, 22), point(33,44)));
+INSERT INTO LSEG_TBL VALUES ('[(-10,2),(-10,3)]');	-- vertical
+INSERT INTO LSEG_TBL VALUES ('[(0,-20),(30,-20)]');	-- horizontal
+INSERT INTO LSEG_TBL VALUES ('[(NaN,1),(NaN,90)]');	-- NaN
 -- bad values for parser testing
 INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
 ERROR:  invalid input syntax for type lseg: "(3asdf,2 ,3,4r2)"
 LINE 1: INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
                                      ^
 INSERT INTO LSEG_TBL VALUES ('[1,2,3, 4');
 ERROR:  invalid input syntax for type lseg: "[1,2,3, 4"
 LINE 1: INSERT INTO LSEG_TBL VALUES ('[1,2,3, 4');
                                      ^
 INSERT INTO LSEG_TBL VALUES ('[(,2),(3,4)]');
@@ -27,26 +30,15 @@ ERROR:  invalid input syntax for type lseg: "[(1,2),(3,4)"
 LINE 1: INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)');
                                      ^
 select * from LSEG_TBL;
                s               
 -------------------------------
  [(1,2),(3,4)]
  [(0,0),(6,6)]
  [(10,-10),(-3,-4)]
  [(-1000000,200),(300000,-40)]
  [(11,22),(33,44)]
-(5 rows)
-
-SELECT * FROM LSEG_TBL WHERE s <= lseg '[(1,2),(3,4)]';
-       s       
----------------
- [(1,2),(3,4)]
-(1 row)
-
-SELECT * FROM LSEG_TBL WHERE (s <-> lseg '[(1,2),(3,4)]') < 10;
-         s          
---------------------
- [(1,2),(3,4)]
- [(0,0),(6,6)]
- [(10,-10),(-3,-4)]
-(3 rows)
+ [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]
+ [(NaN,1),(NaN,90)]
+(8 rows)
 
diff --git a/src/test/regress/expected/path.out b/src/test/regress/expected/path.out
index 08d6d61dda..bd6e467752 100644
--- a/src/test/regress/expected/path.out
+++ b/src/test/regress/expected/path.out
@@ -1,79 +1,82 @@
 --
 -- PATH
 --
 --DROP TABLE PATH_TBL;
 CREATE TABLE PATH_TBL (f1 path);
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)]');
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
-INSERT INTO PATH_TBL VALUES ('[(0,0),(3,0),(4,5),(1,6)]');
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
-INSERT INTO PATH_TBL VALUES ('1,2 ,3,4');
-INSERT INTO PATH_TBL VALUES ('[1,2,3, 4]');
-INSERT INTO PATH_TBL VALUES ('[11,12,13,14]');
-INSERT INTO PATH_TBL VALUES ('(11,12,13,14)');
+INSERT INTO PATH_TBL VALUES (' ( ( 1 , 2 ) , ( 3 , 4 ) ) ');
+INSERT INTO PATH_TBL VALUES ('[ (0,0),(3,0),(4,5),(1,6) ]');
+INSERT INTO PATH_TBL VALUES ('((1,2) ,(3,4 ))');
+INSERT INTO PATH_TBL VALUES ('1,2 ,3,4 ');
+INSERT INTO PATH_TBL VALUES (' [1,2,3, 4] ');
+INSERT INTO PATH_TBL VALUES ('((10,20))');	-- Only one point
+INSERT INTO PATH_TBL VALUES ('[ 11,12,13,14 ]');
+INSERT INTO PATH_TBL VALUES ('( 11,12,13,14) ');
 -- bad values for parser testing
+INSERT INTO PATH_TBL VALUES ('[]');
+ERROR:  invalid input syntax for type path: "[]"
+LINE 1: INSERT INTO PATH_TBL VALUES ('[]');
+                                     ^
 INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
 ERROR:  invalid input syntax for type path: "[(,2),(3,4)]"
 LINE 1: INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
                                      ^
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
 ERROR:  invalid input syntax for type path: "[(1,2),(3,4)"
 LINE 1: INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
                                      ^
-SELECT f1 FROM PATH_TBL;
-            f1             
----------------------------
- [(1,2),(3,4)]
- ((1,2),(3,4))
- [(0,0),(3,0),(4,5),(1,6)]
- ((1,2),(3,4))
- ((1,2),(3,4))
- [(1,2),(3,4)]
- [(11,12),(13,14)]
- ((11,12),(13,14))
-(8 rows)
-
+INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+ERROR:  invalid input syntax for type path: "(1,2,3,4"
+LINE 1: INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+                                     ^
+INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
+ERROR:  invalid input syntax for type path: "(1,2),(3,4)]"
+LINE 1: INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
+                                     ^
 SELECT '' AS count, f1 AS open_path FROM PATH_TBL WHERE isopen(f1);
  count |         open_path         
 -------+---------------------------
        | [(1,2),(3,4)]
        | [(0,0),(3,0),(4,5),(1,6)]
        | [(1,2),(3,4)]
        | [(11,12),(13,14)]
 (4 rows)
 
 SELECT '' AS count, f1 AS closed_path FROM PATH_TBL WHERE isclosed(f1);
  count |    closed_path    
 -------+-------------------
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
+       | ((10,20))
        | ((11,12),(13,14))
-(4 rows)
+(5 rows)
 
 SELECT '' AS count, pclose(f1) AS closed_path FROM PATH_TBL;
  count |        closed_path        
 -------+---------------------------
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((0,0),(3,0),(4,5),(1,6))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
+       | ((10,20))
        | ((11,12),(13,14))
        | ((11,12),(13,14))
-(8 rows)
+(9 rows)
 
 SELECT '' AS count, popen(f1) AS open_path FROM PATH_TBL;
  count |         open_path         
 -------+---------------------------
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
        | [(0,0),(3,0),(4,5),(1,6)]
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
+       | [(10,20)]
        | [(11,12),(13,14)]
        | [(11,12),(13,14)]
-(8 rows)
+(9 rows)
 
diff --git a/src/test/regress/expected/point.out b/src/test/regress/expected/point.out
index bfc0962749..c18e865370 100644
--- a/src/test/regress/expected/point.out
+++ b/src/test/regress/expected/point.out
@@ -1,43 +1,57 @@
 --
 -- POINT
 --
 CREATE TABLE POINT_TBL(f1 point);
 INSERT INTO POINT_TBL(f1) VALUES ('(0.0,0.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-10.0,0.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-3.0,4.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(5.1, 34.5)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-5.0,-12.0)');
+INSERT INTO POINT_TBL(f1) VALUES ('(1e-300,-1e-300)');	-- To underflow
+INSERT INTO POINT_TBL(f1) VALUES ('(1e+300,Inf)');		-- To overflow
+INSERT INTO POINT_TBL(f1) VALUES (' ( Nan , NaN ) ');
 -- bad format points
 INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
 ERROR:  invalid input syntax for type point: "asdfasdf"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
                                           ^
 INSERT INTO POINT_TBL(f1) VALUES ('10.0,10.0');
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
 ERROR:  invalid input syntax for type point: "(10.0 10.0)"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
                                           ^
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+ERROR:  invalid input syntax for type point: "(10.0, 10.0) x"
+LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+                                          ^
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
 ERROR:  invalid input syntax for type point: "(10.0,10.0"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
                                           ^
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');	-- Out of range
+ERROR:  "1e+500" is out of range for type double precision
+LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');
+                                          ^
 SELECT '' AS six, * FROM POINT_TBL;
- six |     f1     
------+------------
+ six |        f1         
+-----+-------------------
      | (0,0)
      | (-10,0)
      | (-3,4)
      | (5.1,34.5)
      | (-5,-12)
+     | (1e-300,-1e-300)
+     | (1e+300,Infinity)
+     | (NaN,NaN)
      | (10,10)
-(6 rows)
+(9 rows)
 
 -- left of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE p.f1 << '(0.0, 0.0)';
  three |    f1    
 -------+----------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
 (3 rows)
 
@@ -85,172 +99,282 @@ 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    
--------+----------
+ three |        f1         
+-------+-------------------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
-(3 rows)
+       | (1e-300,-1e-300)
+       | (1e+300,Infinity)
+       | (NaN,NaN)
+(6 rows)
 
 SELECT '' AS two, p.* FROM POINT_TBL p
    WHERE p.f1 <@ path '[(0,0),(-10,0),(-10,10)]';
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 SELECT '' AS three, p.* FROM POINT_TBL p
    WHERE not box '(0,0,100,100)' @> p.f1;
- three |    f1    
--------+----------
+ three |        f1         
+-------+-------------------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
-(3 rows)
+       | (1e-300,-1e-300)
+       | (1e+300,Infinity)
+       | (NaN,NaN)
+(6 rows)
 
 SELECT '' AS six, p.f1, p.f1 <-> point '(0,0)' AS dist
    FROM POINT_TBL p
    ORDER BY dist;
- six |     f1     |       dist       
------+------------+------------------
-     | (0,0)      |                0
-     | (-3,4)     |                5
-     | (-10,0)    |               10
-     | (-5,-12)   |               13
-     | (10,10)    |  14.142135623731
-     | (5.1,34.5) | 34.8749193547455
-(6 rows)
+ six |        f1         |         dist         
+-----+-------------------+----------------------
+     | (0,0)             |                    0
+     | (1e-300,-1e-300)  | 1.4142135623731e-300
+     | (-3,4)            |                    5
+     | (-10,0)           |                   10
+     | (-5,-12)          |                   13
+     | (10,10)           |      14.142135623731
+     | (5.1,34.5)        |     34.8749193547455
+     | (1e+300,Infinity) |             Infinity
+     | (NaN,NaN)         |                  NaN
+(9 rows)
 
 SELECT '' AS thirtysix, p1.f1 AS point1, p2.f1 AS point2, p1.f1 <-> p2.f1 AS dist
    FROM POINT_TBL p1, POINT_TBL p2
    ORDER BY dist, p1.f1[0], p2.f1[0];
- thirtysix |   point1   |   point2   |       dist       
------------+------------+------------+------------------
-           | (-10,0)    | (-10,0)    |                0
-           | (-5,-12)   | (-5,-12)   |                0
-           | (-3,4)     | (-3,4)     |                0
-           | (0,0)      | (0,0)      |                0
-           | (5.1,34.5) | (5.1,34.5) |                0
-           | (10,10)    | (10,10)    |                0
-           | (-3,4)     | (0,0)      |                5
-           | (0,0)      | (-3,4)     |                5
-           | (-10,0)    | (-3,4)     | 8.06225774829855
-           | (-3,4)     | (-10,0)    | 8.06225774829855
-           | (-10,0)    | (0,0)      |               10
-           | (0,0)      | (-10,0)    |               10
-           | (-10,0)    | (-5,-12)   |               13
-           | (-5,-12)   | (-10,0)    |               13
-           | (-5,-12)   | (0,0)      |               13
-           | (0,0)      | (-5,-12)   |               13
-           | (0,0)      | (10,10)    |  14.142135623731
-           | (10,10)    | (0,0)      |  14.142135623731
-           | (-3,4)     | (10,10)    | 14.3178210632764
-           | (10,10)    | (-3,4)     | 14.3178210632764
-           | (-5,-12)   | (-3,4)     | 16.1245154965971
-           | (-3,4)     | (-5,-12)   | 16.1245154965971
-           | (-10,0)    | (10,10)    | 22.3606797749979
-           | (10,10)    | (-10,0)    | 22.3606797749979
-           | (5.1,34.5) | (10,10)    | 24.9851956166046
-           | (10,10)    | (5.1,34.5) | 24.9851956166046
-           | (-5,-12)   | (10,10)    | 26.6270539113887
-           | (10,10)    | (-5,-12)   | 26.6270539113887
-           | (-3,4)     | (5.1,34.5) | 31.5572495632937
-           | (5.1,34.5) | (-3,4)     | 31.5572495632937
-           | (0,0)      | (5.1,34.5) | 34.8749193547455
-           | (5.1,34.5) | (0,0)      | 34.8749193547455
-           | (-10,0)    | (5.1,34.5) | 37.6597928831267
-           | (5.1,34.5) | (-10,0)    | 37.6597928831267
-           | (-5,-12)   | (5.1,34.5) | 47.5842410888311
-           | (5.1,34.5) | (-5,-12)   | 47.5842410888311
-(36 rows)
+ thirtysix |      point1       |      point2       |         dist         
+-----------+-------------------+-------------------+----------------------
+           | (-10,0)           | (-10,0)           |                    0
+           | (-5,-12)          | (-5,-12)          |                    0
+           | (-3,4)            | (-3,4)            |                    0
+           | (0,0)             | (0,0)             |                    0
+           | (1e-300,-1e-300)  | (1e-300,-1e-300)  |                    0
+           | (5.1,34.5)        | (5.1,34.5)        |                    0
+           | (10,10)           | (10,10)           |                    0
+           | (0,0)             | (1e-300,-1e-300)  | 1.4142135623731e-300
+           | (1e-300,-1e-300)  | (0,0)             | 1.4142135623731e-300
+           | (-3,4)            | (0,0)             |                    5
+           | (-3,4)            | (1e-300,-1e-300)  |                    5
+           | (0,0)             | (-3,4)            |                    5
+           | (1e-300,-1e-300)  | (-3,4)            |                    5
+           | (-10,0)           | (-3,4)            |     8.06225774829855
+           | (-3,4)            | (-10,0)           |     8.06225774829855
+           | (-10,0)           | (0,0)             |                   10
+           | (-10,0)           | (1e-300,-1e-300)  |                   10
+           | (0,0)             | (-10,0)           |                   10
+           | (1e-300,-1e-300)  | (-10,0)           |                   10
+           | (-10,0)           | (-5,-12)          |                   13
+           | (-5,-12)          | (-10,0)           |                   13
+           | (-5,-12)          | (0,0)             |                   13
+           | (-5,-12)          | (1e-300,-1e-300)  |                   13
+           | (0,0)             | (-5,-12)          |                   13
+           | (1e-300,-1e-300)  | (-5,-12)          |                   13
+           | (0,0)             | (10,10)           |      14.142135623731
+           | (1e-300,-1e-300)  | (10,10)           |      14.142135623731
+           | (10,10)           | (0,0)             |      14.142135623731
+           | (10,10)           | (1e-300,-1e-300)  |      14.142135623731
+           | (-3,4)            | (10,10)           |     14.3178210632764
+           | (10,10)           | (-3,4)            |     14.3178210632764
+           | (-5,-12)          | (-3,4)            |     16.1245154965971
+           | (-3,4)            | (-5,-12)          |     16.1245154965971
+           | (-10,0)           | (10,10)           |     22.3606797749979
+           | (10,10)           | (-10,0)           |     22.3606797749979
+           | (5.1,34.5)        | (10,10)           |     24.9851956166046
+           | (10,10)           | (5.1,34.5)        |     24.9851956166046
+           | (-5,-12)          | (10,10)           |     26.6270539113887
+           | (10,10)           | (-5,-12)          |     26.6270539113887
+           | (-3,4)            | (5.1,34.5)        |     31.5572495632937
+           | (5.1,34.5)        | (-3,4)            |     31.5572495632937
+           | (0,0)             | (5.1,34.5)        |     34.8749193547455
+           | (1e-300,-1e-300)  | (5.1,34.5)        |     34.8749193547455
+           | (5.1,34.5)        | (0,0)             |     34.8749193547455
+           | (5.1,34.5)        | (1e-300,-1e-300)  |     34.8749193547455
+           | (-10,0)           | (5.1,34.5)        |     37.6597928831267
+           | (5.1,34.5)        | (-10,0)           |     37.6597928831267
+           | (-5,-12)          | (5.1,34.5)        |     47.5842410888311
+           | (5.1,34.5)        | (-5,-12)          |     47.5842410888311
+           | (-10,0)           | (1e+300,Infinity) |             Infinity
+           | (-5,-12)          | (1e+300,Infinity) |             Infinity
+           | (-3,4)            | (1e+300,Infinity) |             Infinity
+           | (0,0)             | (1e+300,Infinity) |             Infinity
+           | (1e-300,-1e-300)  | (1e+300,Infinity) |             Infinity
+           | (5.1,34.5)        | (1e+300,Infinity) |             Infinity
+           | (10,10)           | (1e+300,Infinity) |             Infinity
+           | (1e+300,Infinity) | (-10,0)           |             Infinity
+           | (1e+300,Infinity) | (-5,-12)          |             Infinity
+           | (1e+300,Infinity) | (-3,4)            |             Infinity
+           | (1e+300,Infinity) | (0,0)             |             Infinity
+           | (1e+300,Infinity) | (1e-300,-1e-300)  |             Infinity
+           | (1e+300,Infinity) | (5.1,34.5)        |             Infinity
+           | (1e+300,Infinity) | (10,10)           |             Infinity
+           | (-10,0)           | (NaN,NaN)         |                  NaN
+           | (-5,-12)          | (NaN,NaN)         |                  NaN
+           | (-3,4)            | (NaN,NaN)         |                  NaN
+           | (0,0)             | (NaN,NaN)         |                  NaN
+           | (1e-300,-1e-300)  | (NaN,NaN)         |                  NaN
+           | (5.1,34.5)        | (NaN,NaN)         |                  NaN
+           | (10,10)           | (NaN,NaN)         |                  NaN
+           | (1e+300,Infinity) | (1e+300,Infinity) |                  NaN
+           | (1e+300,Infinity) | (NaN,NaN)         |                  NaN
+           | (NaN,NaN)         | (-10,0)           |                  NaN
+           | (NaN,NaN)         | (-5,-12)          |                  NaN
+           | (NaN,NaN)         | (-3,4)            |                  NaN
+           | (NaN,NaN)         | (0,0)             |                  NaN
+           | (NaN,NaN)         | (1e-300,-1e-300)  |                  NaN
+           | (NaN,NaN)         | (5.1,34.5)        |                  NaN
+           | (NaN,NaN)         | (10,10)           |                  NaN
+           | (NaN,NaN)         | (1e+300,Infinity) |                  NaN
+           | (NaN,NaN)         | (NaN,NaN)         |                  NaN
+(81 rows)
 
 SELECT '' AS thirty, p1.f1 AS point1, p2.f1 AS point2
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3;
- thirty |   point1   |   point2   
---------+------------+------------
-        | (0,0)      | (-10,0)
-        | (0,0)      | (-3,4)
-        | (0,0)      | (5.1,34.5)
-        | (0,0)      | (-5,-12)
-        | (0,0)      | (10,10)
-        | (-10,0)    | (0,0)
-        | (-10,0)    | (-3,4)
-        | (-10,0)    | (5.1,34.5)
-        | (-10,0)    | (-5,-12)
-        | (-10,0)    | (10,10)
-        | (-3,4)     | (0,0)
-        | (-3,4)     | (-10,0)
-        | (-3,4)     | (5.1,34.5)
-        | (-3,4)     | (-5,-12)
-        | (-3,4)     | (10,10)
-        | (5.1,34.5) | (0,0)
-        | (5.1,34.5) | (-10,0)
-        | (5.1,34.5) | (-3,4)
-        | (5.1,34.5) | (-5,-12)
-        | (5.1,34.5) | (10,10)
-        | (-5,-12)   | (0,0)
-        | (-5,-12)   | (-10,0)
-        | (-5,-12)   | (-3,4)
-        | (-5,-12)   | (5.1,34.5)
-        | (-5,-12)   | (10,10)
-        | (10,10)    | (0,0)
-        | (10,10)    | (-10,0)
-        | (10,10)    | (-3,4)
-        | (10,10)    | (5.1,34.5)
-        | (10,10)    | (-5,-12)
-(30 rows)
+ thirty |      point1       |      point2       
+--------+-------------------+-------------------
+        | (0,0)             | (-10,0)
+        | (0,0)             | (-3,4)
+        | (0,0)             | (5.1,34.5)
+        | (0,0)             | (-5,-12)
+        | (0,0)             | (1e+300,Infinity)
+        | (0,0)             | (NaN,NaN)
+        | (0,0)             | (10,10)
+        | (-10,0)           | (0,0)
+        | (-10,0)           | (-3,4)
+        | (-10,0)           | (5.1,34.5)
+        | (-10,0)           | (-5,-12)
+        | (-10,0)           | (1e-300,-1e-300)
+        | (-10,0)           | (1e+300,Infinity)
+        | (-10,0)           | (NaN,NaN)
+        | (-10,0)           | (10,10)
+        | (-3,4)            | (0,0)
+        | (-3,4)            | (-10,0)
+        | (-3,4)            | (5.1,34.5)
+        | (-3,4)            | (-5,-12)
+        | (-3,4)            | (1e-300,-1e-300)
+        | (-3,4)            | (1e+300,Infinity)
+        | (-3,4)            | (NaN,NaN)
+        | (-3,4)            | (10,10)
+        | (5.1,34.5)        | (0,0)
+        | (5.1,34.5)        | (-10,0)
+        | (5.1,34.5)        | (-3,4)
+        | (5.1,34.5)        | (-5,-12)
+        | (5.1,34.5)        | (1e-300,-1e-300)
+        | (5.1,34.5)        | (1e+300,Infinity)
+        | (5.1,34.5)        | (NaN,NaN)
+        | (5.1,34.5)        | (10,10)
+        | (-5,-12)          | (0,0)
+        | (-5,-12)          | (-10,0)
+        | (-5,-12)          | (-3,4)
+        | (-5,-12)          | (5.1,34.5)
+        | (-5,-12)          | (1e-300,-1e-300)
+        | (-5,-12)          | (1e+300,Infinity)
+        | (-5,-12)          | (NaN,NaN)
+        | (-5,-12)          | (10,10)
+        | (1e-300,-1e-300)  | (-10,0)
+        | (1e-300,-1e-300)  | (-3,4)
+        | (1e-300,-1e-300)  | (5.1,34.5)
+        | (1e-300,-1e-300)  | (-5,-12)
+        | (1e-300,-1e-300)  | (1e+300,Infinity)
+        | (1e-300,-1e-300)  | (NaN,NaN)
+        | (1e-300,-1e-300)  | (10,10)
+        | (1e+300,Infinity) | (0,0)
+        | (1e+300,Infinity) | (-10,0)
+        | (1e+300,Infinity) | (-3,4)
+        | (1e+300,Infinity) | (5.1,34.5)
+        | (1e+300,Infinity) | (-5,-12)
+        | (1e+300,Infinity) | (1e-300,-1e-300)
+        | (1e+300,Infinity) | (1e+300,Infinity)
+        | (1e+300,Infinity) | (NaN,NaN)
+        | (1e+300,Infinity) | (10,10)
+        | (NaN,NaN)         | (0,0)
+        | (NaN,NaN)         | (-10,0)
+        | (NaN,NaN)         | (-3,4)
+        | (NaN,NaN)         | (5.1,34.5)
+        | (NaN,NaN)         | (-5,-12)
+        | (NaN,NaN)         | (1e-300,-1e-300)
+        | (NaN,NaN)         | (1e+300,Infinity)
+        | (NaN,NaN)         | (NaN,NaN)
+        | (NaN,NaN)         | (10,10)
+        | (10,10)           | (0,0)
+        | (10,10)           | (-10,0)
+        | (10,10)           | (-3,4)
+        | (10,10)           | (5.1,34.5)
+        | (10,10)           | (-5,-12)
+        | (10,10)           | (1e-300,-1e-300)
+        | (10,10)           | (1e+300,Infinity)
+        | (10,10)           | (NaN,NaN)
+(72 rows)
 
 -- put distance result into output to allow sorting with GEQ optimizer - tgl 97/05/10
 SELECT '' AS fifteen, p1.f1 AS point1, p2.f1 AS point2, (p1.f1 <-> p2.f1) AS distance
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3 and p1.f1 << p2.f1
    ORDER BY distance, p1.f1[0], p2.f1[0];
- fifteen |   point1   |   point2   |     distance     
----------+------------+------------+------------------
-         | (-3,4)     | (0,0)      |                5
-         | (-10,0)    | (-3,4)     | 8.06225774829855
-         | (-10,0)    | (0,0)      |               10
-         | (-10,0)    | (-5,-12)   |               13
-         | (-5,-12)   | (0,0)      |               13
-         | (0,0)      | (10,10)    |  14.142135623731
-         | (-3,4)     | (10,10)    | 14.3178210632764
-         | (-5,-12)   | (-3,4)     | 16.1245154965971
-         | (-10,0)    | (10,10)    | 22.3606797749979
-         | (5.1,34.5) | (10,10)    | 24.9851956166046
-         | (-5,-12)   | (10,10)    | 26.6270539113887
-         | (-3,4)     | (5.1,34.5) | 31.5572495632937
-         | (0,0)      | (5.1,34.5) | 34.8749193547455
-         | (-10,0)    | (5.1,34.5) | 37.6597928831267
-         | (-5,-12)   | (5.1,34.5) | 47.5842410888311
-(15 rows)
+ fifteen |      point1      |      point2       |     distance     
+---------+------------------+-------------------+------------------
+         | (-3,4)           | (0,0)             |                5
+         | (-3,4)           | (1e-300,-1e-300)  |                5
+         | (-10,0)          | (-3,4)            | 8.06225774829855
+         | (-10,0)          | (0,0)             |               10
+         | (-10,0)          | (1e-300,-1e-300)  |               10
+         | (-10,0)          | (-5,-12)          |               13
+         | (-5,-12)         | (0,0)             |               13
+         | (-5,-12)         | (1e-300,-1e-300)  |               13
+         | (0,0)            | (10,10)           |  14.142135623731
+         | (1e-300,-1e-300) | (10,10)           |  14.142135623731
+         | (-3,4)           | (10,10)           | 14.3178210632764
+         | (-5,-12)         | (-3,4)            | 16.1245154965971
+         | (-10,0)          | (10,10)           | 22.3606797749979
+         | (5.1,34.5)       | (10,10)           | 24.9851956166046
+         | (-5,-12)         | (10,10)           | 26.6270539113887
+         | (-3,4)           | (5.1,34.5)        | 31.5572495632937
+         | (0,0)            | (5.1,34.5)        | 34.8749193547455
+         | (1e-300,-1e-300) | (5.1,34.5)        | 34.8749193547455
+         | (-10,0)          | (5.1,34.5)        | 37.6597928831267
+         | (-5,-12)         | (5.1,34.5)        | 47.5842410888311
+         | (-10,0)          | (1e+300,Infinity) |         Infinity
+         | (-5,-12)         | (1e+300,Infinity) |         Infinity
+         | (-3,4)           | (1e+300,Infinity) |         Infinity
+         | (0,0)            | (1e+300,Infinity) |         Infinity
+         | (1e-300,-1e-300) | (1e+300,Infinity) |         Infinity
+         | (5.1,34.5)       | (1e+300,Infinity) |         Infinity
+         | (10,10)          | (1e+300,Infinity) |         Infinity
+(27 rows)
 
 -- put distance result into output to allow sorting with GEQ optimizer - tgl 97/05/10
 SELECT '' AS three, p1.f1 AS point1, p2.f1 AS point2, (p1.f1 <-> p2.f1) AS distance
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3 and p1.f1 << p2.f1 and p1.f1 >^ p2.f1
    ORDER BY distance;
- three |   point1   |  point2  |     distance     
--------+------------+----------+------------------
-       | (-3,4)     | (0,0)    |                5
-       | (-10,0)    | (-5,-12) |               13
-       | (5.1,34.5) | (10,10)  | 24.9851956166046
-(3 rows)
+ three |   point1   |      point2      |     distance     
+-------+------------+------------------+------------------
+       | (-3,4)     | (0,0)            |                5
+       | (-3,4)     | (1e-300,-1e-300) |                5
+       | (-10,0)    | (-5,-12)         |               13
+       | (5.1,34.5) | (10,10)          | 24.9851956166046
+(4 rows)
 
 -- Test that GiST indexes provide same behavior as sequential scan
 CREATE TEMP TABLE point_gist_tbl(f1 point);
 INSERT INTO point_gist_tbl SELECT '(0,0)' FROM generate_series(0,1000);
 CREATE INDEX point_gist_tbl_index ON point_gist_tbl USING gist (f1);
 INSERT INTO point_gist_tbl VALUES ('(0.0000009,0.0000009)');
 SET enable_seqscan TO true;
 SET enable_indexscan TO false;
 SET enable_bitmapscan TO false;
 SELECT COUNT(*) FROM point_gist_tbl WHERE f1 ~= '(0.0000009,0.0000009)'::point;
diff --git a/src/test/regress/expected/polygon.out b/src/test/regress/expected/polygon.out
index 4a1f60427a..be5f76bf9d 100644
--- a/src/test/regress/expected/polygon.out
+++ b/src/test/regress/expected/polygon.out
@@ -1,18 +1,21 @@
 --
 -- POLYGON
 --
 -- polygon logic
 --
 CREATE TABLE POLYGON_TBL(f1 polygon);
 INSERT INTO POLYGON_TBL(f1) VALUES ('(2.0,0.0),(2.0,4.0),(0.0,0.0)');
 INSERT INTO POLYGON_TBL(f1) VALUES ('(3.0,1.0),(3.0,3.0),(1.0,0.0)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(3,4),(5,6),(7,8)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(7,8),(5,6),(3,4),(1,2)'); -- Reverse
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(7,8),(5,6),(3,-4)');
 -- degenerate polygons
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,0.0)');
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,1.0),(0.0,1.0)');
 -- bad polygon input strings
 INSERT INTO POLYGON_TBL(f1) VALUES ('0.0');
 ERROR:  invalid input syntax for type polygon: "0.0"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('0.0');
                                             ^
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0 0.0');
 ERROR:  invalid input syntax for type polygon: "(0.0 0.0"
@@ -24,215 +27,30 @@ LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2)');
                                             ^
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2,3');
 ERROR:  invalid input syntax for type polygon: "(0,1,2,3"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2,3');
                                             ^
 INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
 ERROR:  invalid input syntax for type polygon: "asdf"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
                                             ^
 SELECT '' AS four, * FROM POLYGON_TBL;
- four |         f1          
-------+---------------------
+ four |             f1             
+------+----------------------------
       | ((2,0),(2,4),(0,0))
       | ((3,1),(3,3),(1,0))
+      | ((1,2),(3,4),(5,6),(7,8))
+      | ((7,8),(5,6),(3,4),(1,2))
+      | ((1,2),(7,8),(5,6),(3,-4))
       | ((0,0))
       | ((0,1),(0,1))
-(4 rows)
-
--- overlap
-SELECT '' AS three, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 && '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- three |         f1          
--------+---------------------
-       | ((2,0),(2,4),(0,0))
-       | ((3,1),(3,3),(1,0))
-(2 rows)
-
--- left overlap
-SELECT '' AS four, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &< '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- four |         f1          
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
-
--- right overlap
-SELECT '' AS two, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- two |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- left of
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 << '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |      f1       
------+---------------
-     | ((0,0))
-     | ((0,1),(0,1))
-(2 rows)
-
--- right of
-SELECT '' AS zero, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 >> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- zero | f1 
-------+----
-(0 rows)
-
--- contained
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- same
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- contains
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
---
--- polygon logic
---
--- left of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- left overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
- true 
-------
- f
-(1 row)
-
--- right overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' &> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- right of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' >> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- contained in
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- contains
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((0,4),(6,4),(3,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
-SELECT '((1,1),(1,4),(5,4),(5,3),(2,3),(2,2),(5,2),(5,1))'::polygon @> '((3,2),(3,3),(4,3),(4,2))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((0,0),(0,3),(3,3),(3,0))'::polygon @> '((2,1),(2,2),(3,2),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
--- same
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' && polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
- true 
-------
- t
-(1 row)
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon && '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
-SELECT '((1,4),(1,1),(4,1),(4,2),(2,2),(2,4),(1,4))'::polygon && '((3,3),(4,3),(4,4),(3,4),(3,3))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((200,800),(800,800),(800,200),(200,200))' &&  '(1000,1000,0,0)'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
--- distance from a point
-SELECT	'(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
-	'(1,1)'::point <-> '((0,0),(2,2),(1,3))'::polygon as on_segment,
-	'(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;
- on_corner | on_segment | inside |   near_corner   | near_segment 
------------+------------+--------+-----------------+--------------
-         0 |          0 |      0 | 1.4142135623731 |          3.2
-(1 row)
+(7 rows)
 
 --
 -- 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
diff --git a/src/test/regress/sql/box.sql b/src/test/regress/sql/box.sql
index 135ac108eb..6710fc90f5 100644
--- a/src/test/regress/sql/box.sql
+++ b/src/test/regress/sql/box.sql
@@ -18,29 +18,38 @@
 
 -- boxes are specified by two points, given by four floats x1,y1,x2,y2
 
 
 CREATE TABLE BOX_TBL (f1 box);
 
 INSERT INTO BOX_TBL (f1) VALUES ('(2.0,2.0,0.0,0.0)');
 
 INSERT INTO BOX_TBL (f1) VALUES ('(1.0,1.0,3.0,3.0)');
 
+INSERT INTO BOX_TBL (f1) VALUES ('((-8, 2), (-2, -10))');
+
+
 -- degenerate cases where the box is a line or a point
 -- note that lines and points boxes all have zero area
 INSERT INTO BOX_TBL (f1) VALUES ('(2.5, 2.5, 2.5,3.5)');
 
 INSERT INTO BOX_TBL (f1) VALUES ('(3.0, 3.0,3.0,3.0)');
 
 -- badly formatted box inputs
 INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
 
+INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+
 INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
 
 
 SELECT '' AS four, * FROM BOX_TBL;
 
 SELECT '' AS four, b.*, area(b.f1) as barea
    FROM BOX_TBL b;
 
 -- overlap
 SELECT '' AS three, b.f1
diff --git a/src/test/regress/sql/circle.sql b/src/test/regress/sql/circle.sql
index c0284b2b59..46c96e1400 100644
--- a/src/test/regress/sql/circle.sql
+++ b/src/test/regress/sql/circle.sql
@@ -7,26 +7,34 @@ CREATE TABLE CIRCLE_TBL (f1 circle);
 INSERT INTO CIRCLE_TBL VALUES ('<(5,1),3>');
 
 INSERT INTO CIRCLE_TBL VALUES ('<(1,2),100>');
 
 INSERT INTO CIRCLE_TBL VALUES ('1,3,5');
 
 INSERT INTO CIRCLE_TBL VALUES ('((1,2),3)');
 
 INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10>');
 
-INSERT INTO CIRCLE_TBL VALUES ('<(100,1),115>');
+INSERT INTO CIRCLE_TBL VALUES (' < ( 100 , 1 ) , 115 > ');
+
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),0>');	-- Zero radius
+
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),NaN>');	-- NaN radius
 
 -- bad values
 
 INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
 
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+
 INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
 
 INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
 
 SELECT * FROM CIRCLE_TBL;
 
 SELECT '' AS six, center(f1) AS center
   FROM CIRCLE_TBL;
 
 SELECT '' AS six, radius(f1) AS radius
diff --git a/src/test/regress/sql/geometry.sql b/src/test/regress/sql/geometry.sql
index 1429ee772a..ce98b3e90c 100644
--- a/src/test/regress/sql/geometry.sql
+++ b/src/test/regress/sql/geometry.sql
@@ -39,74 +39,298 @@ SELECT '' AS two, p1.f1
 -- "is vertical" function
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE isvertical(p1.f1, point '(5.1,34.5)');
 
 -- "is vertical" operator
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?| point '(5.1,34.5)';
 
+-- Slope
+SELECT p1.f1, p2.f1, slope(p1.f1, p2.f1) FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Add point
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Subtract point
+SELECT p1.f1, p2.f1, p1.f1 - p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Multiply with point
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+
+-- Underflow error
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] < 1;
+
+-- Divide by point
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] BETWEEN 1 AND 1000;
+
+-- Overflow error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] > 1000;
+
+-- Division by 0 error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1 ~= '(0,0)'::point;
+
+-- Distance to line
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LINE_TBL l;
+
+-- Distance to line segment
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LSEG_TBL l;
+
+-- Distance to box
+SELECT p.f1, b.f1, p.f1 <-> b.f1 FROM POINT_TBL p, BOX_TBL b;
+
+-- Distance to path
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, PATH_TBL p1;
+
+-- Distance to polygon
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, POLYGON_TBL p1;
+
+-- Closest point to line
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LINE_TBL l;
+
+-- Closest point to line segment
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LSEG_TBL l;
+
+-- Closest point to box
+SELECT p.f1, b.f1, p.f1 ## b.f1 FROM POINT_TBL p, BOX_TBL b;
+
+-- On line
+SELECT p.f1, l.s FROM POINT_TBL p, LINE_TBL l WHERE p.f1 <@ l.s;
+
+-- On line segment
+SELECT p.f1, l.s FROM POINT_TBL p, LSEG_TBL l WHERE p.f1 <@ l.s;
+
+-- On path
+SELECT p.f1, p1.f1 FROM POINT_TBL p, PATH_TBL p1 WHERE p.f1 <@ p1.f1;
+
+--
+-- Lines
+--
+
+-- Vertical
+SELECT s FROM LINE_TBL WHERE ?| s;
+
+-- Horizontal
+SELECT s FROM LINE_TBL WHERE ?- s;
+
+-- Same as line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s = l2.s;
+
+-- Parallel to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?|| l2.s;
+
+-- Perpendicular to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?-| l2.s;
+
+-- Distance to line
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2;
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LINE_TBL l, BOX_TBL b;
+
+-- Intersect with line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?# l2.s;
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LINE_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+
+-- Intersection point with line
+SELECT l1.s, l2.s, l1.s # l2.s FROM LINE_TBL l1, LINE_TBL l2;
+
+-- Closest point to line segment
+SELECT l.s, l1.s, l.s ## l1.s FROM LINE_TBL l, LSEG_TBL l1;
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LINE_TBL l, BOX_TBL b;
+
 --
 -- Line segments
 --
 
 -- intersection
 SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
    FROM LSEG_TBL l, POINT_TBL p;
 
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
+-- Length
+SELECT s, @-@ s FROM LSEG_TBL;
+
+-- Vertical
+SELECT s FROM LSEG_TBL WHERE ?| s;
+
+-- Horizontal
+SELECT s FROM LSEG_TBL WHERE ?- s;
+
+-- Center
+SELECT s, @@ s FROM LSEG_TBL;
+
+-- To point
+SELECT s, s::point FROM LSEG_TBL;
+
+-- Has points less than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s < l2.s;
+
+-- Has points less than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s <= l2.s;
+
+-- Has points equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s = l2.s;
+
+-- Has points greater than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s >= l2.s;
+
+-- Has points greater than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s > l2.s;
+
+-- Has points not equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s != l2.s;
+
+-- Parallel with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?|| l2.s;
+
+-- Perpendicular with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?-| l2.s;
+
+-- Distance to line
+SELECT l.s, l1.s, l.s <-> l1.s FROM LSEG_TBL l, LINE_TBL l1;
+
+-- Distance to line segment
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LSEG_TBL l, BOX_TBL b;
+
+-- Intersect with line segment
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s ?# l1.s;
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+
+-- Intersection point with line segment
+SELECT l1.s, l2.s, l1.s # l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Closest point to line
+SELECT l.s, l1.s, l.s ## l1.s FROM LSEG_TBL l, LINE_TBL l1;
+
+-- Closest point to line segment
+SELECT l1.s, l2.s, l1.s ## l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LSEG_TBL l, BOX_TBL b;
+
+-- On line
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s <@ l1.s;
+
+-- On box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s <@ b.f1;
 
 --
 -- Boxes
 --
 
 SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
 
 -- translation
 SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
 
 SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
 
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
+-- Multiply with point
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
 
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
+-- Overflow error
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] > 1000;
 
+-- Divide by point
+SELECT b.f1, p.f1, b.f1 / p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+
+-- To box
 SELECT f1::box
 	FROM POINT_TBL;
 
 SELECT bound_box(a.f1, b.f1)
 	FROM BOX_TBL a, BOX_TBL b;
 
+-- Below box
+SELECT b1.f1, b2.f1, b1.f1 <^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Above box
+SELECT b1.f1, b2.f1, b1.f1 >^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Intersection point with box
+SELECT b1.f1, b2.f1, b1.f1 # b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Diagonal
+SELECT f1, diagonal(f1) FROM BOX_TBL;
+
+-- Distance to box
+SELECT b1.f1, b2.f1, b1.f1 <-> b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
 --
 -- Paths
 --
 
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
+-- Points
+SELECT f1, npoints(f1) FROM PATH_TBL;
 
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
+-- Area
+SELECT f1, area(f1) FROM PATH_TBL;
 
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
+-- Length
+SELECT f1, @-@ f1 FROM PATH_TBL;
 
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
+-- Center
+SELECT f1, @@ f1 FROM PATH_TBL;
+
+-- To polygon
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isclosed(f1);
+
+-- Open path cannot be converted to polygon error
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isopen(f1);
+
+-- Has points less than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 < p2.f1;
+
+-- Has points less than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 <= p2.f1;
+
+-- Has points equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 = p2.f1;
+
+-- Has points greater than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 >= p2.f1;
+
+-- Has points greater than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 > p2.f1;
+
+-- Add path
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+
+-- Add point
+SELECT p.f1, p1.f1, p.f1 + p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+
+-- Subtract point
+SELECT p.f1, p1.f1, p.f1 - p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+
+-- Multiply with point
+SELECT p.f1, p1.f1, p.f1 * p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+
+-- Divide by point
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+
+-- Division by 0 error
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1 ~= '(0,0)'::point;
+
+-- Distance to path
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
 
 --
 -- Polygons
 --
 
 -- containment
 SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
    FROM POLYGON_TBL poly, POINT_TBL p;
 
 SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
@@ -118,36 +342,166 @@ SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
 SELECT '' AS four, polygon(f1)
    FROM BOX_TBL;
 
 SELECT '' AS four, polygon(f1)
    FROM PATH_TBL WHERE isclosed(f1);
 
 SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
    FROM PATH_TBL
    WHERE isopen(f1);
 
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
+-- To box
+SELECT f1, f1::box FROM POLYGON_TBL;
 
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
+-- To path
+SELECT f1, f1::path FROM POLYGON_TBL;
+
+-- Same as polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 ~= p2.f1;
+
+-- Contained by polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <@ p2.f1;
+
+-- Contains polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 @> p2.f1;
+
+-- Overlap with polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 && p2.f1;
+
+-- Left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 << p2.f1;
+
+-- Overlap of left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &< p2.f1;
+
+-- Right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 >> p2.f1;
+
+-- Overlap of right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &> p2.f1;
+
+-- Below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <<| p2.f1;
+
+-- Overlap or below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &<| p2.f1;
+
+-- Above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |>> p2.f1;
+
+-- Overlap or above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |&> p2.f1;
+
+-- Distance to polygon
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2;
 
 --
 -- Circles
 --
 
 SELECT '' AS six, circle(f1, 50.0)
    FROM POINT_TBL;
 
 SELECT '' AS four, circle(f1)
    FROM BOX_TBL;
 
 SELECT '' AS two, circle(f1)
    FROM POLYGON_TBL
    WHERE (# f1) >= 3;
 
 SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
    FROM CIRCLE_TBL c1, POINT_TBL p1
    WHERE (p1.f1 <-> c1.f1) > 0
    ORDER BY distance, area(c1.f1), p1.f1[0];
+
+-- To polygon
+SELECT f1, f1::polygon FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+
+-- To polygon with less points
+SELECT f1, polygon(8, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+
+-- Too less points error
+SELECT f1, polygon(1, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+
+-- Zero radius error
+SELECT f1, polygon(10, f1) FROM CIRCLE_TBL WHERE f1 < '<(0,0),1>';
+
+-- Same as circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 ~= c2.f1;
+
+-- Overlap with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 && c2.f1;
+
+-- Overlap or left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &< c2.f1;
+
+-- Left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 << c2.f1;
+
+-- Right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >> c2.f1;
+
+-- Overlap or right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &> c2.f1;
+
+-- Contained by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <@ c2.f1;
+
+-- Contain by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 @> c2.f1;
+
+-- Below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <<| c2.f1;
+
+-- Above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |>> c2.f1;
+
+-- Overlap or below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &<| c2.f1;
+
+-- Overlap or above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |&> c2.f1;
+
+-- Area equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 = c2.f1;
+
+-- Area not equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 != c2.f1;
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 > c2.f1;
+
+-- Area less than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <= c2.f1;
+
+-- Area greater than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >= c2.f1;
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+
+-- Add point
+SELECT c.f1, p.f1, c.f1 + p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Subtract point
+SELECT c.f1, p.f1, c.f1 - p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Multiply with point
+SELECT c.f1, p.f1, c.f1 * p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Divide by point
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+
+-- Overflow error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] > 1000;
+
+-- Division by 0 error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1 ~= '(0,0)'::point;
+
+-- Distance to polygon
+SELECT c.f1, p.f1, c.f1 <-> p.f1 FROM CIRCLE_TBL c, POLYGON_TBL p;
diff --git a/src/test/regress/sql/line.sql b/src/test/regress/sql/line.sql
index 94067b0cee..f589ffecc8 100644
--- a/src/test/regress/sql/line.sql
+++ b/src/test/regress/sql/line.sql
@@ -1,87 +1,42 @@
 --
 -- LINE
 -- Infinite lines
 --
 
 --DROP TABLE LINE_TBL;
 CREATE TABLE LINE_TBL (s line);
 
-INSERT INTO LINE_TBL VALUES ('{1,-1,1}');
-INSERT INTO LINE_TBL VALUES ('(0,0),(6,6)');
+INSERT INTO LINE_TBL VALUES ('{0,-1,5}');	-- A == 0
+INSERT INTO LINE_TBL VALUES ('{1,0,5}');	-- B == 0
+INSERT INTO LINE_TBL VALUES ('{0,3,0}');	-- A == C == 0
+INSERT INTO LINE_TBL VALUES (' (0,0), (6,6)');
 INSERT INTO LINE_TBL VALUES ('10,-10 ,-5,-4');
 INSERT INTO LINE_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LINE_TBL VALUES ('(11,22,33,44)');
 
-INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
+INSERT INTO LINE_TBL VALUES ('{3,NaN,5}');
+INSERT INTO LINE_TBL VALUES ('{NaN,NaN,NaN}');
 
 -- horizontal
 INSERT INTO LINE_TBL VALUES ('[(1,3),(2,3)]');
 -- vertical
-INSERT INTO LINE_TBL VALUES ('[(3,1),(3,2)]');
+INSERT INTO LINE_TBL VALUES (line(point '(3,1)', point '(3,2)'));
 
 -- bad values for parser testing
+INSERT INTO LINE_TBL VALUES ('{}');
+INSERT INTO LINE_TBL VALUES ('{0');
+INSERT INTO LINE_TBL VALUES ('{0,0}');
+INSERT INTO LINE_TBL VALUES ('{0,0,1');
 INSERT INTO LINE_TBL VALUES ('{0,0,1}');
+INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
 INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
 INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
 INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
 INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
+INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
+
+INSERT INTO LINE_TBL VALUES (line(point '(1,0)', point '(1,0)'));
 
 select * from LINE_TBL;
 
-
--- functions and operators
-
-SELECT * FROM LINE_TBL WHERE (s <-> line '[(1,2),(3,4)]') < 10;
-
-SELECT * FROM LINE_TBL WHERE (point '(0.1,0.1)' <-> s) < 1;
-
-SELECT * FROM LINE_TBL WHERE (lseg '[(0.1,0.1),(0.2,0.2)]' <-> s) < 1;
-
-SELECT line '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
-SELECT lseg '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
-SELECT point '(-1,1)' <-> line '[(-3,0),(-4,0)]';
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(2,0),(0,2)]';  -- true
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(0,0),(1,0)]';  -- false
-
-SELECT line '[(0,0),(1,1)]' ?# box '(0,0,2,2)';  -- true
-SELECT line '[(3,0),(4,1)]' ?# box '(0,0,2,2)';  -- false
-
-SELECT point '(1,1)' <@ line '[(0,0),(2,2)]';  -- true
-SELECT point '(1,1)' <@ line '[(0,0),(1,0)]';  -- false
-
-SELECT point '(1,1)' @ line '[(0,0),(2,2)]';  -- true
-SELECT point '(1,1)' @ line '[(0,0),(1,0)]';  -- false
-
-SELECT lseg '[(1,1),(2,2)]' <@ line '[(0,0),(2,2)]';  -- true
-SELECT lseg '[(1,1),(2,1)]' <@ line '[(0,0),(1,0)]';  -- false
-
-SELECT lseg '[(1,1),(2,2)]' @ line '[(0,0),(2,2)]';  -- true
-SELECT lseg '[(1,1),(2,1)]' @ line '[(0,0),(1,0)]';  -- false
-
-SELECT point '(0,1)' ## line '[(0,0),(1,1)]';
-
-SELECT line '[(0,0),(1,1)]' ## lseg '[(1,0),(2,0)]';
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(2,1)]';  -- false
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(1,1)]';  -- true
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(2,1)]';
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(1,1)]';
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(2,1)]';  -- true
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(1,1)]';  -- false
-
-SELECT line '[(0,0),(1,0)]' ?-| line '[(0,0),(0,1)]';  -- true
-SELECT line '[(0,0),(1,1)]' ?-| line '[(1,0),(1,1)]';  -- false
-
-SELECT ?- line '[(0,0),(1,0)]';  -- true
-SELECT ?- line '[(0,0),(1,1)]';  -- false
-
-SELECT ?| line '[(0,0),(0,1)]';  -- true
-SELECT ?| line '[(0,0),(1,1)]';  -- false
-
-SELECT line(point '(1,2)', point '(3,4)');
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,5)]';  -- true
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,4)]';  -- false
+select '{nan, 1, nan}'::line = '{nan, 1, nan}'::line as true,
+	   '{nan, 1, nan}'::line = '{nan, 2, nan}'::line as false;
diff --git a/src/test/regress/sql/lseg.sql b/src/test/regress/sql/lseg.sql
index 07c5a29e0a..f266ca3e09 100644
--- a/src/test/regress/sql/lseg.sql
+++ b/src/test/regress/sql/lseg.sql
@@ -3,23 +3,22 @@
 -- Line segments
 --
 
 --DROP TABLE LSEG_TBL;
 CREATE TABLE LSEG_TBL (s lseg);
 
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('(0,0),(6,6)');
 INSERT INTO LSEG_TBL VALUES ('10,-10 ,-3,-4');
 INSERT INTO LSEG_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LSEG_TBL VALUES ('(11,22,33,44)');
+INSERT INTO LSEG_TBL VALUES (lseg(point(11, 22), point(33,44)));
+INSERT INTO LSEG_TBL VALUES ('[(-10,2),(-10,3)]');	-- vertical
+INSERT INTO LSEG_TBL VALUES ('[(0,-20),(30,-20)]');	-- horizontal
+INSERT INTO LSEG_TBL VALUES ('[(NaN,1),(NaN,90)]');	-- NaN
 
 -- bad values for parser testing
 INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
 INSERT INTO LSEG_TBL VALUES ('[1,2,3, 4');
 INSERT INTO LSEG_TBL VALUES ('[(,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)');
 
 select * from LSEG_TBL;
-
-SELECT * FROM LSEG_TBL WHERE s <= lseg '[(1,2),(3,4)]';
-
-SELECT * FROM LSEG_TBL WHERE (s <-> lseg '[(1,2),(3,4)]') < 10;
diff --git a/src/test/regress/sql/path.sql b/src/test/regress/sql/path.sql
index 7e69b539ad..318decf974 100644
--- a/src/test/regress/sql/path.sql
+++ b/src/test/regress/sql/path.sql
@@ -1,38 +1,44 @@
 --
 -- PATH
 --
 
 --DROP TABLE PATH_TBL;
 
 CREATE TABLE PATH_TBL (f1 path);
 
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)]');
 
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
+INSERT INTO PATH_TBL VALUES (' ( ( 1 , 2 ) , ( 3 , 4 ) ) ');
 
-INSERT INTO PATH_TBL VALUES ('[(0,0),(3,0),(4,5),(1,6)]');
+INSERT INTO PATH_TBL VALUES ('[ (0,0),(3,0),(4,5),(1,6) ]');
 
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
+INSERT INTO PATH_TBL VALUES ('((1,2) ,(3,4 ))');
 
-INSERT INTO PATH_TBL VALUES ('1,2 ,3,4');
+INSERT INTO PATH_TBL VALUES ('1,2 ,3,4 ');
 
-INSERT INTO PATH_TBL VALUES ('[1,2,3, 4]');
+INSERT INTO PATH_TBL VALUES (' [1,2,3, 4] ');
 
-INSERT INTO PATH_TBL VALUES ('[11,12,13,14]');
+INSERT INTO PATH_TBL VALUES ('((10,20))');	-- Only one point
 
-INSERT INTO PATH_TBL VALUES ('(11,12,13,14)');
+INSERT INTO PATH_TBL VALUES ('[ 11,12,13,14 ]');
+
+INSERT INTO PATH_TBL VALUES ('( 11,12,13,14) ');
 
 -- bad values for parser testing
+INSERT INTO PATH_TBL VALUES ('[]');
+
 INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
 
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
 
-SELECT f1 FROM PATH_TBL;
+INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+
+INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
 
 SELECT '' AS count, f1 AS open_path FROM PATH_TBL WHERE isopen(f1);
 
 SELECT '' AS count, f1 AS closed_path FROM PATH_TBL WHERE isclosed(f1);
 
 SELECT '' AS count, pclose(f1) AS closed_path FROM PATH_TBL;
 
 SELECT '' AS count, popen(f1) AS open_path FROM PATH_TBL;
diff --git a/src/test/regress/sql/point.sql b/src/test/regress/sql/point.sql
index 63a803a809..a209f3bfeb 100644
--- a/src/test/regress/sql/point.sql
+++ b/src/test/regress/sql/point.sql
@@ -7,29 +7,39 @@ CREATE TABLE POINT_TBL(f1 point);
 INSERT INTO POINT_TBL(f1) VALUES ('(0.0,0.0)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-10.0,0.0)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-3.0,4.0)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(5.1, 34.5)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-5.0,-12.0)');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(1e-300,-1e-300)');	-- To underflow
+
+INSERT INTO POINT_TBL(f1) VALUES ('(1e+300,Inf)');		-- To overflow
+
+INSERT INTO POINT_TBL(f1) VALUES (' ( Nan , NaN ) ');
+
 -- bad format points
 INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
 
 INSERT INTO POINT_TBL(f1) VALUES ('10.0,10.0');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');	-- Out of range
+
 
 SELECT '' AS six, * FROM POINT_TBL;
 
 -- left of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE p.f1 << '(0.0, 0.0)';
 
 -- right of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE '(0.0,0.0)' >> p.f1;
 
 -- above
diff --git a/src/test/regress/sql/polygon.sql b/src/test/regress/sql/polygon.sql
index 7e8cb08cd8..d3d2fe3457 100644
--- a/src/test/regress/sql/polygon.sql
+++ b/src/test/regress/sql/polygon.sql
@@ -4,126 +4,43 @@
 -- polygon logic
 --
 
 CREATE TABLE POLYGON_TBL(f1 polygon);
 
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(2.0,0.0),(2.0,4.0),(0.0,0.0)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(3.0,1.0),(3.0,3.0),(1.0,0.0)');
 
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(3,4),(5,6),(7,8)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(7,8),(5,6),(3,4),(1,2)'); -- Reverse
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(7,8),(5,6),(3,-4)');
+
 -- degenerate polygons
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,0.0)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,1.0),(0.0,1.0)');
 
 -- bad polygon input strings
 INSERT INTO POLYGON_TBL(f1) VALUES ('0.0');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0 0.0');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2,3');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
 
 
 SELECT '' AS four, * FROM POLYGON_TBL;
 
--- overlap
-SELECT '' AS three, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 && '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- left overlap
-SELECT '' AS four, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &< '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- right overlap
-SELECT '' AS two, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- left of
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 << '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- right of
-SELECT '' AS zero, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 >> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- contained
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- same
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- contains
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
---
--- polygon logic
---
--- left of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- left overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
-
--- right overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' &> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- right of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' >> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- contained in
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- contains
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "false";
-
-SELECT '((0,4),(6,4),(3,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
-
-SELECT '((1,1),(1,4),(5,4),(5,3),(2,3),(2,2),(5,2),(5,1))'::polygon @> '((3,2),(3,3),(4,3),(4,2))'::polygon AS "false";
-
-SELECT '((0,0),(0,3),(3,3),(3,0))'::polygon @> '((2,1),(2,2),(3,2),(3,1))'::polygon AS "true";
-
--- same
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' && polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon && '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
-
-SELECT '((1,4),(1,1),(4,1),(4,2),(2,2),(2,4),(1,4))'::polygon && '((3,3),(4,3),(4,4),(3,4),(3,3))'::polygon AS "false";
-SELECT '((200,800),(800,800),(800,200),(200,200))' &&  '(1000,1000,0,0)'::polygon AS "true";
-
--- distance from a point
-SELECT	'(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
-	'(1,1)'::point <-> '((0,0),(2,2),(1,3))'::polygon as on_segment,
-	'(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;
-- 
2.14.3 (Apple Git-98)

#71Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Emre Hasegeli (#70)
6 attachment(s)
Re: [PATCH] Improve geometric types

On 07/11/2018 07:13 PM, Emre Hasegeli wrote:

New versions are attached after the <float.h> patch got in. I noticed
tests failing on Windows [1] and added alternative .out file.

[1] https://ci.appveyor.com/project/postgresql-cfbot/postgresql/build/1.0.5235

The version posted about two weeks ago is slightly broken - AFAICS the
float.h includes in geo_ops.c and gistproc.c need to be part of 0002,
not 0003. Attached is a version fixing that.

Barring objections, I'll get this committed over the next few days, once
I review all the individual parts once more. I'm planning to commit the
6 parts separately, as submitted. No backpatching, as discussed before.

regards

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

Attachments:

0001-Refactor-geometric-functions-and-operators-code.patchtext/x-patch; name=0001-Refactor-geometric-functions-and-operators-code.patchDownload
From 5ab7ffb5ce88dd7113246121d6447967e54d495a Mon Sep 17 00:00:00 2001
From: Tomas Vondra <tomas@2ndquadrant.com>
Date: Thu, 26 Jul 2018 12:50:33 +0200
Subject: [PATCH 1/6] Refactor geometric functions and operators code

Most of the geometric types were not using functions of each other's.
I believe the reason behind this is simpler types line point and line
being developed after more complicated ones.  This patch reduces
duplicate code and makes functions of different datatypes more
compatible.  The changes can be summarised as:

* Eliminate SQL level function calls
* Re-use more functions to implement others
* Unify internal function names and signatures
* Remove private functions from geo_decls.h
* Replace not-possible checks with Assert()
* Add comments to describe some functions
* Remove some unreachable code
* Define delimiter symbols of line datatype like the other ones
* Remove debugging print()s from the refactored functions
* Unify code style of a few oddly formatted lines

This commits aims to not cause any user visible changes, but it is
almost impossible to stay completely bug-compatible with the old code.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com
---
 src/backend/utils/adt/geo_ops.c    | 1882 +++++++++++++++++-------------------
 src/backend/utils/adt/geo_spgist.c |    3 +-
 src/include/utils/geo_decls.h      |    4 -
 src/test/regress/regress.c         |    7 +-
 4 files changed, 870 insertions(+), 1026 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index f57380a4df..3e7519015d 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -38,24 +38,62 @@ enum path_delim
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
+/* Routines for points */
+static inline void point_construct(Point *result, float8 x, float8 y);
+static inline void point_add_point(Point *result, Point *pt1, Point *pt2);
+static inline void point_sub_point(Point *result, Point *pt1, Point *pt2);
+static inline void point_mul_point(Point *result, Point *pt1, Point *pt2);
+static inline void point_div_point(Point *result, Point *pt1, Point *pt2);
+static inline bool point_eq_point(Point *pt1, Point *pt2);
+static inline float8 point_dt(Point *pt1, Point *pt2);
+static inline float8 point_sl(Point *pt1, Point *pt2);
 static int	point_inside(Point *p, int npts, Point *plist);
+
+/* Routines for lines */
+static inline void line_construct(LINE *result, Point *pt, float8 m);
+static inline float8 line_invsl(LINE *line);
+static bool	line_interpt_line(Point *result, LINE *l1, LINE *l2);
+static bool line_contain_point(LINE *line, Point *point);
+static float8 line_closept_point(Point *result, LINE *line, Point *pt);
+
+/* Routines for line segments */
+static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
+static inline float8 lseg_sl(LSEG *lseg);
+static inline float8 lseg_invsl(LSEG *lseg);
+static bool	lseg_interpt_line(Point *result, LSEG *lseg, LINE *line);
+static bool	lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2);
 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_fill(BOX *result, double x1, double x2, double y1, double y2);
+static bool	lseg_contain_point(LSEG *lseg, Point *point);
+static float8 lseg_closept_point(Point *result, LSEG *lseg, Point *pt);
+static float8 lseg_closept_line(Point *result, LSEG *lseg, LINE *line);
+static float8 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2);
+
+/* Routines for boxes */
+static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
+static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
+static double box_ar(BOX *box);
 static double box_ht(BOX *box);
 static double box_wd(BOX *box);
+static bool box_contain_point(BOX *box, Point *point);
+static bool box_contain_box(BOX *box1, BOX *box2);
+static bool box_contain_lseg(BOX *box, LSEG *lseg);
+static bool box_interpt_lseg(Point *result, BOX *box, LSEG *lseg);
+static float8 box_closept_point(Point *result, BOX *box, Point *point);
+static float8 box_closept_lseg(Point *result, BOX *box, LSEG *lseg);
+
+/* Routines for circles */
 static double circle_ar(CIRCLE *circle);
-static CIRCLE *circle_copy(CIRCLE *circle);
-static LINE *line_construct_pm(Point *pt, double m);
-static void line_construct_pts(LINE *line, Point *pt1, Point *pt2);
-static bool lseg_intersect_internal(LSEG *l1, LSEG *l2);
-static double lseg_dt(LSEG *l1, LSEG *l2);
-static bool on_ps_internal(Point *pt, LSEG *lseg);
+
+/* Routines for polygons */
 static void make_bound_box(POLYGON *poly);
+static void poly_to_circle(CIRCLE *result, POLYGON *poly);
+static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
+static bool poly_contain_poly(POLYGON *polya, POLYGON *polyb);
 static bool plist_same(int npts, Point *p1, Point *p2);
-static Point *point_construct(double x, double y);
-static Point *point_copy(Point *pt);
+static float8 dist_ppoly_internal(Point *pt, POLYGON *poly);
+
+/* Routines for encoding and decoding */
 static double single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
@@ -67,17 +105,6 @@ static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
-static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
-static double box_ar(BOX *box);
-static void box_cn(Point *center, BOX *box);
-static Point *interpt_sl(LSEG *lseg, LINE *line);
-static bool has_interpt_sl(LSEG *lseg, LINE *line);
-static double dist_pl_internal(Point *pt, LINE *line);
-static double dist_ps_internal(Point *pt, LSEG *lseg);
-static Point *line_interpt_internal(LINE *l1, LINE *l2);
-static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
-static Point *lseg_interpt_internal(LSEG *l1, LSEG *l2);
-static double dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 
 /*
@@ -93,6 +120,8 @@ static double dist_ppoly_internal(Point *pt, POLYGON *poly);
 #define RDELIM_EP		']'
 #define LDELIM_C		'<'
 #define RDELIM_C		'>'
+#define LDELIM_L		'{'
+#define RDELIM_L		'}'
 
 
 /*
@@ -236,12 +265,9 @@ path_decode(char *str, bool opentype, int npts, Point *p,
 		p++;
 	}
 
-	while (isspace((unsigned char) *str))
-		str++;
 	while (depth > 0)
 	{
-		if ((*str == RDELIM)
-			|| ((*str == RDELIM_EP) && (*isopen) && (depth == 1)))
+		if (*str == RDELIM || (*str == RDELIM_EP && *isopen && depth == 1))
 		{
 			depth--;
 			str++;
@@ -440,55 +466,29 @@ box_send(PG_FUNCTION_ARGS)
 
 /*		box_construct	-		fill in a new box.
  */
-static BOX *
-box_construct(double x1, double x2, double y1, double y2)
-{
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	return box_fill(result, x1, x2, y1, y2);
-}
-
-
-/*		box_fill		-		fill in a given box struct
- */
-static BOX *
-box_fill(BOX *result, double x1, double x2, double y1, double y2)
+static inline void
+box_construct(BOX *result, Point *pt1, Point *pt2)
 {
-	if (x1 > x2)
+	if (pt1->x > pt2->x)
 	{
-		result->high.x = x1;
-		result->low.x = x2;
+		result->high.x = pt1->x;
+		result->low.x = pt2->x;
 	}
 	else
 	{
-		result->high.x = x2;
-		result->low.x = x1;
+		result->high.x = pt2->x;
+		result->low.x = pt1->x;
 	}
-	if (y1 > y2)
+	if (pt1->y > pt2->y)
 	{
-		result->high.y = y1;
-		result->low.y = y2;
+		result->high.y = pt1->y;
+		result->low.y = pt2->y;
 	}
 	else
 	{
-		result->high.y = y2;
-		result->low.y = y1;
+		result->high.y = pt2->y;
+		result->low.y = pt1->y;
 	}
-
-	return result;
-}
-
-
-/*		box_copy		-		copy a box
- */
-BOX *
-box_copy(BOX *box)
-{
-	BOX		   *result = (BOX *) palloc(sizeof(BOX));
-
-	memcpy((char *) result, (char *) box, sizeof(BOX));
-
-	return result;
 }
 
 
@@ -505,10 +505,8 @@ box_same(PG_FUNCTION_ARGS)
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPeq(box1->high.x, box2->high.x) &&
-				   FPeq(box1->low.x, box2->low.x) &&
-				   FPeq(box1->high.y, box2->high.y) &&
-				   FPeq(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(point_eq_point(&box1->high, &box2->high) &&
+				   point_eq_point(&box1->low, &box2->low));
 }
 
 /*		box_overlap		-		does box1 overlap box2?
@@ -637,10 +635,7 @@ box_contained(PG_FUNCTION_ARGS)
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPle(box1->high.x, box2->high.x) &&
-				   FPge(box1->low.x, box2->low.x) &&
-				   FPle(box1->high.y, box2->high.y) &&
-				   FPge(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(box_contain_box(box2, box1));
 }
 
 /*		box_contain		-		does box1 contain box2?
@@ -651,10 +646,19 @@ box_contain(PG_FUNCTION_ARGS)
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(FPge(box1->high.x, box2->high.x) &&
-				   FPle(box1->low.x, box2->low.x) &&
-				   FPge(box1->high.y, box2->high.y) &&
-				   FPle(box1->low.y, box2->low.y));
+	PG_RETURN_BOOL(box_contain_box(box1, box2));
+}
+
+/*
+ * Check whether the box is in the box or on its border
+ */
+static bool
+box_contain_box(BOX *box1, BOX *box2)
+{
+	return FPge(box1->high.x, box2->high.x) &&
+		   FPle(box1->low.x, box2->low.x) &&
+		   FPge(box1->high.y, box2->high.y) &&
+		   FPle(box1->low.y, box2->low.y);
 }
 
 
@@ -757,7 +761,7 @@ box_width(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.x - box->low.x);
+	PG_RETURN_FLOAT8(box_wd(box));
 }
 
 
@@ -769,7 +773,7 @@ box_height(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
-	PG_RETURN_FLOAT8(box->high.y - box->low.y);
+	PG_RETURN_FLOAT8(box_ht(box));
 }
 
 
@@ -787,7 +791,7 @@ box_distance(PG_FUNCTION_ARGS)
 	box_cn(&a, box1);
 	box_cn(&b, box2);
 
-	PG_RETURN_FLOAT8(HYPOT(a.x - b.x, a.y - b.y));
+	PG_RETURN_FLOAT8(point_dt(&a, &b));
 }
 
 
@@ -905,7 +909,7 @@ line_decode(char *s, const char *str, LINE *line)
 	if (*s++ != DELIM)
 		return false;
 	line->C = single_decode(s, &s, "line", str);
-	if (*s++ != '}')
+	if (*s++ != RDELIM_L)
 		return false;
 	while (isspace((unsigned char) *s))
 		s++;
@@ -926,7 +930,7 @@ line_in(PG_FUNCTION_ARGS)
 	s = str;
 	while (isspace((unsigned char) *s))
 		s++;
-	if (*s == '{')
+	if (*s == LDELIM_L)
 	{
 		if (!line_decode(s + 1, str, line))
 			ereport(ERROR,
@@ -940,12 +944,12 @@ line_in(PG_FUNCTION_ARGS)
 	}
 	else
 	{
-		path_decode(s, true, 2, &(lseg.p[0]), &isopen, NULL, "line", str);
-		if (FPeq(lseg.p[0].x, lseg.p[1].x) && FPeq(lseg.p[0].y, lseg.p[1].y))
+		path_decode(s, true, 2, &lseg.p[0], &isopen, NULL, "line", str);
+		if (point_eq_point(&lseg.p[0], &lseg.p[1]))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: must be two distinct points")));
-		line_construct_pts(line, &lseg.p[0], &lseg.p[1]);
+		line_construct(line, &lseg.p[0], lseg_sl(&lseg));
 	}
 
 	PG_RETURN_LINE_P(line);
@@ -960,7 +964,8 @@ line_out(PG_FUNCTION_ARGS)
 	char	   *bstr = float8out_internal(line->B);
 	char	   *cstr = float8out_internal(line->C);
 
-	PG_RETURN_CSTRING(psprintf("{%s,%s,%s}", astr, bstr, cstr));
+	PG_RETURN_CSTRING(psprintf("%c%s%c%s%c%s%c", LDELIM_L, astr, DELIM, bstr,
+							   DELIM, cstr, RDELIM_L));
 }
 
 /*
@@ -1003,14 +1008,12 @@ line_send(PG_FUNCTION_ARGS)
  *		Internal form:	Ax+By+C=0
  *---------------------------------------------------------*/
 
-/* line_construct_pm()
- * point-slope
+/*
+ * Fill already-allocated LINE struct from the point and the slope
  */
-static LINE *
-line_construct_pm(Point *pt, double m)
+static inline void
+line_construct(LINE *result, Point *pt, float8 m)
 {
-	LINE	   *result = (LINE *) palloc(sizeof(LINE));
-
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
@@ -1025,50 +1028,6 @@ line_construct_pm(Point *pt, double m)
 		result->B = -1.0;
 		result->C = pt->y - m * pt->x;
 	}
-
-	return result;
-}
-
-/*
- * Fill already-allocated LINE struct from two points on the line
- */
-static void
-line_construct_pts(LINE *line, Point *pt1, Point *pt2)
-{
-	if (FPeq(pt1->x, pt2->x))
-	{							/* vertical */
-		/* use "x = C" */
-		line->A = -1;
-		line->B = 0;
-		line->C = pt1->x;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is vertical\n");
-#endif
-	}
-	else if (FPeq(pt1->y, pt2->y))
-	{							/* horizontal */
-		/* use "y = C" */
-		line->A = 0;
-		line->B = -1;
-		line->C = pt1->y;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is horizontal\n");
-#endif
-	}
-	else
-	{
-		/* use "mx - y + yinter = 0" */
-		line->A = (pt2->y - pt1->y) / (pt2->x - pt1->x);
-		line->B = -1.0;
-		line->C = pt1->y - line->A * pt1->x;
-		/* on some platforms, the preceding expression tends to produce -0 */
-		if (line->C == 0.0)
-			line->C = 0.0;
-#ifdef GEODEBUG
-		printf("line_construct_pts- line is neither vertical nor horizontal (diffs x=%.*g, y=%.*g\n",
-			   DBL_DIG, (pt2->x - pt1->x), DBL_DIG, (pt2->y - pt1->y));
-#endif
-	}
 }
 
 /* line_construct_pp()
@@ -1081,7 +1040,8 @@ line_construct_pp(PG_FUNCTION_ARGS)
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 	LINE	   *result = (LINE *) palloc(sizeof(LINE));
 
-	line_construct_pts(result, pt1, pt2);
+	line_construct(result, pt1, point_sl(pt1, pt2));
+
 	PG_RETURN_LINE_P(result);
 }
 
@@ -1096,9 +1056,7 @@ line_intersect(PG_FUNCTION_ARGS)
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(!DatumGetBool(DirectFunctionCall2(line_parallel,
-													 LinePGetDatum(l1),
-													 LinePGetDatum(l2))));
+	PG_RETURN_BOOL(line_interpt_line(NULL, l1, l2));
 }
 
 Datum
@@ -1107,10 +1065,7 @@ line_parallel(PG_FUNCTION_ARGS)
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
-	if (FPzero(l1->B))
-		PG_RETURN_BOOL(FPzero(l2->B));
-
-	PG_RETURN_BOOL(FPeq(l2->A, l1->A * (l2->B / l1->B)));
+	PG_RETURN_BOOL(!line_interpt_line(NULL, l1, l2));
 }
 
 Datum
@@ -1169,6 +1124,20 @@ line_eq(PG_FUNCTION_ARGS)
  *	Line arithmetic routines.
  *---------------------------------------------------------*/
 
+/*
+ * Return inverse slope of the line
+ */
+static inline float8
+line_invsl(LINE *line)
+{
+	if (FPzero(line->A))
+		return DBL_MAX;
+	if (FPzero(line->B))
+		return 0.0;
+	return line->B / line->A;
+}
+
+
 /* line_distance()
  * Distance between two lines.
  */
@@ -1178,16 +1147,14 @@ line_distance(PG_FUNCTION_ARGS)
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
-	Point	   *tmp;
+	Point		tmp;
 
-	if (!DatumGetBool(DirectFunctionCall2(line_parallel,
-										  LinePGetDatum(l1),
-										  LinePGetDatum(l2))))
+	if (line_interpt_line(NULL, l1, l2))	/* intersecting? */
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
 		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
-	tmp = point_construct(0.0, l1->C);
-	result = dist_pl_internal(tmp, l2);
+	point_construct(&tmp, 0.0, l1->C);
+	result = line_closept_point(NULL, l2, &tmp);
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -1201,9 +1168,9 @@ line_interpt(PG_FUNCTION_ARGS)
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
-	result = line_interpt_internal(l1, l2);
+	result = (Point *) palloc(sizeof(Point));
 
-	if (result == NULL)
+	if (!line_interpt_line(result, l1, l2))
 		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
@@ -1211,27 +1178,25 @@ line_interpt(PG_FUNCTION_ARGS)
 /*
  * Internal version of line_interpt
  *
- * returns a NULL pointer if no intersection point
+ * This returns true if two lines intersect (they do, if they are not
+ * parallel), false if they do not.  This also sets the intersection point
+ * to *result, if it is not NULL.
+ *
+ * NOTE: If the lines are identical then we will find they are parallel
+ * and report "no intersection".  This is a little weird, but since
+ * there's no *unique* intersection, maybe it's appropriate behavior.
  */
-static Point *
-line_interpt_internal(LINE *l1, LINE *l2)
+static bool
+line_interpt_line(Point *result, LINE *l1, LINE *l2)
 {
-	Point	   *result;
 	double		x,
 				y;
 
-	/*
-	 * NOTE: if the lines are identical then we will find they are parallel
-	 * and report "no intersection".  This is a little weird, but since
-	 * there's no *unique* intersection, maybe it's appropriate behavior.
-	 */
-	if (DatumGetBool(DirectFunctionCall2(line_parallel,
-										 LinePGetDatum(l1),
-										 LinePGetDatum(l2))))
-		return NULL;
-
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
+		if (FPzero(l2->B))		/* l2 vertical? */
+			return false;
+
 		x = l1->C;
 		y = (l2->A * x + l2->C);
 	}
@@ -1242,18 +1207,17 @@ line_interpt_internal(LINE *l1, LINE *l2)
 	}
 	else
 	{
+		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+			return false;
+
 		x = (l1->C - l2->C) / (l2->A - l1->A);
 		y = (l1->A * x + l1->C);
 	}
-	result = point_construct(x, y);
 
-#ifdef GEODEBUG
-	printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
-		   DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
-	printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
-#endif
+	if (result != NULL)
+		point_construct(result, x, y);
 
-	return result;
+	return true;
 }
 
 
@@ -1562,8 +1526,7 @@ path_inter(PG_FUNCTION_ARGS)
 	LSEG		seg1,
 				seg2;
 
-	if (p1->npts <= 0 || p2->npts <= 0)
-		PG_RETURN_BOOL(false);
+	Assert(p1->npts > 0 && p2->npts > 0);
 
 	b1.high.x = b1.low.x = p1->p[0].x;
 	b1.high.y = b1.low.y = p1->p[0].y;
@@ -1615,7 +1578,7 @@ path_inter(PG_FUNCTION_ARGS)
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
-			if (lseg_intersect_internal(&seg1, &seg2))
+			if (lseg_interpt_lseg(NULL, &seg1, &seg2))
 				PG_RETURN_BOOL(true);
 		}
 	}
@@ -1670,9 +1633,7 @@ path_distance(PG_FUNCTION_ARGS)
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
-			tmp = DatumGetFloat8(DirectFunctionCall2(lseg_distance,
-													 LsegPGetDatum(&seg1),
-													 LsegPGetDatum(&seg2)));
+			tmp = lseg_closept_lseg(NULL, &seg1, &seg2);
 			if (!have_min || tmp < min)
 			{
 				min = tmp;
@@ -1780,30 +1741,14 @@ point_send(PG_FUNCTION_ARGS)
 }
 
 
-static Point *
-point_construct(double x, double y)
+/*
+ * Initialize a point
+ */
+static inline void
+point_construct(Point *result, float8 x, float8 y)
 {
-	Point	   *result = (Point *) palloc(sizeof(Point));
-
 	result->x = x;
 	result->y = y;
-	return result;
-}
-
-
-static Point *
-point_copy(Point *pt)
-{
-	Point	   *result;
-
-	if (!PointerIsValid(pt))
-		return NULL;
-
-	result = (Point *) palloc(sizeof(Point));
-
-	result->x = pt->x;
-	result->y = pt->y;
-	return result;
 }
 
 
@@ -1876,7 +1821,7 @@ point_eq(PG_FUNCTION_ARGS)
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y));
+	PG_RETURN_BOOL(point_eq_point(pt1, pt2));
 }
 
 Datum
@@ -1885,9 +1830,16 @@ point_ne(PG_FUNCTION_ARGS)
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_BOOL(FPne(pt1->x, pt2->x) || FPne(pt1->y, pt2->y));
+	PG_RETURN_BOOL(!point_eq_point(pt1, pt2));
+}
+
+static inline bool
+point_eq_point(Point *pt1, Point *pt2)
+{
+	return FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y);
 }
 
+
 /*----------------------------------------------------------
  *	"Arithmetic" operators on points.
  *---------------------------------------------------------*/
@@ -1898,16 +1850,12 @@ point_distance(PG_FUNCTION_ARGS)
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_FLOAT8(HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
+	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
-double
+static inline float8
 point_dt(Point *pt1, Point *pt2)
 {
-#ifdef GEODEBUG
-	printf("point_dt- segment (%f,%f),(%f,%f) length is %f\n",
-		   pt1->x, pt1->y, pt2->x, pt2->y, HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
-#endif
 	return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
 }
 
@@ -1921,12 +1869,35 @@ point_slope(PG_FUNCTION_ARGS)
 }
 
 
-double
+/*
+ * Return slope of two points
+ *
+ * Note that this function returns DBL_MAX when the points are the same.
+ */
+static inline float8
 point_sl(Point *pt1, Point *pt2)
 {
-	return (FPeq(pt1->x, pt2->x)
-			? (double) DBL_MAX
-			: (pt1->y - pt2->y) / (pt1->x - pt2->x));
+	if (FPeq(pt1->x, pt2->x))
+		return DBL_MAX;
+	if (FPeq(pt1->y, pt2->y))
+		return 0.0;
+	return (pt1->y - pt2->y) / (pt1->x - pt2->x);
+}
+
+
+/*
+ * Return inverse slope of two points
+ *
+ * Note that this function returns 0.0 when the points are the same.
+ */
+static inline float8
+point_invsl(Point *pt1, Point *pt2)
+{
+	if (FPeq(pt1->x, pt2->x))
+		return 0.0;
+	if (FPeq(pt1->y, pt2->y))
+		return DBL_MAX;
+	return (pt1->x - pt2->x) / (pt2->y - pt1->y);
 }
 
 
@@ -1952,7 +1923,7 @@ lseg_in(PG_FUNCTION_ARGS)
 	LSEG	   *lseg = (LSEG *) palloc(sizeof(LSEG));
 	bool		isopen;
 
-	path_decode(str, true, 2, &(lseg->p[0]), &isopen, NULL, "lseg", str);
+	path_decode(str, true, 2, &lseg->p[0], &isopen, NULL, "lseg", str);
 	PG_RETURN_LSEG_P(lseg);
 }
 
@@ -1962,7 +1933,7 @@ lseg_out(PG_FUNCTION_ARGS)
 {
 	LSEG	   *ls = PG_GETARG_LSEG_P(0);
 
-	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, (Point *) &(ls->p[0])));
+	PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, &ls->p[0]));
 }
 
 /*
@@ -2012,16 +1983,13 @@ lseg_construct(PG_FUNCTION_ARGS)
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 	LSEG	   *result = (LSEG *) palloc(sizeof(LSEG));
 
-	result->p[0].x = pt1->x;
-	result->p[0].y = pt1->y;
-	result->p[1].x = pt2->x;
-	result->p[1].y = pt2->y;
+	statlseg_construct(result, pt1, pt2);
 
 	PG_RETURN_LSEG_P(result);
 }
 
 /* like lseg_construct, but assume space already allocated */
-static void
+static inline void
 statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2)
 {
 	lseg->p[0].x = pt1->x;
@@ -2030,6 +1998,27 @@ statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2)
 	lseg->p[1].y = pt2->y;
 }
 
+
+/*
+ * Return slope of the line segment
+ */
+static inline float8
+lseg_sl(LSEG *lseg)
+{
+	return point_sl(&lseg->p[0], &lseg->p[1]);
+}
+
+
+/*
+ * Return inverse slope of the line segment
+ */
+static inline float8
+lseg_invsl(LSEG *lseg)
+{
+	return point_invsl(&lseg->p[0], &lseg->p[1]);
+}
+
+
 Datum
 lseg_length(PG_FUNCTION_ARGS)
 {
@@ -2052,25 +2041,9 @@ lseg_intersect(PG_FUNCTION_ARGS)
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(lseg_intersect_internal(l1, l2));
+	PG_RETURN_BOOL(lseg_interpt_lseg(NULL, l1, l2));
 }
 
-static bool
-lseg_intersect_internal(LSEG *l1, LSEG *l2)
-{
-	LINE		ln;
-	Point	   *interpt;
-	bool		retval;
-
-	line_construct_pts(&ln, &l2->p[0], &l2->p[1]);
-	interpt = interpt_sl(l1, &ln);
-
-	if (interpt != NULL && on_ps_internal(interpt, l2))
-		retval = true;			/* interpt on l1 and l2 */
-	else
-		retval = false;
-	return retval;
-}
 
 Datum
 lseg_parallel(PG_FUNCTION_ARGS)
@@ -2078,39 +2051,19 @@ lseg_parallel(PG_FUNCTION_ARGS)
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPeq(point_sl(&l1->p[0], &l1->p[1]),
-						point_sl(&l2->p[0], &l2->p[1])));
+	PG_RETURN_BOOL(FPeq(lseg_sl(l1), lseg_sl(l2)));
 }
 
-/* lseg_perp()
+/*
  * Determine if two line segments are perpendicular.
- *
- * This code did not get the correct answer for
- *	'((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg
- * So, modified it to check explicitly for slope of vertical line
- *	returned by point_sl() and the results seem better.
- * - thomas 1998-01-31
  */
 Datum
 lseg_perp(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	double		m1,
-				m2;
 
-	m1 = point_sl(&(l1->p[0]), &(l1->p[1]));
-	m2 = point_sl(&(l2->p[0]), &(l2->p[1]));
-
-#ifdef GEODEBUG
-	printf("lseg_perp- slopes are %g and %g\n", m1, m2);
-#endif
-	if (FPzero(m1))
-		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
-	else if (FPzero(m2))
-		PG_RETURN_BOOL(FPeq(m1, DBL_MAX));
-
-	PG_RETURN_BOOL(FPeq(m1 / m2, -1.0));
+	PG_RETURN_BOOL(FPeq(lseg_sl(l1), lseg_invsl(l2)));
 }
 
 Datum
@@ -2136,10 +2089,8 @@ lseg_eq(PG_FUNCTION_ARGS)
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPeq(l1->p[0].x, l2->p[0].x) &&
-				   FPeq(l1->p[0].y, l2->p[0].y) &&
-				   FPeq(l1->p[1].x, l2->p[1].x) &&
-				   FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(point_eq_point(&l1->p[0], &l2->p[0]) &&
+				   point_eq_point(&l1->p[1], &l2->p[1]));
 }
 
 Datum
@@ -2148,10 +2099,8 @@ lseg_ne(PG_FUNCTION_ARGS)
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(!FPeq(l1->p[0].x, l2->p[0].x) ||
-				   !FPeq(l1->p[0].y, l2->p[0].y) ||
-				   !FPeq(l1->p[1].x, l2->p[1].x) ||
-				   !FPeq(l1->p[1].y, l2->p[1].y));
+	PG_RETURN_BOOL(!point_eq_point(&l1->p[0], &l2->p[0]) ||
+				   !point_eq_point(&l1->p[1], &l2->p[1]));
 }
 
 Datum
@@ -2210,33 +2159,7 @@ lseg_distance(PG_FUNCTION_ARGS)
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_FLOAT8(lseg_dt(l1, l2));
-}
-
-/* lseg_dt()
- * Distance between two line segments.
- * Must check both sets of endpoints to ensure minimum distance is found.
- * - thomas 1998-02-01
- */
-static double
-lseg_dt(LSEG *l1, LSEG *l2)
-{
-	double		result,
-				d;
-
-	if (lseg_intersect_internal(l1, l2))
-		return 0.0;
-
-	d = dist_ps_internal(&l1->p[0], l2);
-	result = d;
-	d = dist_ps_internal(&l1->p[1], l2);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[0], l1);
-	result = Min(result, d);
-	d = dist_ps_internal(&l2->p[1], l1);
-	result = Min(result, d);
-
-	return result;
+	PG_RETURN_FLOAT8(lseg_closept_lseg(NULL, l1, l2));
 }
 
 
@@ -2254,57 +2177,38 @@ lseg_center(PG_FUNCTION_ARGS)
 	PG_RETURN_POINT_P(result);
 }
 
-static Point *
-lseg_interpt_internal(LSEG *l1, LSEG *l2)
+
+/*
+ *		Find the intersection point of two segments (if any).
+ *
+ * This returns true if two line segments intersect, false if they do not.
+ * This also sets the intersection point to *result, if it is not NULL.
+ * This function is almost perfectly symmetric, even though it doesn't look
+ * like it.  See lseg_interpt_line() for the other half of it.
+ */
+static bool
+lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2)
 {
-	Point	   *result;
-	LINE		tmp1,
-				tmp2;
+	Point		interpt;
+	LINE		tmp;
 
-	/*
-	 * Find the intersection of the appropriate lines, if any.
-	 */
-	line_construct_pts(&tmp1, &l1->p[0], &l1->p[1]);
-	line_construct_pts(&tmp2, &l2->p[0], &l2->p[1]);
-	result = line_interpt_internal(&tmp1, &tmp2);
-	if (!PointerIsValid(result))
-		return NULL;
+	line_construct(&tmp, &l2->p[0], lseg_sl(l2));
+	if (!lseg_interpt_line(&interpt, l1, &tmp))
+		return false;
 
 	/*
-	 * If the line intersection point isn't within l1 (or equivalently l2),
-	 * there is no valid segment intersection point at all.
+	 * If the line intersection point isn't within l2, there is no valid
+	 * segment intersection point at all.
 	 */
-	if (!on_ps_internal(result, l1) ||
-		!on_ps_internal(result, l2))
-	{
-		pfree(result);
-		return NULL;
-	}
+	if (!lseg_contain_point(l2, &interpt))
+		return false;
 
-	/*
-	 * If there is an intersection, then check explicitly for matching
-	 * endpoints since there may be rounding effects with annoying lsb
-	 * residue. - tgl 1997-07-09
-	 */
-	if ((FPeq(l1->p[0].x, l2->p[0].x) && FPeq(l1->p[0].y, l2->p[0].y)) ||
-		(FPeq(l1->p[0].x, l2->p[1].x) && FPeq(l1->p[0].y, l2->p[1].y)))
-	{
-		result->x = l1->p[0].x;
-		result->y = l1->p[0].y;
-	}
-	else if ((FPeq(l1->p[1].x, l2->p[0].x) && FPeq(l1->p[1].y, l2->p[0].y)) ||
-			 (FPeq(l1->p[1].x, l2->p[1].x) && FPeq(l1->p[1].y, l2->p[1].y)))
-	{
-		result->x = l1->p[1].x;
-		result->y = l1->p[1].y;
-	}
+	if (result != NULL)
+		*result = interpt;
 
-	return result;
+	return true;
 }
 
-/* lseg_interpt -
- *		Find the intersection point of two segments (if any).
- */
 Datum
 lseg_interpt(PG_FUNCTION_ARGS)
 {
@@ -2312,10 +2216,10 @@ lseg_interpt(PG_FUNCTION_ARGS)
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
-	result = lseg_interpt_internal(l1, l2);
-	if (!PointerIsValid(result))
-		PG_RETURN_NULL();
+	result = (Point *) palloc(sizeof(Point));
 
+	if (!lseg_interpt_lseg(result, l1, l2))
+		PG_RETURN_NULL();
 	PG_RETURN_POINT_P(result);
 }
 
@@ -2340,15 +2244,9 @@ dist_pl(PG_FUNCTION_ARGS)
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_FLOAT8(dist_pl_internal(pt, line));
+	PG_RETURN_FLOAT8(line_closept_point(NULL, line, pt));
 }
 
-static double
-dist_pl_internal(Point *pt, LINE *line)
-{
-	return fabs((line->A * pt->x + line->B * pt->y + line->C) /
-				HYPOT(line->A, line->B));
-}
 
 /*
  * Distance from a point to a lseg
@@ -2359,60 +2257,7 @@ dist_ps(PG_FUNCTION_ARGS)
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_FLOAT8(dist_ps_internal(pt, lseg));
-}
-
-static double
-dist_ps_internal(Point *pt, LSEG *lseg)
-{
-	double		m;				/* slope of perp. */
-	LINE	   *ln;
-	double		result,
-				tmpdist;
-	Point	   *ip;
-
-	/*
-	 * Construct a line perpendicular to the input segment and through the
-	 * input point
-	 */
-	if (lseg->p[1].x == lseg->p[0].x)
-		m = 0;
-	else if (lseg->p[1].y == lseg->p[0].y)
-		m = (double) DBL_MAX;	/* slope is infinite */
-	else
-		m = (lseg->p[0].x - lseg->p[1].x) / (lseg->p[1].y - lseg->p[0].y);
-	ln = line_construct_pm(pt, m);
-
-#ifdef GEODEBUG
-	printf("dist_ps- line is A=%g B=%g C=%g from (point) slope (%f,%f) %g\n",
-		   ln->A, ln->B, ln->C, pt->x, pt->y, m);
-#endif
-
-	/*
-	 * Calculate distance to the line segment or to the nearest endpoint of
-	 * the segment.
-	 */
-
-	/* intersection is on the line segment? */
-	if ((ip = interpt_sl(lseg, ln)) != NULL)
-	{
-		/* yes, so use distance to the intersection point */
-		result = point_dt(pt, ip);
-#ifdef GEODEBUG
-		printf("dist_ps- distance is %f to intersection point is (%f,%f)\n",
-			   result, ip->x, ip->y);
-#endif
-	}
-	else
-	{
-		/* no, so use distance to the nearer endpoint */
-		result = point_dt(pt, &lseg->p[0]);
-		tmpdist = point_dt(pt, &lseg->p[1]);
-		if (tmpdist < result)
-			result = tmpdist;
-	}
-
-	return result;
+	PG_RETURN_FLOAT8(lseg_closept_point(NULL, lseg, pt));
 }
 
 /*
@@ -2429,46 +2274,34 @@ dist_ppath(PG_FUNCTION_ARGS)
 	int			i;
 	LSEG		lseg;
 
-	switch (path->npts)
-	{
-		case 0:
-			/* no points in path? then result is undefined... */
-			PG_RETURN_NULL();
-		case 1:
-			/* one point in path? then get distance between two points... */
-			result = point_dt(pt, &path->p[0]);
-			break;
-		default:
-			/* make sure the path makes sense... */
-			Assert(path->npts > 1);
+	Assert(path->npts > 0);
 
-			/*
-			 * the distance from a point to a path is the smallest distance
-			 * from the point to any of its constituent segments.
-			 */
-			for (i = 0; i < path->npts; i++)
-			{
-				int			iprev;
+	/*
+	 * The distance from a point to a path is the smallest distance
+	 * from the point to any of its constituent segments.
+	 */
+	for (i = 0; i < path->npts; i++)
+	{
+		int			iprev;
 
-				if (i > 0)
-					iprev = i - 1;
-				else
-				{
-					if (!path->closed)
-						continue;
-					iprev = path->npts - 1; /* include the closure segment */
-				}
+		if (i > 0)
+			iprev = i - 1;
+		else
+		{
+			if (!path->closed)
+				continue;
+			iprev = path->npts - 1; /* Include the closure segment */
+		}
 
-				statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
-				tmp = dist_ps_internal(pt, &lseg);
-				if (!have_min || tmp < result)
-				{
-					result = tmp;
-					have_min = true;
-				}
-			}
-			break;
+		statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
+		tmp = lseg_closept_point(NULL, &lseg, pt);
+		if (!have_min || tmp < result)
+		{
+			result = tmp;
+			have_min = true;
+		}
 	}
+
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -2480,15 +2313,8 @@ dist_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
-	float8		result;
-	Point	   *near;
-
-	near = DatumGetPointP(DirectFunctionCall2(close_pb,
-											  PointPGetDatum(pt),
-											  BoxPGetDatum(box)));
-	result = point_dt(near, pt);
 
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(box_closept_point(NULL, box, pt));
 }
 
 /*
@@ -2502,12 +2328,12 @@ dist_sl(PG_FUNCTION_ARGS)
 	float8		result,
 				d2;
 
-	if (has_interpt_sl(lseg, line))
+	if (lseg_interpt_line(NULL, lseg, line))
 		result = 0.0;
 	else
 	{
-		result = dist_pl_internal(&lseg->p[0], line);
-		d2 = dist_pl_internal(&lseg->p[1], line);
+		result = line_closept_point(NULL, line, &lseg->p[0]);
+		d2 = line_closept_point(NULL, line, &lseg->p[1]);
 		/* XXX shouldn't we take the min not max? */
 		if (d2 > result)
 			result = d2;
@@ -2524,17 +2350,8 @@ dist_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
-	Point	   *tmp;
-	Datum		result;
-
-	tmp = DatumGetPointP(DirectFunctionCall2(close_sb,
-											 LsegPGetDatum(lseg),
-											 BoxPGetDatum(box)));
-	result = DirectFunctionCall2(dist_pb,
-								 PointPGetDatum(tmp),
-								 BoxPGetDatum(box));
 
-	PG_RETURN_DATUM(result);
+	PG_RETURN_FLOAT8(box_closept_lseg(NULL, box, lseg));
 }
 
 /*
@@ -2584,11 +2401,8 @@ dist_ppoly(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	POLYGON    *poly = PG_GETARG_POLYGON_P(1);
-	float8		result;
-
-	result = dist_ppoly_internal(point, poly);
 
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(dist_ppoly_internal(point, poly));
 }
 
 Datum
@@ -2596,11 +2410,8 @@ dist_polyp(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	float8		result;
 
-	result = dist_ppoly_internal(point, poly);
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(dist_ppoly_internal(point, poly));
 }
 
 static double
@@ -2624,19 +2435,19 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
 	seg.p[0].y = poly->p[0].y;
 	seg.p[1].x = poly->p[poly->npts - 1].x;
 	seg.p[1].y = poly->p[poly->npts - 1].y;
-	result = dist_ps_internal(pt, &seg);
+	result = lseg_closept_point(NULL, &seg, pt);
 #ifdef GEODEBUG
 	printf("dist_ppoly_internal- segment 0/n distance is %f\n", result);
 #endif
 
 	/* check distances for other segments */
-	for (i = 0; (i < poly->npts - 1); i++)
+	for (i = 0; i < poly->npts - 1; i++)
 	{
 		seg.p[0].x = poly->p[i].x;
 		seg.p[0].y = poly->p[i].y;
 		seg.p[1].x = poly->p[i + 1].x;
 		seg.p[1].y = poly->p[i + 1].y;
-		d = dist_ps_internal(pt, &seg);
+		d = lseg_closept_point(NULL, &seg, pt);
 #ifdef GEODEBUG
 		printf("dist_ppoly_internal- segment %d distance is %f\n", (i + 1), d);
 #endif
@@ -2655,49 +2466,51 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
  *				  lines and boxes, since there are typically two.
  *-------------------------------------------------------------------*/
 
-/* Get intersection point of lseg and line; returns NULL if no intersection */
-static Point *
-interpt_sl(LSEG *lseg, LINE *line)
+/*
+ * Check if the line segment intersects with the line
+ *
+ * This returns true if line segment intersects with line, false if they
+ * do not.  This also sets the intersection point to *result, if it is not
+ * NULL.
+ */
+static bool
+lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
 {
+	Point		interpt;
 	LINE		tmp;
-	Point	   *p;
 
-	line_construct_pts(&tmp, &lseg->p[0], &lseg->p[1]);
-	p = line_interpt_internal(&tmp, line);
-#ifdef GEODEBUG
-	printf("interpt_sl- segment is (%.*g %.*g) (%.*g %.*g)\n",
-		   DBL_DIG, lseg->p[0].x, DBL_DIG, lseg->p[0].y, DBL_DIG, lseg->p[1].x, DBL_DIG, lseg->p[1].y);
-	printf("interpt_sl- segment becomes line A=%.*g B=%.*g C=%.*g\n",
-		   DBL_DIG, tmp.A, DBL_DIG, tmp.B, DBL_DIG, tmp.C);
-#endif
-	if (PointerIsValid(p))
-	{
-#ifdef GEODEBUG
-		printf("interpt_sl- intersection point is (%.*g %.*g)\n", DBL_DIG, p->x, DBL_DIG, p->y);
-#endif
-		if (on_ps_internal(p, lseg))
-		{
-#ifdef GEODEBUG
-			printf("interpt_sl- intersection point is on segment\n");
-#endif
-		}
-		else
-			p = NULL;
-	}
-
-	return p;
-}
+	/*
+	 * First, we promote the line segment to a line, because we know how
+	 * to find the intersection point of two lines.  If they don't have
+	 * an intersection point, we are done.
+	 */
+	line_construct(&tmp, &lseg->p[0], lseg_sl(lseg));
+	if (!line_interpt_line(&interpt, &tmp, line))
+		return false;
 
-/* variant: just indicate if intersection point exists */
-static bool
-has_interpt_sl(LSEG *lseg, LINE *line)
-{
-	Point	   *tmp;
+	/*
+	 * Then, we check whether the intersection point is actually on the line
+	 * segment.
+	 */
+	if (!lseg_contain_point(lseg, &interpt))
+		return false;
 
-	tmp = interpt_sl(lseg, line);
-	if (tmp)
+	if (result == NULL)
 		return true;
-	return false;
+
+	/*
+	 * If there is an intersection, then check explicitly for matching
+	 * endpoints since there may be rounding effects with annoying LSB
+	 * residue.
+	 */
+	if (point_eq_point(&lseg->p[0], &interpt))
+		*result = lseg->p[0];
+	else if (point_eq_point(&lseg->p[1], &interpt))
+		*result = lseg->p[1];
+	else
+		*result = interpt;
+
+	return true;
 }
 
 /*---------------------------------------------------------------------
@@ -2705,277 +2518,217 @@ has_interpt_sl(LSEG *lseg, LINE *line)
  *				Point of closest proximity between objects.
  *-------------------------------------------------------------------*/
 
-/* close_pl -
+/*
  *		The intersection point of a perpendicular of the line
  *		through the point.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
+static float8
+line_closept_point(Point *result, LINE *line, Point *point)
+{
+	bool		retval;
+	Point       closept;
+	LINE		tmp;
+
+	/* We drop a perpendicular to find the intersection point. */
+	line_construct(&tmp, point, line_invsl(line));
+	retval = line_interpt_line(&closept, line, &tmp);
+	Assert(retval);		/* XXX: We need something better. */
+
+	if (result != NULL)
+		*result = closept;
+
+	/* Then we calculate the distance between the points. */
+	return point_dt(&closept, point);
+}
+
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
-	LINE	   *tmp;
-	double		invm;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	if (FPzero(line->B))		/* vertical? */
-	{
-		result->x = line->C;
-		result->y = pt->y;
-		PG_RETURN_POINT_P(result);
-	}
-	if (FPzero(line->A))		/* horizontal? */
-	{
-		result->x = pt->x;
-		result->y = line->C;
-		PG_RETURN_POINT_P(result);
-	}
-	/* drop a perpendicular and find the intersection point */
+	line_closept_point(result, line, pt);
 
-	/* invert and flip the sign on the slope to get a perpendicular */
-	invm = line->B / line->A;
-	tmp = line_construct_pm(pt, invm);
-	result = line_interpt_internal(tmp, line);
-	Assert(result != NULL);
 	PG_RETURN_POINT_P(result);
 }
 
 
-/* close_ps()
+/*
  * Closest point on line segment to specified point.
- * Take the closest endpoint if the point is left, right,
- *	above, or below the segment, otherwise find the intersection
- *	point of the segment and its perpendicular through the point.
  *
- * Some tricky code here, relying on boolean expressions
- *	evaluating to only zero or one to use as an array index.
- *		bug fixes by gthaker@atl.lmco.com; May 1, 1998
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
-Datum
-close_ps(PG_FUNCTION_ARGS)
+static float8
+lseg_closept_point(Point *result, LSEG *lseg, Point *pt)
 {
-	Point	   *pt = PG_GETARG_POINT_P(0);
-	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
-	LINE	   *tmp;
-	double		invm;
-	int			xh,
-				yh;
-
-#ifdef GEODEBUG
-	printf("close_sp:pt->x %f pt->y %f\nlseg(0).x %f lseg(0).y %f  lseg(1).x %f lseg(1).y %f\n",
-		   pt->x, pt->y, lseg->p[0].x, lseg->p[0].y,
-		   lseg->p[1].x, lseg->p[1].y);
-#endif
-
-	/* xh (or yh) is the index of upper x( or y) end point of lseg */
-	/* !xh (or !yh) is the index of lower x( or y) end point of lseg */
-	xh = lseg->p[0].x < lseg->p[1].x;
-	yh = lseg->p[0].y < lseg->p[1].y;
-
-	if (FPeq(lseg->p[0].x, lseg->p[1].x))	/* vertical? */
-	{
-#ifdef GEODEBUG
-		printf("close_ps- segment is vertical\n");
-#endif
-		/* first check if point is below or above the entire lseg. */
-		if (pt->y < lseg->p[!yh].y)
-			result = point_copy(&lseg->p[!yh]); /* below the lseg */
-		else if (pt->y > lseg->p[yh].y)
-			result = point_copy(&lseg->p[yh]);	/* above the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
-
-		/* point lines along (to left or right) of the vertical lseg. */
-
-		result = (Point *) palloc(sizeof(Point));
-		result->x = lseg->p[0].x;
-		result->y = pt->y;
-		PG_RETURN_POINT_P(result);
-	}
-	else if (FPeq(lseg->p[0].y, lseg->p[1].y))	/* horizontal? */
-	{
-#ifdef GEODEBUG
-		printf("close_ps- segment is horizontal\n");
-#endif
-		/* first check if point is left or right of the entire lseg. */
-		if (pt->x < lseg->p[!xh].x)
-			result = point_copy(&lseg->p[!xh]); /* left of the lseg */
-		else if (pt->x > lseg->p[xh].x)
-			result = point_copy(&lseg->p[xh]);	/* right of the lseg */
-		if (result != NULL)
-			PG_RETURN_POINT_P(result);
-
-		/* point lines along (at top or below) the horiz. lseg. */
-		result = (Point *) palloc(sizeof(Point));
-		result->x = pt->x;
-		result->y = lseg->p[0].y;
-		PG_RETURN_POINT_P(result);
-	}
+	Point		closept;
+	LINE		tmp;
 
 	/*
-	 * vert. and horiz. cases are down, now check if the closest point is one
-	 * of the end points or someplace on the lseg.
+	 * To find the closest point, we draw a perpendicular line from the point
+	 * to the line segment.
 	 */
+	line_construct(&tmp, pt, point_invsl(&lseg->p[0], &lseg->p[1]));
+	lseg_closept_line(&closept, lseg, &tmp);
 
-	invm = -1.0 / point_sl(&(lseg->p[0]), &(lseg->p[1]));
-	tmp = line_construct_pm(&lseg->p[!yh], invm);	/* lower edge of the
-													 * "band" */
-	if (pt->y < (tmp->A * pt->x + tmp->C))
-	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[!yh]); /* below the lseg, take lower end
-											 * pt */
-#ifdef GEODEBUG
-		printf("close_ps below: tmp A %f  B %f   C %f\n",
-			   tmp->A, tmp->B, tmp->C);
-#endif
-		PG_RETURN_POINT_P(result);
-	}
-	tmp = line_construct_pm(&lseg->p[yh], invm);	/* upper edge of the
-													 * "band" */
-	if (pt->y > (tmp->A * pt->x + tmp->C))
-	{							/* we are below the lower edge */
-		result = point_copy(&lseg->p[yh]);	/* above the lseg, take higher end
-											 * pt */
-#ifdef GEODEBUG
-		printf("close_ps above: tmp A %f  B %f   C %f\n",
-			   tmp->A, tmp->B, tmp->C);
-#endif
-		PG_RETURN_POINT_P(result);
-	}
+	if (result != NULL)
+		*result = closept;
 
-	/*
-	 * at this point the "normal" from point will hit lseg. The closest point
-	 * will be somewhere on the lseg
-	 */
-	tmp = line_construct_pm(pt, invm);
-#ifdef GEODEBUG
-	printf("close_ps- tmp A %f  B %f   C %f\n",
-		   tmp->A, tmp->B, tmp->C);
-#endif
-	result = interpt_sl(lseg, tmp);
+	return point_dt(&closept, pt);
+}
 
-	/*
-	 * ordinarily we should always find an intersection point, but that could
-	 * fail in the presence of NaN coordinates, and perhaps even from simple
-	 * roundoff issues.  Return a SQL NULL if so.
-	 */
-	if (result == NULL)
+Datum
+close_ps(PG_FUNCTION_ARGS)
+{
+	Point	   *pt = PG_GETARG_POINT_P(0);
+	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
+	Point	   *result;
+
+	result = (Point *) palloc(sizeof(Point));
+
+	if (isnan(lseg_closept_point(result, lseg, pt)))
 		PG_RETURN_NULL();
 
-#ifdef GEODEBUG
-	printf("close_ps- result.x %f  result.y %f\n", result->x, result->y);
-#endif
 	PG_RETURN_POINT_P(result);
 }
 
 
-/* close_lseg()
- * Closest point to l1 on l2.
+/*
+ * Closest point on line segment to line segment
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
-Datum
-close_lseg(PG_FUNCTION_ARGS)
+static float8
+lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
 {
-	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
-	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
-	Point	   *result = NULL;
 	Point		point;
 	double		dist;
 	double		d;
 
-	d = dist_ps_internal(&l1->p[0], l2);
+	d = lseg_closept_point(NULL, l1, &l2->p[0]);
 	dist = d;
-	memcpy(&point, &l1->p[0], sizeof(Point));
+	if (result != NULL)
+		*result = l2->p[0];
 
-	if ((d = dist_ps_internal(&l1->p[1], l2)) < dist)
+	d = lseg_closept_point(NULL, l1, &l2->p[1]);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&point, &l1->p[1], sizeof(Point));
+		if (result != NULL)
+			*result = l2->p[1];
 	}
 
-	if (dist_ps_internal(&l2->p[0], l1) < dist)
-	{
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&l2->p[0]),
-													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
-													LsegPGetDatum(l2)));
-	}
+	if (lseg_closept_point(&point, l2, &l1->p[0]) < dist)
+		d = lseg_closept_point(result, l1, &point);
 
-	if (dist_ps_internal(&l2->p[1], l1) < dist)
-	{
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&l2->p[1]),
-													LsegPGetDatum(l1)));
-		memcpy(&point, result, sizeof(Point));
-		result = DatumGetPointP(DirectFunctionCall2(close_ps,
-													PointPGetDatum(&point),
-													LsegPGetDatum(l2)));
-	}
+	if (lseg_closept_point(&point, l2, &l1->p[1]) < dist)
+		d = lseg_closept_point(result, l1, &point);
 
-	if (result == NULL)
-		result = point_copy(&point);
+	if (d < dist)
+		dist = d;
+
+	return dist;
+}
+
+Datum
+close_lseg(PG_FUNCTION_ARGS)
+{
+	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
+	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
+	Point	   *result;
+
+	result = (Point *) palloc(sizeof(Point));
+
+	lseg_closept_lseg(result, l2, l1);
 
 	PG_RETURN_POINT_P(result);
 }
 
-/* close_pb()
+
+/*
  * Closest point on or in box to specified point.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
-Datum
-close_pb(PG_FUNCTION_ARGS)
+static float8
+box_closept_point(Point *result, BOX *box, Point *pt)
 {
-	Point	   *pt = PG_GETARG_POINT_P(0);
-	BOX		   *box = PG_GETARG_BOX_P(1);
-	LSEG		lseg,
-				seg;
-	Point		point;
+	LSEG		lseg;
+	Point		point,
+				closept;
 	double		dist,
 				d;
 
-	if (DatumGetBool(DirectFunctionCall2(on_pb,
-										 PointPGetDatum(pt),
-										 BoxPGetDatum(box))))
-		PG_RETURN_POINT_P(pt);
+	if (box_contain_point(box, pt))
+	{
+		if (result != NULL)
+			*result = *pt;
+
+		return 0.0;
+	}
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&lseg, &box->low, &point);
-	dist = dist_ps_internal(pt, &lseg);
+	dist = lseg_closept_point(result, &lseg, pt);
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	statlseg_construct(&lseg, &box->high, &point);
+	d = lseg_closept_point(&closept, &lseg, pt);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&lseg, &seg, sizeof(lseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
-	statlseg_construct(&seg, &box->low, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	statlseg_construct(&lseg, &box->low, &point);
+	d = lseg_closept_point(&closept, &lseg, pt);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&lseg, &seg, sizeof(lseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = dist_ps_internal(pt, &seg)) < dist)
+	statlseg_construct(&lseg, &box->high, &point);
+	d = lseg_closept_point(&closept, &lseg, pt);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&lseg, &seg, sizeof(lseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
-										PointPGetDatum(pt),
-										LsegPGetDatum(&lseg)));
+	return dist;
 }
 
+Datum
+close_pb(PG_FUNCTION_ARGS)
+{
+	Point	   *pt = PG_GETARG_POINT_P(0);
+	BOX		   *box = PG_GETARG_BOX_P(1);
+	Point	   *result;
+
+	result = (Point *) palloc(sizeof(Point));
+
+	box_closept_point(result, box, pt);
+
+	PG_RETURN_POINT_P(result);
+}
+
+
 /* close_sl()
  * Closest point on line to line segment.
  *
@@ -2995,16 +2748,17 @@ close_sl(PG_FUNCTION_ARGS)
 	float8		d1,
 				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
+	result = (Point *) palloc(sizeof(Point));
+
+	if (lseg_interpt_line(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
-	d1 = dist_pl_internal(&lseg->p[0], line);
-	d2 = dist_pl_internal(&lseg->p[1], line);
+	d1 = line_closept_point(NULL, line, &lseg->p[0]);
+	d2 = line_closept_point(NULL, line, &lseg->p[1]);
 	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
+		*result = lseg->p[0];
 	else
-		result = point_copy(&lseg->p[1]);
+		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
@@ -3016,93 +2770,133 @@ close_sl(PG_FUNCTION_ARGS)
 	PG_RETURN_NULL();
 }
 
-/* close_ls()
+/*
  * Closest point on line segment to line.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
+ *
+ * NOTE: When the lines are parallel, endpoints of one of the line segment
+ * are FPeq(), in presence of NaN or Infinitive coordinates, or perhaps =
+ * even because of simple roundoff issues, there may not be a single closest
+ * point.  We are likely to set the result to the second endpoint in these
+ * cases.
  */
+static float8
+lseg_closept_line(Point *result, LSEG *lseg, LINE *line)
+{
+	float8		dist1,
+				dist2;
+
+	if (lseg_interpt_line(result, lseg, line))
+		return 0.0;
+
+	dist1 = line_closept_point(NULL, line, &lseg->p[0]);
+	dist2 = line_closept_point(NULL, line, &lseg->p[1]);
+
+	if (dist1 < dist2)
+	{
+		if (result != NULL)
+			*result = lseg->p[0];
+
+		return dist1;
+	}
+	else
+	{
+		if (result != NULL)
+			*result = lseg->p[1];
+
+		return dist2;
+	}
+}
+
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
-	float8		d1,
-				d2;
 
-	result = interpt_sl(lseg, line);
-	if (result)
-		PG_RETURN_POINT_P(result);
+	result = (Point *) palloc(sizeof(Point));
 
-	d1 = dist_pl_internal(&lseg->p[0], line);
-	d2 = dist_pl_internal(&lseg->p[1], line);
-	if (d1 < d2)
-		result = point_copy(&lseg->p[0]);
-	else
-		result = point_copy(&lseg->p[1]);
+	lseg_closept_line(result, lseg, line);
 
 	PG_RETURN_POINT_P(result);
 }
 
-/* close_sb()
+
+/*
  * Closest point on or in box to line segment.
+ *
+ * This sets the closest point to the *result if it is not NULL and returns
+ * the distance to the closest point.
  */
-Datum
-close_sb(PG_FUNCTION_ARGS)
+static float8
+box_closept_lseg(Point *result, BOX *box, LSEG *lseg)
 {
-	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
-	BOX		   *box = PG_GETARG_BOX_P(1);
-	Point		point;
-	LSEG		bseg,
-				seg;
+	Point		point,
+				closept;
+	LSEG		bseg;
 	double		dist,
 				d;
 
-	/* segment intersects box? then just return closest point to center */
-	if (DatumGetBool(DirectFunctionCall2(inter_sb,
-										 LsegPGetDatum(lseg),
-										 BoxPGetDatum(box))))
-	{
-		box_cn(&point, box);
-		PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
-											PointPGetDatum(&point),
-											LsegPGetDatum(lseg)));
-	}
+	if (box_interpt_lseg(result, box, lseg))
+		return 0.0;
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	dist = lseg_dt(lseg, &bseg);
+	dist = lseg_closept_lseg(result, &bseg, lseg);
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	statlseg_construct(&bseg, &box->high, &point);
+	d = lseg_closept_lseg(&closept, &bseg, lseg);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&bseg, &seg, sizeof(bseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
-	statlseg_construct(&seg, &box->low, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	statlseg_construct(&bseg, &box->low, &point);
+	d = lseg_closept_lseg(&closept, &bseg, lseg);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&bseg, &seg, sizeof(bseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	statlseg_construct(&seg, &box->high, &point);
-	if ((d = lseg_dt(lseg, &seg)) < dist)
+	statlseg_construct(&bseg, &box->high, &point);
+	d = lseg_closept_lseg(&closept, &bseg, lseg);
+	if (d < dist)
 	{
 		dist = d;
-		memcpy(&bseg, &seg, sizeof(bseg));
+		if (result != NULL)
+			*result = closept;
 	}
 
-	/* OK, we now have the closest line segment on the box boundary */
-	PG_RETURN_DATUM(DirectFunctionCall2(close_lseg,
-										LsegPGetDatum(lseg),
-										LsegPGetDatum(&bseg)));
+	return dist;
 }
 
 Datum
+close_sb(PG_FUNCTION_ARGS)
+{
+	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
+	BOX		   *box = PG_GETARG_BOX_P(1);
+	Point	   *result;
+
+	result = (Point *) palloc(sizeof(Point));
+
+	box_closept_lseg(result, box, lseg);
+
+	PG_RETURN_POINT_P(result);
+}
+
+
+Datum
 close_lb(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
@@ -3123,37 +2917,55 @@ close_lb(PG_FUNCTION_ARGS)
  *				Whether one object lies completely within another.
  *-------------------------------------------------------------------*/
 
-/* on_pl -
+/*
  *		Does the point satisfy the equation?
  */
+static bool
+line_contain_point(LINE *line, Point *point)
+{
+	return FPzero(line->A * point->x + line->B * point->y + line->C);
+}
+
 Datum
 on_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(FPzero(line->A * pt->x + line->B * pt->y + line->C));
+	PG_RETURN_BOOL(line_contain_point(line, pt));
 }
 
 
-/* on_ps -
+/*
  *		Determine colinearity by detecting a triangle inequality.
  * This algorithm seems to behave nicely even with lsb residues - tgl 1997-07-09
  */
+static bool
+lseg_contain_point(LSEG *lseg, Point *pt)
+{
+	return FPeq(point_dt(pt, &lseg->p[0]) +
+				point_dt(pt, &lseg->p[1]),
+				point_dt(&lseg->p[0], &lseg->p[1]));
+}
+
 Datum
 on_ps(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(on_ps_internal(pt, lseg));
+	PG_RETURN_BOOL(lseg_contain_point(lseg, pt));
 }
 
+
+/*
+ * Check whether the point is in the box or on its border
+ */
 static bool
-on_ps_internal(Point *pt, LSEG *lseg)
+box_contain_point(BOX *box, Point *point)
 {
-	return FPeq(point_dt(pt, &lseg->p[0]) + point_dt(pt, &lseg->p[1]),
-				point_dt(&lseg->p[0], &lseg->p[1]));
+	return box->high.x >= point->x && box->low.x <= point->x &&
+		   box->high.y >= point->y && box->low.y <= point-> y;
 }
 
 Datum
@@ -3162,8 +2974,7 @@ on_pb(PG_FUNCTION_ARGS)
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_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);
+	PG_RETURN_BOOL(box_contain_point(box, pt));
 }
 
 Datum
@@ -3172,8 +2983,7 @@ 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);
+	PG_RETURN_BOOL(box_contain_point(box, pt));
 }
 
 /* on_ppath -
@@ -3217,18 +3027,33 @@ on_ppath(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
 }
 
+
+/*
+ * Check whether the line segment is on the line or close enough
+ *
+ * It is, if both of its points are on the line or close enough.
+ */
 Datum
 on_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(DatumGetBool(DirectFunctionCall2(on_pl,
-													PointPGetDatum(&lseg->p[0]),
-													LinePGetDatum(line))) &&
-				   DatumGetBool(DirectFunctionCall2(on_pl,
-													PointPGetDatum(&lseg->p[1]),
-													LinePGetDatum(line))));
+	PG_RETURN_BOOL(line_contain_point(line, &lseg->p[0]) &&
+				   line_contain_point(line, &lseg->p[1]));
+}
+
+
+/*
+ * Check whether the line segment is in the box or on its border
+ *
+ * It is, if both of its points are in the box or on its border.
+ */
+static bool
+box_contain_lseg(BOX *box, LSEG *lseg)
+{
+	return box_contain_point(box, &lseg->p[0]) &&
+		   box_contain_point(box, &lseg->p[1]);
 }
 
 Datum
@@ -3237,12 +3062,7 @@ on_sb(PG_FUNCTION_ARGS)
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 
-	PG_RETURN_BOOL(DatumGetBool(DirectFunctionCall2(on_pb,
-													PointPGetDatum(&lseg->p[0]),
-													BoxPGetDatum(box))) &&
-				   DatumGetBool(DirectFunctionCall2(on_pb,
-													PointPGetDatum(&lseg->p[1]),
-													BoxPGetDatum(box))));
+	PG_RETURN_BOOL(box_contain_lseg(box, lseg));
 }
 
 /*---------------------------------------------------------------------
@@ -3256,24 +3076,28 @@ inter_sl(PG_FUNCTION_ARGS)
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
-	PG_RETURN_BOOL(has_interpt_sl(lseg, line));
+	PG_RETURN_BOOL(lseg_interpt_line(NULL, lseg, line));
 }
 
-/* inter_sb()
+
+/*
  * Do line segment and box intersect?
  *
  * Segment completely inside box counts as intersection.
  * If you want only segments crossing box boundaries,
  *	try converting box to path first.
  *
+ * This function also sets the *result to the closest point on the line
+ * segment to the center of the box when they overlap and the result is
+ * not NULL.  It is somewhat arbitrary, but maybe the best we can do as
+ * there are typically two points they intersect.
+ *
  * Optimize for non-intersection by checking for box intersection first.
  * - thomas 1998-01-30
  */
-Datum
-inter_sb(PG_FUNCTION_ARGS)
+static bool
+box_interpt_lseg(Point *result, BOX *box, LSEG *lseg)
 {
-	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
-	BOX		   *box = PG_GETARG_BOX_P(1);
 	BOX			lbox;
 	LSEG		bseg;
 	Point		point;
@@ -3285,42 +3109,54 @@ inter_sb(PG_FUNCTION_ARGS)
 
 	/* nothing close to overlap? then not going to intersect */
 	if (!box_ov(&lbox, box))
-		PG_RETURN_BOOL(false);
+		return false;
+
+	if (result != NULL)
+	{
+		box_cn(&point, box);
+		lseg_closept_point(result, lseg, &point);
+	}
 
 	/* an endpoint of segment is inside box? then clearly intersects */
-	if (DatumGetBool(DirectFunctionCall2(on_pb,
-										 PointPGetDatum(&lseg->p[0]),
-										 BoxPGetDatum(box))) ||
-		DatumGetBool(DirectFunctionCall2(on_pb,
-										 PointPGetDatum(&lseg->p[1]),
-										 BoxPGetDatum(box))))
-		PG_RETURN_BOOL(true);
+	if (box_contain_point(box, &lseg->p[0]) ||
+		box_contain_point(box, &lseg->p[1]))
+		return true;
 
 	/* pairwise check lseg intersections */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&bseg, &box->low, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	statlseg_construct(&bseg, &box->high, &point);
-	if (lseg_intersect_internal(&bseg, lseg))
-		PG_RETURN_BOOL(true);
+	if (lseg_interpt_lseg(NULL, &bseg, lseg))
+		return true;
 
 	/* if we dropped through, no two segs intersected */
-	PG_RETURN_BOOL(false);
+	return false;
 }
 
+Datum
+inter_sb(PG_FUNCTION_ARGS)
+{
+	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
+	BOX		   *box = PG_GETARG_BOX_P(1);
+
+	PG_RETURN_BOOL(box_interpt_lseg(NULL, box, lseg));
+}
+
+
 /* inter_lb()
  * Do line and box intersect?
  */
@@ -3339,22 +3175,22 @@ inter_lb(PG_FUNCTION_ARGS)
 	p2.x = box->low.x;
 	p2.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->high.x;
 	p1.y = box->high.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p2.x = box->high.x;
 	p2.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 	p1.x = box->low.x;
 	p1.y = box->low.y;
 	statlseg_construct(&bseg, &p1, &p2);
-	if (has_interpt_sl(&bseg, line))
+	if (lseg_interpt_line(NULL, &bseg, line))
 		PG_RETURN_BOOL(true);
 
 	/* if we dropped through, no intersection */
@@ -3381,28 +3217,26 @@ make_bound_box(POLYGON *poly)
 				x2,
 				y2;
 
-	if (poly->npts > 0)
-	{
-		x2 = x1 = poly->p[0].x;
-		y2 = y1 = poly->p[0].y;
-		for (i = 1; i < poly->npts; i++)
-		{
-			if (poly->p[i].x < x1)
-				x1 = poly->p[i].x;
-			if (poly->p[i].x > x2)
-				x2 = poly->p[i].x;
-			if (poly->p[i].y < y1)
-				y1 = poly->p[i].y;
-			if (poly->p[i].y > y2)
-				y2 = poly->p[i].y;
-		}
+	Assert(poly->npts > 0);
 
-		box_fill(&(poly->boundbox), x1, x2, y1, y2);
+	x1 = x2 = poly->p[0].x;
+	y2 = y1 = poly->p[0].y;
+	for (i = 1; i < poly->npts; i++)
+	{
+		if (poly->p[i].x < x1)
+			x1 = poly->p[i].x;
+		if (poly->p[i].x > x2)
+			x2 = poly->p[i].x;
+		if (poly->p[i].y < y1)
+			y1 = poly->p[i].y;
+		if (poly->p[i].y > y2)
+			y2 = poly->p[i].y;
 	}
-	else
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot create bounding box for empty polygon")));
+
+	poly->boundbox.low.x = x1;
+	poly->boundbox.high.x = x2;
+	poly->boundbox.low.y = y1;
+	poly->boundbox.high.y = y2;
 }
 
 /*------------------------------------------------------------------
@@ -3746,9 +3580,10 @@ poly_overlap(PG_FUNCTION_ARGS)
 	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
 	bool		result;
 
+	Assert(polya->npts > 0 && polyb->npts > 0);
+
 	/* Quick check by bounding box */
-	result = (polya->npts > 0 && polyb->npts > 0 &&
-			  box_ov(&polya->boundbox, &polyb->boundbox)) ? true : false;
+	result = box_ov(&polya->boundbox, &polyb->boundbox);
 
 	/*
 	 * Brute-force algorithm - try to find intersected edges, if so then
@@ -3766,7 +3601,7 @@ poly_overlap(PG_FUNCTION_ARGS)
 		sa.p[0] = polya->p[polya->npts - 1];
 		result = false;
 
-		for (ia = 0; ia < polya->npts && result == false; ia++)
+		for (ia = 0; ia < polya->npts && !result; ia++)
 		{
 			/* Second point of polya's edge is a current one */
 			sa.p[1] = polya->p[ia];
@@ -3774,10 +3609,10 @@ poly_overlap(PG_FUNCTION_ARGS)
 			/* Init first of polyb's edge with last point */
 			sb.p[0] = polyb->p[polyb->npts - 1];
 
-			for (ib = 0; ib < polyb->npts && result == false; ib++)
+			for (ib = 0; ib < polyb->npts && !result; ib++)
 			{
 				sb.p[1] = polyb->p[ib];
-				result = lseg_intersect_internal(&sa, &sb);
+				result = lseg_interpt_lseg(NULL, &sa, &sb);
 				sb.p[0] = sb.p[1];
 			}
 
@@ -3787,10 +3622,9 @@ poly_overlap(PG_FUNCTION_ARGS)
 			sa.p[0] = sa.p[1];
 		}
 
-		if (result == false)
+		if (!result)
 		{
-			result = (point_inside(polya->p, polyb->npts, polyb->p)
-					  ||
+			result = (point_inside(polya->p, polyb->npts, polyb->p) ||
 					  point_inside(polyb->p, polya->npts, polya->p));
 		}
 	}
@@ -3824,22 +3658,21 @@ touched_lseg_inside_poly(Point *a, Point *b, LSEG *s, POLYGON *poly, int start)
 	t.p[0] = *a;
 	t.p[1] = *b;
 
-#define POINTEQ(pt1, pt2)	(FPeq((pt1)->x, (pt2)->x) && FPeq((pt1)->y, (pt2)->y))
-	if (POINTEQ(a, s->p))
+	if (point_eq_point(a, s->p))
 	{
-		if (on_ps_internal(s->p + 1, &t))
+		if (lseg_contain_point(&t, s->p + 1))
 			return lseg_inside_poly(b, s->p + 1, poly, start);
 	}
-	else if (POINTEQ(a, s->p + 1))
+	else if (point_eq_point(a, s->p + 1))
 	{
-		if (on_ps_internal(s->p, &t))
+		if (lseg_contain_point(&t, s->p))
 			return lseg_inside_poly(b, s->p, poly, start);
 	}
-	else if (on_ps_internal(s->p, &t))
+	else if (lseg_contain_point(&t, s->p))
 	{
 		return lseg_inside_poly(b, s->p, poly, start);
 	}
-	else if (on_ps_internal(s->p + 1, &t))
+	else if (lseg_contain_point(&t, s->p + 1))
 	{
 		return lseg_inside_poly(b, s->p + 1, poly, start);
 	}
@@ -3867,36 +3700,35 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 
 	for (i = start; i < poly->npts && res; i++)
 	{
-		Point	   *interpt;
+		Point		interpt;
 
 		CHECK_FOR_INTERRUPTS();
 
 		s.p[1] = poly->p[i];
 
-		if (on_ps_internal(t.p, &s))
+		if (lseg_contain_point(&s, t.p))
 		{
-			if (on_ps_internal(t.p + 1, &s))
+			if (lseg_contain_point(&s, t.p + 1))
 				return true;	/* t is contained by s */
 
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p, t.p + 1, &s, poly, i + 1);
 		}
-		else if (on_ps_internal(t.p + 1, &s))
+		else if (lseg_contain_point(&s, t.p + 1))
 		{
 			/* Y-cross */
 			res = touched_lseg_inside_poly(t.p + 1, t.p, &s, poly, i + 1);
 		}
-		else if ((interpt = lseg_interpt_internal(&t, &s)) != NULL)
+		else if (lseg_interpt_lseg(&interpt, &t, &s))
 		{
 			/*
 			 * segments are X-crossing, go to check each subsegment
 			 */
 
 			intersection = true;
-			res = lseg_inside_poly(t.p, interpt, poly, i + 1);
+			res = lseg_inside_poly(t.p, &interpt, poly, i + 1);
 			if (res)
-				res = lseg_inside_poly(t.p + 1, interpt, poly, i + 1);
-			pfree(interpt);
+				res = lseg_inside_poly(t.p + 1, &interpt, poly, i + 1);
 		}
 
 		s.p[0] = s.p[1];
@@ -3922,39 +3754,42 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 /*-----------------------------------------------------------------
  * Determine if polygon A contains polygon B.
  *-----------------------------------------------------------------*/
-Datum
-poly_contain(PG_FUNCTION_ARGS)
+static bool
+poly_contain_poly(POLYGON *polya, POLYGON *polyb)
 {
-	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
-	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
-	bool		result;
+	int			i;
+	LSEG		s;
+
+	Assert(polya->npts > 0 && polyb->npts > 0);
 
 	/*
 	 * Quick check to see if bounding box is contained.
 	 */
-	if (polya->npts > 0 && polyb->npts > 0 &&
-		DatumGetBool(DirectFunctionCall2(box_contain,
-										 BoxPGetDatum(&polya->boundbox),
-										 BoxPGetDatum(&polyb->boundbox))))
-	{
-		int			i;
-		LSEG		s;
+	if (!box_contain_box(&polya->boundbox, &polyb->boundbox))
+		return false;
 
-		s.p[0] = polyb->p[polyb->npts - 1];
-		result = true;
+	s.p[0] = polyb->p[polyb->npts - 1];
 
-		for (i = 0; i < polyb->npts && result; i++)
-		{
-			s.p[1] = polyb->p[i];
-			result = lseg_inside_poly(s.p, s.p + 1, polya, 0);
-			s.p[0] = s.p[1];
-		}
-	}
-	else
+	for (i = 0; i < polyb->npts; i++)
 	{
-		result = false;
+		s.p[1] = polyb->p[i];
+		if (!lseg_inside_poly(s.p, s.p + 1, polya, 0))
+			return false;
+		s.p[0] = s.p[1];
 	}
 
+	return true;
+}
+
+Datum
+poly_contain(PG_FUNCTION_ARGS)
+{
+	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
+	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
+	bool		result;
+
+	result = poly_contain_poly(polya, polyb);
+
 	/*
 	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
 	 */
@@ -3971,11 +3806,20 @@ poly_contain(PG_FUNCTION_ARGS)
 Datum
 poly_contained(PG_FUNCTION_ARGS)
 {
-	Datum		polya = PG_GETARG_DATUM(0);
-	Datum		polyb = PG_GETARG_DATUM(1);
+	POLYGON    *polya = PG_GETARG_POLYGON_P(0);
+	POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
+	bool		result;
 
 	/* Just switch the arguments and pass it off to poly_contain */
-	PG_RETURN_DATUM(DirectFunctionCall2(poly_contain, polyb, polya));
+	result = poly_contain_poly(polyb, polya);
+
+	/*
+	 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
+	 */
+	PG_FREE_IF_COPY(polya, 0);
+	PG_FREE_IF_COPY(polyb, 1);
+
+	PG_RETURN_BOOL(result);
 }
 
 
@@ -4025,8 +3869,22 @@ construct_point(PG_FUNCTION_ARGS)
 {
 	float8		x = PG_GETARG_FLOAT8(0);
 	float8		y = PG_GETARG_FLOAT8(1);
+	Point	   *result;
+
+	result = (Point *) palloc(sizeof(Point));
+
+	point_construct(result, x, y);
 
-	PG_RETURN_POINT_P(point_construct(x, y));
+	PG_RETURN_POINT_P(result);
+}
+
+
+static inline void
+point_add_point(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x + pt2->x,
+					pt1->y + pt2->y);
 }
 
 Datum
@@ -4038,12 +3896,20 @@ point_add(PG_FUNCTION_ARGS)
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x + p2->x);
-	result->y = (p1->y + p2->y);
+	point_add_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+
+static inline void
+point_sub_point(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					pt1->x - pt2->x,
+					pt1->y - pt2->y);
+}
+
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
@@ -4053,12 +3919,20 @@ point_sub(PG_FUNCTION_ARGS)
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x - p2->x);
-	result->y = (p1->y - p2->y);
+	point_sub_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
+
+static inline void
+point_mul_point(Point *result, Point *pt1, Point *pt2)
+{
+	point_construct(result,
+					(pt1->x * pt2->x) - (pt1->y * pt2->y),
+					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+}
+
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
@@ -4068,31 +3942,39 @@ point_mul(PG_FUNCTION_ARGS)
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (p1->x * p2->x) - (p1->y * p2->y);
-	result->y = (p1->x * p2->y) + (p1->y * p2->x);
+	point_mul_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
-Datum
-point_div(PG_FUNCTION_ARGS)
+
+static inline void
+point_div_point(Point *result, Point *pt1, Point *pt2)
 {
-	Point	   *p1 = PG_GETARG_POINT_P(0);
-	Point	   *p2 = PG_GETARG_POINT_P(1);
-	Point	   *result;
 	double		div;
 
-	result = (Point *) palloc(sizeof(Point));
-
-	div = (p2->x * p2->x) + (p2->y * p2->y);
+	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
 
 	if (div == 0.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_DIVISION_BY_ZERO),
 				 errmsg("division by zero")));
 
-	result->x = ((p1->x * p2->x) + (p1->y * p2->y)) / div;
-	result->y = ((p2->x * p1->y) - (p2->y * p1->x)) / div;
+	point_construct(result,
+					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
+					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+}
+
+Datum
+point_div(PG_FUNCTION_ARGS)
+{
+	Point	   *p1 = PG_GETARG_POINT_P(0);
+	Point	   *p2 = PG_GETARG_POINT_P(1);
+	Point	   *result;
+
+	result = (Point *) palloc(sizeof(Point));
+
+	point_div_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
@@ -4109,8 +3991,13 @@ points_box(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct(p1->x, p2->x, p1->y, p2->y));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	box_construct(result, p1, p2);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
@@ -4118,11 +4005,14 @@ box_add(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
+
+	result = (BOX *) palloc(sizeof(BOX));
 
-	PG_RETURN_BOX_P(box_construct((box->high.x + p->x),
-								  (box->low.x + p->x),
-								  (box->high.y + p->y),
-								  (box->low.y + p->y)));
+	point_add_point(&result->high, &box->high, p);
+	point_add_point(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
@@ -4130,11 +4020,14 @@ box_sub(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
+	BOX		   *result;
 
-	PG_RETURN_BOX_P(box_construct((box->high.x - p->x),
-								  (box->low.x - p->x),
-								  (box->high.y - p->y),
-								  (box->low.y - p->y)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_sub_point(&result->high, &box->high, p);
+	point_sub_point(&result->low, &box->low, p);
+
+	PG_RETURN_BOX_P(result);
 }
 
 Datum
@@ -4143,17 +4036,15 @@ box_mul(PG_FUNCTION_ARGS)
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
 
-	high = DatumGetPointP(DirectFunctionCall2(point_mul,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_mul,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	result = (BOX *) palloc(sizeof(BOX));
+
+	point_mul_point(&high, &box->high, p);
+	point_mul_point(&low, &box->low, p);
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	box_construct(result, &high, &low);
 
 	PG_RETURN_BOX_P(result);
 }
@@ -4164,17 +4055,15 @@ box_div(PG_FUNCTION_ARGS)
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *p = PG_GETARG_POINT_P(1);
 	BOX		   *result;
-	Point	   *high,
-			   *low;
+	Point		high,
+				low;
+
+	result = (BOX *) palloc(sizeof(BOX));
 
-	high = DatumGetPointP(DirectFunctionCall2(point_div,
-											  PointPGetDatum(&box->high),
-											  PointPGetDatum(p)));
-	low = DatumGetPointP(DirectFunctionCall2(point_div,
-											 PointPGetDatum(&box->low),
-											 PointPGetDatum(p)));
+	point_div_point(&high, &box->high, p);
+	point_div_point(&low, &box->low, p);
 
-	result = box_construct(high->x, low->x, high->y, low->y);
+	box_construct(result, &high, &low);
 
 	PG_RETURN_BOX_P(result);
 }
@@ -4284,10 +4173,7 @@ path_add_pt(PG_FUNCTION_ARGS)
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x += point->x;
-		path->p[i].y += point->y;
-	}
+		point_add_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
@@ -4300,10 +4186,7 @@ path_sub_pt(PG_FUNCTION_ARGS)
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		path->p[i].x -= point->x;
-		path->p[i].y -= point->y;
-	}
+		point_sub_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
@@ -4316,17 +4199,10 @@ path_mul_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_mul,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_mul_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
@@ -4336,17 +4212,10 @@ path_div_pt(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P_COPY(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	Point	   *p;
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-	{
-		p = DatumGetPointP(DirectFunctionCall2(point_div,
-											   PointPGetDatum(&path->p[i]),
-											   PointPGetDatum(point)));
-		path->p[i].x = p->x;
-		path->p[i].y = p->y;
-	}
+		point_div_point(&path->p[i], &path->p[i], point);
 
 	PG_RETURN_PATH_P(path);
 }
@@ -4421,15 +4290,15 @@ Datum
 poly_center(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
-	Datum		result;
-	CIRCLE	   *circle;
+	Point	   *result;
+	CIRCLE		circle;
+
+	result = (Point *) palloc(sizeof(Point));
 
-	circle = DatumGetCircleP(DirectFunctionCall1(poly_circle,
-												 PolygonPGetDatum(poly)));
-	result = DirectFunctionCall1(circle_center,
-								 CirclePGetDatum(circle));
+	poly_to_circle(&circle, poly);
+	*result = circle.center;
 
-	PG_RETURN_DATUM(result);
+	PG_RETURN_POINT_P(result);
 }
 
 
@@ -4439,10 +4308,8 @@ poly_box(PG_FUNCTION_ARGS)
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	BOX		   *box;
 
-	if (poly->npts < 1)
-		PG_RETURN_NULL();
-
-	box = box_copy(&poly->boundbox);
+	box = (BOX *) palloc(sizeof(BOX));
+	*box = poly->boundbox;
 
 	PG_RETURN_BOX_P(box);
 }
@@ -4474,8 +4341,7 @@ box_poly(PG_FUNCTION_ARGS)
 	poly->p[3].x = box->high.x;
 	poly->p[3].y = box->low.y;
 
-	box_fill(&poly->boundbox, box->high.x, box->low.x,
-			 box->high.y, box->low.y);
+	box_construct(&poly->boundbox, &box->high, &box->low);
 
 	PG_RETURN_POLYGON_P(poly);
 }
@@ -4564,8 +4430,7 @@ circle_in(PG_FUNCTION_ARGS)
 
 	while (depth > 0)
 	{
-		if ((*s == RDELIM)
-			|| ((*s == RDELIM_C) && (depth == 1)))
+		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
 			s++;
@@ -4663,8 +4528,7 @@ circle_same(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPeq(circle1->radius, circle2->radius) &&
-				   FPeq(circle1->center.x, circle2->center.x) &&
-				   FPeq(circle1->center.y, circle2->center.y));
+				   point_eq_point(&circle1->center, &circle2->center));
 }
 
 /*		circle_overlap	-		does circle1 overlap circle2?
@@ -4737,7 +4601,8 @@ circle_contained(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle1->radius), circle2->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						circle2->radius - circle1->radius));
 }
 
 /*		circle_contain	-		does circle1 contain circle2?
@@ -4748,7 +4613,8 @@ circle_contain(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle2->radius), circle1->radius));
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+						circle1->radius - circle2->radius));
 }
 
 
@@ -4865,20 +4731,6 @@ circle_ge(PG_FUNCTION_ARGS)
  *	"Arithmetic" operators on circles.
  *---------------------------------------------------------*/
 
-static CIRCLE *
-circle_copy(CIRCLE *circle)
-{
-	CIRCLE	   *result;
-
-	if (!PointerIsValid(circle))
-		return NULL;
-
-	result = (CIRCLE *) palloc(sizeof(CIRCLE));
-	memcpy((char *) result, (char *) circle, sizeof(CIRCLE));
-	return result;
-}
-
-
 /* circle_add_pt()
  * Translation operator.
  */
@@ -4889,10 +4741,10 @@ circle_add_pt(PG_FUNCTION_ARGS)
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x += point->x;
-	result->center.y += point->y;
+	point_add_point(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
@@ -4904,10 +4756,10 @@ circle_sub_pt(PG_FUNCTION_ARGS)
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	result->center.x -= point->x;
-	result->center.y -= point->y;
+	point_sub_point(&result->center, &circle->center, point);
+	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
@@ -4922,16 +4774,11 @@ circle_mul_pt(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_mul,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
-	result->radius *= HYPOT(point->x, point->y);
+	point_mul_point(&result->center, &circle->center, point);
+	result->radius = circle->radius * HYPOT(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
@@ -4942,16 +4789,11 @@ circle_div_pt(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
-	Point	   *p;
 
-	result = circle_copy(circle);
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	p = DatumGetPointP(DirectFunctionCall2(point_div,
-										   PointPGetDatum(&circle->center),
-										   PointPGetDatum(point)));
-	result->center.x = p->x;
-	result->center.y = p->y;
-	result->radius /= HYPOT(point->x, point->y);
+	point_div_point(&result->center, &circle->center, point);
+	result->radius = circle->radius / HYPOT(point->x, point->y);
 
 	PG_RETURN_CIRCLE_P(result);
 }
@@ -5000,8 +4842,8 @@ circle_distance(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(&circle1->center, &circle2->center)
-		- (circle1->radius + circle2->radius);
+	result = point_dt(&circle1->center, &circle2->center) -
+		(circle1->radius + circle2->radius);
 	if (result < 0)
 		result = 0;
 	PG_RETURN_FLOAT8(result);
@@ -5197,42 +5039,46 @@ circle_poly(PG_FUNCTION_ARGS)
 	PG_RETURN_POLYGON_P(poly);
 }
 
-/*		poly_circle		- convert polygon to circle
+/*
+ * Convert polygon to circle
+ *
+ * The result must be preallocated.
  *
  * XXX This algorithm should use weighted means of line segments
  *	rather than straight average values of points - tgl 97/01/21.
  */
-Datum
-poly_circle(PG_FUNCTION_ARGS)
+static void
+poly_to_circle(CIRCLE *result, POLYGON *poly)
 {
-	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
-	CIRCLE	   *circle;
 	int			i;
 
-	if (poly->npts < 1)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot convert empty polygon to circle")));
+	Assert(poly->npts > 0);
 
-	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
-
-	circle->center.x = 0;
-	circle->center.y = 0;
-	circle->radius = 0;
+	result->center.x = 0;
+	result->center.y = 0;
+	result->radius = 0;
 
 	for (i = 0; i < poly->npts; i++)
-	{
-		circle->center.x += poly->p[i].x;
-		circle->center.y += poly->p[i].y;
-	}
-	circle->center.x /= poly->npts;
-	circle->center.y /= poly->npts;
+		point_add_point(&result->center, &result->center, &poly->p[i]);
+	result->center.x /= poly->npts;
+	result->center.y /= poly->npts;
 
 	for (i = 0; i < poly->npts; i++)
-		circle->radius += point_dt(&poly->p[i], &circle->center);
-	circle->radius /= poly->npts;
+		result->radius += point_dt(&poly->p[i], &result->center);
+	result->radius /= poly->npts;
+}
 
-	PG_RETURN_CIRCLE_P(circle);
+Datum
+poly_circle(PG_FUNCTION_ARGS)
+{
+	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
+	CIRCLE	   *result;
+
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
+
+	poly_to_circle(result, poly);
+
+	PG_RETURN_CIRCLE_P(result);
 }
 
 
@@ -5268,8 +5114,7 @@ point_inside(Point *p, int npts, Point *plist)
 	int			cross,
 				total_cross = 0;
 
-	if (npts <= 0)
-		return 0;
+	Assert(npts > 0);
 
 	/* compute first polygon point relative to single point */
 	x0 = plist[0].x - p->x;
@@ -5378,8 +5223,7 @@ plist_same(int npts, Point *p1, Point *p2)
 	/* find match for first point */
 	for (i = 0; i < npts; i++)
 	{
-		if ((FPeq(p2[i].x, p1[0].x))
-			&& (FPeq(p2[i].y, p1[0].y)))
+		if (point_eq_point(&p2[i], &p1[0]))
 		{
 
 			/* match found? then look forward through remaining points */
@@ -5387,8 +5231,7 @@ plist_same(int npts, Point *p1, Point *p2)
 			{
 				if (j >= npts)
 					j = 0;
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_point(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed forward match with %d\n", j, ii);
@@ -5407,8 +5250,7 @@ plist_same(int npts, Point *p1, Point *p2)
 			{
 				if (j < 0)
 					j = (npts - 1);
-				if ((!FPeq(p2[j].x, p1[ii].x))
-					|| (!FPeq(p2[j].y, p1[ii].y)))
+				if (!point_eq_point(&p2[j], &p1[ii]))
 				{
 #ifdef GEODEBUG
 					printf("plist_same- %d failed reverse match with %d\n", j, ii);
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index 06411aea9e..d7c807f8d9 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -793,7 +793,8 @@ spg_poly_quad_compress(PG_FUNCTION_ARGS)
 	POLYGON    *polygon = PG_GETARG_POLYGON_P(0);
 	BOX		   *box;
 
-	box = box_copy(&polygon->boundbox);
+	box = (BOX *) palloc(sizeof(BOX));
+	*box = polygon->boundbox;
 
 	PG_RETURN_BOX_P(box);
 }
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index a589e4239f..0e066894cd 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -178,10 +178,6 @@ typedef struct
  * 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/regress.c b/src/test/regress/regress.c
index 6a0d5f45e8..a2e57768d4 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -176,8 +176,13 @@ pt_in_widget(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	WIDGET	   *widget = (WIDGET *) PG_GETARG_POINTER(1);
+	float8		distance;
 
-	PG_RETURN_BOOL(point_dt(point, &widget->center) < widget->radius);
+	distance = DatumGetFloat8(DirectFunctionCall2(point_distance,
+												  PointPGetDatum(point),
+											PointPGetDatum(&widget->center)));
+
+	PG_RETURN_BOOL(distance < widget->radius);
 }
 
 PG_FUNCTION_INFO_V1(reverse_name);
-- 
2.13.6

0002-Provide-header-file-for-built-in-float-datatypes.patchtext/x-patch; name=0002-Provide-header-file-for-built-in-float-datatypes.patchDownload
From cd5678df60bd2a290264a2c5e5b3f7f4201d00f0 Mon Sep 17 00:00:00 2001
From: Tomas Vondra <tomas@2ndquadrant.com>
Date: Thu, 26 Jul 2018 14:39:29 +0200
Subject: [PATCH 2/6] Provide header file for built-in float datatypes

Even though, some datatypes under adt/ have separate header files,
most of the simple ones do not.  Their public functions were on
the builtins.h.  We would need to make more functions of floats public
to let the geometric types built on top of them.  This is a good
opportunity to make a separate header file for floats.

1acf7572554515b99ef6e783750aaea8777524ec made _cmp functions public
to solve NaN problem locally for GiST indexes.  This patch reworks it
in favour of a more extensive API.  The API uses inline functions
instead of macros, as they are easier to use compared to macros,
and avoid double-evaluation hazards.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com
---
 contrib/btree_gin/btree_gin.c                 |   1 +
 contrib/btree_gist/btree_ts.c                 |   1 +
 contrib/cube/cube.c                           |   2 +-
 contrib/cube/cubeparse.y                      |   2 +-
 contrib/postgres_fdw/postgres_fdw.c           |   1 +
 src/backend/access/gist/gistget.c             |   2 +-
 src/backend/access/gist/gistproc.c            |  56 ++-
 src/backend/access/gist/gistutil.c            |   2 +-
 src/backend/utils/adt/float.c                 | 589 ++++++--------------------
 src/backend/utils/adt/formatting.c            |   1 +
 src/backend/utils/adt/geo_ops.c               |   7 +-
 src/backend/utils/adt/geo_spgist.c            |   3 +-
 src/backend/utils/adt/numeric.c               |   1 +
 src/backend/utils/adt/rangetypes_gist.c       |   3 +-
 src/backend/utils/adt/rangetypes_selfuncs.c   |   3 +-
 src/backend/utils/adt/rangetypes_typanalyze.c |   3 +-
 src/backend/utils/adt/timestamp.c             |   1 +
 src/backend/utils/misc/guc.c                  |   1 +
 src/include/utils/builtins.h                  |  14 -
 src/include/utils/float.h                     | 376 ++++++++++++++++
 20 files changed, 556 insertions(+), 513 deletions(-)
 create mode 100644 src/include/utils/float.h

diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index b6d22d2b00..2ecf7a2d87 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -10,6 +10,7 @@
 #include "utils/bytea.h"
 #include "utils/cash.h"
 #include "utils/date.h"
+#include "utils/float.h"
 #include "utils/inet.h"
 #include "utils/numeric.h"
 #include "utils/timestamp.h"
diff --git a/contrib/btree_gist/btree_ts.c b/contrib/btree_gist/btree_ts.c
index 18740cad38..49d1849d88 100644
--- a/contrib/btree_gist/btree_ts.c
+++ b/contrib/btree_gist/btree_ts.c
@@ -9,6 +9,7 @@
 #include "btree_utils_num.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 typedef struct
 {
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c
index f02ac24ea1..dfa8465d74 100644
--- a/contrib/cube/cube.c
+++ b/contrib/cube/cube.c
@@ -13,7 +13,7 @@
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 
 #include "cubedata.h"
 
diff --git a/contrib/cube/cubeparse.y b/contrib/cube/cubeparse.y
index 1b65fa967c..deb2efdc0d 100644
--- a/contrib/cube/cubeparse.y
+++ b/contrib/cube/cubeparse.y
@@ -7,7 +7,7 @@
 #include "postgres.h"
 
 #include "cubedata.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 
 /* All grammar constructs return strings */
 #define YYSTYPE char *
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 5699252091..0803c30a48 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -35,6 +35,7 @@
 #include "optimizer/tlist.h"
 #include "parser/parsetree.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c
index c4e8a3b913..ad07b9e63c 100644
--- a/src/backend/access/gist/gistget.c
+++ b/src/backend/access/gist/gistget.c
@@ -22,7 +22,7 @@
 #include "storage/predicate.h"
 #include "pgstat.h"
 #include "lib/pairingheap.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 
diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index 0536b318cc..d6ce5ccf6c 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -22,6 +22,7 @@
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/geo_decls.h"
 
 
@@ -33,15 +34,6 @@ static bool rtree_internal_consistent(BOX *key, BOX *query,
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
 
-/* Convenience macros for NaN-aware comparisons */
-#define FLOAT8_EQ(a,b)	(float8_cmp_internal(a, b) == 0)
-#define FLOAT8_LT(a,b)	(float8_cmp_internal(a, b) < 0)
-#define FLOAT8_LE(a,b)	(float8_cmp_internal(a, b) <= 0)
-#define FLOAT8_GT(a,b)	(float8_cmp_internal(a, b) > 0)
-#define FLOAT8_GE(a,b)	(float8_cmp_internal(a, b) >= 0)
-#define FLOAT8_MAX(a,b)  (FLOAT8_GT(a, b) ? (a) : (b))
-#define FLOAT8_MIN(a,b)  (FLOAT8_LT(a, b) ? (a) : (b))
-
 
 /**************************************************
  * Box ops
@@ -53,10 +45,10 @@ static bool rtree_internal_consistent(BOX *key, BOX *query,
 static void
 rt_box_union(BOX *n, const BOX *a, const BOX *b)
 {
-	n->high.x = FLOAT8_MAX(a->high.x, b->high.x);
-	n->high.y = FLOAT8_MAX(a->high.y, b->high.y);
-	n->low.x = FLOAT8_MIN(a->low.x, b->low.x);
-	n->low.y = FLOAT8_MIN(a->low.y, b->low.y);
+	n->high.x = float8_max(a->high.x, b->high.x);
+	n->high.y = float8_max(a->high.y, b->high.y);
+	n->low.x = float8_min(a->low.x, b->low.x);
+	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
@@ -73,8 +65,8 @@ size_box(const BOX *box)
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
-	if (FLOAT8_LE(box->high.x, box->low.x) ||
-		FLOAT8_LE(box->high.y, box->low.y))
+	if (float8_le(box->high.x, box->low.x) ||
+		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
@@ -143,13 +135,13 @@ gist_box_consistent(PG_FUNCTION_ARGS)
 static void
 adjustBox(BOX *b, const BOX *addon)
 {
-	if (FLOAT8_LT(b->high.x, addon->high.x))
+	if (float8_lt(b->high.x, addon->high.x))
 		b->high.x = addon->high.x;
-	if (FLOAT8_GT(b->low.x, addon->low.x))
+	if (float8_gt(b->low.x, addon->low.x))
 		b->low.x = addon->low.x;
-	if (FLOAT8_LT(b->high.y, addon->high.y))
+	if (float8_lt(b->high.y, addon->high.y))
 		b->high.y = addon->high.y;
-	if (FLOAT8_GT(b->low.y, addon->low.y))
+	if (float8_gt(b->low.y, addon->low.y))
 		b->low.y = addon->low.y;
 }
 
@@ -615,9 +607,9 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 			 * Find next lower bound of right group.
 			 */
 			while (i1 < nentries &&
-				   FLOAT8_EQ(rightLower, intervalsLower[i1].lower))
+				   float8_eq(rightLower, intervalsLower[i1].lower))
 			{
-				if (FLOAT8_LT(leftUpper, intervalsLower[i1].upper))
+				if (float8_lt(leftUpper, intervalsLower[i1].upper))
 					leftUpper = intervalsLower[i1].upper;
 				i1++;
 			}
@@ -630,7 +622,7 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 			 * left group.
 			 */
 			while (i2 < nentries &&
-				   FLOAT8_LE(intervalsUpper[i2].upper, leftUpper))
+				   float8_le(intervalsUpper[i2].upper, leftUpper))
 				i2++;
 
 			/*
@@ -652,9 +644,9 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 			/*
 			 * Find next upper bound of left group.
 			 */
-			while (i2 >= 0 && FLOAT8_EQ(leftUpper, intervalsUpper[i2].upper))
+			while (i2 >= 0 && float8_eq(leftUpper, intervalsUpper[i2].upper))
 			{
-				if (FLOAT8_GT(rightLower, intervalsUpper[i2].lower))
+				if (float8_gt(rightLower, intervalsUpper[i2].lower))
 					rightLower = intervalsUpper[i2].lower;
 				i2--;
 			}
@@ -666,7 +658,7 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 			 * Find count of intervals which anyway should be placed to the
 			 * right group.
 			 */
-			while (i1 >= 0 && FLOAT8_GE(intervalsLower[i1].lower, rightLower))
+			while (i1 >= 0 && float8_ge(intervalsLower[i1].lower, rightLower))
 				i1--;
 
 			/*
@@ -754,10 +746,10 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 			upper = box->high.y;
 		}
 
-		if (FLOAT8_LE(upper, context.leftUpper))
+		if (float8_le(upper, context.leftUpper))
 		{
 			/* Fits to the left group */
-			if (FLOAT8_GE(lower, context.rightLower))
+			if (float8_ge(lower, context.rightLower))
 			{
 				/* Fits also to the right group, so "common entry" */
 				commonEntries[commonEntriesCount++].index = i;
@@ -775,7 +767,7 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 			 * entry didn't fit on the left group, it better fit in the right
 			 * group.
 			 */
-			Assert(FLOAT8_GE(lower, context.rightLower));
+			Assert(float8_ge(lower, context.rightLower));
 
 			/* Doesn't fit to the left group, so join to the right group */
 			PLACE_RIGHT(box, i);
@@ -859,10 +851,10 @@ gist_box_same(PG_FUNCTION_ARGS)
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
 	if (b1 && b2)
-		*result = (FLOAT8_EQ(b1->low.x, b2->low.x) &&
-				   FLOAT8_EQ(b1->low.y, b2->low.y) &&
-				   FLOAT8_EQ(b1->high.x, b2->high.x) &&
-				   FLOAT8_EQ(b1->high.y, b2->high.y));
+		*result = (float8_eq(b1->low.x, b2->low.x) &&
+				   float8_eq(b1->low.y, b2->low.y) &&
+				   float8_eq(b1->high.x, b2->high.x) &&
+				   float8_eq(b1->high.y, b2->high.y));
 	else
 		*result = (b1 == NULL && b2 == NULL);
 	PG_RETURN_POINTER(result);
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 12804c321c..dddfe0ae2c 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -21,7 +21,7 @@
 #include "catalog/pg_opclass.h"
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/syscache.h"
 
 
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index b86205b098..df35557b73 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -23,44 +23,11 @@
 #include "common/int.h"
 #include "libpq/pqformat.h"
 #include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/sortsupport.h"
 
 
-#ifndef M_PI
-/* from my RH5.2 gcc math.h file - thomas 2000-04-03 */
-#define M_PI 3.14159265358979323846
-#endif
-
-/* Radians per degree, a.k.a. PI / 180 */
-#define RADIANS_PER_DEGREE 0.0174532925199432957692
-
-/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0.  NAN definition from
- * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfNotNumberNANItems.asp
- */
-#if defined(WIN32) && !defined(NAN)
-static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
-
-#define NAN (*(const double *) nan)
-#endif
-
-/*
- * check to see if a float4/8 val has underflowed or overflowed
- */
-#define CHECKFLOATVAL(val, inf_is_valid, zero_is_valid)			\
-do {															\
-	if (isinf(val) && !(inf_is_valid))							\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		  errmsg("value out of range: overflow")));				\
-																\
-	if ((val) == 0.0 && !(zero_is_valid))						\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		 errmsg("value out of range: underflow")));				\
-} while(0)
-
-
 /* Configurable GUC parameter */
 int			extra_float_digits = 0; /* Added to DBL_DIG or FLT_DIG */
 
@@ -106,86 +73,6 @@ static double cbrt(double x);
 
 
 /*
- * Routines to provide reasonably platform-independent handling of
- * infinity and NaN.  We assume that isinf() and isnan() are available
- * and work per spec.  (On some platforms, we have to supply our own;
- * see src/port.)  However, generating an Infinity or NaN in the first
- * place is less well standardized; pre-C99 systems tend not to have C99's
- * INFINITY and NAN macros.  We centralize our workarounds for this here.
- */
-
-double
-get_float8_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (double) INFINITY;
-#else
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (double) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-/*
-* The funny placements of the two #pragmas is necessary because of a
-* long lived bug in the Microsoft compilers.
-* See http://support.microsoft.com/kb/120968/en-us for details
-*/
-#if (_MSC_VER >= 1800)
-#pragma warning(disable:4756)
-#endif
-float
-get_float4_infinity(void)
-{
-#ifdef INFINITY
-	/* C99 standard way */
-	return (float) INFINITY;
-#else
-#if (_MSC_VER >= 1800)
-#pragma warning(default:4756)
-#endif
-
-	/*
-	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
-	 * largest normal double.  We assume forcing an overflow will get us a
-	 * true infinity.
-	 */
-	return (float) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-double
-get_float8_nan(void)
-{
-	/* (double) NAN doesn't work on some NetBSD/MIPS releases */
-#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
-	/* C99 standard way */
-	return (double) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (double) (0.0 / 0.0);
-#endif
-}
-
-float
-get_float4_nan(void)
-{
-#ifdef NAN
-	/* C99 standard way */
-	return (float) NAN;
-#else
-	/* Assume we can get a NAN via zero divide */
-	return (float) (0.0 / 0.0);
-#endif
-}
-
-
-/*
  * Returns -1 if 'val' represents negative infinity, 1 if 'val'
  * represents (positive) infinity, and 0 otherwise. On some platforms,
  * this is equivalent to the isinf() macro, but not everywhere: C99
@@ -343,7 +230,7 @@ float4in(PG_FUNCTION_ARGS)
 	 * if we get here, we have a legal double, still need to check to see if
 	 * it's a legal float4
 	 */
-	CHECKFLOATVAL((float4) val, isinf(val), val == 0);
+	check_float4_val((float4) val, isinf(val), val == 0);
 
 	PG_RETURN_FLOAT4((float4) val);
 }
@@ -693,7 +580,7 @@ float4larger(PG_FUNCTION_ARGS)
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) > 0)
+	if (float4_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
@@ -707,7 +594,7 @@ float4smaller(PG_FUNCTION_ARGS)
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) < 0)
+	if (float4_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
@@ -760,7 +647,7 @@ float8larger(PG_FUNCTION_ARGS)
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) > 0)
+	if (float8_gt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
@@ -774,7 +661,7 @@ float8smaller(PG_FUNCTION_ARGS)
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) < 0)
+	if (float8_lt(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
@@ -799,19 +686,8 @@ float4pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
-
-	result = arg1 + arg2;
 
-	/*
-	 * There isn't any way to check for underflow of addition/subtraction
-	 * because numbers near the underflow value have already been rounded to
-	 * the point where we can't detect that the two values were originally
-	 * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
-	 * 1.4013e-45.
-	 */
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_pl(arg1, arg2));
 }
 
 Datum
@@ -819,11 +695,8 @@ float4mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mi(arg1, arg2));
 }
 
 Datum
@@ -831,12 +704,8 @@ float4mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_mul(arg1, arg2));
 }
 
 Datum
@@ -844,17 +713,8 @@ float4div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float4		result;
-
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
 
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT4(result);
+	PG_RETURN_FLOAT4(float4_div(arg1, arg2));
 }
 
 /*
@@ -868,12 +728,8 @@ float8pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
-
-	result = arg1 + arg2;
 
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, arg2));
 }
 
 Datum
@@ -881,12 +737,8 @@ float8mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
-
-	result = arg1 - arg2;
 
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, arg2));
 }
 
 Datum
@@ -894,13 +746,8 @@ float8mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
-
-	result = arg1 * arg2;
 
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, arg2));
 }
 
 Datum
@@ -908,17 +755,8 @@ float8div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, arg2));
 }
 
 
@@ -934,31 +772,11 @@ float8div(PG_FUNCTION_ARGS)
 int
 float4_cmp_internal(float4 a, float4 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float4_gt(a, b))
+		return 1;
+	if (float4_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
@@ -967,7 +785,7 @@ float4eq(PG_FUNCTION_ARGS)
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float4_eq(arg1, arg2));
 }
 
 Datum
@@ -976,7 +794,7 @@ float4ne(PG_FUNCTION_ARGS)
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float4_ne(arg1, arg2));
 }
 
 Datum
@@ -985,7 +803,7 @@ float4lt(PG_FUNCTION_ARGS)
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float4_lt(arg1, arg2));
 }
 
 Datum
@@ -994,7 +812,7 @@ float4le(PG_FUNCTION_ARGS)
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float4_le(arg1, arg2));
 }
 
 Datum
@@ -1003,7 +821,7 @@ float4gt(PG_FUNCTION_ARGS)
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float4_gt(arg1, arg2));
 }
 
 Datum
@@ -1012,7 +830,7 @@ float4ge(PG_FUNCTION_ARGS)
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float4_ge(arg1, arg2));
 }
 
 Datum
@@ -1048,31 +866,11 @@ btfloat4sortsupport(PG_FUNCTION_ARGS)
 int
 float8_cmp_internal(float8 a, float8 b)
 {
-	/*
-	 * We consider all NANs to be equal and larger than any non-NAN. This is
-	 * somewhat arbitrary; the important thing is to have a consistent sort
-	 * order.
-	 */
-	if (isnan(a))
-	{
-		if (isnan(b))
-			return 0;			/* NAN = NAN */
-		else
-			return 1;			/* NAN > non-NAN */
-	}
-	else if (isnan(b))
-	{
-		return -1;				/* non-NAN < NAN */
-	}
-	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+	if (float8_gt(a, b))
+		return 1;
+	if (float8_lt(a, b))
+		return -1;
+	return 0;
 }
 
 Datum
@@ -1081,7 +879,7 @@ float8eq(PG_FUNCTION_ARGS)
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, arg2));
 }
 
 Datum
@@ -1090,7 +888,7 @@ float8ne(PG_FUNCTION_ARGS)
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, arg2));
 }
 
 Datum
@@ -1099,7 +897,7 @@ float8lt(PG_FUNCTION_ARGS)
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, arg2));
 }
 
 Datum
@@ -1108,7 +906,7 @@ float8le(PG_FUNCTION_ARGS)
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, arg2));
 }
 
 Datum
@@ -1117,7 +915,7 @@ float8gt(PG_FUNCTION_ARGS)
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, arg2));
 }
 
 Datum
@@ -1126,7 +924,7 @@ float8ge(PG_FUNCTION_ARGS)
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, arg2));
 }
 
 Datum
@@ -1341,7 +1139,7 @@ dtof(PG_FUNCTION_ARGS)
 {
 	float8		num = PG_GETARG_FLOAT8(0);
 
-	CHECKFLOATVAL((float4) num, isinf(num), num == 0);
+	check_float4_val((float4) num, isinf(num), num == 0);
 
 	PG_RETURN_FLOAT4((float4) num);
 }
@@ -1566,7 +1364,7 @@ dsqrt(PG_FUNCTION_ARGS)
 
 	result = sqrt(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -1581,7 +1379,7 @@ dcbrt(PG_FUNCTION_ARGS)
 	float8		result;
 
 	result = cbrt(arg1);
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+	check_float8_val(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -1653,7 +1451,7 @@ dpow(PG_FUNCTION_ARGS)
 	else if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
+	check_float8_val(result, isinf(arg1) || isinf(arg2), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -1672,7 +1470,7 @@ dexp(PG_FUNCTION_ARGS)
 	if (errno == ERANGE && result != 0 && !isinf(result))
 		result = get_float8_infinity();
 
-	CHECKFLOATVAL(result, isinf(arg1), false);
+	check_float8_val(result, isinf(arg1), false);
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -1701,7 +1499,7 @@ dlog1(PG_FUNCTION_ARGS)
 
 	result = log(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -1731,7 +1529,7 @@ dlog10(PG_FUNCTION_ARGS)
 
 	result = log10(arg1);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+	check_float8_val(result, isinf(arg1), arg1 == 1);
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -1761,7 +1559,7 @@ dacos(PG_FUNCTION_ARGS)
 
 	result = acos(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -1791,7 +1589,7 @@ dasin(PG_FUNCTION_ARGS)
 
 	result = asin(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -1816,7 +1614,7 @@ datan(PG_FUNCTION_ARGS)
 	 */
 	result = atan(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -1841,7 +1639,7 @@ datan2(PG_FUNCTION_ARGS)
 	 */
 	result = atan2(arg1, arg2);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -1881,7 +1679,7 @@ dcos(PG_FUNCTION_ARGS)
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -1908,7 +1706,7 @@ dcot(PG_FUNCTION_ARGS)
 				 errmsg("input is out of range")));
 
 	result = 1.0 / result;
-	CHECKFLOATVAL(result, true /* cot(0) == Inf */ , true);
+	check_float8_val(result, true /* cot(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -1934,7 +1732,7 @@ dsin(PG_FUNCTION_ARGS)
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -1960,7 +1758,7 @@ dtan(PG_FUNCTION_ARGS)
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 
-	CHECKFLOATVAL(result, true /* tan(pi/2) == Inf */ , true);
+	check_float8_val(result, true /* tan(pi/2) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -2112,7 +1910,7 @@ dacosd(PG_FUNCTION_ARGS)
 	else
 		result = 90.0 + asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -2147,7 +1945,7 @@ dasind(PG_FUNCTION_ARGS)
 	else
 		result = -asind_q1(-arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -2177,7 +1975,7 @@ datand(PG_FUNCTION_ARGS)
 	atan_arg1 = atan(arg1);
 	result = (atan_arg1 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -2211,7 +2009,7 @@ datan2d(PG_FUNCTION_ARGS)
 	atan2_arg1_arg2 = atan2(arg1, arg2);
 	result = (atan2_arg1_arg2 / atan_1_0) * 45.0;
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -2332,7 +2130,7 @@ dcosd(PG_FUNCTION_ARGS)
 
 	result = sign * cosd_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -2397,7 +2195,7 @@ dcotd(PG_FUNCTION_ARGS)
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* cotd(0) == Inf */ , true);
+	check_float8_val(result, true /* cotd(0) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -2451,7 +2249,7 @@ dsind(PG_FUNCTION_ARGS)
 
 	result = sign * sind_q1(arg1);
 
-	CHECKFLOATVAL(result, false, true);
+	check_float8_val(result, false, true);
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -2516,7 +2314,7 @@ dtand(PG_FUNCTION_ARGS)
 	if (result == 0.0)
 		result = 0.0;
 
-	CHECKFLOATVAL(result, true /* tand(90) == Inf */ , true);
+	check_float8_val(result, true /* tand(90) == Inf */ , true);
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -2528,12 +2326,8 @@ Datum
 degrees(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
-
-	result = arg1 / RADIANS_PER_DEGREE;
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, RADIANS_PER_DEGREE));
 }
 
 
@@ -2554,12 +2348,8 @@ Datum
 radians(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
-	float8		result;
 
-	result = arg1 * RADIANS_PER_DEGREE;
-
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, RADIANS_PER_DEGREE));
 }
 
 
@@ -2651,31 +2441,16 @@ float8_combine(PG_FUNCTION_ARGS)
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_combine", 3);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-
 	transvalues2 = check_float8_array(transarray2, "float8_combine", 3);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
@@ -2686,20 +2461,8 @@ float8_accum(PG_FUNCTION_ARGS)
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8		newval = PG_GETARG_FLOAT8(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float8_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
@@ -2708,9 +2471,9 @@ float8_accum(PG_FUNCTION_ARGS)
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
@@ -2719,9 +2482,9 @@ float8_accum(PG_FUNCTION_ARGS)
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
@@ -2739,20 +2502,8 @@ float4_accum(PG_FUNCTION_ARGS)
 	/* do computations as float8 */
 	float8		newval = PG_GETARG_FLOAT4(1);
 	float8	   *transvalues;
-	float8		N,
-				sumX,
-				sumX2;
 
 	transvalues = check_float8_array(transarray, "float4_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
@@ -2761,9 +2512,9 @@ float4_accum(PG_FUNCTION_ARGS)
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
-		transvalues[0] = N;
-		transvalues[1] = sumX;
-		transvalues[2] = sumX2;
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		PG_RETURN_ARRAYTYPE_P(transarray);
 	}
@@ -2772,9 +2523,9 @@ float4_accum(PG_FUNCTION_ARGS)
 		Datum		transdatums[3];
 		ArrayType  *result;
 
-		transdatums[0] = Float8GetDatumFast(N);
-		transdatums[1] = Float8GetDatumFast(sumX);
-		transdatums[2] = Float8GetDatumFast(sumX2);
+		transvalues[0] = transvalues[0] + 1.0;
+		transvalues[1] = float8_pl(transvalues[1], newval);
+		transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
 
 		result = construct_array(transdatums, 3,
 								 FLOAT8OID,
@@ -2824,7 +2575,7 @@ float8_var_pop(PG_FUNCTION_ARGS)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
@@ -2853,7 +2604,7 @@ float8_var_samp(PG_FUNCTION_ARGS)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
@@ -2882,7 +2633,7 @@ float8_stddev_pop(PG_FUNCTION_ARGS)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
@@ -2911,7 +2662,7 @@ float8_stddev_samp(PG_FUNCTION_ARGS)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
@@ -2960,16 +2711,16 @@ float8_regr_accum(PG_FUNCTION_ARGS)
 
 	N += 1.0;
 	sumX += newvalX;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
+	check_float8_val(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
 	sumX2 += newvalX * newvalX;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
+	check_float8_val(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
 	sumY += newvalY;
-	CHECKFLOATVAL(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
+	check_float8_val(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
 	sumY2 += newvalY * newvalY;
-	CHECKFLOATVAL(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
+	check_float8_val(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
 	sumXY += newvalX * newvalY;
-	CHECKFLOATVAL(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
-				  isinf(newvalY), true);
+	check_float8_val(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
+					 isinf(newvalY), true);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
@@ -3022,49 +2773,19 @@ float8_regr_combine(PG_FUNCTION_ARGS)
 	ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
 	float8	   *transvalues1;
 	float8	   *transvalues2;
-	float8		N,
-				sumX,
-				sumX2,
-				sumY,
-				sumY2,
-				sumXY;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_regr_combine", 6);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-	sumY = transvalues1[3];
-	sumY2 = transvalues1[4];
-	sumXY = transvalues1[5];
-
 	transvalues2 = check_float8_array(transarray2, "float8_regr_combine", 6);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-	sumY += transvalues2[3];
-	CHECKFLOATVAL(sumY, isinf(transvalues1[3]) || isinf(transvalues2[3]),
-				  true);
-	sumY2 += transvalues2[4];
-	CHECKFLOATVAL(sumY2, isinf(transvalues1[4]) || isinf(transvalues2[4]),
-				  true);
-	sumXY += transvalues2[5];
-	CHECKFLOATVAL(sumXY, isinf(transvalues1[5]) || isinf(transvalues2[5]),
-				  true);
-
-	transvalues1[0] = N;
-	transvalues1[1] = sumX;
-	transvalues1[2] = sumX2;
-	transvalues1[3] = sumY;
-	transvalues1[4] = sumY2;
-	transvalues1[5] = sumXY;
+	transvalues1[0] = transvalues1[0] + transvalues2[0];
+	transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+	transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
+	transvalues1[3] = float8_pl(transvalues1[3], transvalues2[3]);
+	transvalues1[4] = float8_pl(transvalues1[4], transvalues2[4]);
+	transvalues1[5] = float8_pl(transvalues1[5], transvalues2[5]);
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
@@ -3090,7 +2811,7 @@ float8_regr_sxx(PG_FUNCTION_ARGS)
 		PG_RETURN_NULL();
 
 	numerator = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
@@ -3119,7 +2840,7 @@ float8_regr_syy(PG_FUNCTION_ARGS)
 		PG_RETURN_NULL();
 
 	numerator = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumY2) || isinf(sumY), true);
 
 	/* Watch out for roundoff error producing a negative numerator */
 	if (numerator <= 0.0)
@@ -3150,8 +2871,8 @@ float8_regr_sxy(PG_FUNCTION_ARGS)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	/* A negative result is valid here */
 
@@ -3218,8 +2939,8 @@ float8_covar_pop(PG_FUNCTION_ARGS)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * N));
 }
@@ -3246,8 +2967,8 @@ float8_covar_samp(PG_FUNCTION_ARGS)
 		PG_RETURN_NULL();
 
 	numerator = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 
 	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
 }
@@ -3280,12 +3001,12 @@ float8_corr(PG_FUNCTION_ARGS)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0 || numeratorY <= 0)
 		PG_RETURN_NULL();
 
@@ -3320,12 +3041,12 @@ float8_regr_r2(PG_FUNCTION_ARGS)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorY = N * sumY2 - sumY * sumY;
-	CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+	check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 	/* per spec, horizontal line produces 1.0 */
@@ -3361,10 +3082,10 @@ float8_regr_slope(PG_FUNCTION_ARGS)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXY = N * sumXY - sumX * sumY;
-	CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
-				  isinf(sumY), true);
+	check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+					 isinf(sumY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
@@ -3396,10 +3117,10 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
 		PG_RETURN_NULL();
 
 	numeratorX = N * sumX2 - sumX * sumX;
-	CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+	check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
 	numeratorXXY = sumY * sumX2 - sumX * sumXY;
-	CHECKFLOATVAL(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
-				  isinf(sumX) || isinf(sumXY), true);
+	check_float8_val(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
+					 isinf(sumX) || isinf(sumXY), true);
 	if (numeratorX <= 0)
 		PG_RETURN_NULL();
 
@@ -3424,11 +3145,8 @@ float48pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 + arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl((float8) arg1, arg2));
 }
 
 Datum
@@ -3436,11 +3154,8 @@ float48mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi((float8) arg1, arg2));
 }
 
 Datum
@@ -3448,12 +3163,8 @@ float48mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul((float8) arg1, arg2));
 }
 
 Datum
@@ -3461,16 +3172,8 @@ float48div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div((float8) arg1, arg2));
 }
 
 /*
@@ -3484,12 +3187,8 @@ float84pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
-
-	result = arg1 + arg2;
 
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_pl(arg1, (float8) arg2));
 }
 
 Datum
@@ -3497,12 +3196,8 @@ float84mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
-
-	result = arg1 - arg2;
 
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mi(arg1, (float8) arg2));
 }
 
 Datum
@@ -3510,13 +3205,8 @@ float84mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
-
-	result = arg1 * arg2;
 
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_mul(arg1, (float8) arg2));
 }
 
 Datum
@@ -3524,17 +3214,8 @@ float84div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
-	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
-
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(float8_div(arg1, (float8) arg2));
 }
 
 /*
@@ -3552,7 +3233,7 @@ float48eq(PG_FUNCTION_ARGS)
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq((float8) arg1, arg2));
 }
 
 Datum
@@ -3561,7 +3242,7 @@ float48ne(PG_FUNCTION_ARGS)
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne((float8) arg1, arg2));
 }
 
 Datum
@@ -3570,7 +3251,7 @@ float48lt(PG_FUNCTION_ARGS)
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt((float8) arg1, arg2));
 }
 
 Datum
@@ -3579,7 +3260,7 @@ float48le(PG_FUNCTION_ARGS)
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le((float8) arg1, arg2));
 }
 
 Datum
@@ -3588,7 +3269,7 @@ float48gt(PG_FUNCTION_ARGS)
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt((float8) arg1, arg2));
 }
 
 Datum
@@ -3597,7 +3278,7 @@ float48ge(PG_FUNCTION_ARGS)
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge((float8) arg1, arg2));
 }
 
 /*
@@ -3609,7 +3290,7 @@ float84eq(PG_FUNCTION_ARGS)
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(float8_eq(arg1, (float8) arg2));
 }
 
 Datum
@@ -3618,7 +3299,7 @@ float84ne(PG_FUNCTION_ARGS)
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(float8_ne(arg1, (float8) arg2));
 }
 
 Datum
@@ -3627,7 +3308,7 @@ float84lt(PG_FUNCTION_ARGS)
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(float8_lt(arg1, (float8) arg2));
 }
 
 Datum
@@ -3636,7 +3317,7 @@ float84le(PG_FUNCTION_ARGS)
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(float8_le(arg1, (float8) arg2));
 }
 
 Datum
@@ -3645,7 +3326,7 @@ float84gt(PG_FUNCTION_ARGS)
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(float8_gt(arg1, (float8) arg2));
 }
 
 Datum
@@ -3654,7 +3335,7 @@ float84ge(PG_FUNCTION_ARGS)
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(float8_ge(arg1, (float8) arg2));
 }
 
 /*
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c
index a345c65605..30696e3575 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -91,6 +91,7 @@
 #include "utils/builtins.h"
 #include "utils/date.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 #include "utils/formatting.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 3e7519015d..1fb2ff2603 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -21,13 +21,10 @@
 
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
 
 /*
  * Internal routines
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index d7c807f8d9..fea36f361a 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -76,7 +76,8 @@
 #include "access/spgist.h"
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 4d5042b278..444e575e1d 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -36,6 +36,7 @@
 #include "nodes/nodeFuncs.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
diff --git a/src/backend/utils/adt/rangetypes_gist.c b/src/backend/utils/adt/rangetypes_gist.c
index 2fe61043d9..450479e31c 100644
--- a/src/backend/utils/adt/rangetypes_gist.c
+++ b/src/backend/utils/adt/rangetypes_gist.c
@@ -16,7 +16,8 @@
 
 #include "access/gist.h"
 #include "access/stratnum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/datum.h"
 #include "utils/rangetypes.h"
 
diff --git a/src/backend/utils/adt/rangetypes_selfuncs.c b/src/backend/utils/adt/rangetypes_selfuncs.c
index 59761ecf34..f9a5117492 100644
--- a/src/backend/utils/adt/rangetypes_selfuncs.c
+++ b/src/backend/utils/adt/rangetypes_selfuncs.c
@@ -21,7 +21,8 @@
 #include "catalog/pg_operator.h"
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 #include "utils/selfuncs.h"
diff --git a/src/backend/utils/adt/rangetypes_typanalyze.c b/src/backend/utils/adt/rangetypes_typanalyze.c
index f2c11f54bc..9c50e4c1be 100644
--- a/src/backend/utils/adt/rangetypes_typanalyze.c
+++ b/src/backend/utils/adt/rangetypes_typanalyze.c
@@ -26,7 +26,8 @@
 
 #include "catalog/pg_operator.h"
 #include "commands/vacuum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 9a481f6eb9..284e14dd73 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -33,6 +33,7 @@
 #include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 /*
  * gcc's -ffast-math switch breaks routines that expect exact results from
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index a88ea6cfc9..c123de1a59 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -80,6 +80,7 @@
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/guc_tables.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/pg_locale.h"
 #include "utils/plancache.h"
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 88a42b345c..6f55699912 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -52,20 +52,6 @@ extern char *pg_ltostr_zeropad(char *str, int32 value, int32 minwidth);
 extern char *pg_ltostr(char *str, int32 value);
 extern uint64 pg_strtouint64(const char *str, char **endptr, int base);
 
-/* float.c */
-extern PGDLLIMPORT int extra_float_digits;
-
-extern double get_float8_infinity(void);
-extern float get_float4_infinity(void);
-extern double get_float8_nan(void);
-extern float get_float4_nan(void);
-extern int	is_infinite(double val);
-extern double float8in_internal(char *num, char **endptr_p,
-				  const char *type_name, const char *orig_string);
-extern char *float8out_internal(double num);
-extern int	float4_cmp_internal(float4 a, float4 b);
-extern int	float8_cmp_internal(float8 a, float8 b);
-
 /* oid.c */
 extern oidvector *buildoidvector(const Oid *oids, int n);
 extern Oid	oidparse(Node *node);
diff --git a/src/include/utils/float.h b/src/include/utils/float.h
new file mode 100644
index 0000000000..0e8483c930
--- /dev/null
+++ b/src/include/utils/float.h
@@ -0,0 +1,376 @@
+/*-------------------------------------------------------------------------
+ *
+ * float.h
+ *	  Definitions for the built-in floating-point types
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/include/utils/float.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef FLOAT_H
+#define FLOAT_H
+
+#include <math.h>
+
+#ifndef M_PI
+/* From my RH5.2 gcc math.h file - thomas 2000-04-03 */
+#define M_PI 3.14159265358979323846
+#endif
+
+/* Radians per degree, a.k.a. PI / 180 */
+#define RADIANS_PER_DEGREE 0.0174532925199432957692
+
+/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0. */
+#if defined(WIN32) && !defined(NAN)
+static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
+
+#define NAN (*(const float8 *) nan)
+#endif
+
+extern PGDLLIMPORT int extra_float_digits;
+
+/*
+ * Utility functions in float.c
+ */
+extern int	is_infinite(float8 val);
+extern float8 float8in_internal(char *num, char **endptr_p,
+				  const char *type_name, const char *orig_string);
+extern char *float8out_internal(float8 num);
+extern int	float4_cmp_internal(float4 a, float4 b);
+extern int	float8_cmp_internal(float8 a, float8 b);
+
+/*
+ * Routines to provide reasonably platform-independent handling of
+ * infinity and NaN
+ *
+ * We assume that isinf() and isnan() are available and work per spec.
+ * (On some platforms, we have to supply our own; see src/port.)  However,
+ * generating an Infinity or NaN in the first place is less well standardized;
+ * pre-C99 systems tend not to have C99's INFINITY and NaN macros.  We
+ * centralize our workarounds for this here.
+ */
+
+/*
+ * The funny placements of the two #pragmas is necessary because of a
+ * long lived bug in the Microsoft compilers.
+ * See http://support.microsoft.com/kb/120968/en-us for details
+ */
+#if (_MSC_VER >= 1800)
+#pragma warning(disable:4756)
+#endif
+static inline float4
+get_float4_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float4) INFINITY;
+#else
+#if (_MSC_VER >= 1800)
+#pragma warning(default:4756)
+#endif
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float4) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float8
+get_float8_infinity(void)
+{
+#ifdef INFINITY
+	/* C99 standard way */
+	return (float8) INFINITY;
+#else
+
+	/*
+	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
+	 * largest normal float8.  We assume forcing an overflow will get us a
+	 * true infinity.
+	 */
+	return (float8) (HUGE_VAL * HUGE_VAL);
+#endif
+}
+
+static inline float4
+get_float4_nan(void)
+{
+#ifdef NAN
+	/* C99 standard way */
+	return (float4) NAN;
+#else
+	/* Assume we can get a NAN via zero divide */
+	return (float4) (0.0 / 0.0);
+#endif
+}
+
+static inline float8
+get_float8_nan(void)
+{
+	/* (float8) NAN doesn't work on some NetBSD/MIPS releases */
+#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
+	/* C99 standard way */
+	return (float8) NAN;
+#else
+	/* Assume we can get a NaN via zero divide */
+	return (float8) (0.0 / 0.0);
+#endif
+}
+
+/*
+ * Checks to see if a float4/8 val has underflowed or overflowed
+ */
+
+static inline void
+check_float4_val(const float4 val, const bool inf_is_valid,
+				 const bool zero_is_valid)
+{
+	if (!inf_is_valid && unlikely(isinf(val)))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if (!zero_is_valid && unlikely(val == 0.0))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+static inline void
+check_float8_val(const float8 val, const bool inf_is_valid,
+				 const bool zero_is_valid)
+{
+	if (!inf_is_valid && unlikely(isinf(val)))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: overflow")));
+
+	if (!zero_is_valid && unlikely(val == 0.0))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("value out of range: underflow")));
+}
+
+/*
+ * Routines for operations with the checks above
+ *
+ * There isn't any way to check for underflow of addition/subtraction
+ * because numbers near the underflow value have already been rounded to
+ * the point where we can't detect that the two values were originally
+ * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
+ * 1.4013e-45.
+ */
+
+static inline float4
+float4_pl(const float4 val1, const float4 val2)
+{
+	float4		result;
+
+	result = val1 + val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_pl(const float8 val1, const float8 val2)
+{
+	float8		result;
+
+	result = val1 + val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mi(const float4 val1, const float4 val2)
+{
+	float4		result;
+
+	result = val1 - val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float8
+float8_mi(const float8 val1, const float8 val2)
+{
+	float8		result;
+
+	result = val1 - val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), true);
+
+	return result;
+}
+
+static inline float4
+float4_mul(const float4 val1, const float4 val2)
+{
+	float4		result;
+
+	result = val1 * val2;
+	check_float4_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0f || val2 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_mul(const float8 val1, const float8 val2)
+{
+	float8		result;
+
+	result = val1 * val2;
+	check_float8_val(result, isinf(val1) || isinf(val2),
+					 val1 == 0.0 || val2 == 0.0);
+
+	return result;
+}
+
+static inline float4
+float4_div(const float4 val1, const float4 val2)
+{
+	float4		result;
+
+	if (val2 == 0.0f)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float4_val(result, isinf(val1) || isinf(val2), val1 == 0.0f);
+
+	return result;
+}
+
+static inline float8
+float8_div(const float8 val1, const float8 val2)
+{
+	float8		result;
+
+	if (val2 == 0.0)
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+
+	result = val1 / val2;
+	check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
+
+	return result;
+}
+
+/*
+ * Routines for NaN-aware comparisons
+ *
+ * We consider all NaNs to be equal and larger than any non-NaN. This is
+ * somewhat arbitrary; the important thing is to have a consistent sort
+ * order.
+ */
+
+static inline bool
+float4_eq(const float4 val1, const float4 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float8_eq(const float8 val1, const float8 val2)
+{
+	return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+}
+
+static inline bool
+float4_ne(const float4 val1, const float4 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float8_ne(const float8 val1, const float8 val2)
+{
+	return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+}
+
+static inline bool
+float4_lt(const float4 val1, const float4 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float8_lt(const float8 val1, const float8 val2)
+{
+	return !isnan(val1) && (isnan(val2) || val1 < val2);
+}
+
+static inline bool
+float4_le(const float4 val1, const float4 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float8_le(const float8 val1, const float8 val2)
+{
+	return isnan(val2) || (!isnan(val1) && val1 <= val2);
+}
+
+static inline bool
+float4_gt(const float4 val1, const float4 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float8_gt(const float8 val1, const float8 val2)
+{
+	return !isnan(val2) && (isnan(val1) || val1 > val2);
+}
+
+static inline bool
+float4_ge(const float4 val1, const float4 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline bool
+float8_ge(const float8 val1, const float8 val2)
+{
+	return isnan(val1) || (!isnan(val2) && val1 >= val2);
+}
+
+static inline float4
+float4_min(const float4 val1, const float4 val2)
+{
+	return float4_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_min(const float8 val1, const float8 val2)
+{
+	return float8_lt(val1, val2) ? val1 : val2;
+}
+
+static inline float4
+float4_max(const float4 val1, const float4 val2)
+{
+	return float4_gt(val1, val2) ? val1 : val2;
+}
+
+static inline float8
+float8_max(const float8 val1, const float8 val2)
+{
+	return float8_gt(val1, val2) ? val1 : val2;
+}
+
+#endif							/* FLOAT_H */
-- 
2.13.6

0006-Improve-test-coverage-of-geometric-types.patchtext/x-patch; name=0006-Improve-test-coverage-of-geometric-types.patchDownload
From 39e0f3a33220566cf26a43a3f67d4136db5be2ea Mon Sep 17 00:00:00 2001
From: Tomas Vondra <tomas@2ndquadrant.com>
Date: Thu, 26 Jul 2018 16:42:28 +0200
Subject: [PATCH 6/6] Improve test coverage of geometric types

The tests for the geometric functions and operators were in sad state.
This commit increases test coverage of geo_ops.c significantly.  It
removes the alternative results to expect -0 on some platforms.  We
better try to return the same results on different platforms, but if we
can't we can add them back using the results from build farm.

The tests are added to geometric.sql file.  It is not clear where to
put them as there are many cross datatype operators.  Organising them
on a single file sorted by the left hand side of the operators appear
to be a simple solution.  We may take this further and remove the other
tests later.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com
---
 src/test/regress/expected/box.out          |   44 +-
 src/test/regress/expected/circle.out       |   39 +-
 src/test/regress/expected/create_index.out |   73 +-
 src/test/regress/expected/geometry.out     | 4881 ++++++++++++++++++++++++++--
 src/test/regress/expected/geometry_1.out   | 4881 ++++++++++++++++++++++++++--
 src/test/regress/expected/geometry_2.out   |  563 ----
 src/test/regress/expected/line.out         |  272 +-
 src/test/regress/expected/lseg.out         |   24 +-
 src/test/regress/expected/path.out         |   49 +-
 src/test/regress/expected/point.out        |  358 +-
 src/test/regress/expected/polygon.out      |  200 +-
 src/test/regress/sql/box.sql               |    9 +
 src/test/regress/sql/circle.sql            |   10 +-
 src/test/regress/sql/geometry.sql          |  400 ++-
 src/test/regress/sql/line.sql              |   79 +-
 src/test/regress/sql/lseg.sql              |    9 +-
 src/test/regress/sql/path.sql              |   22 +-
 src/test/regress/sql/point.sql             |   10 +
 src/test/regress/sql/polygon.sql           |   91 +-
 19 files changed, 10088 insertions(+), 1926 deletions(-)
 delete mode 100644 src/test/regress/expected/geometry_2.out

diff --git a/src/test/regress/expected/box.out b/src/test/regress/expected/box.out
index 49af242c8c..998b52223c 100644
--- a/src/test/regress/expected/box.out
+++ b/src/test/regress/expected/box.out
@@ -18,6 +18,7 @@
 CREATE TABLE BOX_TBL (f1 box);
 INSERT INTO BOX_TBL (f1) VALUES ('(2.0,2.0,0.0,0.0)');
 INSERT INTO BOX_TBL (f1) VALUES ('(1.0,1.0,3.0,3.0)');
+INSERT INTO BOX_TBL (f1) VALUES ('((-8, 2), (-2, -10))');
 -- degenerate cases where the box is a line or a point
 -- note that lines and points boxes all have zero area
 INSERT INTO BOX_TBL (f1) VALUES ('(2.5, 2.5, 2.5,3.5)');
@@ -27,6 +28,18 @@ INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
 ERROR:  invalid input syntax for type box: "(2.3, 4.5)"
 LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
                                          ^
+INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+ERROR:  invalid input syntax for type box: "[1, 2, 3, 4)"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+                                         ^
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+ERROR:  invalid input syntax for type box: "(1, 2, 3, 4]"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+                                         ^
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+ERROR:  invalid input syntax for type box: "(1, 2, 3, 4) x"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+                                         ^
 INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
 ERROR:  invalid input syntax for type box: "asdfasdf(ad"
 LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
@@ -36,9 +49,10 @@ SELECT '' AS four, * FROM BOX_TBL;
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
+      | (-2,2),(-8,-10)
       | (2.5,3.5),(2.5,2.5)
       | (3,3),(3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, b.*, area(b.f1) as barea
    FROM BOX_TBL b;
@@ -46,9 +60,10 @@ SELECT '' AS four, b.*, area(b.f1) as barea
 ------+---------------------+-------
       | (2,2),(0,0)         |     4
       | (3,3),(1,1)         |     4
+      | (-2,2),(-8,-10)     |    72
       | (2.5,3.5),(2.5,2.5) |     0
       | (3,3),(3,3)         |     0
-(4 rows)
+(5 rows)
 
 -- overlap
 SELECT '' AS three, b.f1
@@ -68,8 +83,9 @@ SELECT '' AS two, b1.*
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- right-or-overlap (x only)
 SELECT '' AS two, b1.*
@@ -88,8 +104,9 @@ SELECT '' AS two, b.f1
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- area <=
 SELECT '' AS four, b.f1
@@ -127,11 +144,12 @@ SELECT '' AS two, b.f1
 SELECT '' AS two, b.f1
    FROM BOX_TBL b				-- zero area
    WHERE b.f1 > box '(3.5,3.0,4.5,3.0)';
- two |     f1      
------+-------------
+ two |       f1        
+-----+-----------------
      | (2,2),(0,0)
      | (3,3),(1,1)
-(2 rows)
+     | (-2,2),(-8,-10)
+(3 rows)
 
 -- area >=
 SELECT '' AS four, b.f1
@@ -141,9 +159,10 @@ SELECT '' AS four, b.f1
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
+      | (-2,2),(-8,-10)
       | (2.5,3.5),(2.5,2.5)
       | (3,3),(3,3)
-(4 rows)
+(5 rows)
 
 -- right of
 SELECT '' AS two, b.f1
@@ -152,8 +171,9 @@ SELECT '' AS two, b.f1
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- contained in
 SELECT '' AS three, b.f1
@@ -193,9 +213,10 @@ SELECT '' AS four, @@(b1.f1) AS p
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 -- wholly-contained
 SELECT '' AS one, b1.*, b2.*
@@ -211,9 +232,10 @@ SELECT '' AS four, height(f1), width(f1) FROM BOX_TBL;
 ------+--------+-------
       |      2 |     2
       |      2 |     2
+      |     12 |     6
       |      1 |     0
       |      0 |     0
-(4 rows)
+(5 rows)
 
 --
 -- Test the SP-GiST index
diff --git a/src/test/regress/expected/circle.out b/src/test/regress/expected/circle.out
index 9ba4a0495d..2ed74cc6aa 100644
--- a/src/test/regress/expected/circle.out
+++ b/src/test/regress/expected/circle.out
@@ -7,12 +7,22 @@ INSERT INTO CIRCLE_TBL VALUES ('<(1,2),100>');
 INSERT INTO CIRCLE_TBL VALUES ('1,3,5');
 INSERT INTO CIRCLE_TBL VALUES ('((1,2),3)');
 INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10>');
-INSERT INTO CIRCLE_TBL VALUES ('<(100,1),115>');
+INSERT INTO CIRCLE_TBL VALUES (' < ( 100 , 1 ) , 115 > ');
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),0>');	-- Zero radius
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),NaN>');	-- NaN radius
 -- bad values
 INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
 ERROR:  invalid input syntax for type circle: "<(-100,0),-100>"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
                                        ^
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+ERROR:  invalid input syntax for type circle: "<(100,200),10"
+LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+                                       ^
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+ERROR:  invalid input syntax for type circle: "<(100,200),10> x"
+LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+                                       ^
 INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
 ERROR:  invalid input syntax for type circle: "1abc,3,5"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
@@ -30,7 +40,9 @@ SELECT * FROM CIRCLE_TBL;
  <(1,2),3>
  <(100,200),10>
  <(100,1),115>
-(6 rows)
+ <(3,5),0>
+ <(3,5),NaN>
+(8 rows)
 
 SELECT '' AS six, center(f1) AS center
   FROM CIRCLE_TBL;
@@ -42,7 +54,9 @@ SELECT '' AS six, center(f1) AS center
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS six, radius(f1) AS radius
   FROM CIRCLE_TBL;
@@ -54,7 +68,9 @@ SELECT '' AS six, radius(f1) AS radius
      |      3
      |     10
      |    115
-(6 rows)
+     |      0
+     |    NaN
+(8 rows)
 
 SELECT '' AS six, diameter(f1) AS diameter
   FROM CIRCLE_TBL;
@@ -66,14 +82,17 @@ SELECT '' AS six, diameter(f1) AS diameter
      |        6
      |       20
      |      230
-(6 rows)
+     |        0
+     |      NaN
+(8 rows)
 
 SELECT '' AS two, f1 FROM CIRCLE_TBL WHERE radius(f1) < 5;
  two |    f1     
 -----+-----------
      | <(5,1),3>
      | <(1,2),3>
-(2 rows)
+     | <(3,5),0>
+(3 rows)
 
 SELECT '' AS four, f1 FROM CIRCLE_TBL WHERE diameter(f1) >= 10;
  four |       f1       
@@ -82,7 +101,8 @@ SELECT '' AS four, f1 FROM CIRCLE_TBL WHERE diameter(f1) >= 10;
       | <(1,3),5>
       | <(100,200),10>
       | <(100,1),115>
-(4 rows)
+      | <(3,5),NaN>
+(5 rows)
 
 SELECT '' as five, c1.f1 AS one, c2.f1 AS two, (c1.f1 <-> c2.f1) AS distance
   FROM CIRCLE_TBL c1, CIRCLE_TBL c2
@@ -90,10 +110,13 @@ SELECT '' as five, c1.f1 AS one, c2.f1 AS two, (c1.f1 <-> c2.f1) AS distance
   ORDER BY distance, area(c1.f1), area(c2.f1);
  five |      one       |      two       |     distance     
 ------+----------------+----------------+------------------
+      | <(3,5),0>      | <(1,2),3>      | 0.60555127546399
+      | <(3,5),0>      | <(5,1),3>      | 1.47213595499958
       | <(100,200),10> | <(100,1),115>  |               74
       | <(100,200),10> | <(1,2),100>    | 111.370729772479
       | <(1,3),5>      | <(100,200),10> | 205.476756144497
       | <(5,1),3>      | <(100,200),10> |  207.51303816328
+      | <(3,5),0>      | <(100,200),10> | 207.793480159531
       | <(1,2),3>      | <(100,200),10> | 208.370729772479
-(5 rows)
+(8 rows)
 
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index be25101db2..c33910c392 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -157,7 +157,7 @@ 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)';
  count 
 -------
-     3
+     5
 (1 row)
 
 SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>';
@@ -175,7 +175,7 @@ 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)';
  count 
 -------
-     2
+     3
 (1 row)
 
 SELECT count(*) FROM point_tbl p WHERE p.f1 <^ '(0.0, 0.0)';
@@ -187,7 +187,7 @@ 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)';
  count 
 -------
-     3
+     4
 (1 row)
 
 SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
@@ -197,16 +197,19 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
 (1 row)
 
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
  (-5,-12)
  (5.1,34.5)
+ (1e+300,Infinity)
+ (NaN,NaN)
  
-(7 rows)
+(10 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NULL;
  f1 
@@ -215,24 +218,28 @@ SELECT * FROM point_tbl WHERE f1 IS NULL;
 (1 row)
 
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (1e-300,-1e-300)
  (0,0)
  (-3,4)
  (-10,0)
  (10,10)
  (-5,-12)
  (5.1,34.5)
-(6 rows)
+ (1e+300,Infinity)
+ (NaN,NaN)
+(9 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
  count 
@@ -574,7 +581,7 @@ SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,
 SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,50),(100,0),(0,0)';
  count 
 -------
-     3
+     4
 (1 row)
 
 EXPLAIN (COSTS OFF)
@@ -619,7 +626,7 @@ 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)';
  count 
 -------
-     2
+     3
 (1 row)
 
 EXPLAIN (COSTS OFF)
@@ -649,7 +656,7 @@ 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)';
  count 
 -------
-     3
+     4
 (1 row)
 
 EXPLAIN (COSTS OFF)
@@ -676,16 +683,19 @@ SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
 (2 rows)
 
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (10,10)
+ (NaN,NaN)
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
- (10,10)
  (-5,-12)
  (5.1,34.5)
  
-(7 rows)
+ (1e+300,Infinity)
+(10 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 IS NULL;
@@ -711,15 +721,18 @@ SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
 (3 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (10,10)
+ (NaN,NaN)
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
- (10,10)
  (-5,-12)
  (5.1,34.5)
-(6 rows)
+ (1e+300,Infinity)
+(9 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
@@ -731,13 +744,14 @@ SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0
 (3 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
@@ -1268,13 +1282,14 @@ SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0
 (6 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
diff --git a/src/test/regress/expected/geometry.out b/src/test/regress/expected/geometry.out
index e4c0039040..b4da3baa37 100644
--- a/src/test/regress/expected/geometry.out
+++ b/src/test/regress/expected/geometry.out
@@ -13,9 +13,10 @@ SELECT '' AS four, center(f1) AS center
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, (@@ f1) AS center
    FROM BOX_TBL;
@@ -23,9 +24,10 @@ SELECT '' AS four, (@@ f1) AS center
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS six, point(f1) AS center
    FROM CIRCLE_TBL;
@@ -37,7 +39,9 @@ SELECT '' AS six, point(f1) AS center
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS six, (@@ f1) AS center
    FROM CIRCLE_TBL;
@@ -49,7 +53,9 @@ SELECT '' AS six, (@@ f1) AS center
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS two, (@@ f1) AS center
    FROM POLYGON_TBL
@@ -58,27 +64,32 @@ SELECT '' AS two, (@@ f1) AS center
 -----+-------------------------------
      | (1.33333333333,1.33333333333)
      | (2.33333333333,1.33333333333)
-(2 rows)
+     | (4,5)
+     | (4,5)
+     | (4,3)
+(5 rows)
 
 -- "is horizontal" function
 SELECT '' AS two, p1.f1
    FROM POINT_TBL p1
    WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 -- "is horizontal" operator
 SELECT '' AS two, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 -- "is vertical" function
 SELECT '' AS one, p1.f1
@@ -98,6 +109,1453 @@ SELECT '' AS one, p1.f1
      | (5.1,34.5)
 (1 row)
 
+-- Slope
+SELECT p1.f1, p2.f1, slope(p1.f1, p2.f1) FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |       slope        
+-------------------+-------------------+--------------------
+ (0,0)             | (0,0)             | 1.79769313486e+308
+ (0,0)             | (-10,0)           |                  0
+ (0,0)             | (-3,4)            |     -1.33333333333
+ (0,0)             | (5.1,34.5)        |      6.76470588235
+ (0,0)             | (-5,-12)          |                2.4
+ (0,0)             | (1e-300,-1e-300)  | 1.79769313486e+308
+ (0,0)             | (1e+300,Infinity) |           Infinity
+ (0,0)             | (NaN,NaN)         |                NaN
+ (0,0)             | (10,10)           |                  1
+ (-10,0)           | (0,0)             |                  0
+ (-10,0)           | (-10,0)           | 1.79769313486e+308
+ (-10,0)           | (-3,4)            |     0.571428571429
+ (-10,0)           | (5.1,34.5)        |      2.28476821192
+ (-10,0)           | (-5,-12)          |               -2.4
+ (-10,0)           | (1e-300,-1e-300)  |                  0
+ (-10,0)           | (1e+300,Infinity) |           Infinity
+ (-10,0)           | (NaN,NaN)         |                NaN
+ (-10,0)           | (10,10)           |                0.5
+ (-3,4)            | (0,0)             |     -1.33333333333
+ (-3,4)            | (-10,0)           |     0.571428571429
+ (-3,4)            | (-3,4)            | 1.79769313486e+308
+ (-3,4)            | (5.1,34.5)        |      3.76543209877
+ (-3,4)            | (-5,-12)          |                  8
+ (-3,4)            | (1e-300,-1e-300)  |     -1.33333333333
+ (-3,4)            | (1e+300,Infinity) |           Infinity
+ (-3,4)            | (NaN,NaN)         |                NaN
+ (-3,4)            | (10,10)           |     0.461538461538
+ (5.1,34.5)        | (0,0)             |      6.76470588235
+ (5.1,34.5)        | (-10,0)           |      2.28476821192
+ (5.1,34.5)        | (-3,4)            |      3.76543209877
+ (5.1,34.5)        | (5.1,34.5)        | 1.79769313486e+308
+ (5.1,34.5)        | (-5,-12)          |      4.60396039604
+ (5.1,34.5)        | (1e-300,-1e-300)  |      6.76470588235
+ (5.1,34.5)        | (1e+300,Infinity) |           Infinity
+ (5.1,34.5)        | (NaN,NaN)         |                NaN
+ (5.1,34.5)        | (10,10)           |                 -5
+ (-5,-12)          | (0,0)             |                2.4
+ (-5,-12)          | (-10,0)           |               -2.4
+ (-5,-12)          | (-3,4)            |                  8
+ (-5,-12)          | (5.1,34.5)        |      4.60396039604
+ (-5,-12)          | (-5,-12)          | 1.79769313486e+308
+ (-5,-12)          | (1e-300,-1e-300)  |                2.4
+ (-5,-12)          | (1e+300,Infinity) |           Infinity
+ (-5,-12)          | (NaN,NaN)         |                NaN
+ (-5,-12)          | (10,10)           |      1.46666666667
+ (1e-300,-1e-300)  | (0,0)             | 1.79769313486e+308
+ (1e-300,-1e-300)  | (-10,0)           |                  0
+ (1e-300,-1e-300)  | (-3,4)            |     -1.33333333333
+ (1e-300,-1e-300)  | (5.1,34.5)        |      6.76470588235
+ (1e-300,-1e-300)  | (-5,-12)          |                2.4
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | 1.79769313486e+308
+ (1e-300,-1e-300)  | (1e+300,Infinity) |           Infinity
+ (1e-300,-1e-300)  | (NaN,NaN)         |                NaN
+ (1e-300,-1e-300)  | (10,10)           |                  1
+ (1e+300,Infinity) | (0,0)             |           Infinity
+ (1e+300,Infinity) | (-10,0)           |           Infinity
+ (1e+300,Infinity) | (-3,4)            |           Infinity
+ (1e+300,Infinity) | (5.1,34.5)        |           Infinity
+ (1e+300,Infinity) | (-5,-12)          |           Infinity
+ (1e+300,Infinity) | (1e-300,-1e-300)  |           Infinity
+ (1e+300,Infinity) | (1e+300,Infinity) | 1.79769313486e+308
+ (1e+300,Infinity) | (NaN,NaN)         |                NaN
+ (1e+300,Infinity) | (10,10)           |           Infinity
+ (NaN,NaN)         | (0,0)             |                NaN
+ (NaN,NaN)         | (-10,0)           |                NaN
+ (NaN,NaN)         | (-3,4)            |                NaN
+ (NaN,NaN)         | (5.1,34.5)        |                NaN
+ (NaN,NaN)         | (-5,-12)          |                NaN
+ (NaN,NaN)         | (1e-300,-1e-300)  |                NaN
+ (NaN,NaN)         | (1e+300,Infinity) |                NaN
+ (NaN,NaN)         | (NaN,NaN)         |                NaN
+ (NaN,NaN)         | (10,10)           |                NaN
+ (10,10)           | (0,0)             |                  1
+ (10,10)           | (-10,0)           |                0.5
+ (10,10)           | (-3,4)            |     0.461538461538
+ (10,10)           | (5.1,34.5)        |                 -5
+ (10,10)           | (-5,-12)          |      1.46666666667
+ (10,10)           | (1e-300,-1e-300)  |                  1
+ (10,10)           | (1e+300,Infinity) |           Infinity
+ (10,10)           | (NaN,NaN)         |                NaN
+ (10,10)           | (10,10)           | 1.79769313486e+308
+(81 rows)
+
+-- Add point
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |     ?column?      
+-------------------+-------------------+-------------------
+ (0,0)             | (0,0)             | (0,0)
+ (0,0)             | (-10,0)           | (-10,0)
+ (0,0)             | (-3,4)            | (-3,4)
+ (0,0)             | (5.1,34.5)        | (5.1,34.5)
+ (0,0)             | (-5,-12)          | (-5,-12)
+ (0,0)             | (1e-300,-1e-300)  | (1e-300,-1e-300)
+ (0,0)             | (1e+300,Infinity) | (1e+300,Infinity)
+ (0,0)             | (NaN,NaN)         | (NaN,NaN)
+ (0,0)             | (10,10)           | (10,10)
+ (-10,0)           | (0,0)             | (-10,0)
+ (-10,0)           | (-10,0)           | (-20,0)
+ (-10,0)           | (-3,4)            | (-13,4)
+ (-10,0)           | (5.1,34.5)        | (-4.9,34.5)
+ (-10,0)           | (-5,-12)          | (-15,-12)
+ (-10,0)           | (1e-300,-1e-300)  | (-10,-1e-300)
+ (-10,0)           | (1e+300,Infinity) | (1e+300,Infinity)
+ (-10,0)           | (NaN,NaN)         | (NaN,NaN)
+ (-10,0)           | (10,10)           | (0,10)
+ (-3,4)            | (0,0)             | (-3,4)
+ (-3,4)            | (-10,0)           | (-13,4)
+ (-3,4)            | (-3,4)            | (-6,8)
+ (-3,4)            | (5.1,34.5)        | (2.1,38.5)
+ (-3,4)            | (-5,-12)          | (-8,-8)
+ (-3,4)            | (1e-300,-1e-300)  | (-3,4)
+ (-3,4)            | (1e+300,Infinity) | (1e+300,Infinity)
+ (-3,4)            | (NaN,NaN)         | (NaN,NaN)
+ (-3,4)            | (10,10)           | (7,14)
+ (5.1,34.5)        | (0,0)             | (5.1,34.5)
+ (5.1,34.5)        | (-10,0)           | (-4.9,34.5)
+ (5.1,34.5)        | (-3,4)            | (2.1,38.5)
+ (5.1,34.5)        | (5.1,34.5)        | (10.2,69)
+ (5.1,34.5)        | (-5,-12)          | (0.1,22.5)
+ (5.1,34.5)        | (1e-300,-1e-300)  | (5.1,34.5)
+ (5.1,34.5)        | (1e+300,Infinity) | (1e+300,Infinity)
+ (5.1,34.5)        | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5)        | (10,10)           | (15.1,44.5)
+ (-5,-12)          | (0,0)             | (-5,-12)
+ (-5,-12)          | (-10,0)           | (-15,-12)
+ (-5,-12)          | (-3,4)            | (-8,-8)
+ (-5,-12)          | (5.1,34.5)        | (0.1,22.5)
+ (-5,-12)          | (-5,-12)          | (-10,-24)
+ (-5,-12)          | (1e-300,-1e-300)  | (-5,-12)
+ (-5,-12)          | (1e+300,Infinity) | (1e+300,Infinity)
+ (-5,-12)          | (NaN,NaN)         | (NaN,NaN)
+ (-5,-12)          | (10,10)           | (5,-2)
+ (1e-300,-1e-300)  | (0,0)             | (1e-300,-1e-300)
+ (1e-300,-1e-300)  | (-10,0)           | (-10,-1e-300)
+ (1e-300,-1e-300)  | (-3,4)            | (-3,4)
+ (1e-300,-1e-300)  | (5.1,34.5)        | (5.1,34.5)
+ (1e-300,-1e-300)  | (-5,-12)          | (-5,-12)
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | (2e-300,-2e-300)
+ (1e-300,-1e-300)  | (1e+300,Infinity) | (1e+300,Infinity)
+ (1e-300,-1e-300)  | (NaN,NaN)         | (NaN,NaN)
+ (1e-300,-1e-300)  | (10,10)           | (10,10)
+ (1e+300,Infinity) | (0,0)             | (1e+300,Infinity)
+ (1e+300,Infinity) | (-10,0)           | (1e+300,Infinity)
+ (1e+300,Infinity) | (-3,4)            | (1e+300,Infinity)
+ (1e+300,Infinity) | (5.1,34.5)        | (1e+300,Infinity)
+ (1e+300,Infinity) | (-5,-12)          | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e-300,-1e-300)  | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e+300,Infinity) | (2e+300,Infinity)
+ (1e+300,Infinity) | (NaN,NaN)         | (NaN,NaN)
+ (1e+300,Infinity) | (10,10)           | (1e+300,Infinity)
+ (NaN,NaN)         | (0,0)             | (NaN,NaN)
+ (NaN,NaN)         | (-10,0)           | (NaN,NaN)
+ (NaN,NaN)         | (-3,4)            | (NaN,NaN)
+ (NaN,NaN)         | (5.1,34.5)        | (NaN,NaN)
+ (NaN,NaN)         | (-5,-12)          | (NaN,NaN)
+ (NaN,NaN)         | (1e-300,-1e-300)  | (NaN,NaN)
+ (NaN,NaN)         | (1e+300,Infinity) | (NaN,NaN)
+ (NaN,NaN)         | (NaN,NaN)         | (NaN,NaN)
+ (NaN,NaN)         | (10,10)           | (NaN,NaN)
+ (10,10)           | (0,0)             | (10,10)
+ (10,10)           | (-10,0)           | (0,10)
+ (10,10)           | (-3,4)            | (7,14)
+ (10,10)           | (5.1,34.5)        | (15.1,44.5)
+ (10,10)           | (-5,-12)          | (5,-2)
+ (10,10)           | (1e-300,-1e-300)  | (10,10)
+ (10,10)           | (1e+300,Infinity) | (1e+300,Infinity)
+ (10,10)           | (NaN,NaN)         | (NaN,NaN)
+ (10,10)           | (10,10)           | (20,20)
+(81 rows)
+
+-- Subtract point
+SELECT p1.f1, p2.f1, p1.f1 - p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |      ?column?       
+-------------------+-------------------+---------------------
+ (0,0)             | (0,0)             | (0,0)
+ (0,0)             | (-10,0)           | (10,0)
+ (0,0)             | (-3,4)            | (3,-4)
+ (0,0)             | (5.1,34.5)        | (-5.1,-34.5)
+ (0,0)             | (-5,-12)          | (5,12)
+ (0,0)             | (1e-300,-1e-300)  | (-1e-300,1e-300)
+ (0,0)             | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (0,0)             | (NaN,NaN)         | (NaN,NaN)
+ (0,0)             | (10,10)           | (-10,-10)
+ (-10,0)           | (0,0)             | (-10,0)
+ (-10,0)           | (-10,0)           | (0,0)
+ (-10,0)           | (-3,4)            | (-7,-4)
+ (-10,0)           | (5.1,34.5)        | (-15.1,-34.5)
+ (-10,0)           | (-5,-12)          | (-5,12)
+ (-10,0)           | (1e-300,-1e-300)  | (-10,1e-300)
+ (-10,0)           | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-10,0)           | (NaN,NaN)         | (NaN,NaN)
+ (-10,0)           | (10,10)           | (-20,-10)
+ (-3,4)            | (0,0)             | (-3,4)
+ (-3,4)            | (-10,0)           | (7,4)
+ (-3,4)            | (-3,4)            | (0,0)
+ (-3,4)            | (5.1,34.5)        | (-8.1,-30.5)
+ (-3,4)            | (-5,-12)          | (2,16)
+ (-3,4)            | (1e-300,-1e-300)  | (-3,4)
+ (-3,4)            | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-3,4)            | (NaN,NaN)         | (NaN,NaN)
+ (-3,4)            | (10,10)           | (-13,-6)
+ (5.1,34.5)        | (0,0)             | (5.1,34.5)
+ (5.1,34.5)        | (-10,0)           | (15.1,34.5)
+ (5.1,34.5)        | (-3,4)            | (8.1,30.5)
+ (5.1,34.5)        | (5.1,34.5)        | (0,0)
+ (5.1,34.5)        | (-5,-12)          | (10.1,46.5)
+ (5.1,34.5)        | (1e-300,-1e-300)  | (5.1,34.5)
+ (5.1,34.5)        | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (5.1,34.5)        | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5)        | (10,10)           | (-4.9,24.5)
+ (-5,-12)          | (0,0)             | (-5,-12)
+ (-5,-12)          | (-10,0)           | (5,-12)
+ (-5,-12)          | (-3,4)            | (-2,-16)
+ (-5,-12)          | (5.1,34.5)        | (-10.1,-46.5)
+ (-5,-12)          | (-5,-12)          | (0,0)
+ (-5,-12)          | (1e-300,-1e-300)  | (-5,-12)
+ (-5,-12)          | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-5,-12)          | (NaN,NaN)         | (NaN,NaN)
+ (-5,-12)          | (10,10)           | (-15,-22)
+ (1e-300,-1e-300)  | (0,0)             | (1e-300,-1e-300)
+ (1e-300,-1e-300)  | (-10,0)           | (10,-1e-300)
+ (1e-300,-1e-300)  | (-3,4)            | (3,-4)
+ (1e-300,-1e-300)  | (5.1,34.5)        | (-5.1,-34.5)
+ (1e-300,-1e-300)  | (-5,-12)          | (5,12)
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | (0,0)
+ (1e-300,-1e-300)  | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (1e-300,-1e-300)  | (NaN,NaN)         | (NaN,NaN)
+ (1e-300,-1e-300)  | (10,10)           | (-10,-10)
+ (1e+300,Infinity) | (0,0)             | (1e+300,Infinity)
+ (1e+300,Infinity) | (-10,0)           | (1e+300,Infinity)
+ (1e+300,Infinity) | (-3,4)            | (1e+300,Infinity)
+ (1e+300,Infinity) | (5.1,34.5)        | (1e+300,Infinity)
+ (1e+300,Infinity) | (-5,-12)          | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e-300,-1e-300)  | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e+300,Infinity) | (0,NaN)
+ (1e+300,Infinity) | (NaN,NaN)         | (NaN,NaN)
+ (1e+300,Infinity) | (10,10)           | (1e+300,Infinity)
+ (NaN,NaN)         | (0,0)             | (NaN,NaN)
+ (NaN,NaN)         | (-10,0)           | (NaN,NaN)
+ (NaN,NaN)         | (-3,4)            | (NaN,NaN)
+ (NaN,NaN)         | (5.1,34.5)        | (NaN,NaN)
+ (NaN,NaN)         | (-5,-12)          | (NaN,NaN)
+ (NaN,NaN)         | (1e-300,-1e-300)  | (NaN,NaN)
+ (NaN,NaN)         | (1e+300,Infinity) | (NaN,NaN)
+ (NaN,NaN)         | (NaN,NaN)         | (NaN,NaN)
+ (NaN,NaN)         | (10,10)           | (NaN,NaN)
+ (10,10)           | (0,0)             | (10,10)
+ (10,10)           | (-10,0)           | (20,10)
+ (10,10)           | (-3,4)            | (13,6)
+ (10,10)           | (5.1,34.5)        | (4.9,-24.5)
+ (10,10)           | (-5,-12)          | (15,22)
+ (10,10)           | (1e-300,-1e-300)  | (10,10)
+ (10,10)           | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (10,10)           | (NaN,NaN)         | (NaN,NaN)
+ (10,10)           | (10,10)           | (0,0)
+(81 rows)
+
+-- Multiply with point
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+     f1     |        f1         |       ?column?        
+------------+-------------------+-----------------------
+ (5.1,34.5) | (0,0)             | (0,0)
+ (10,10)    | (0,0)             | (0,0)
+ (5.1,34.5) | (-10,0)           | (-51,-345)
+ (10,10)    | (-10,0)           | (-100,-100)
+ (5.1,34.5) | (-3,4)            | (-153.3,-83.1)
+ (10,10)    | (-3,4)            | (-70,10)
+ (5.1,34.5) | (5.1,34.5)        | (-1164.24,351.9)
+ (10,10)    | (5.1,34.5)        | (-294,396)
+ (5.1,34.5) | (-5,-12)          | (388.5,-233.7)
+ (10,10)    | (-5,-12)          | (70,-170)
+ (5.1,34.5) | (1e-300,-1e-300)  | (3.96e-299,2.94e-299)
+ (10,10)    | (1e-300,-1e-300)  | (2e-299,0)
+ (5.1,34.5) | (1e+300,Infinity) | (-Infinity,Infinity)
+ (10,10)    | (1e+300,Infinity) | (-Infinity,Infinity)
+ (5.1,34.5) | (NaN,NaN)         | (NaN,NaN)
+ (10,10)    | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5) | (10,10)           | (-294,396)
+ (10,10)    | (10,10)           | (0,200)
+(18 rows)
+
+-- Underflow error
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] < 1;
+ERROR:  value out of range: underflow
+-- Divide by point
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] BETWEEN 1 AND 1000;
+        f1         |     f1     |                 ?column?                  
+-------------------+------------+-------------------------------------------
+ (0,0)             | (5.1,34.5) | (0,0)
+ (0,0)             | (10,10)    | (0,0)
+ (-10,0)           | (5.1,34.5) | (-0.0419318237877,0.283656455034)
+ (-10,0)           | (10,10)    | (-0.5,0.5)
+ (-3,4)            | (5.1,34.5) | (0.100883034877,0.101869666025)
+ (-3,4)            | (10,10)    | (0.05,0.35)
+ (5.1,34.5)        | (5.1,34.5) | (1,0)
+ (5.1,34.5)        | (10,10)    | (1.98,1.47)
+ (-5,-12)          | (5.1,34.5) | (-0.361353657935,0.0915100389719)
+ (-5,-12)          | (10,10)    | (-0.85,-0.35)
+ (1e-300,-1e-300)  | (5.1,34.5) | (-2.41724631247e-302,-3.25588278822e-302)
+ (1e-300,-1e-300)  | (10,10)    | (0,-1e-301)
+ (1e+300,Infinity) | (5.1,34.5) | (Infinity,Infinity)
+ (1e+300,Infinity) | (10,10)    | (Infinity,Infinity)
+ (NaN,NaN)         | (5.1,34.5) | (NaN,NaN)
+ (NaN,NaN)         | (10,10)    | (NaN,NaN)
+ (10,10)           | (5.1,34.5) | (0.325588278822,-0.241724631247)
+ (10,10)           | (10,10)    | (1,0)
+(18 rows)
+
+-- Overflow error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] > 1000;
+ERROR:  value out of range: overflow
+-- Division by 0 error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to line
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LINE_TBL l;
+        f1         |                   s                   |      ?column?      
+-------------------+---------------------------------------+--------------------
+ (0,0)             | {0,-1,5}                              |                  5
+ (0,0)             | {1,0,5}                               |                  5
+ (0,0)             | {0,3,0}                               |                  0
+ (0,0)             | {1,-1,0}                              |                  0
+ (0,0)             | {-0.4,-1,-6}                          |      5.57086014531
+ (0,0)             | {-0.000184615384615,-1,15.3846153846} |      15.3846151224
+ (0,0)             | {3,NaN,5}                             |                NaN
+ (0,0)             | {NaN,NaN,NaN}                         |                NaN
+ (0,0)             | {0,-1,3}                              |                  3
+ (0,0)             | {-1,0,3}                              |                  3
+ (-10,0)           | {0,-1,5}                              |                  5
+ (-10,0)           | {1,0,5}                               |                  5
+ (-10,0)           | {0,3,0}                               |                  0
+ (-10,0)           | {1,-1,0}                              |      7.07106781187
+ (-10,0)           | {-0.4,-1,-6}                          |      1.85695338177
+ (-10,0)           | {-0.000184615384615,-1,15.3846153846} |      15.3864612763
+ (-10,0)           | {3,NaN,5}                             |                NaN
+ (-10,0)           | {NaN,NaN,NaN}                         |                NaN
+ (-10,0)           | {0,-1,3}                              |                  3
+ (-10,0)           | {-1,0,3}                              |                 13
+ (-3,4)            | {0,-1,5}                              |                  1
+ (-3,4)            | {1,0,5}                               |                  2
+ (-3,4)            | {0,3,0}                               |                  4
+ (-3,4)            | {1,-1,0}                              |      4.94974746831
+ (-3,4)            | {-0.4,-1,-6}                          |      8.17059487979
+ (-3,4)            | {-0.000184615384615,-1,15.3846153846} |      11.3851690368
+ (-3,4)            | {3,NaN,5}                             |                NaN
+ (-3,4)            | {NaN,NaN,NaN}                         |                NaN
+ (-3,4)            | {0,-1,3}                              |                  1
+ (-3,4)            | {-1,0,3}                              |                  6
+ (5.1,34.5)        | {0,-1,5}                              |               29.5
+ (5.1,34.5)        | {1,0,5}                               |               10.1
+ (5.1,34.5)        | {0,3,0}                               |               34.5
+ (5.1,34.5)        | {1,-1,0}                              |      20.7889393669
+ (5.1,34.5)        | {-0.4,-1,-6}                          |      39.4973984303
+ (5.1,34.5)        | {-0.000184615384615,-1,15.3846153846} |      19.1163258281
+ (5.1,34.5)        | {3,NaN,5}                             |                NaN
+ (5.1,34.5)        | {NaN,NaN,NaN}                         |                NaN
+ (5.1,34.5)        | {0,-1,3}                              |               31.5
+ (5.1,34.5)        | {-1,0,3}                              |                2.1
+ (-5,-12)          | {0,-1,5}                              |                 17
+ (-5,-12)          | {1,0,5}                               |                  0
+ (-5,-12)          | {0,3,0}                               |                 12
+ (-5,-12)          | {1,-1,0}                              |      4.94974746831
+ (-5,-12)          | {-0.4,-1,-6}                          |      7.42781352708
+ (-5,-12)          | {-0.000184615384615,-1,15.3846153846} |      27.3855379948
+ (-5,-12)          | {3,NaN,5}                             |                NaN
+ (-5,-12)          | {NaN,NaN,NaN}                         |                NaN
+ (-5,-12)          | {0,-1,3}                              |                 15
+ (-5,-12)          | {-1,0,3}                              |                  8
+ (1e-300,-1e-300)  | {0,-1,5}                              |                  5
+ (1e-300,-1e-300)  | {1,0,5}                               |                  5
+ (1e-300,-1e-300)  | {0,3,0}                               |             1e-300
+ (1e-300,-1e-300)  | {1,-1,0}                              | 1.41421356237e-300
+ (1e-300,-1e-300)  | {-0.4,-1,-6}                          |      5.57086014531
+ (1e-300,-1e-300)  | {-0.000184615384615,-1,15.3846153846} |      15.3846151224
+ (1e-300,-1e-300)  | {3,NaN,5}                             |                NaN
+ (1e-300,-1e-300)  | {NaN,NaN,NaN}                         |                NaN
+ (1e-300,-1e-300)  | {0,-1,3}                              |                  3
+ (1e-300,-1e-300)  | {-1,0,3}                              |                  3
+ (1e+300,Infinity) | {0,-1,5}                              |           Infinity
+ (1e+300,Infinity) | {1,0,5}                               |                NaN
+ (1e+300,Infinity) | {0,3,0}                               |           Infinity
+ (1e+300,Infinity) | {1,-1,0}                              |           Infinity
+ (1e+300,Infinity) | {-0.4,-1,-6}                          |           Infinity
+ (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} |           Infinity
+ (1e+300,Infinity) | {3,NaN,5}                             |                NaN
+ (1e+300,Infinity) | {NaN,NaN,NaN}                         |                NaN
+ (1e+300,Infinity) | {0,-1,3}                              |           Infinity
+ (1e+300,Infinity) | {-1,0,3}                              |                NaN
+ (NaN,NaN)         | {0,-1,5}                              |                NaN
+ (NaN,NaN)         | {1,0,5}                               |                NaN
+ (NaN,NaN)         | {0,3,0}                               |                NaN
+ (NaN,NaN)         | {1,-1,0}                              |                NaN
+ (NaN,NaN)         | {-0.4,-1,-6}                          |                NaN
+ (NaN,NaN)         | {-0.000184615384615,-1,15.3846153846} |                NaN
+ (NaN,NaN)         | {3,NaN,5}                             |                NaN
+ (NaN,NaN)         | {NaN,NaN,NaN}                         |                NaN
+ (NaN,NaN)         | {0,-1,3}                              |                NaN
+ (NaN,NaN)         | {-1,0,3}                              |                NaN
+ (10,10)           | {0,-1,5}                              |                  5
+ (10,10)           | {1,0,5}                               |                 15
+ (10,10)           | {0,3,0}                               |                 10
+ (10,10)           | {1,-1,0}                              |                  0
+ (10,10)           | {-0.4,-1,-6}                          |      18.5695338177
+ (10,10)           | {-0.000184615384615,-1,15.3846153846} |      5.38276913903
+ (10,10)           | {3,NaN,5}                             |                NaN
+ (10,10)           | {NaN,NaN,NaN}                         |                NaN
+ (10,10)           | {0,-1,3}                              |                  7
+ (10,10)           | {-1,0,3}                              |                  7
+(90 rows)
+
+-- Distance to line segment
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LSEG_TBL l;
+        f1         |               s               |      ?column?      
+-------------------+-------------------------------+--------------------
+ (0,0)             | [(1,2),(3,4)]                 |       2.2360679775
+ (0,0)             | [(0,0),(6,6)]                 |                  0
+ (0,0)             | [(10,-10),(-3,-4)]            |      4.88901207039
+ (0,0)             | [(-1000000,200),(300000,-40)] |      15.3846151224
+ (0,0)             | [(11,22),(33,44)]             |      24.5967477525
+ (0,0)             | [(-10,2),(-10,3)]             |      10.1980390272
+ (0,0)             | [(0,-20),(30,-20)]            |                 20
+ (0,0)             | [(NaN,1),(NaN,90)]            |                NaN
+ (-10,0)           | [(1,2),(3,4)]                 |      11.1803398875
+ (-10,0)           | [(0,0),(6,6)]                 |                 10
+ (-10,0)           | [(10,-10),(-3,-4)]            |       8.0622577483
+ (-10,0)           | [(-1000000,200),(300000,-40)] |      15.3864612763
+ (-10,0)           | [(11,22),(33,44)]             |      30.4138126515
+ (-10,0)           | [(-10,2),(-10,3)]             |                  2
+ (-10,0)           | [(0,-20),(30,-20)]            |       22.360679775
+ (-10,0)           | [(NaN,1),(NaN,90)]            |                NaN
+ (-3,4)            | [(1,2),(3,4)]                 |        4.472135955
+ (-3,4)            | [(0,0),(6,6)]                 |      4.94974746831
+ (-3,4)            | [(10,-10),(-3,-4)]            |                  8
+ (-3,4)            | [(-1000000,200),(300000,-40)] |      11.3851690367
+ (-3,4)            | [(11,22),(33,44)]             |       22.803508502
+ (-3,4)            | [(-10,2),(-10,3)]             |      7.07106781187
+ (-3,4)            | [(0,-20),(30,-20)]            |      24.1867732449
+ (-3,4)            | [(NaN,1),(NaN,90)]            |                NaN
+ (5.1,34.5)        | [(1,2),(3,4)]                 |      30.5722096028
+ (5.1,34.5)        | [(0,0),(6,6)]                 |      28.5142069853
+ (5.1,34.5)        | [(10,-10),(-3,-4)]            |      39.3428519556
+ (5.1,34.5)        | [(-1000000,200),(300000,-40)] |      19.1163258281
+ (5.1,34.5)        | [(11,22),(33,44)]             |      13.0107647738
+ (5.1,34.5)        | [(-10,2),(-10,3)]             |       34.932220084
+ (5.1,34.5)        | [(0,-20),(30,-20)]            |               54.5
+ (5.1,34.5)        | [(NaN,1),(NaN,90)]            |                NaN
+ (-5,-12)          | [(1,2),(3,4)]                 |      15.2315462117
+ (-5,-12)          | [(0,0),(6,6)]                 |                 13
+ (-5,-12)          | [(10,-10),(-3,-4)]            |      8.10179143093
+ (-5,-12)          | [(-1000000,200),(300000,-40)] |      27.3855379949
+ (-5,-12)          | [(11,22),(33,44)]             |      37.5765884561
+ (-5,-12)          | [(-10,2),(-10,3)]             |      14.8660687473
+ (-5,-12)          | [(0,-20),(30,-20)]            |      9.43398113206
+ (-5,-12)          | [(NaN,1),(NaN,90)]            |                NaN
+ (1e-300,-1e-300)  | [(1,2),(3,4)]                 |       2.2360679775
+ (1e-300,-1e-300)  | [(0,0),(6,6)]                 | 1.41421356237e-300
+ (1e-300,-1e-300)  | [(10,-10),(-3,-4)]            |      4.88901207039
+ (1e-300,-1e-300)  | [(-1000000,200),(300000,-40)] |      15.3846151224
+ (1e-300,-1e-300)  | [(11,22),(33,44)]             |      24.5967477525
+ (1e-300,-1e-300)  | [(-10,2),(-10,3)]             |      10.1980390272
+ (1e-300,-1e-300)  | [(0,-20),(30,-20)]            |                 20
+ (1e-300,-1e-300)  | [(NaN,1),(NaN,90)]            |                NaN
+ (1e+300,Infinity) | [(1,2),(3,4)]                 |           Infinity
+ (1e+300,Infinity) | [(0,0),(6,6)]                 |           Infinity
+ (1e+300,Infinity) | [(10,-10),(-3,-4)]            |           Infinity
+ (1e+300,Infinity) | [(-1000000,200),(300000,-40)] |           Infinity
+ (1e+300,Infinity) | [(11,22),(33,44)]             |           Infinity
+ (1e+300,Infinity) | [(-10,2),(-10,3)]             |           Infinity
+ (1e+300,Infinity) | [(0,-20),(30,-20)]            |           Infinity
+ (1e+300,Infinity) | [(NaN,1),(NaN,90)]            |           Infinity
+ (NaN,NaN)         | [(1,2),(3,4)]                 |                NaN
+ (NaN,NaN)         | [(0,0),(6,6)]                 |                NaN
+ (NaN,NaN)         | [(10,-10),(-3,-4)]            |                NaN
+ (NaN,NaN)         | [(-1000000,200),(300000,-40)] |                NaN
+ (NaN,NaN)         | [(11,22),(33,44)]             |                NaN
+ (NaN,NaN)         | [(-10,2),(-10,3)]             |                NaN
+ (NaN,NaN)         | [(0,-20),(30,-20)]            |                NaN
+ (NaN,NaN)         | [(NaN,1),(NaN,90)]            |                NaN
+ (10,10)           | [(1,2),(3,4)]                 |      9.21954445729
+ (10,10)           | [(0,0),(6,6)]                 |      5.65685424949
+ (10,10)           | [(10,-10),(-3,-4)]            |        18.15918769
+ (10,10)           | [(-1000000,200),(300000,-40)] |      5.38276913904
+ (10,10)           | [(11,22),(33,44)]             |      12.0415945788
+ (10,10)           | [(-10,2),(-10,3)]             |      21.1896201004
+ (10,10)           | [(0,-20),(30,-20)]            |                 30
+ (10,10)           | [(NaN,1),(NaN,90)]            |                NaN
+(72 rows)
+
+-- Distance to box
+SELECT p.f1, b.f1, p.f1 <-> b.f1 FROM POINT_TBL p, BOX_TBL b;
+        f1         |         f1          |      ?column?      
+-------------------+---------------------+--------------------
+ (0,0)             | (2,2),(0,0)         |                  0
+ (0,0)             | (3,3),(1,1)         |      1.41421356237
+ (0,0)             | (-2,2),(-8,-10)     |                  2
+ (0,0)             | (2.5,3.5),(2.5,2.5) |      3.53553390593
+ (0,0)             | (3,3),(3,3)         |      4.24264068712
+ (-10,0)           | (2,2),(0,0)         |                 10
+ (-10,0)           | (3,3),(1,1)         |      11.0453610172
+ (-10,0)           | (-2,2),(-8,-10)     |                  2
+ (-10,0)           | (2.5,3.5),(2.5,2.5) |       12.747548784
+ (-10,0)           | (3,3),(3,3)         |      13.3416640641
+ (-3,4)            | (2,2),(0,0)         |      3.60555127546
+ (-3,4)            | (3,3),(1,1)         |      4.12310562562
+ (-3,4)            | (-2,2),(-8,-10)     |                  2
+ (-3,4)            | (2.5,3.5),(2.5,2.5) |      5.52268050859
+ (-3,4)            | (3,3),(3,3)         |       6.0827625303
+ (5.1,34.5)        | (2,2),(0,0)         |      32.6475113906
+ (5.1,34.5)        | (3,3),(1,1)         |      31.5699223946
+ (5.1,34.5)        | (-2,2),(-8,-10)     |      33.2664996656
+ (5.1,34.5)        | (2.5,3.5),(2.5,2.5) |       31.108841187
+ (5.1,34.5)        | (3,3),(3,3)         |      31.5699223946
+ (-5,-12)          | (2,2),(0,0)         |                 13
+ (-5,-12)          | (3,3),(1,1)         |      14.3178210633
+ (-5,-12)          | (-2,2),(-8,-10)     |                  2
+ (-5,-12)          | (2.5,3.5),(2.5,2.5) |      16.3248277173
+ (-5,-12)          | (3,3),(3,3)         |                 17
+ (1e-300,-1e-300)  | (2,2),(0,0)         | 1.41421356237e-300
+ (1e-300,-1e-300)  | (3,3),(1,1)         |      1.41421356237
+ (1e-300,-1e-300)  | (-2,2),(-8,-10)     |                  2
+ (1e-300,-1e-300)  | (2.5,3.5),(2.5,2.5) |      3.53553390593
+ (1e-300,-1e-300)  | (3,3),(3,3)         |      4.24264068712
+ (1e+300,Infinity) | (2,2),(0,0)         |           Infinity
+ (1e+300,Infinity) | (3,3),(1,1)         |           Infinity
+ (1e+300,Infinity) | (-2,2),(-8,-10)     |           Infinity
+ (1e+300,Infinity) | (2.5,3.5),(2.5,2.5) |           Infinity
+ (1e+300,Infinity) | (3,3),(3,3)         |           Infinity
+ (NaN,NaN)         | (2,2),(0,0)         |                NaN
+ (NaN,NaN)         | (3,3),(1,1)         |                NaN
+ (NaN,NaN)         | (-2,2),(-8,-10)     |                NaN
+ (NaN,NaN)         | (2.5,3.5),(2.5,2.5) |                NaN
+ (NaN,NaN)         | (3,3),(3,3)         |                NaN
+ (10,10)           | (2,2),(0,0)         |       11.313708499
+ (10,10)           | (3,3),(1,1)         |      9.89949493661
+ (10,10)           | (-2,2),(-8,-10)     |      14.4222051019
+ (10,10)           | (2.5,3.5),(2.5,2.5) |      9.92471662064
+ (10,10)           | (3,3),(3,3)         |      9.89949493661
+(45 rows)
+
+-- Distance to path
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, PATH_TBL p1;
+        f1         |            f1             |      ?column?      
+-------------------+---------------------------+--------------------
+ (0,0)             | [(1,2),(3,4)]             |       2.2360679775
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | [(0,0),(3,0),(4,5),(1,6)] |                  0
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | [(1,2),(3,4)]             |       2.2360679775
+ (0,0)             | ((10,20))                 |       22.360679775
+ (0,0)             | [(11,12),(13,14)]         |      16.2788205961
+ (0,0)             | ((11,12),(13,14))         |      16.2788205961
+ (-10,0)           | [(1,2),(3,4)]             |      11.1803398875
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | [(0,0),(3,0),(4,5),(1,6)] |                 10
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | [(1,2),(3,4)]             |      11.1803398875
+ (-10,0)           | ((10,20))                 |      28.2842712475
+ (-10,0)           | [(11,12),(13,14)]         |      24.1867732449
+ (-10,0)           | ((11,12),(13,14))         |      24.1867732449
+ (-3,4)            | [(1,2),(3,4)]             |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | [(0,0),(3,0),(4,5),(1,6)] |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | [(1,2),(3,4)]             |        4.472135955
+ (-3,4)            | ((10,20))                 |      20.6155281281
+ (-3,4)            | [(11,12),(13,14)]         |      16.1245154966
+ (-3,4)            | ((11,12),(13,14))         |      16.1245154966
+ (5.1,34.5)        | [(1,2),(3,4)]             |      30.5722096028
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | [(0,0),(3,0),(4,5),(1,6)] |       28.793402022
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | [(1,2),(3,4)]             |      30.5722096028
+ (5.1,34.5)        | ((10,20))                 |      15.3055545473
+ (5.1,34.5)        | [(11,12),(13,14)]         |      21.9695243462
+ (5.1,34.5)        | ((11,12),(13,14))         |      21.9695243462
+ (-5,-12)          | [(1,2),(3,4)]             |      15.2315462117
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | [(0,0),(3,0),(4,5),(1,6)] |                 13
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | [(1,2),(3,4)]             |      15.2315462117
+ (-5,-12)          | ((10,20))                 |      35.3411940941
+ (-5,-12)          | [(11,12),(13,14)]         |      28.8444102037
+ (-5,-12)          | ((11,12),(13,14))         |      28.8444102037
+ (1e-300,-1e-300)  | [(1,2),(3,4)]             |       2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | [(0,0),(3,0),(4,5),(1,6)] | 1.41421356237e-300
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | [(1,2),(3,4)]             |       2.2360679775
+ (1e-300,-1e-300)  | ((10,20))                 |       22.360679775
+ (1e-300,-1e-300)  | [(11,12),(13,14)]         |      16.2788205961
+ (1e-300,-1e-300)  | ((11,12),(13,14))         |      16.2788205961
+ (1e+300,Infinity) | [(1,2),(3,4)]             |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | [(0,0),(3,0),(4,5),(1,6)] |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | [(1,2),(3,4)]             |           Infinity
+ (1e+300,Infinity) | ((10,20))                 |           Infinity
+ (1e+300,Infinity) | [(11,12),(13,14)]         |           Infinity
+ (1e+300,Infinity) | ((11,12),(13,14))         |           Infinity
+ (NaN,NaN)         | [(1,2),(3,4)]             |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | [(0,0),(3,0),(4,5),(1,6)] |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | [(1,2),(3,4)]             |                NaN
+ (NaN,NaN)         | ((10,20))                 |                NaN
+ (NaN,NaN)         | [(11,12),(13,14)]         |                NaN
+ (NaN,NaN)         | ((11,12),(13,14))         |                NaN
+ (10,10)           | [(1,2),(3,4)]             |      9.21954445729
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | [(0,0),(3,0),(4,5),(1,6)] |      7.81024967591
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | [(1,2),(3,4)]             |      9.21954445729
+ (10,10)           | ((10,20))                 |                 10
+ (10,10)           | [(11,12),(13,14)]         |       2.2360679775
+ (10,10)           | ((11,12),(13,14))         |       2.2360679775
+(81 rows)
+
+-- Distance to polygon
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, POLYGON_TBL p1;
+        f1         |             f1             |   ?column?    
+-------------------+----------------------------+---------------
+ (0,0)             | ((2,0),(2,4),(0,0))        |             0
+ (0,0)             | ((3,1),(3,3),(1,0))        |             1
+ (0,0)             | ((1,2),(3,4),(5,6),(7,8))  |  2.2360679775
+ (0,0)             | ((7,8),(5,6),(3,4),(1,2))  |  2.2360679775
+ (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | 1.58113883008
+ (0,0)             | ((0,0))                    |             0
+ (0,0)             | ((0,1),(0,1))              |             1
+ (-10,0)           | ((2,0),(2,4),(0,0))        |            10
+ (-10,0)           | ((3,1),(3,3),(1,0))        |            11
+ (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | 11.1803398875
+ (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | 11.1803398875
+ (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | 11.1803398875
+ (-10,0)           | ((0,0))                    |            10
+ (-10,0)           | ((0,1),(0,1))              | 10.0498756211
+ (-3,4)            | ((2,0),(2,4),(0,0))        |   4.472135955
+ (-3,4)            | ((3,1),(3,3),(1,0))        | 5.54700196225
+ (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  |   4.472135955
+ (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  |   4.472135955
+ (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) |   4.472135955
+ (-3,4)            | ((0,0))                    |             5
+ (-3,4)            | ((0,1),(0,1))              | 4.24264068712
+ (5.1,34.5)        | ((2,0),(2,4),(0,0))        | 30.6571362002
+ (5.1,34.5)        | ((3,1),(3,3),(1,0))        | 31.5699223946
+ (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | 26.5680258958
+ (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | 26.5680258958
+ (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | 26.5680258958
+ (5.1,34.5)        | ((0,0))                    | 34.8749193547
+ (5.1,34.5)        | ((0,1),(0,1))              | 33.8859853037
+ (-5,-12)          | ((2,0),(2,4),(0,0))        |            13
+ (-5,-12)          | ((3,1),(3,3),(1,0))        |  13.416407865
+ (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | 15.2315462117
+ (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | 15.2315462117
+ (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) |  11.313708499
+ (-5,-12)          | ((0,0))                    |            13
+ (-5,-12)          | ((0,1),(0,1))              | 13.9283882772
+ (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        |             0
+ (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        |             1
+ (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  |  2.2360679775
+ (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  |  2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | 1.58113883008
+ (1e-300,-1e-300)  | ((0,0))                    |             0
+ (1e-300,-1e-300)  | ((0,1),(0,1))              |             1
+ (1e+300,Infinity) | ((2,0),(2,4),(0,0))        |      Infinity
+ (1e+300,Infinity) | ((3,1),(3,3),(1,0))        |      Infinity
+ (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  |      Infinity
+ (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  |      Infinity
+ (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) |      Infinity
+ (1e+300,Infinity) | ((0,0))                    |      Infinity
+ (1e+300,Infinity) | ((0,1),(0,1))              |      Infinity
+ (NaN,NaN)         | ((2,0),(2,4),(0,0))        |             0
+ (NaN,NaN)         | ((3,1),(3,3),(1,0))        |             0
+ (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  |             0
+ (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  |             0
+ (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) |             0
+ (NaN,NaN)         | ((0,0))                    |             0
+ (NaN,NaN)         | ((0,1),(0,1))              |             0
+ (10,10)           | ((2,0),(2,4),(0,0))        |            10
+ (10,10)           | ((3,1),(3,3),(1,0))        | 9.89949493661
+ (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | 3.60555127546
+ (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | 3.60555127546
+ (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | 3.60555127546
+ (10,10)           | ((0,0))                    | 14.1421356237
+ (10,10)           | ((0,1),(0,1))              | 13.4536240471
+(63 rows)
+
+-- Closest point to line
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LINE_TBL l;
+        f1         |                   s                   |             ?column?             
+-------------------+---------------------------------------+----------------------------------
+ (0,0)             | {0,-1,5}                              | (0,5)
+ (0,0)             | {1,0,5}                               | (-5,0)
+ (0,0)             | {0,3,0}                               | (0,0)
+ (0,0)             | {1,-1,0}                              | (0,0)
+ (0,0)             | {-0.4,-1,-6}                          | (-2.06896551724,-5.1724137931)
+ (0,0)             | {-0.000184615384615,-1,15.3846153846} | (0.00284023658959,15.3846148603)
+ (0,0)             | {3,NaN,5}                             | 
+ (0,0)             | {NaN,NaN,NaN}                         | 
+ (0,0)             | {0,-1,3}                              | (0,3)
+ (0,0)             | {-1,0,3}                              | (3,0)
+ (-10,0)           | {0,-1,5}                              | (-10,5)
+ (-10,0)           | {1,0,5}                               | (-5,0)
+ (-10,0)           | {0,3,0}                               | (-10,0)
+ (-10,0)           | {1,-1,0}                              | (-5,-5)
+ (-10,0)           | {-0.4,-1,-6}                          | (-10.6896551724,-1.72413793103)
+ (-10,0)           | {-0.000184615384615,-1,15.3846153846} | (-9.99715942258,15.386461014)
+ (-10,0)           | {3,NaN,5}                             | 
+ (-10,0)           | {NaN,NaN,NaN}                         | 
+ (-10,0)           | {0,-1,3}                              | (-10,3)
+ (-10,0)           | {-1,0,3}                              | (3,0)
+ (-3,4)            | {0,-1,5}                              | (-3,5)
+ (-3,4)            | {1,0,5}                               | (-5,4)
+ (-3,4)            | {0,3,0}                               | (-3,0)
+ (-3,4)            | {1,-1,0}                              | (0.5,0.5)
+ (-3,4)            | {-0.4,-1,-6}                          | (-6.03448275862,-3.58620689655)
+ (-3,4)            | {-0.000184615384615,-1,15.3846153846} | (-2.99789812268,15.3851688427)
+ (-3,4)            | {3,NaN,5}                             | 
+ (-3,4)            | {NaN,NaN,NaN}                         | 
+ (-3,4)            | {0,-1,3}                              | (-3,3)
+ (-3,4)            | {-1,0,3}                              | (3,4)
+ (5.1,34.5)        | {0,-1,5}                              | (5.1,5)
+ (5.1,34.5)        | {1,0,5}                               | (-5,34.5)
+ (5.1,34.5)        | {0,3,0}                               | (5.1,0)
+ (5.1,34.5)        | {1,-1,0}                              | (19.8,19.8)
+ (5.1,34.5)        | {-0.4,-1,-6}                          | (-9.56896551724,-2.1724137931)
+ (5.1,34.5)        | {-0.000184615384615,-1,15.3846153846} | (5.09647083221,15.3836744977)
+ (5.1,34.5)        | {3,NaN,5}                             | 
+ (5.1,34.5)        | {NaN,NaN,NaN}                         | 
+ (5.1,34.5)        | {0,-1,3}                              | (5.1,3)
+ (5.1,34.5)        | {-1,0,3}                              | (3,34.5)
+ (-5,-12)          | {0,-1,5}                              | (-5,5)
+ (-5,-12)          | {1,0,5}                               | (-5,-12)
+ (-5,-12)          | {0,3,0}                               | (-5,0)
+ (-5,-12)          | {1,-1,0}                              | (-8.5,-8.5)
+ (-5,-12)          | {-0.4,-1,-6}                          | (-2.24137931034,-5.10344827586)
+ (-5,-12)          | {-0.000184615384615,-1,15.3846153846} | (-4.99494420846,15.3855375282)
+ (-5,-12)          | {3,NaN,5}                             | 
+ (-5,-12)          | {NaN,NaN,NaN}                         | 
+ (-5,-12)          | {0,-1,3}                              | (-5,3)
+ (-5,-12)          | {-1,0,3}                              | (3,-12)
+ (1e-300,-1e-300)  | {0,-1,5}                              | (1e-300,5)
+ (1e-300,-1e-300)  | {1,0,5}                               | (-5,-1e-300)
+ (1e-300,-1e-300)  | {0,3,0}                               | (1e-300,0)
+ (1e-300,-1e-300)  | {1,-1,0}                              | (0,0)
+ (1e-300,-1e-300)  | {-0.4,-1,-6}                          | (-2.06896551724,-5.1724137931)
+ (1e-300,-1e-300)  | {-0.000184615384615,-1,15.3846153846} | (0.00284023658959,15.3846148603)
+ (1e-300,-1e-300)  | {3,NaN,5}                             | 
+ (1e-300,-1e-300)  | {NaN,NaN,NaN}                         | 
+ (1e-300,-1e-300)  | {0,-1,3}                              | (1e-300,3)
+ (1e-300,-1e-300)  | {-1,0,3}                              | (3,-1e-300)
+ (1e+300,Infinity) | {0,-1,5}                              | (1e+300,5)
+ (1e+300,Infinity) | {1,0,5}                               | 
+ (1e+300,Infinity) | {0,3,0}                               | (1e+300,0)
+ (1e+300,Infinity) | {1,-1,0}                              | (Infinity,NaN)
+ (1e+300,Infinity) | {-0.4,-1,-6}                          | (-Infinity,NaN)
+ (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} | (-Infinity,NaN)
+ (1e+300,Infinity) | {3,NaN,5}                             | 
+ (1e+300,Infinity) | {NaN,NaN,NaN}                         | 
+ (1e+300,Infinity) | {0,-1,3}                              | (1e+300,3)
+ (1e+300,Infinity) | {-1,0,3}                              | 
+ (NaN,NaN)         | {0,-1,5}                              | 
+ (NaN,NaN)         | {1,0,5}                               | 
+ (NaN,NaN)         | {0,3,0}                               | 
+ (NaN,NaN)         | {1,-1,0}                              | 
+ (NaN,NaN)         | {-0.4,-1,-6}                          | 
+ (NaN,NaN)         | {-0.000184615384615,-1,15.3846153846} | 
+ (NaN,NaN)         | {3,NaN,5}                             | 
+ (NaN,NaN)         | {NaN,NaN,NaN}                         | 
+ (NaN,NaN)         | {0,-1,3}                              | 
+ (NaN,NaN)         | {-1,0,3}                              | 
+ (10,10)           | {0,-1,5}                              | (10,5)
+ (10,10)           | {1,0,5}                               | (-5,10)
+ (10,10)           | {0,3,0}                               | (10,0)
+ (10,10)           | {1,-1,0}                              | (10,10)
+ (10,10)           | {-0.4,-1,-6}                          | (3.10344827586,-7.24137931034)
+ (10,10)           | {-0.000184615384615,-1,15.3846153846} | (10.000993742,15.3827690473)
+ (10,10)           | {3,NaN,5}                             | 
+ (10,10)           | {NaN,NaN,NaN}                         | 
+ (10,10)           | {0,-1,3}                              | (10,3)
+ (10,10)           | {-1,0,3}                              | (3,10)
+(90 rows)
+
+-- Closest point to line segment
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LSEG_TBL l;
+        f1         |               s               |             ?column?             
+-------------------+-------------------------------+----------------------------------
+ (0,0)             | [(1,2),(3,4)]                 | (1,2)
+ (0,0)             | [(0,0),(6,6)]                 | (0,0)
+ (0,0)             | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ (0,0)             | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
+ (0,0)             | [(11,22),(33,44)]             | (11,22)
+ (0,0)             | [(-10,2),(-10,3)]             | (-10,2)
+ (0,0)             | [(0,-20),(30,-20)]            | (0,-20)
+ (0,0)             | [(NaN,1),(NaN,90)]            | 
+ (-10,0)           | [(1,2),(3,4)]                 | (1,2)
+ (-10,0)           | [(0,0),(6,6)]                 | (0,0)
+ (-10,0)           | [(10,-10),(-3,-4)]            | (-3,-4)
+ (-10,0)           | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
+ (-10,0)           | [(11,22),(33,44)]             | (11,22)
+ (-10,0)           | [(-10,2),(-10,3)]             | (-10,2)
+ (-10,0)           | [(0,-20),(30,-20)]            | (0,-20)
+ (-10,0)           | [(NaN,1),(NaN,90)]            | 
+ (-3,4)            | [(1,2),(3,4)]                 | (1,2)
+ (-3,4)            | [(0,0),(6,6)]                 | (0.5,0.5)
+ (-3,4)            | [(10,-10),(-3,-4)]            | (-3,-4)
+ (-3,4)            | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
+ (-3,4)            | [(11,22),(33,44)]             | (11,22)
+ (-3,4)            | [(-10,2),(-10,3)]             | (-10,3)
+ (-3,4)            | [(0,-20),(30,-20)]            | (0,-20)
+ (-3,4)            | [(NaN,1),(NaN,90)]            | 
+ (5.1,34.5)        | [(1,2),(3,4)]                 | (3,4)
+ (5.1,34.5)        | [(0,0),(6,6)]                 | (6,6)
+ (5.1,34.5)        | [(10,-10),(-3,-4)]            | (-3,-4)
+ (5.1,34.5)        | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
+ (5.1,34.5)        | [(11,22),(33,44)]             | (14.3,25.3)
+ (5.1,34.5)        | [(-10,2),(-10,3)]             | (-10,3)
+ (5.1,34.5)        | [(0,-20),(30,-20)]            | (5.1,-20)
+ (5.1,34.5)        | [(NaN,1),(NaN,90)]            | 
+ (-5,-12)          | [(1,2),(3,4)]                 | (1,2)
+ (-5,-12)          | [(0,0),(6,6)]                 | (0,0)
+ (-5,-12)          | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
+ (-5,-12)          | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
+ (-5,-12)          | [(11,22),(33,44)]             | (11,22)
+ (-5,-12)          | [(-10,2),(-10,3)]             | (-10,2)
+ (-5,-12)          | [(0,-20),(30,-20)]            | (0,-20)
+ (-5,-12)          | [(NaN,1),(NaN,90)]            | 
+ (1e-300,-1e-300)  | [(1,2),(3,4)]                 | (1,2)
+ (1e-300,-1e-300)  | [(0,0),(6,6)]                 | (0,0)
+ (1e-300,-1e-300)  | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ (1e-300,-1e-300)  | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
+ (1e-300,-1e-300)  | [(11,22),(33,44)]             | (11,22)
+ (1e-300,-1e-300)  | [(-10,2),(-10,3)]             | (-10,2)
+ (1e-300,-1e-300)  | [(0,-20),(30,-20)]            | (0,-20)
+ (1e-300,-1e-300)  | [(NaN,1),(NaN,90)]            | 
+ (1e+300,Infinity) | [(1,2),(3,4)]                 | (3,4)
+ (1e+300,Infinity) | [(0,0),(6,6)]                 | (6,6)
+ (1e+300,Infinity) | [(10,-10),(-3,-4)]            | (-3,-4)
+ (1e+300,Infinity) | [(-1000000,200),(300000,-40)] | (300000,-40)
+ (1e+300,Infinity) | [(11,22),(33,44)]             | (33,44)
+ (1e+300,Infinity) | [(-10,2),(-10,3)]             | (-10,3)
+ (1e+300,Infinity) | [(0,-20),(30,-20)]            | (30,-20)
+ (1e+300,Infinity) | [(NaN,1),(NaN,90)]            | (NaN,90)
+ (NaN,NaN)         | [(1,2),(3,4)]                 | 
+ (NaN,NaN)         | [(0,0),(6,6)]                 | 
+ (NaN,NaN)         | [(10,-10),(-3,-4)]            | 
+ (NaN,NaN)         | [(-1000000,200),(300000,-40)] | 
+ (NaN,NaN)         | [(11,22),(33,44)]             | 
+ (NaN,NaN)         | [(-10,2),(-10,3)]             | 
+ (NaN,NaN)         | [(0,-20),(30,-20)]            | 
+ (NaN,NaN)         | [(NaN,1),(NaN,90)]            | 
+ (10,10)           | [(1,2),(3,4)]                 | (3,4)
+ (10,10)           | [(0,0),(6,6)]                 | (6,6)
+ (10,10)           | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
+ (10,10)           | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
+ (10,10)           | [(11,22),(33,44)]             | (11,22)
+ (10,10)           | [(-10,2),(-10,3)]             | (-10,3)
+ (10,10)           | [(0,-20),(30,-20)]            | (10,-20)
+ (10,10)           | [(NaN,1),(NaN,90)]            | 
+(72 rows)
+
+-- Closest point to box
+SELECT p.f1, b.f1, p.f1 ## b.f1 FROM POINT_TBL p, BOX_TBL b;
+        f1         |         f1          |   ?column?   
+-------------------+---------------------+--------------
+ (0,0)             | (2,2),(0,0)         | (0,0)
+ (0,0)             | (3,3),(1,1)         | (1,1)
+ (0,0)             | (-2,2),(-8,-10)     | (-2,0)
+ (0,0)             | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (0,0)             | (3,3),(3,3)         | (3,3)
+ (-10,0)           | (2,2),(0,0)         | (0,0)
+ (-10,0)           | (3,3),(1,1)         | (1,1)
+ (-10,0)           | (-2,2),(-8,-10)     | (-8,0)
+ (-10,0)           | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (-10,0)           | (3,3),(3,3)         | (3,3)
+ (-3,4)            | (2,2),(0,0)         | (0,2)
+ (-3,4)            | (3,3),(1,1)         | (1,3)
+ (-3,4)            | (-2,2),(-8,-10)     | (-3,2)
+ (-3,4)            | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (-3,4)            | (3,3),(3,3)         | (3,3)
+ (5.1,34.5)        | (2,2),(0,0)         | (2,2)
+ (5.1,34.5)        | (3,3),(1,1)         | (3,3)
+ (5.1,34.5)        | (-2,2),(-8,-10)     | (-2,2)
+ (5.1,34.5)        | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (5.1,34.5)        | (3,3),(3,3)         | (3,3)
+ (-5,-12)          | (2,2),(0,0)         | (0,0)
+ (-5,-12)          | (3,3),(1,1)         | (1,1)
+ (-5,-12)          | (-2,2),(-8,-10)     | (-5,-10)
+ (-5,-12)          | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (-5,-12)          | (3,3),(3,3)         | (3,3)
+ (1e-300,-1e-300)  | (2,2),(0,0)         | (0,0)
+ (1e-300,-1e-300)  | (3,3),(1,1)         | (1,1)
+ (1e-300,-1e-300)  | (-2,2),(-8,-10)     | (-2,-1e-300)
+ (1e-300,-1e-300)  | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (1e-300,-1e-300)  | (3,3),(3,3)         | (3,3)
+ (1e+300,Infinity) | (2,2),(0,0)         | (0,2)
+ (1e+300,Infinity) | (3,3),(1,1)         | (1,3)
+ (1e+300,Infinity) | (-2,2),(-8,-10)     | (-8,2)
+ (1e+300,Infinity) | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (1e+300,Infinity) | (3,3),(3,3)         | (3,3)
+ (NaN,NaN)         | (2,2),(0,0)         | 
+ (NaN,NaN)         | (3,3),(1,1)         | 
+ (NaN,NaN)         | (-2,2),(-8,-10)     | 
+ (NaN,NaN)         | (2.5,3.5),(2.5,2.5) | 
+ (NaN,NaN)         | (3,3),(3,3)         | 
+ (10,10)           | (2,2),(0,0)         | (2,2)
+ (10,10)           | (3,3),(1,1)         | (3,3)
+ (10,10)           | (-2,2),(-8,-10)     | (-2,2)
+ (10,10)           | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (10,10)           | (3,3),(3,3)         | (3,3)
+(45 rows)
+
+-- On line
+SELECT p.f1, l.s FROM POINT_TBL p, LINE_TBL l WHERE p.f1 <@ l.s;
+        f1        |    s     
+------------------+----------
+ (0,0)            | {0,3,0}
+ (0,0)            | {1,-1,0}
+ (-10,0)          | {0,3,0}
+ (-5,-12)         | {1,0,5}
+ (1e-300,-1e-300) | {0,3,0}
+ (1e-300,-1e-300) | {1,-1,0}
+ (10,10)          | {1,-1,0}
+(7 rows)
+
+-- On line segment
+SELECT p.f1, l.s FROM POINT_TBL p, LSEG_TBL l WHERE p.f1 <@ l.s;
+        f1        |       s       
+------------------+---------------
+ (0,0)            | [(0,0),(6,6)]
+ (1e-300,-1e-300) | [(0,0),(6,6)]
+(2 rows)
+
+-- On path
+SELECT p.f1, p1.f1 FROM POINT_TBL p, PATH_TBL p1 WHERE p.f1 <@ p1.f1;
+        f1        |            f1             
+------------------+---------------------------
+ (0,0)            | [(0,0),(3,0),(4,5),(1,6)]
+ (1e-300,-1e-300) | [(0,0),(3,0),(4,5),(1,6)]
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((10,20))
+ (NaN,NaN)        | ((11,12),(13,14))
+(7 rows)
+
+--
+-- Lines
+--
+-- Vertical
+SELECT s FROM LINE_TBL WHERE ?| s;
+    s     
+----------
+ {1,0,5}
+ {-1,0,3}
+(2 rows)
+
+-- Horizontal
+SELECT s FROM LINE_TBL WHERE ?- s;
+    s     
+----------
+ {0,-1,5}
+ {0,3,0}
+ {0,-1,3}
+(3 rows)
+
+-- Same as line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s = l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {0,-1,5}
+ {1,0,5}                               | {1,0,5}
+ {0,3,0}                               | {0,3,0}
+ {1,-1,0}                              | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846}
+ {3,NaN,5}                             | {3,NaN,5}
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}
+ {0,-1,3}                              | {0,-1,3}
+ {-1,0,3}                              | {-1,0,3}
+(10 rows)
+
+-- Parallel to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?|| l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {0,-1,5}
+ {0,-1,5}                              | {0,3,0}
+ {0,-1,5}                              | {0,-1,3}
+ {1,0,5}                               | {1,0,5}
+ {1,0,5}                               | {-1,0,3}
+ {0,3,0}                               | {0,-1,5}
+ {0,3,0}                               | {0,3,0}
+ {0,3,0}                               | {0,-1,3}
+ {1,-1,0}                              | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,3}                              | {0,-1,5}
+ {0,-1,3}                              | {0,3,0}
+ {0,-1,3}                              | {0,-1,3}
+ {-1,0,3}                              | {1,0,5}
+ {-1,0,3}                              | {-1,0,3}
+(16 rows)
+
+-- Perpendicular to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?-| l2.s;
+    s     |    s     
+----------+----------
+ {0,-1,5} | {1,0,5}
+ {0,-1,5} | {-1,0,3}
+ {1,0,5}  | {0,-1,5}
+ {1,0,5}  | {0,3,0}
+ {1,0,5}  | {0,-1,3}
+ {0,3,0}  | {1,0,5}
+ {0,3,0}  | {-1,0,3}
+ {0,-1,3} | {1,0,5}
+ {0,-1,3} | {-1,0,3}
+ {-1,0,3} | {0,-1,5}
+ {-1,0,3} | {0,3,0}
+ {-1,0,3} | {0,-1,3}
+(12 rows)
+
+-- Distance to line
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2;
+                   s                   |                   s                   | ?column? 
+---------------------------------------+---------------------------------------+----------
+ {0,-1,5}                              | {0,-1,5}                              |        0
+ {0,-1,5}                              | {1,0,5}                               |        0
+ {0,-1,5}                              | {0,3,0}                               |        5
+ {0,-1,5}                              | {1,-1,0}                              |        0
+ {0,-1,5}                              | {-0.4,-1,-6}                          |        0
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,-1,5}                              | {3,NaN,5}                             |        0
+ {0,-1,5}                              | {NaN,NaN,NaN}                         |        0
+ {0,-1,5}                              | {0,-1,3}                              |        2
+ {0,-1,5}                              | {-1,0,3}                              |        0
+ {1,0,5}                               | {0,-1,5}                              |        0
+ {1,0,5}                               | {1,0,5}                               |        0
+ {1,0,5}                               | {0,3,0}                               |        0
+ {1,0,5}                               | {1,-1,0}                              |        0
+ {1,0,5}                               | {-0.4,-1,-6}                          |        0
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846} |        0
+ {1,0,5}                               | {3,NaN,5}                             |        0
+ {1,0,5}                               | {NaN,NaN,NaN}                         |        0
+ {1,0,5}                               | {0,-1,3}                              |        0
+ {1,0,5}                               | {-1,0,3}                              |        8
+ {0,3,0}                               | {0,-1,5}                              |        5
+ {0,3,0}                               | {1,0,5}                               |        0
+ {0,3,0}                               | {0,3,0}                               |        0
+ {0,3,0}                               | {1,-1,0}                              |        0
+ {0,3,0}                               | {-0.4,-1,-6}                          |        0
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,3,0}                               | {3,NaN,5}                             |        0
+ {0,3,0}                               | {NaN,NaN,NaN}                         |        0
+ {0,3,0}                               | {0,-1,3}                              |        3
+ {0,3,0}                               | {-1,0,3}                              |        0
+ {1,-1,0}                              | {0,-1,5}                              |        0
+ {1,-1,0}                              | {1,0,5}                               |        0
+ {1,-1,0}                              | {0,3,0}                               |        0
+ {1,-1,0}                              | {1,-1,0}                              |        0
+ {1,-1,0}                              | {-0.4,-1,-6}                          |        0
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {1,-1,0}                              | {3,NaN,5}                             |        0
+ {1,-1,0}                              | {NaN,NaN,NaN}                         |        0
+ {1,-1,0}                              | {0,-1,3}                              |        0
+ {1,-1,0}                              | {-1,0,3}                              |        0
+ {-0.4,-1,-6}                          | {0,-1,5}                              |        0
+ {-0.4,-1,-6}                          | {1,0,5}                               |        0
+ {-0.4,-1,-6}                          | {0,3,0}                               |        0
+ {-0.4,-1,-6}                          | {1,-1,0}                              |        0
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}                          |        0
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846} |        0
+ {-0.4,-1,-6}                          | {3,NaN,5}                             |        0
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}                         |        0
+ {-0.4,-1,-6}                          | {0,-1,3}                              |        0
+ {-0.4,-1,-6}                          | {-1,0,3}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}                               |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}                               |        0
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}                          |        0
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} |        0
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}                             |        0
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}                         |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}                              |        0
+ {3,NaN,5}                             | {0,-1,5}                              |        0
+ {3,NaN,5}                             | {1,0,5}                               |        0
+ {3,NaN,5}                             | {0,3,0}                               |        0
+ {3,NaN,5}                             | {1,-1,0}                              |        0
+ {3,NaN,5}                             | {-0.4,-1,-6}                          |        0
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846} |        0
+ {3,NaN,5}                             | {3,NaN,5}                             |        0
+ {3,NaN,5}                             | {NaN,NaN,NaN}                         |        0
+ {3,NaN,5}                             | {0,-1,3}                              |        0
+ {3,NaN,5}                             | {-1,0,3}                              |        0
+ {NaN,NaN,NaN}                         | {0,-1,5}                              |        0
+ {NaN,NaN,NaN}                         | {1,0,5}                               |        0
+ {NaN,NaN,NaN}                         | {0,3,0}                               |        0
+ {NaN,NaN,NaN}                         | {1,-1,0}                              |        0
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}                          |        0
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846} |        0
+ {NaN,NaN,NaN}                         | {3,NaN,5}                             |        0
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}                         |        0
+ {NaN,NaN,NaN}                         | {0,-1,3}                              |        0
+ {NaN,NaN,NaN}                         | {-1,0,3}                              |        0
+ {0,-1,3}                              | {0,-1,5}                              |        2
+ {0,-1,3}                              | {1,0,5}                               |        0
+ {0,-1,3}                              | {0,3,0}                               |        3
+ {0,-1,3}                              | {1,-1,0}                              |        0
+ {0,-1,3}                              | {-0.4,-1,-6}                          |        0
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,-1,3}                              | {3,NaN,5}                             |        0
+ {0,-1,3}                              | {NaN,NaN,NaN}                         |        0
+ {0,-1,3}                              | {0,-1,3}                              |        0
+ {0,-1,3}                              | {-1,0,3}                              |        0
+ {-1,0,3}                              | {0,-1,5}                              |        0
+ {-1,0,3}                              | {1,0,5}                               |        8
+ {-1,0,3}                              | {0,3,0}                               |        0
+ {-1,0,3}                              | {1,-1,0}                              |        0
+ {-1,0,3}                              | {-0.4,-1,-6}                          |        0
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {-1,0,3}                              | {3,NaN,5}                             |        0
+ {-1,0,3}                              | {NaN,NaN,NaN}                         |        0
+ {-1,0,3}                              | {0,-1,3}                              |        0
+ {-1,0,3}                              | {-1,0,3}                              |        0
+(100 rows)
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LINE_TBL l, BOX_TBL b;
+ERROR:  function "dist_lb" not implemented
+-- Intersect with line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?# l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {1,0,5}
+ {0,-1,5}                              | {1,-1,0}
+ {0,-1,5}                              | {-0.4,-1,-6}
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,5}                              | {3,NaN,5}
+ {0,-1,5}                              | {NaN,NaN,NaN}
+ {0,-1,5}                              | {-1,0,3}
+ {1,0,5}                               | {0,-1,5}
+ {1,0,5}                               | {0,3,0}
+ {1,0,5}                               | {1,-1,0}
+ {1,0,5}                               | {-0.4,-1,-6}
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846}
+ {1,0,5}                               | {3,NaN,5}
+ {1,0,5}                               | {NaN,NaN,NaN}
+ {1,0,5}                               | {0,-1,3}
+ {0,3,0}                               | {1,0,5}
+ {0,3,0}                               | {1,-1,0}
+ {0,3,0}                               | {-0.4,-1,-6}
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846}
+ {0,3,0}                               | {3,NaN,5}
+ {0,3,0}                               | {NaN,NaN,NaN}
+ {0,3,0}                               | {-1,0,3}
+ {1,-1,0}                              | {0,-1,5}
+ {1,-1,0}                              | {1,0,5}
+ {1,-1,0}                              | {0,3,0}
+ {1,-1,0}                              | {-0.4,-1,-6}
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846}
+ {1,-1,0}                              | {3,NaN,5}
+ {1,-1,0}                              | {NaN,NaN,NaN}
+ {1,-1,0}                              | {0,-1,3}
+ {1,-1,0}                              | {-1,0,3}
+ {-0.4,-1,-6}                          | {0,-1,5}
+ {-0.4,-1,-6}                          | {1,0,5}
+ {-0.4,-1,-6}                          | {0,3,0}
+ {-0.4,-1,-6}                          | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846}
+ {-0.4,-1,-6}                          | {3,NaN,5}
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}
+ {-0.4,-1,-6}                          | {0,-1,3}
+ {-0.4,-1,-6}                          | {-1,0,3}
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}
+ {3,NaN,5}                             | {0,-1,5}
+ {3,NaN,5}                             | {1,0,5}
+ {3,NaN,5}                             | {0,3,0}
+ {3,NaN,5}                             | {1,-1,0}
+ {3,NaN,5}                             | {-0.4,-1,-6}
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846}
+ {3,NaN,5}                             | {3,NaN,5}
+ {3,NaN,5}                             | {NaN,NaN,NaN}
+ {3,NaN,5}                             | {0,-1,3}
+ {3,NaN,5}                             | {-1,0,3}
+ {NaN,NaN,NaN}                         | {0,-1,5}
+ {NaN,NaN,NaN}                         | {1,0,5}
+ {NaN,NaN,NaN}                         | {0,3,0}
+ {NaN,NaN,NaN}                         | {1,-1,0}
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846}
+ {NaN,NaN,NaN}                         | {3,NaN,5}
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}
+ {NaN,NaN,NaN}                         | {0,-1,3}
+ {NaN,NaN,NaN}                         | {-1,0,3}
+ {0,-1,3}                              | {1,0,5}
+ {0,-1,3}                              | {1,-1,0}
+ {0,-1,3}                              | {-0.4,-1,-6}
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,3}                              | {3,NaN,5}
+ {0,-1,3}                              | {NaN,NaN,NaN}
+ {0,-1,3}                              | {-1,0,3}
+ {-1,0,3}                              | {0,-1,5}
+ {-1,0,3}                              | {0,3,0}
+ {-1,0,3}                              | {1,-1,0}
+ {-1,0,3}                              | {-0.4,-1,-6}
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846}
+ {-1,0,3}                              | {3,NaN,5}
+ {-1,0,3}                              | {NaN,NaN,NaN}
+ {-1,0,3}                              | {0,-1,3}
+(84 rows)
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LINE_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+      s       |         f1          
+--------------+---------------------
+ {1,0,5}      | (-2,2),(-8,-10)
+ {0,3,0}      | (2,2),(0,0)
+ {0,3,0}      | (-2,2),(-8,-10)
+ {1,-1,0}     | (2,2),(0,0)
+ {1,-1,0}     | (3,3),(1,1)
+ {1,-1,0}     | (-2,2),(-8,-10)
+ {1,-1,0}     | (2.5,3.5),(2.5,2.5)
+ {1,-1,0}     | (3,3),(3,3)
+ {-0.4,-1,-6} | (-2,2),(-8,-10)
+ {0,-1,3}     | (3,3),(1,1)
+ {0,-1,3}     | (2.5,3.5),(2.5,2.5)
+ {0,-1,3}     | (3,3),(3,3)
+ {-1,0,3}     | (3,3),(1,1)
+(13 rows)
+
+-- Intersection point with line
+SELECT l1.s, l2.s, l1.s # l2.s FROM LINE_TBL l1, LINE_TBL l2;
+                   s                   |                   s                   |             ?column?              
+---------------------------------------+---------------------------------------+-----------------------------------
+ {0,-1,5}                              | {0,-1,5}                              | 
+ {0,-1,5}                              | {1,0,5}                               | (-5,5)
+ {0,-1,5}                              | {0,3,0}                               | 
+ {0,-1,5}                              | {1,-1,0}                              | (5,5)
+ {0,-1,5}                              | {-0.4,-1,-6}                          | (-27.5,5)
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846} | (56250,5)
+ {0,-1,5}                              | {3,NaN,5}                             | (NaN,NaN)
+ {0,-1,5}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,-1,5}                              | {0,-1,3}                              | 
+ {0,-1,5}                              | {-1,0,3}                              | (3,5)
+ {1,0,5}                               | {0,-1,5}                              | (-5,5)
+ {1,0,5}                               | {1,0,5}                               | 
+ {1,0,5}                               | {0,3,0}                               | (-5,0)
+ {1,0,5}                               | {1,-1,0}                              | (-5,-5)
+ {1,0,5}                               | {-0.4,-1,-6}                          | (-5,-4)
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846} | (-5,15.3855384615)
+ {1,0,5}                               | {3,NaN,5}                             | (NaN,NaN)
+ {1,0,5}                               | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {1,0,5}                               | {0,-1,3}                              | (-5,3)
+ {1,0,5}                               | {-1,0,3}                              | 
+ {0,3,0}                               | {0,-1,5}                              | 
+ {0,3,0}                               | {1,0,5}                               | (-5,0)
+ {0,3,0}                               | {0,3,0}                               | 
+ {0,3,0}                               | {1,-1,0}                              | (0,0)
+ {0,3,0}                               | {-0.4,-1,-6}                          | (-15,0)
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846} | (83333.3333333,0)
+ {0,3,0}                               | {3,NaN,5}                             | (NaN,NaN)
+ {0,3,0}                               | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,3,0}                               | {0,-1,3}                              | 
+ {0,3,0}                               | {-1,0,3}                              | (3,0)
+ {1,-1,0}                              | {0,-1,5}                              | (5,5)
+ {1,-1,0}                              | {1,0,5}                               | (-5,-5)
+ {1,-1,0}                              | {0,3,0}                               | (0,0)
+ {1,-1,0}                              | {1,-1,0}                              | 
+ {1,-1,0}                              | {-0.4,-1,-6}                          | (-4.28571428571,-4.28571428571)
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846} | (15.3817756722,15.3817756722)
+ {1,-1,0}                              | {3,NaN,5}                             | (NaN,NaN)
+ {1,-1,0}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {1,-1,0}                              | {0,-1,3}                              | (3,3)
+ {1,-1,0}                              | {-1,0,3}                              | (3,3)
+ {-0.4,-1,-6}                          | {0,-1,5}                              | (-27.5,5)
+ {-0.4,-1,-6}                          | {1,0,5}                               | (-5,-4)
+ {-0.4,-1,-6}                          | {0,3,0}                               | (-15,0)
+ {-0.4,-1,-6}                          | {1,-1,0}                              | (-4.28571428571,-4.28571428571)
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}                          | 
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846} | (-53.4862244113,15.3944897645)
+ {-0.4,-1,-6}                          | {3,NaN,5}                             | (NaN,NaN)
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-0.4,-1,-6}                          | {0,-1,3}                              | (-22.5,3)
+ {-0.4,-1,-6}                          | {-1,0,3}                              | (3,-7.2)
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}                              | (56250,5)
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}                               | (-5,15.3855384615)
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}                               | (83333.3333333,-1.7763568394e-15)
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}                              | (15.3817756722,15.3817756722)
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}                          | (-53.4862244113,15.3944897645)
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} | 
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}                             | (NaN,NaN)
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}                              | (67083.3333333,3)
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}                              | (3,15.3840615385)
+ {3,NaN,5}                             | {0,-1,5}                              | (NaN,NaN)
+ {3,NaN,5}                             | {1,0,5}                               | (NaN,NaN)
+ {3,NaN,5}                             | {0,3,0}                               | (NaN,NaN)
+ {3,NaN,5}                             | {1,-1,0}                              | (NaN,NaN)
+ {3,NaN,5}                             | {-0.4,-1,-6}                          | (NaN,NaN)
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ {3,NaN,5}                             | {3,NaN,5}                             | (NaN,NaN)
+ {3,NaN,5}                             | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {3,NaN,5}                             | {0,-1,3}                              | (NaN,NaN)
+ {3,NaN,5}                             | {-1,0,3}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,-1,5}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {1,0,5}                               | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,3,0}                               | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {1,-1,0}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}                          | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {3,NaN,5}                             | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,-1,3}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-1,0,3}                              | (NaN,NaN)
+ {0,-1,3}                              | {0,-1,5}                              | 
+ {0,-1,3}                              | {1,0,5}                               | (-5,3)
+ {0,-1,3}                              | {0,3,0}                               | 
+ {0,-1,3}                              | {1,-1,0}                              | (3,3)
+ {0,-1,3}                              | {-0.4,-1,-6}                          | (-22.5,3)
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846} | (67083.3333333,3)
+ {0,-1,3}                              | {3,NaN,5}                             | (NaN,NaN)
+ {0,-1,3}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,-1,3}                              | {0,-1,3}                              | 
+ {0,-1,3}                              | {-1,0,3}                              | (3,3)
+ {-1,0,3}                              | {0,-1,5}                              | (3,5)
+ {-1,0,3}                              | {1,0,5}                               | 
+ {-1,0,3}                              | {0,3,0}                               | (3,0)
+ {-1,0,3}                              | {1,-1,0}                              | (3,3)
+ {-1,0,3}                              | {-0.4,-1,-6}                          | (3,-7.2)
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846} | (3,15.3840615385)
+ {-1,0,3}                              | {3,NaN,5}                             | (NaN,NaN)
+ {-1,0,3}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-1,0,3}                              | {0,-1,3}                              | (3,3)
+ {-1,0,3}                              | {-1,0,3}                              | 
+(100 rows)
+
+-- Closest point to line segment
+SELECT l.s, l1.s, l.s ## l1.s FROM LINE_TBL l, LSEG_TBL l1;
+                   s                   |               s               |             ?column?              
+---------------------------------------+-------------------------------+-----------------------------------
+ {0,-1,5}                              | [(1,2),(3,4)]                 | (3,4)
+ {0,-1,5}                              | [(0,0),(6,6)]                 | (5,5)
+ {0,-1,5}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,-1,5}                              | [(-1000000,200),(300000,-40)] | (56250,5)
+ {0,-1,5}                              | [(11,22),(33,44)]             | (11,22)
+ {0,-1,5}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {0,-1,5}                              | [(0,-20),(30,-20)]            | 
+ {0,-1,5}                              | [(NaN,1),(NaN,90)]            | 
+ {1,0,5}                               | [(1,2),(3,4)]                 | (1,2)
+ {1,0,5}                               | [(0,0),(6,6)]                 | (0,0)
+ {1,0,5}                               | [(10,-10),(-3,-4)]            | (-3,-4)
+ {1,0,5}                               | [(-1000000,200),(300000,-40)] | (-5,15.3855384615)
+ {1,0,5}                               | [(11,22),(33,44)]             | (11,22)
+ {1,0,5}                               | [(-10,2),(-10,3)]             | 
+ {1,0,5}                               | [(0,-20),(30,-20)]            | (0,-20)
+ {1,0,5}                               | [(NaN,1),(NaN,90)]            | 
+ {0,3,0}                               | [(1,2),(3,4)]                 | (1,2)
+ {0,3,0}                               | [(0,0),(6,6)]                 | (0,0)
+ {0,3,0}                               | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,3,0}                               | [(-1000000,200),(300000,-40)] | (83333.3333333,-1.7763568394e-15)
+ {0,3,0}                               | [(11,22),(33,44)]             | (11,22)
+ {0,3,0}                               | [(-10,2),(-10,3)]             | (-10,2)
+ {0,3,0}                               | [(0,-20),(30,-20)]            | 
+ {0,3,0}                               | [(NaN,1),(NaN,90)]            | 
+ {1,-1,0}                              | [(1,2),(3,4)]                 | 
+ {1,-1,0}                              | [(0,0),(6,6)]                 | 
+ {1,-1,0}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {1,-1,0}                              | [(-1000000,200),(300000,-40)] | (15.3817756722,15.3817756722)
+ {1,-1,0}                              | [(11,22),(33,44)]             | 
+ {1,-1,0}                              | [(-10,2),(-10,3)]             | (-10,2)
+ {1,-1,0}                              | [(0,-20),(30,-20)]            | (0,-20)
+ {1,-1,0}                              | [(NaN,1),(NaN,90)]            | 
+ {-0.4,-1,-6}                          | [(1,2),(3,4)]                 | (1,2)
+ {-0.4,-1,-6}                          | [(0,0),(6,6)]                 | (0,0)
+ {-0.4,-1,-6}                          | [(10,-10),(-3,-4)]            | (10,-10)
+ {-0.4,-1,-6}                          | [(-1000000,200),(300000,-40)] | (-53.4862244113,15.3944897645)
+ {-0.4,-1,-6}                          | [(11,22),(33,44)]             | (11,22)
+ {-0.4,-1,-6}                          | [(-10,2),(-10,3)]             | (-10,2)
+ {-0.4,-1,-6}                          | [(0,-20),(30,-20)]            | (30,-20)
+ {-0.4,-1,-6}                          | [(NaN,1),(NaN,90)]            | 
+ {-0.000184615384615,-1,15.3846153846} | [(1,2),(3,4)]                 | (3,4)
+ {-0.000184615384615,-1,15.3846153846} | [(0,0),(6,6)]                 | (6,6)
+ {-0.000184615384615,-1,15.3846153846} | [(10,-10),(-3,-4)]            | (-3,-4)
+ {-0.000184615384615,-1,15.3846153846} | [(-1000000,200),(300000,-40)] | 
+ {-0.000184615384615,-1,15.3846153846} | [(11,22),(33,44)]             | (11,22)
+ {-0.000184615384615,-1,15.3846153846} | [(-10,2),(-10,3)]             | (-10,3)
+ {-0.000184615384615,-1,15.3846153846} | [(0,-20),(30,-20)]            | (30,-20)
+ {-0.000184615384615,-1,15.3846153846} | [(NaN,1),(NaN,90)]            | 
+ {3,NaN,5}                             | [(1,2),(3,4)]                 | 
+ {3,NaN,5}                             | [(0,0),(6,6)]                 | 
+ {3,NaN,5}                             | [(10,-10),(-3,-4)]            | 
+ {3,NaN,5}                             | [(-1000000,200),(300000,-40)] | 
+ {3,NaN,5}                             | [(11,22),(33,44)]             | 
+ {3,NaN,5}                             | [(-10,2),(-10,3)]             | 
+ {3,NaN,5}                             | [(0,-20),(30,-20)]            | 
+ {3,NaN,5}                             | [(NaN,1),(NaN,90)]            | 
+ {NaN,NaN,NaN}                         | [(1,2),(3,4)]                 | 
+ {NaN,NaN,NaN}                         | [(0,0),(6,6)]                 | 
+ {NaN,NaN,NaN}                         | [(10,-10),(-3,-4)]            | 
+ {NaN,NaN,NaN}                         | [(-1000000,200),(300000,-40)] | 
+ {NaN,NaN,NaN}                         | [(11,22),(33,44)]             | 
+ {NaN,NaN,NaN}                         | [(-10,2),(-10,3)]             | 
+ {NaN,NaN,NaN}                         | [(0,-20),(30,-20)]            | 
+ {NaN,NaN,NaN}                         | [(NaN,1),(NaN,90)]            | 
+ {0,-1,3}                              | [(1,2),(3,4)]                 | (2,3)
+ {0,-1,3}                              | [(0,0),(6,6)]                 | (3,3)
+ {0,-1,3}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,-1,3}                              | [(-1000000,200),(300000,-40)] | (67083.3333333,3)
+ {0,-1,3}                              | [(11,22),(33,44)]             | (11,22)
+ {0,-1,3}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {0,-1,3}                              | [(0,-20),(30,-20)]            | 
+ {0,-1,3}                              | [(NaN,1),(NaN,90)]            | 
+ {-1,0,3}                              | [(1,2),(3,4)]                 | (3,4)
+ {-1,0,3}                              | [(0,0),(6,6)]                 | (3,3)
+ {-1,0,3}                              | [(10,-10),(-3,-4)]            | (3,-6.76923076923)
+ {-1,0,3}                              | [(-1000000,200),(300000,-40)] | (3,15.3840615385)
+ {-1,0,3}                              | [(11,22),(33,44)]             | (11,22)
+ {-1,0,3}                              | [(-10,2),(-10,3)]             | 
+ {-1,0,3}                              | [(0,-20),(30,-20)]            | (3,-20)
+ {-1,0,3}                              | [(NaN,1),(NaN,90)]            | 
+(80 rows)
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LINE_TBL l, BOX_TBL b;
+ERROR:  function "close_lb" not implemented
 --
 -- Line segments
 --
@@ -108,42 +1566,728 @@ ERROR:  operator does not exist: lseg # point
 LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
                                            ^
 HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (-0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
+-- Length
+SELECT s, @-@ s FROM LSEG_TBL;
+               s               |   ?column?    
+-------------------------------+---------------
+ [(1,2),(3,4)]                 | 2.82842712475
+ [(0,0),(6,6)]                 | 8.48528137424
+ [(10,-10),(-3,-4)]            | 14.3178210633
+ [(-1000000,200),(300000,-40)] | 1300000.02215
+ [(11,22),(33,44)]             | 31.1126983722
+ [(-10,2),(-10,3)]             |             1
+ [(0,-20),(30,-20)]            |            30
+ [(NaN,1),(NaN,90)]            |           NaN
+(8 rows)
+
+-- Vertical
+SELECT s FROM LSEG_TBL WHERE ?| s;
+         s         
+-------------------
+ [(-10,2),(-10,3)]
+(1 row)
+
+-- Horizontal
+SELECT s FROM LSEG_TBL WHERE ?- s;
+         s          
+--------------------
+ [(0,-20),(30,-20)]
+(1 row)
+
+-- Center
+SELECT s, @@ s FROM LSEG_TBL;
+               s               |   ?column?   
+-------------------------------+--------------
+ [(1,2),(3,4)]                 | (2,3)
+ [(0,0),(6,6)]                 | (3,3)
+ [(10,-10),(-3,-4)]            | (3.5,-7)
+ [(-1000000,200),(300000,-40)] | (-350000,80)
+ [(11,22),(33,44)]             | (22,33)
+ [(-10,2),(-10,3)]             | (-10,2.5)
+ [(0,-20),(30,-20)]            | (15,-20)
+ [(NaN,1),(NaN,90)]            | (NaN,45.5)
+(8 rows)
+
+-- To point
+SELECT s, s::point FROM LSEG_TBL;
+               s               |      s       
+-------------------------------+--------------
+ [(1,2),(3,4)]                 | (2,3)
+ [(0,0),(6,6)]                 | (3,3)
+ [(10,-10),(-3,-4)]            | (3.5,-7)
+ [(-1000000,200),(300000,-40)] | (-350000,80)
+ [(11,22),(33,44)]             | (22,33)
+ [(-10,2),(-10,3)]             | (-10,2.5)
+ [(0,-20),(30,-20)]            | (15,-20)
+ [(NaN,1),(NaN,90)]            | (NaN,45.5)
+(8 rows)
+
+-- Has points less than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s < l2.s;
+         s          |               s               
+--------------------+-------------------------------
+ [(1,2),(3,4)]      | [(0,0),(6,6)]
+ [(1,2),(3,4)]      | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]      | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]      | [(11,22),(33,44)]
+ [(1,2),(3,4)]      | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]      | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]      | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]      | [(11,22),(33,44)]
+ [(0,0),(6,6)]      | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)] | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)] | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]  | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]  | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]  | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]  | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]  | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]  | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]  | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)] | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)] | [(11,22),(33,44)]
+(21 rows)
+
+-- Has points less than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s <= l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(28 rows)
+
+-- Has points equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s = l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]
+(8 rows)
+
+-- Has points greater than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s >= l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(28 rows)
+
+-- Has points greater than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s > l2.s;
+               s               |         s          
+-------------------------------+--------------------
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+(21 rows)
+
+-- Has points not equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s != l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)]
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]
+(56 rows)
+
+-- Parallel with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?|| l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(13 rows)
+
+-- Perpendicular with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?-| l2.s;
+         s          |         s          
+--------------------+--------------------
+ [(-10,2),(-10,3)]  | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)] | [(-10,2),(-10,3)]
+(2 rows)
+
+-- Distance to line
+SELECT l.s, l1.s, l.s <-> l1.s FROM LSEG_TBL l, LINE_TBL l1;
+               s               |                   s                   |    ?column?    
+-------------------------------+---------------------------------------+----------------
+ [(1,2),(3,4)]                 | {0,-1,5}                              |              1
+ [(0,0),(6,6)]                 | {0,-1,5}                              |              0
+ [(10,-10),(-3,-4)]            | {0,-1,5}                              |              9
+ [(-1000000,200),(300000,-40)] | {0,-1,5}                              |              0
+ [(11,22),(33,44)]             | {0,-1,5}                              |             17
+ [(-10,2),(-10,3)]             | {0,-1,5}                              |              2
+ [(0,-20),(30,-20)]            | {0,-1,5}                              |             25
+ [(NaN,1),(NaN,90)]            | {0,-1,5}                              |            NaN
+ [(1,2),(3,4)]                 | {1,0,5}                               |              6
+ [(0,0),(6,6)]                 | {1,0,5}                               |              5
+ [(10,-10),(-3,-4)]            | {1,0,5}                               |              2
+ [(-1000000,200),(300000,-40)] | {1,0,5}                               |              0
+ [(11,22),(33,44)]             | {1,0,5}                               |             16
+ [(-10,2),(-10,3)]             | {1,0,5}                               |              5
+ [(0,-20),(30,-20)]            | {1,0,5}                               |              5
+ [(NaN,1),(NaN,90)]            | {1,0,5}                               |            NaN
+ [(1,2),(3,4)]                 | {0,3,0}                               |              2
+ [(0,0),(6,6)]                 | {0,3,0}                               |              0
+ [(10,-10),(-3,-4)]            | {0,3,0}                               |              4
+ [(-1000000,200),(300000,-40)] | {0,3,0}                               |              0
+ [(11,22),(33,44)]             | {0,3,0}                               |             22
+ [(-10,2),(-10,3)]             | {0,3,0}                               |              2
+ [(0,-20),(30,-20)]            | {0,3,0}                               |             20
+ [(NaN,1),(NaN,90)]            | {0,3,0}                               |            NaN
+ [(1,2),(3,4)]                 | {1,-1,0}                              | 0.707106781187
+ [(0,0),(6,6)]                 | {1,-1,0}                              |              0
+ [(10,-10),(-3,-4)]            | {1,-1,0}                              | 0.707106781187
+ [(-1000000,200),(300000,-40)] | {1,-1,0}                              |              0
+ [(11,22),(33,44)]             | {1,-1,0}                              |  7.77817459305
+ [(-10,2),(-10,3)]             | {1,-1,0}                              |  8.48528137424
+ [(0,-20),(30,-20)]            | {1,-1,0}                              |  14.1421356237
+ [(NaN,1),(NaN,90)]            | {1,-1,0}                              |            NaN
+ [(1,2),(3,4)]                 | {-0.4,-1,-6}                          |  7.79920420344
+ [(0,0),(6,6)]                 | {-0.4,-1,-6}                          |  5.57086014531
+ [(10,-10),(-3,-4)]            | {-0.4,-1,-6}                          |              0
+ [(-1000000,200),(300000,-40)] | {-0.4,-1,-6}                          |              0
+ [(11,22),(33,44)]             | {-0.4,-1,-6}                          |  30.0826447847
+ [(-10,2),(-10,3)]             | {-0.4,-1,-6}                          |  3.71390676354
+ [(0,-20),(30,-20)]            | {-0.4,-1,-6}                          |  1.85695338177
+ [(NaN,1),(NaN,90)]            | {-0.4,-1,-6}                          |            NaN
+ [(1,2),(3,4)]                 | {-0.000184615384615,-1,15.3846153846} |  11.3840613445
+ [(0,0),(6,6)]                 | {-0.000184615384615,-1,15.3846153846} |   9.3835075324
+ [(10,-10),(-3,-4)]            | {-0.000184615384615,-1,15.3846153846} |  19.3851689004
+ [(-1000000,200),(300000,-40)] | {-0.000184615384615,-1,15.3846153846} |              0
+ [(11,22),(33,44)]             | {-0.000184615384615,-1,15.3846153846} |  6.61741527185
+ [(-10,2),(-10,3)]             | {-0.000184615384615,-1,15.3846153846} |  12.3864613274
+ [(0,-20),(30,-20)]            | {-0.000184615384615,-1,15.3846153846} |  35.3790763202
+ [(NaN,1),(NaN,90)]            | {-0.000184615384615,-1,15.3846153846} |            NaN
+ [(1,2),(3,4)]                 | {3,NaN,5}                             |            NaN
+ [(0,0),(6,6)]                 | {3,NaN,5}                             |            NaN
+ [(10,-10),(-3,-4)]            | {3,NaN,5}                             |            NaN
+ [(-1000000,200),(300000,-40)] | {3,NaN,5}                             |            NaN
+ [(11,22),(33,44)]             | {3,NaN,5}                             |            NaN
+ [(-10,2),(-10,3)]             | {3,NaN,5}                             |            NaN
+ [(0,-20),(30,-20)]            | {3,NaN,5}                             |            NaN
+ [(NaN,1),(NaN,90)]            | {3,NaN,5}                             |            NaN
+ [(1,2),(3,4)]                 | {NaN,NaN,NaN}                         |            NaN
+ [(0,0),(6,6)]                 | {NaN,NaN,NaN}                         |            NaN
+ [(10,-10),(-3,-4)]            | {NaN,NaN,NaN}                         |            NaN
+ [(-1000000,200),(300000,-40)] | {NaN,NaN,NaN}                         |            NaN
+ [(11,22),(33,44)]             | {NaN,NaN,NaN}                         |            NaN
+ [(-10,2),(-10,3)]             | {NaN,NaN,NaN}                         |            NaN
+ [(0,-20),(30,-20)]            | {NaN,NaN,NaN}                         |            NaN
+ [(NaN,1),(NaN,90)]            | {NaN,NaN,NaN}                         |            NaN
+ [(1,2),(3,4)]                 | {0,-1,3}                              |              0
+ [(0,0),(6,6)]                 | {0,-1,3}                              |              0
+ [(10,-10),(-3,-4)]            | {0,-1,3}                              |              7
+ [(-1000000,200),(300000,-40)] | {0,-1,3}                              |              0
+ [(11,22),(33,44)]             | {0,-1,3}                              |             19
+ [(-10,2),(-10,3)]             | {0,-1,3}                              |              0
+ [(0,-20),(30,-20)]            | {0,-1,3}                              |             23
+ [(NaN,1),(NaN,90)]            | {0,-1,3}                              |            NaN
+ [(1,2),(3,4)]                 | {-1,0,3}                              |              0
+ [(0,0),(6,6)]                 | {-1,0,3}                              |              0
+ [(10,-10),(-3,-4)]            | {-1,0,3}                              |              0
+ [(-1000000,200),(300000,-40)] | {-1,0,3}                              |              0
+ [(11,22),(33,44)]             | {-1,0,3}                              |              8
+ [(-10,2),(-10,3)]             | {-1,0,3}                              |             13
+ [(0,-20),(30,-20)]            | {-1,0,3}                              |              0
+ [(NaN,1),(NaN,90)]            | {-1,0,3}                              |            NaN
+(80 rows)
+
+-- Distance to line segment
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               |    ?column?    
+-------------------------------+-------------------------------+----------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 |              0
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 0.707106781187
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            |  7.12398901685
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] |  11.3840613445
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             |  19.6977156036
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             |             11
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            |             22
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            |            NaN
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 0.707106781187
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 |              0
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            |  4.88901207039
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] |   9.3835075324
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             |  16.7630546142
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             |  10.1980390272
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            |             20
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            |            NaN
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 |  7.12398901685
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 |  4.88901207039
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            |              0
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] |  19.3851689004
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             |  29.4737584815
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             |  9.21954445729
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            |             10
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            |            NaN
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 |  11.3840613445
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 |   9.3835075324
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            |  19.3851689004
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] |              0
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             |  6.61741527185
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             |  12.3864613274
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            |  35.3790763202
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            |            NaN
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 |  19.6977156036
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 |  16.7630546142
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            |  29.4737584815
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] |  6.61741527185
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             |              0
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             |   28.319604517
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            |             42
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            |            NaN
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 |             11
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 |  10.1980390272
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            |  9.21954445729
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] |  12.3864613274
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             |   28.319604517
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             |              0
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            |  24.1660919472
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            |            NaN
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 |             22
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 |             20
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            |             10
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] |  35.3790763202
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             |             42
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             |  24.1660919472
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            |              0
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 |            NaN
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 |            NaN
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] |            NaN
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             |            NaN
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             |            NaN
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            |            NaN
+(64 rows)
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LSEG_TBL l, BOX_TBL b;
+               s               |         f1          |    ?column?    
+-------------------------------+---------------------+----------------
+ [(1,2),(3,4)]                 | (2,2),(0,0)         |              0
+ [(1,2),(3,4)]                 | (3,3),(1,1)         |              0
+ [(1,2),(3,4)]                 | (-2,2),(-8,-10)     |              3
+ [(1,2),(3,4)]                 | (2.5,3.5),(2.5,2.5) |              0
+ [(1,2),(3,4)]                 | (3,3),(3,3)         | 0.707106781187
+ [(0,0),(6,6)]                 | (2,2),(0,0)         |              0
+ [(0,0),(6,6)]                 | (3,3),(1,1)         |              0
+ [(0,0),(6,6)]                 | (-2,2),(-8,-10)     |              2
+ [(0,0),(6,6)]                 | (2.5,3.5),(2.5,2.5) |              0
+ [(0,0),(6,6)]                 | (3,3),(3,3)         |              0
+ [(10,-10),(-3,-4)]            | (2,2),(0,0)         |  4.88901207039
+ [(10,-10),(-3,-4)]            | (3,3),(1,1)         |  6.21602963235
+ [(10,-10),(-3,-4)]            | (-2,2),(-8,-10)     |              0
+ [(10,-10),(-3,-4)]            | (2.5,3.5),(2.5,2.5) |  8.20655597529
+ [(10,-10),(-3,-4)]            | (3,3),(3,3)         |  8.87006475627
+ [(-1000000,200),(300000,-40)] | (2,2),(0,0)         |  13.3842459258
+ [(-1000000,200),(300000,-40)] | (3,3),(1,1)         |  12.3840613274
+ [(-1000000,200),(300000,-40)] | (-2,2),(-8,-10)     |  13.3849843873
+ [(-1000000,200),(300000,-40)] | (2.5,3.5),(2.5,2.5) |  11.8841536436
+ [(-1000000,200),(300000,-40)] | (3,3),(3,3)         |  12.3840613274
+ [(11,22),(33,44)]             | (2,2),(0,0)         |  21.9317121995
+ [(11,22),(33,44)]             | (3,3),(1,1)         |  20.6155281281
+ [(11,22),(33,44)]             | (-2,2),(-8,-10)     |  23.8537208838
+ [(11,22),(33,44)]             | (2.5,3.5),(2.5,2.5) |  20.3592730715
+ [(11,22),(33,44)]             | (3,3),(3,3)         |  20.6155281281
+ [(-10,2),(-10,3)]             | (2,2),(0,0)         |             10
+ [(-10,2),(-10,3)]             | (3,3),(1,1)         |             11
+ [(-10,2),(-10,3)]             | (-2,2),(-8,-10)     |              2
+ [(-10,2),(-10,3)]             | (2.5,3.5),(2.5,2.5) |           12.5
+ [(-10,2),(-10,3)]             | (3,3),(3,3)         |             13
+ [(0,-20),(30,-20)]            | (2,2),(0,0)         |             20
+ [(0,-20),(30,-20)]            | (3,3),(1,1)         |             21
+ [(0,-20),(30,-20)]            | (-2,2),(-8,-10)     |  10.1980390272
+ [(0,-20),(30,-20)]            | (2.5,3.5),(2.5,2.5) |           22.5
+ [(0,-20),(30,-20)]            | (3,3),(3,3)         |             23
+ [(NaN,1),(NaN,90)]            | (2,2),(0,0)         |            NaN
+ [(NaN,1),(NaN,90)]            | (3,3),(1,1)         |            NaN
+ [(NaN,1),(NaN,90)]            | (-2,2),(-8,-10)     |            NaN
+ [(NaN,1),(NaN,90)]            | (2.5,3.5),(2.5,2.5) |            NaN
+ [(NaN,1),(NaN,90)]            | (3,3),(3,3)         |            NaN
+(40 rows)
+
+-- Intersect with line segment
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s ?# l1.s;
+               s               |      s       
+-------------------------------+--------------
+ [(0,0),(6,6)]                 | {0,-1,5}
+ [(-1000000,200),(300000,-40)] | {0,-1,5}
+ [(-1000000,200),(300000,-40)] | {1,0,5}
+ [(0,0),(6,6)]                 | {0,3,0}
+ [(-1000000,200),(300000,-40)] | {0,3,0}
+ [(-1000000,200),(300000,-40)] | {1,-1,0}
+ [(10,-10),(-3,-4)]            | {-0.4,-1,-6}
+ [(-1000000,200),(300000,-40)] | {-0.4,-1,-6}
+ [(1,2),(3,4)]                 | {0,-1,3}
+ [(0,0),(6,6)]                 | {0,-1,3}
+ [(-1000000,200),(300000,-40)] | {0,-1,3}
+ [(-10,2),(-10,3)]             | {0,-1,3}
+ [(1,2),(3,4)]                 | {-1,0,3}
+ [(0,0),(6,6)]                 | {-1,0,3}
+ [(10,-10),(-3,-4)]            | {-1,0,3}
+ [(-1000000,200),(300000,-40)] | {-1,0,3}
+ [(0,-20),(30,-20)]            | {-1,0,3}
+(17 rows)
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+         s          |         f1          
+--------------------+---------------------
+ [(1,2),(3,4)]      | (2,2),(0,0)
+ [(1,2),(3,4)]      | (3,3),(1,1)
+ [(1,2),(3,4)]      | (2.5,3.5),(2.5,2.5)
+ [(0,0),(6,6)]      | (2,2),(0,0)
+ [(0,0),(6,6)]      | (3,3),(1,1)
+ [(0,0),(6,6)]      | (2.5,3.5),(2.5,2.5)
+ [(0,0),(6,6)]      | (3,3),(3,3)
+ [(10,-10),(-3,-4)] | (-2,2),(-8,-10)
+(8 rows)
+
+-- Intersection point with line segment
+SELECT l1.s, l2.s, l1.s # l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               | ?column? 
+-------------------------------+-------------------------------+----------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 | 
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            | 
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] | 
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             | 
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             | 
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            | 
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            | 
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 | 
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            | 
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] | 
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             | 
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             | 
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            | 
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            | 
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 | 
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 | 
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            | 
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] | 
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             | 
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             | 
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            | 
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            | 
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 | 
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 | 
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            | 
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] | 
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             | 
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             | 
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            | 
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            | 
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 | 
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 | 
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            | 
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] | 
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             | 
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             | 
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            | 
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            | 
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 | 
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 | 
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            | 
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] | 
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             | 
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             | 
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            | 
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            | 
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 | 
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 | 
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            | 
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] | 
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             | 
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             | 
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            | 
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            | 
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 | 
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 | 
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            | 
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] | 
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             | 
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             | 
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            | 
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            | 
+(64 rows)
+
+-- Closest point to line
+SELECT l.s, l1.s, l.s ## l1.s FROM LSEG_TBL l, LINE_TBL l1;
+ERROR:  function "close_sl" not implemented
+-- Closest point to line segment
+SELECT l1.s, l2.s, l1.s ## l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               |            ?column?             
+-------------------------------+-------------------------------+---------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 | 
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            | (-1.98536585366,-4.46829268293)
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] | (3.00210167283,15.3840611505)
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             | 
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             | (-10,2)
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            | (1,-20)
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            | 
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 | 
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] | (6.00173233982,15.3835073725)
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             | 
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             | (-10,2)
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            | (0,-20)
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            | 
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 | (1,2)
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 | (0,0)
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            | 
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] | (-2.99642119965,15.3851685701)
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             | (11,22)
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             | (-10,2)
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            | (10,-20)
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            | 
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 | (3,4)
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 | (6,6)
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            | (-3,-4)
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] | 
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             | (11,22)
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             | (-10,3)
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            | (30,-20)
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            | 
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 | 
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 | 
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            | (-1.3512195122,-4.76097560976)
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] | (10.9987783234,15.3825848409)
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             | 
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             | (-10,3)
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            | (11,-20)
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            | 
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 | (1,2)
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 | (0,0)
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            | (-3,-4)
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] | (-9.99771326872,15.3864611163)
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             | (11,22)
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             | 
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            | (0,-20)
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            | 
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 | (1,2)
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 | (0,0)
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            | (10,-10)
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] | (30.0065315217,15.3790757173)
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             | (11,22)
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             | (-10,2)
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            | 
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            | 
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 | 
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 | 
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            | 
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] | 
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             | 
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             | 
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            | 
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            | 
+(64 rows)
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LSEG_TBL l, BOX_TBL b;
+               s               |         f1          |  ?column?   
+-------------------------------+---------------------+-------------
+ [(1,2),(3,4)]                 | (2,2),(0,0)         | (1,2)
+ [(1,2),(3,4)]                 | (3,3),(1,1)         | (1.5,2.5)
+ [(1,2),(3,4)]                 | (-2,2),(-8,-10)     | (-2,2)
+ [(1,2),(3,4)]                 | (2.5,3.5),(2.5,2.5) | (2.25,3.25)
+ [(1,2),(3,4)]                 | (3,3),(3,3)         | (3,3)
+ [(0,0),(6,6)]                 | (2,2),(0,0)         | (1,1)
+ [(0,0),(6,6)]                 | (3,3),(1,1)         | (2,2)
+ [(0,0),(6,6)]                 | (-2,2),(-8,-10)     | (-2,0)
+ [(0,0),(6,6)]                 | (2.5,3.5),(2.5,2.5) | (2.75,2.75)
+ [(0,0),(6,6)]                 | (3,3),(3,3)         | (3,3)
+ [(10,-10),(-3,-4)]            | (2,2),(0,0)         | (0,0)
+ [(10,-10),(-3,-4)]            | (3,3),(1,1)         | (1,1)
+ [(10,-10),(-3,-4)]            | (-2,2),(-8,-10)     | (-3,-4)
+ [(10,-10),(-3,-4)]            | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ [(10,-10),(-3,-4)]            | (3,3),(3,3)         | (3,3)
+ [(-1000000,200),(300000,-40)] | (2,2),(0,0)         | (2,2)
+ [(-1000000,200),(300000,-40)] | (3,3),(1,1)         | (3,3)
+ [(-1000000,200),(300000,-40)] | (-2,2),(-8,-10)     | (-2,2)
+ [(-1000000,200),(300000,-40)] | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ [(-1000000,200),(300000,-40)] | (3,3),(3,3)         | (3,3)
+ [(11,22),(33,44)]             | (2,2),(0,0)         | (2,2)
+ [(11,22),(33,44)]             | (3,3),(1,1)         | (3,3)
+ [(11,22),(33,44)]             | (-2,2),(-8,-10)     | (-2,2)
+ [(11,22),(33,44)]             | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ [(11,22),(33,44)]             | (3,3),(3,3)         | (3,3)
+ [(-10,2),(-10,3)]             | (2,2),(0,0)         | (0,2)
+ [(-10,2),(-10,3)]             | (3,3),(1,1)         | (1,2)
+ [(-10,2),(-10,3)]             | (-2,2),(-8,-10)     | (-8,2)
+ [(-10,2),(-10,3)]             | (2.5,3.5),(2.5,2.5) | (2.5,3)
+ [(-10,2),(-10,3)]             | (3,3),(3,3)         | (3,3)
+ [(0,-20),(30,-20)]            | (2,2),(0,0)         | (0,0)
+ [(0,-20),(30,-20)]            | (3,3),(1,1)         | (1,1)
+ [(0,-20),(30,-20)]            | (-2,2),(-8,-10)     | (-2,-10)
+ [(0,-20),(30,-20)]            | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ [(0,-20),(30,-20)]            | (3,3),(3,3)         | (3,3)
+ [(NaN,1),(NaN,90)]            | (2,2),(0,0)         | 
+ [(NaN,1),(NaN,90)]            | (3,3),(1,1)         | 
+ [(NaN,1),(NaN,90)]            | (-2,2),(-8,-10)     | 
+ [(NaN,1),(NaN,90)]            | (2.5,3.5),(2.5,2.5) | 
+ [(NaN,1),(NaN,90)]            | (3,3),(3,3)         | 
+(40 rows)
+
+-- On line
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s <@ l1.s;
+               s               |                   s                   
+-------------------------------+---------------------------------------
+ [(0,0),(6,6)]                 | {1,-1,0}
+ [(-1000000,200),(300000,-40)] | {-0.000184615384615,-1,15.3846153846}
+(2 rows)
+
+-- On box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s <@ b.f1;
+ s | f1 
+---+----
+(0 rows)
 
 --
 -- Boxes
@@ -157,138 +2301,176 @@ SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
      | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
      | (107.071067812,207.071067812),(92.9289321881,192.928932188)
      | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
+     | (3,5),(3,5)
+     | (NaN,NaN),(NaN,NaN)
+(8 rows)
 
 -- translation
 SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
+ twentyfour |             translation             
+------------+-------------------------------------
             | (2,2),(0,0)
             | (3,3),(1,1)
+            | (-2,2),(-8,-10)
             | (2.5,3.5),(2.5,2.5)
             | (3,3),(3,3)
             | (-8,2),(-10,0)
             | (-7,3),(-9,1)
+            | (-12,2),(-18,-10)
             | (-7.5,3.5),(-7.5,2.5)
             | (-7,3),(-7,3)
             | (-1,6),(-3,4)
             | (0,7),(-2,5)
+            | (-5,6),(-11,-6)
             | (-0.5,7.5),(-0.5,6.5)
             | (0,7),(0,7)
             | (7.1,36.5),(5.1,34.5)
             | (8.1,37.5),(6.1,35.5)
+            | (3.1,36.5),(-2.9,24.5)
             | (7.6,38),(7.6,37)
             | (8.1,37.5),(8.1,37.5)
             | (-3,-10),(-5,-12)
             | (-2,-9),(-4,-11)
+            | (-7,-10),(-13,-22)
             | (-2.5,-8.5),(-2.5,-9.5)
             | (-2,-9),(-2,-9)
+            | (2,2),(1e-300,-1e-300)
+            | (3,3),(1,1)
+            | (-2,2),(-8,-10)
+            | (2.5,3.5),(2.5,2.5)
+            | (3,3),(3,3)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
             | (12,12),(10,10)
             | (13,13),(11,11)
+            | (8,12),(2,0)
             | (12.5,13.5),(12.5,12.5)
             | (13,13),(13,13)
-(24 rows)
+(45 rows)
 
 SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
+ twentyfour |               translation               
+------------+-----------------------------------------
             | (2,2),(0,0)
             | (3,3),(1,1)
+            | (-2,2),(-8,-10)
             | (2.5,3.5),(2.5,2.5)
             | (3,3),(3,3)
             | (12,2),(10,0)
             | (13,3),(11,1)
+            | (8,2),(2,-10)
             | (12.5,3.5),(12.5,2.5)
             | (13,3),(13,3)
             | (5,-2),(3,-4)
             | (6,-1),(4,-3)
+            | (1,-2),(-5,-14)
             | (5.5,-0.5),(5.5,-1.5)
             | (6,-1),(6,-1)
             | (-3.1,-32.5),(-5.1,-34.5)
             | (-2.1,-31.5),(-4.1,-33.5)
+            | (-7.1,-32.5),(-13.1,-44.5)
             | (-2.6,-31),(-2.6,-32)
             | (-2.1,-31.5),(-2.1,-31.5)
             | (7,14),(5,12)
             | (8,15),(6,13)
+            | (3,14),(-3,2)
             | (7.5,15.5),(7.5,14.5)
             | (8,15),(8,15)
+            | (2,2),(-1e-300,1e-300)
+            | (3,3),(1,1)
+            | (-2,2),(-8,-10)
+            | (2.5,3.5),(2.5,2.5)
+            | (3,3),(3,3)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
             | (-8,-8),(-10,-10)
             | (-7,-7),(-9,-9)
+            | (-12,-8),(-18,-20)
             | (-7.5,-6.5),(-7.5,-7.5)
             | (-7,-7),(-7,-7)
-(24 rows)
+(45 rows)
 
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (-0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (-0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,-0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
-
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,-0),(-0.2,-0.2)
-        | (0.08,-0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (-0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
+-- Multiply with point
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+         f1          |     f1     |          ?column?           
+---------------------+------------+-----------------------------
+ (2,2),(0,0)         | (5.1,34.5) | (0,79.2),(-58.8,0)
+ (2,2),(0,0)         | (10,10)    | (0,40),(0,0)
+ (3,3),(1,1)         | (5.1,34.5) | (-29.4,118.8),(-88.2,39.6)
+ (3,3),(1,1)         | (10,10)    | (0,60),(0,20)
+ (-2,2),(-8,-10)     | (5.1,34.5) | (304.2,-58.8),(-79.2,-327)
+ (-2,2),(-8,-10)     | (10,10)    | (20,0),(-40,-180)
+ (2.5,3.5),(2.5,2.5) | (5.1,34.5) | (-73.5,104.1),(-108,99)
+ (2.5,3.5),(2.5,2.5) | (10,10)    | (0,60),(-10,50)
+ (3,3),(3,3)         | (5.1,34.5) | (-88.2,118.8),(-88.2,118.8)
+ (3,3),(3,3)         | (10,10)    | (0,60),(0,60)
+(10 rows)
+
+-- Overflow error
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] > 1000;
+         f1          |        f1         |                  ?column?                  
+---------------------+-------------------+--------------------------------------------
+ (2,2),(0,0)         | (1e+300,Infinity) | (NaN,NaN),(-Infinity,Infinity)
+ (2,2),(0,0)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (3,3),(1,1)         | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (3,3),(1,1)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (-2,2),(-8,-10)     | (1e+300,Infinity) | (Infinity,-Infinity),(-Infinity,-Infinity)
+ (-2,2),(-8,-10)     | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (2.5,3.5),(2.5,2.5) | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (2.5,3.5),(2.5,2.5) | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (3,3),(3,3)         | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (3,3),(3,3)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+(10 rows)
+
+-- Divide by point
+SELECT b.f1, p.f1, b.f1 / p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+         f1          |     f1     |                               ?column?                               
+---------------------+------------+----------------------------------------------------------------------
+ (2,2),(0,0)         | (5.1,34.5) | (0.0651176557644,0),(0,-0.0483449262493)
+ (2,2),(0,0)         | (10,10)    | (0.2,0),(0,0)
+ (3,3),(1,1)         | (5.1,34.5) | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
+ (3,3),(1,1)         | (10,10)    | (0.3,0),(0.1,0)
+ (-2,2),(-8,-10)     | (5.1,34.5) | (0.0483449262493,0.18499334024),(-0.317201914064,0.0651176557644)
+ (-2,2),(-8,-10)     | (10,10)    | (0,0.2),(-0.9,-0.1)
+ (2.5,3.5),(2.5,2.5) | (5.1,34.5) | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
+ (2.5,3.5),(2.5,2.5) | (10,10)    | (0.3,0.05),(0.25,0)
+ (3,3),(3,3)         | (5.1,34.5) | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
+ (3,3),(3,3)         | (10,10)    | (0.3,0),(0.3,0)
+(10 rows)
 
+-- To box
 SELECT f1::box
 	FROM POINT_TBL;
-          f1           
------------------------
+                 f1                  
+-------------------------------------
  (0,0),(0,0)
  (-10,0),(-10,0)
  (-3,4),(-3,4)
  (5.1,34.5),(5.1,34.5)
  (-5,-12),(-5,-12)
+ (1e-300,-1e-300),(1e-300,-1e-300)
+ (1e+300,Infinity),(1e+300,Infinity)
+ (NaN,NaN),(NaN,NaN)
  (10,10),(10,10)
-(6 rows)
+(9 rows)
 
 SELECT bound_box(a.f1, b.f1)
 	FROM BOX_TBL a, BOX_TBL b;
@@ -296,76 +2478,935 @@ SELECT bound_box(a.f1, b.f1)
 ---------------------
  (2,2),(0,0)
  (3,3),(0,0)
+ (2,2),(-8,-10)
  (2.5,3.5),(0,0)
  (3,3),(0,0)
  (3,3),(0,0)
  (3,3),(1,1)
+ (3,3),(-8,-10)
  (3,3.5),(1,1)
  (3,3),(1,1)
+ (2,2),(-8,-10)
+ (3,3),(-8,-10)
+ (-2,2),(-8,-10)
+ (2.5,3.5),(-8,-10)
+ (3,3),(-8,-10)
  (2.5,3.5),(0,0)
  (3,3.5),(1,1)
+ (2.5,3.5),(-8,-10)
  (2.5,3.5),(2.5,2.5)
  (3,3.5),(2.5,2.5)
  (3,3),(0,0)
  (3,3),(1,1)
+ (3,3),(-8,-10)
  (3,3.5),(2.5,2.5)
  (3,3),(3,3)
-(16 rows)
+(25 rows)
+
+-- Below box
+SELECT b1.f1, b2.f1, b1.f1 <^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          | ?column? 
+---------------------+---------------------+----------
+ (2,2),(0,0)         | (2,2),(0,0)         | f
+ (2,2),(0,0)         | (3,3),(1,1)         | f
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | f
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | t
+ (2,2),(0,0)         | (3,3),(3,3)         | t
+ (3,3),(1,1)         | (2,2),(0,0)         | f
+ (3,3),(1,1)         | (3,3),(1,1)         | f
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | f
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(1,1)         | (3,3),(3,3)         | t
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | f
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | f
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | f
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | t
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | t
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | f
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | f
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | f
+ (3,3),(3,3)         | (2,2),(0,0)         | f
+ (3,3),(3,3)         | (3,3),(1,1)         | f
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | f
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(3,3)         | (3,3),(3,3)         | t
+(25 rows)
+
+-- Above box
+SELECT b1.f1, b2.f1, b1.f1 >^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          | ?column? 
+---------------------+---------------------+----------
+ (2,2),(0,0)         | (2,2),(0,0)         | f
+ (2,2),(0,0)         | (3,3),(1,1)         | f
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | f
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | f
+ (2,2),(0,0)         | (3,3),(3,3)         | f
+ (3,3),(1,1)         | (2,2),(0,0)         | f
+ (3,3),(1,1)         | (3,3),(1,1)         | f
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | f
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(1,1)         | (3,3),(3,3)         | f
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | f
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | f
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | f
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | f
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | f
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | t
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | f
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | t
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | f
+ (3,3),(3,3)         | (2,2),(0,0)         | t
+ (3,3),(3,3)         | (3,3),(1,1)         | t
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | t
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(3,3)         | (3,3),(3,3)         | t
+(25 rows)
+
+-- Intersection point with box
+SELECT b1.f1, b2.f1, b1.f1 # b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          |      ?column?       
+---------------------+---------------------+---------------------
+ (2,2),(0,0)         | (2,2),(0,0)         | (2,2),(0,0)
+ (2,2),(0,0)         | (3,3),(1,1)         | (2,2),(1,1)
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | 
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | 
+ (2,2),(0,0)         | (3,3),(3,3)         | 
+ (3,3),(1,1)         | (2,2),(0,0)         | (2,2),(1,1)
+ (3,3),(1,1)         | (3,3),(1,1)         | (3,3),(1,1)
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | 
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | (2.5,3),(2.5,2.5)
+ (3,3),(1,1)         | (3,3),(3,3)         | (3,3),(3,3)
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | 
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | 
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | (-2,2),(-8,-10)
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | 
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | 
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | 
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | (2.5,3),(2.5,2.5)
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | 
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5)
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | 
+ (3,3),(3,3)         | (2,2),(0,0)         | 
+ (3,3),(3,3)         | (3,3),(1,1)         | (3,3),(3,3)
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | 
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | 
+ (3,3),(3,3)         | (3,3),(3,3)         | (3,3),(3,3)
+(25 rows)
+
+-- Diagonal
+SELECT f1, diagonal(f1) FROM BOX_TBL;
+         f1          |       diagonal        
+---------------------+-----------------------
+ (2,2),(0,0)         | [(2,2),(0,0)]
+ (3,3),(1,1)         | [(3,3),(1,1)]
+ (-2,2),(-8,-10)     | [(-2,2),(-8,-10)]
+ (2.5,3.5),(2.5,2.5) | [(2.5,3.5),(2.5,2.5)]
+ (3,3),(3,3)         | [(3,3),(3,3)]
+(5 rows)
+
+-- Distance to box
+SELECT b1.f1, b2.f1, b1.f1 <-> b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          |   ?column?    
+---------------------+---------------------+---------------
+ (2,2),(0,0)         | (2,2),(0,0)         |             0
+ (2,2),(0,0)         | (3,3),(1,1)         | 1.41421356237
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | 7.81024967591
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) |           2.5
+ (2,2),(0,0)         | (3,3),(3,3)         | 2.82842712475
+ (3,3),(1,1)         | (2,2),(0,0)         | 1.41421356237
+ (3,3),(1,1)         | (3,3),(1,1)         |             0
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | 9.21954445729
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | 1.11803398875
+ (3,3),(1,1)         | (3,3),(3,3)         | 1.41421356237
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | 7.81024967591
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | 9.21954445729
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     |             0
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | 10.2591422643
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | 10.6301458127
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         |           2.5
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | 1.11803398875
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | 10.2591422643
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) |             0
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         |           0.5
+ (3,3),(3,3)         | (2,2),(0,0)         | 2.82842712475
+ (3,3),(3,3)         | (3,3),(1,1)         | 1.41421356237
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | 10.6301458127
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) |           0.5
+ (3,3),(3,3)         | (3,3),(3,3)         |             0
+(25 rows)
 
 --
 -- Paths
 --
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
+-- Points
+SELECT f1, npoints(f1) FROM PATH_TBL;
+            f1             | npoints 
+---------------------------+---------
+ [(1,2),(3,4)]             |       2
+ ((1,2),(3,4))             |       2
+ [(0,0),(3,0),(4,5),(1,6)] |       4
+ ((1,2),(3,4))             |       2
+ ((1,2),(3,4))             |       2
+ [(1,2),(3,4)]             |       2
+ ((10,20))                 |       1
+ [(11,12),(13,14)]         |       2
+ ((11,12),(13,14))         |       2
+(9 rows)
 
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
+-- Area
+SELECT f1, area(f1) FROM PATH_TBL;
+            f1             | area 
+---------------------------+------
+ [(1,2),(3,4)]             |     
+ ((1,2),(3,4))             |    0
+ [(0,0),(3,0),(4,5),(1,6)] |     
+ ((1,2),(3,4))             |    0
+ ((1,2),(3,4))             |    0
+ [(1,2),(3,4)]             |     
+ ((10,20))                 |    0
+ [(11,12),(13,14)]         |     
+ ((11,12),(13,14))         |    0
+(9 rows)
 
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
+-- Length
+SELECT f1, @-@ f1 FROM PATH_TBL;
+            f1             |   ?column?    
+---------------------------+---------------
+ [(1,2),(3,4)]             | 2.82842712475
+ ((1,2),(3,4))             | 5.65685424949
+ [(0,0),(3,0),(4,5),(1,6)] | 11.2612971738
+ ((1,2),(3,4))             | 5.65685424949
+ ((1,2),(3,4))             | 5.65685424949
+ [(1,2),(3,4)]             | 2.82842712475
+ ((10,20))                 |             0
+ [(11,12),(13,14)]         | 2.82842712475
+ ((11,12),(13,14))         | 5.65685424949
+(9 rows)
 
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
+-- Center
+SELECT f1, @@ f1 FROM PATH_TBL;
+ERROR:  function "path_center" not implemented
+-- To polygon
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isclosed(f1);
+        f1         |        f1         
+-------------------+-------------------
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((10,20))         | ((10,20))
+ ((11,12),(13,14)) | ((11,12),(13,14))
+(5 rows)
+
+-- Open path cannot be converted to polygon error
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isopen(f1);
+ERROR:  open path cannot be converted to polygon
+-- Has points less than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 < p2.f1;
+        f1         |            f1             
+-------------------+---------------------------
+ [(1,2),(3,4)]     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]     | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))         | [(1,2),(3,4)]
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | [(1,2),(3,4)]
+ ((10,20))         | [(11,12),(13,14)]
+ ((10,20))         | ((11,12),(13,14))
+ [(11,12),(13,14)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((11,12),(13,14)) | [(0,0),(3,0),(4,5),(1,6)]
+(15 rows)
+
+-- Has points less than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 <= p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | [(1,2),(3,4)]
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | [(1,2),(3,4)]
+ ((10,20))                 | ((10,20))
+ ((10,20))                 | [(11,12),(13,14)]
+ ((10,20))                 | ((11,12),(13,14))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(66 rows)
+
+-- Has points equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 = p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | ((10,20))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(51 rows)
+
+-- Has points greater than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 >= p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | ((10,20))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((10,20))
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((10,20))
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(66 rows)
+
+-- Has points greater than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 > p2.f1;
+            f1             |        f1         
+---------------------------+-------------------
+ [(1,2),(3,4)]             | ((10,20))
+ ((1,2),(3,4))             | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | ((10,20))
+ [(1,2),(3,4)]             | ((10,20))
+ [(11,12),(13,14)]         | ((10,20))
+ ((11,12),(13,14))         | ((10,20))
+(15 rows)
+
+-- Add path
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+            f1             |            f1             |                     ?column?                      
+---------------------------+---------------------------+---------------------------------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4),(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))                 | 
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         | [(1,2),(3,4),(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6),(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6),(0,0),(3,0),(4,5),(1,6)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6),(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))                 | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6),(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4),(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))                 | 
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         | [(1,2),(3,4),(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))         | 
+ ((10,20))                 | [(1,2),(3,4)]             | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | [(1,2),(3,4)]             | 
+ ((10,20))                 | ((10,20))                 | 
+ ((10,20))                 | [(11,12),(13,14)]         | 
+ ((10,20))                 | ((11,12),(13,14))         | 
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             | [(11,12),(13,14),(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14),(0,0),(3,0),(4,5),(1,6)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             | [(11,12),(13,14),(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((10,20))                 | 
+ [(11,12),(13,14)]         | [(11,12),(13,14)]         | [(11,12),(13,14),(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))         | 
+ ((11,12),(13,14))         | [(1,2),(3,4)]             | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | [(1,2),(3,4)]             | 
+ ((11,12),(13,14))         | ((10,20))                 | 
+ ((11,12),(13,14))         | [(11,12),(13,14)]         | 
+ ((11,12),(13,14))         | ((11,12),(13,14))         | 
+(81 rows)
+
+-- Add point
+SELECT p.f1, p1.f1, p.f1 + p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                                 ?column?                                  
+---------------------------+-------------------+---------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((10,20))                 | (0,0)             | ((10,20))
+ [(11,12),(13,14)]         | (0,0)             | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (0,0)             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (-10,0)           | [(-9,2),(-7,4)]
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(-10,0),(-7,0),(-6,5),(-9,6)]
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ [(1,2),(3,4)]             | (-10,0)           | [(-9,2),(-7,4)]
+ ((10,20))                 | (-10,0)           | ((0,20))
+ [(11,12),(13,14)]         | (-10,0)           | [(1,12),(3,14)]
+ ((11,12),(13,14))         | (-10,0)           | ((1,12),(3,14))
+ [(1,2),(3,4)]             | (-3,4)            | [(-2,6),(0,8)]
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(-3,4),(0,4),(1,9),(-2,10)]
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ [(1,2),(3,4)]             | (-3,4)            | [(-2,6),(0,8)]
+ ((10,20))                 | (-3,4)            | ((7,24))
+ [(11,12),(13,14)]         | (-3,4)            | [(8,16),(10,18)]
+ ((11,12),(13,14))         | (-3,4)            | ((8,16),(10,18))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(6.1,36.5),(8.1,38.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(5.1,34.5),(8.1,34.5),(9.1,39.5),(6.1,40.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(6.1,36.5),(8.1,38.5)]
+ ((10,20))                 | (5.1,34.5)        | ((15.1,54.5))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(16.1,46.5),(18.1,48.5)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((16.1,46.5),(18.1,48.5))
+ [(1,2),(3,4)]             | (-5,-12)          | [(-4,-10),(-2,-8)]
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(-5,-12),(-2,-12),(-1,-7),(-4,-6)]
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ [(1,2),(3,4)]             | (-5,-12)          | [(-4,-10),(-2,-8)]
+ ((10,20))                 | (-5,-12)          | ((5,8))
+ [(11,12),(13,14)]         | (-5,-12)          | [(6,0),(8,2)]
+ ((11,12),(13,14))         | (-5,-12)          | ((6,0),(8,2))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(1e-300,-1e-300),(3,-1e-300),(4,5),(1,6)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((10,20))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity),(1e+300,Infinity),(1e+300,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((1e+300,Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(11,12),(13,14)]
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(10,10),(13,10),(14,15),(11,16)]
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (10,10)           | [(11,12),(13,14)]
+ ((10,20))                 | (10,10)           | ((20,30))
+ [(11,12),(13,14)]         | (10,10)           | [(21,22),(23,24)]
+ ((11,12),(13,14))         | (10,10)           | ((21,22),(23,24))
+(81 rows)
+
+-- Subtract point
+SELECT p.f1, p1.f1, p.f1 - p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                                     ?column?                                      
+---------------------------+-------------------+-----------------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((10,20))                 | (0,0)             | ((10,20))
+ [(11,12),(13,14)]         | (0,0)             | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (0,0)             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (-10,0)           | [(11,2),(13,4)]
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(10,0),(13,0),(14,5),(11,6)]
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ [(1,2),(3,4)]             | (-10,0)           | [(11,2),(13,4)]
+ ((10,20))                 | (-10,0)           | ((20,20))
+ [(11,12),(13,14)]         | (-10,0)           | [(21,12),(23,14)]
+ ((11,12),(13,14))         | (-10,0)           | ((21,12),(23,14))
+ [(1,2),(3,4)]             | (-3,4)            | [(4,-2),(6,0)]
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(3,-4),(6,-4),(7,1),(4,2)]
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ [(1,2),(3,4)]             | (-3,4)            | [(4,-2),(6,0)]
+ ((10,20))                 | (-3,4)            | ((13,16))
+ [(11,12),(13,14)]         | (-3,4)            | [(14,8),(16,10)]
+ ((11,12),(13,14))         | (-3,4)            | ((14,8),(16,10))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-4.1,-32.5),(-2.1,-30.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(-5.1,-34.5),(-2.1,-34.5),(-1.1,-29.5),(-4.1,-28.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-4.1,-32.5),(-2.1,-30.5)]
+ ((10,20))                 | (5.1,34.5)        | ((4.9,-14.5))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(5.9,-22.5),(7.9,-20.5)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((5.9,-22.5),(7.9,-20.5))
+ [(1,2),(3,4)]             | (-5,-12)          | [(6,14),(8,16)]
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(5,12),(8,12),(9,17),(6,18)]
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ [(1,2),(3,4)]             | (-5,-12)          | [(6,14),(8,16)]
+ ((10,20))                 | (-5,-12)          | ((15,32))
+ [(11,12),(13,14)]         | (-5,-12)          | [(16,24),(18,26)]
+ ((11,12),(13,14))         | (-5,-12)          | ((16,24),(18,26))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(-1e-300,1e-300),(3,1e-300),(4,5),(1,6)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((10,20))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity),(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((-1e+300,-Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(-9,-8),(-7,-6)]
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(-10,-10),(-7,-10),(-6,-5),(-9,-4)]
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ [(1,2),(3,4)]             | (10,10)           | [(-9,-8),(-7,-6)]
+ ((10,20))                 | (10,10)           | ((0,10))
+ [(11,12),(13,14)]         | (10,10)           | [(1,2),(3,4)]
+ ((11,12),(13,14))         | (10,10)           | ((1,2),(3,4))
+(81 rows)
+
+-- Multiply with point
+SELECT p.f1, p1.f1, p.f1 * p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                               ?column?                               
+---------------------------+-------------------+----------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(0,0),(0,0)]
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(0,0),(0,0),(0,0)]
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ [(1,2),(3,4)]             | (0,0)             | [(0,0),(0,0)]
+ ((10,20))                 | (0,0)             | ((0,0))
+ [(11,12),(13,14)]         | (0,0)             | [(0,0),(0,0)]
+ ((11,12),(13,14))         | (0,0)             | ((0,0),(0,0))
+ [(1,2),(3,4)]             | (-10,0)           | [(-10,-20),(-30,-40)]
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(0,0),(-30,0),(-40,-50),(-10,-60)]
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ [(1,2),(3,4)]             | (-10,0)           | [(-10,-20),(-30,-40)]
+ ((10,20))                 | (-10,0)           | ((-100,-200))
+ [(11,12),(13,14)]         | (-10,0)           | [(-110,-120),(-130,-140)]
+ ((11,12),(13,14))         | (-10,0)           | ((-110,-120),(-130,-140))
+ [(1,2),(3,4)]             | (-3,4)            | [(-11,-2),(-25,0)]
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(0,0),(-9,12),(-32,1),(-27,-14)]
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ [(1,2),(3,4)]             | (-3,4)            | [(-11,-2),(-25,0)]
+ ((10,20))                 | (-3,4)            | ((-110,-20))
+ [(11,12),(13,14)]         | (-3,4)            | [(-81,8),(-95,10)]
+ ((11,12),(13,14))         | (-3,4)            | ((-81,8),(-95,10))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-63.9,44.7),(-122.7,123.9)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(0,0),(15.3,103.5),(-152.1,163.5),(-201.9,65.1)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-63.9,44.7),(-122.7,123.9)]
+ ((10,20))                 | (5.1,34.5)        | ((-639,447))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(-357.9,440.7),(-416.7,519.9)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((-357.9,440.7),(-416.7,519.9))
+ [(1,2),(3,4)]             | (-5,-12)          | [(19,-22),(33,-56)]
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(0,0),(-15,-36),(40,-73),(67,-42)]
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ [(1,2),(3,4)]             | (-5,-12)          | [(19,-22),(33,-56)]
+ ((10,20))                 | (-5,-12)          | ((190,-220))
+ [(11,12),(13,14)]         | (-5,-12)          | [(89,-192),(103,-226)]
+ ((11,12),(13,14))         | (-5,-12)          | ((89,-192),(103,-226))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(3e-300,1e-300),(7e-300,1e-300)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(0,0),(3e-300,-3e-300),(9e-300,1e-300),(7e-300,5e-300)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(3e-300,1e-300),(7e-300,1e-300)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((3e-299,1e-299))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(2.3e-299,1e-300),(2.7e-299,1e-300)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((2.3e-299,1e-300),(2.7e-299,1e-300))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(NaN,NaN),(NaN,Infinity),(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((-Infinity,Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(-10,30),(-10,70)]
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(0,0),(30,30),(-10,90),(-50,70)]
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ [(1,2),(3,4)]             | (10,10)           | [(-10,30),(-10,70)]
+ ((10,20))                 | (10,10)           | ((-100,300))
+ [(11,12),(13,14)]         | (10,10)           | [(-10,230),(-10,270)]
+ ((11,12),(13,14))         | (10,10)           | ((-10,230),(-10,270))
+(81 rows)
+
+-- Divide by point
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+            f1             |     f1     |                                                    ?column?                                                     
+---------------------------+------------+-----------------------------------------------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (5.1,34.5) | [(0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952)]
+ [(1,2),(3,4)]             | (10,10)    | [(0.15,0.05),(0.35,0.05)]
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5) | [(0,0),(0.0125795471363,-0.0850969365103),(0.158600957032,-0.0924966701199),(0.174387055399,-0.00320655123082)]
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)    | [(0,0),(0.15,-0.15),(0.45,0.05),(0.35,0.25)]
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ [(1,2),(3,4)]             | (5.1,34.5) | [(0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952)]
+ [(1,2),(3,4)]             | (10,10)    | [(0.15,0.05),(0.35,0.05)]
+ ((10,20))                 | (5.1,34.5) | ((0.609244733856,-0.199792807459))
+ ((10,20))                 | (10,10)    | ((1.5,0.5))
+ [(11,12),(13,14)]         | (5.1,34.5) | [(0.386512752208,-0.261703911993),(0.451630407972,-0.310048838242)]
+ [(11,12),(13,14)]         | (10,10)    | [(1.15,0.05),(1.35,0.05)]
+ ((11,12),(13,14))         | (5.1,34.5) | ((0.386512752208,-0.261703911993),(0.451630407972,-0.310048838242))
+ ((11,12),(13,14))         | (10,10)    | ((1.15,0.05),(1.35,0.05))
+(18 rows)
+
+-- Division by 0 error
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to path
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+            f1             |            f1             |    ?column?    
+---------------------------+---------------------------+----------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((10,20))                 |  17.4642491966
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         |   11.313708499
+ [(1,2),(3,4)]             | ((11,12),(13,14))         |   11.313708499
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)] |              0
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))                 |  16.1554944214
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]         |  9.89949493661
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))         |  9.89949493661
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((10,20))                 |  17.4642491966
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         |   11.313708499
+ [(1,2),(3,4)]             | ((11,12),(13,14))         |   11.313708499
+ ((10,20))                 | [(1,2),(3,4)]             |  17.4642491966
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)] |  16.1554944214
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | [(1,2),(3,4)]             |  17.4642491966
+ ((10,20))                 | ((10,20))                 |              0
+ ((10,20))                 | [(11,12),(13,14)]         |   6.7082039325
+ ((10,20))                 | ((11,12),(13,14))         |   6.7082039325
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             |   11.313708499
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)] |  9.89949493661
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             |   11.313708499
+ [(11,12),(13,14)]         | ((10,20))                 |   6.7082039325
+ [(11,12),(13,14)]         | [(11,12),(13,14)]         |              0
+ [(11,12),(13,14)]         | ((11,12),(13,14))         |              0
+ ((11,12),(13,14))         | [(1,2),(3,4)]             |   11.313708499
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)] |  9.89949493661
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | [(1,2),(3,4)]             |   11.313708499
+ ((11,12),(13,14))         | ((10,20))                 |   6.7082039325
+ ((11,12),(13,14))         | [(11,12),(13,14)]         |              0
+ ((11,12),(13,14))         | ((11,12),(13,14))         |              0
+(81 rows)
 
 --
 -- Polygons
@@ -373,73 +3414,154 @@ SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
 -- containment
 SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
    FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
+ twentyfour |        f1         |             f1             | contains 
+------------+-------------------+----------------------------+----------
+            | (0,0)             | ((2,0),(2,4),(0,0))        | t
+            | (0,0)             | ((3,1),(3,3),(1,0))        | f
+            | (0,0)             | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (0,0)             | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (0,0)             | ((0,0))                    | t
+            | (0,0)             | ((0,1),(0,1))              | f
+            | (-10,0)           | ((2,0),(2,4),(0,0))        | f
+            | (-10,0)           | ((3,1),(3,3),(1,0))        | f
+            | (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-10,0)           | ((0,0))                    | f
+            | (-10,0)           | ((0,1),(0,1))              | f
+            | (-3,4)            | ((2,0),(2,4),(0,0))        | f
+            | (-3,4)            | ((3,1),(3,3),(1,0))        | f
+            | (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-3,4)            | ((0,0))                    | f
+            | (-3,4)            | ((0,1),(0,1))              | f
+            | (5.1,34.5)        | ((2,0),(2,4),(0,0))        | f
+            | (5.1,34.5)        | ((3,1),(3,3),(1,0))        | f
+            | (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (5.1,34.5)        | ((0,0))                    | f
+            | (5.1,34.5)        | ((0,1),(0,1))              | f
+            | (-5,-12)          | ((2,0),(2,4),(0,0))        | f
+            | (-5,-12)          | ((3,1),(3,3),(1,0))        | f
+            | (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-5,-12)          | ((0,0))                    | f
+            | (-5,-12)          | ((0,1),(0,1))              | f
+            | (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        | t
+            | (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        | f
+            | (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e-300,-1e-300)  | ((0,0))                    | t
+            | (1e-300,-1e-300)  | ((0,1),(0,1))              | f
+            | (1e+300,Infinity) | ((2,0),(2,4),(0,0))        | f
+            | (1e+300,Infinity) | ((3,1),(3,3),(1,0))        | f
+            | (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e+300,Infinity) | ((0,0))                    | f
+            | (1e+300,Infinity) | ((0,1),(0,1))              | f
+            | (NaN,NaN)         | ((2,0),(2,4),(0,0))        | t
+            | (NaN,NaN)         | ((3,1),(3,3),(1,0))        | t
+            | (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  | t
+            | (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  | t
+            | (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) | t
+            | (NaN,NaN)         | ((0,0))                    | t
+            | (NaN,NaN)         | ((0,1),(0,1))              | t
+            | (10,10)           | ((2,0),(2,4),(0,0))        | f
+            | (10,10)           | ((3,1),(3,3),(1,0))        | f
+            | (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (10,10)           | ((0,0))                    | f
+            | (10,10)           | ((0,1),(0,1))              | f
+(63 rows)
 
 SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
    FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
+ twentyfour |        f1         |             f1             | contained 
+------------+-------------------+----------------------------+-----------
+            | (0,0)             | ((2,0),(2,4),(0,0))        | t
+            | (0,0)             | ((3,1),(3,3),(1,0))        | f
+            | (0,0)             | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (0,0)             | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (0,0)             | ((0,0))                    | t
+            | (0,0)             | ((0,1),(0,1))              | f
+            | (-10,0)           | ((2,0),(2,4),(0,0))        | f
+            | (-10,0)           | ((3,1),(3,3),(1,0))        | f
+            | (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-10,0)           | ((0,0))                    | f
+            | (-10,0)           | ((0,1),(0,1))              | f
+            | (-3,4)            | ((2,0),(2,4),(0,0))        | f
+            | (-3,4)            | ((3,1),(3,3),(1,0))        | f
+            | (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-3,4)            | ((0,0))                    | f
+            | (-3,4)            | ((0,1),(0,1))              | f
+            | (5.1,34.5)        | ((2,0),(2,4),(0,0))        | f
+            | (5.1,34.5)        | ((3,1),(3,3),(1,0))        | f
+            | (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (5.1,34.5)        | ((0,0))                    | f
+            | (5.1,34.5)        | ((0,1),(0,1))              | f
+            | (-5,-12)          | ((2,0),(2,4),(0,0))        | f
+            | (-5,-12)          | ((3,1),(3,3),(1,0))        | f
+            | (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-5,-12)          | ((0,0))                    | f
+            | (-5,-12)          | ((0,1),(0,1))              | f
+            | (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        | t
+            | (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        | f
+            | (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e-300,-1e-300)  | ((0,0))                    | t
+            | (1e-300,-1e-300)  | ((0,1),(0,1))              | f
+            | (1e+300,Infinity) | ((2,0),(2,4),(0,0))        | f
+            | (1e+300,Infinity) | ((3,1),(3,3),(1,0))        | f
+            | (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e+300,Infinity) | ((0,0))                    | f
+            | (1e+300,Infinity) | ((0,1),(0,1))              | f
+            | (NaN,NaN)         | ((2,0),(2,4),(0,0))        | t
+            | (NaN,NaN)         | ((3,1),(3,3),(1,0))        | t
+            | (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  | t
+            | (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  | t
+            | (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) | t
+            | (NaN,NaN)         | ((0,0))                    | t
+            | (NaN,NaN)         | ((0,1),(0,1))              | t
+            | (10,10)           | ((2,0),(2,4),(0,0))        | f
+            | (10,10)           | ((3,1),(3,3),(1,0))        | f
+            | (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (10,10)           | ((0,0))                    | f
+            | (10,10)           | ((0,1),(0,1))              | f
+(63 rows)
 
 SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
    FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
+ four | npoints |          polygon           
+------+---------+----------------------------
       |       3 | ((2,0),(2,4),(0,0))
       |       3 | ((3,1),(3,3),(1,0))
+      |       4 | ((1,2),(3,4),(5,6),(7,8))
+      |       4 | ((7,8),(5,6),(3,4),(1,2))
+      |       4 | ((1,2),(7,8),(5,6),(3,-4))
       |       1 | ((0,0))
       |       2 | ((0,1),(0,1))
-(4 rows)
+(7 rows)
 
 SELECT '' AS four, polygon(f1)
    FROM BOX_TBL;
@@ -447,9 +3569,10 @@ SELECT '' AS four, polygon(f1)
 ------+-------------------------------------------
       | ((0,0),(0,2),(2,2),(2,0))
       | ((1,1),(1,3),(3,3),(3,1))
+      | ((-8,-10),(-8,2),(-2,2),(-2,-10))
       | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
       | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, polygon(f1)
    FROM PATH_TBL WHERE isclosed(f1);
@@ -458,8 +3581,9 @@ SELECT '' AS four, polygon(f1)
       | ((1,2),(3,4))
       | ((1,2),(3,4))
       | ((1,2),(3,4))
+      | ((10,20))
       | ((11,12),(13,14))
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
    FROM PATH_TBL
@@ -472,56 +3596,351 @@ SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
       | [(11,12),(13,14)]         | ((11,12),(13,14))
 (4 rows)
 
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
+-- To box
+SELECT f1, f1::box FROM POLYGON_TBL;
+             f1             |      f1      
+----------------------------+--------------
+ ((2,0),(2,4),(0,0))        | (2,4),(0,0)
+ ((3,1),(3,3),(1,0))        | (3,3),(1,0)
+ ((1,2),(3,4),(5,6),(7,8))  | (7,8),(1,2)
+ ((7,8),(5,6),(3,4),(1,2))  | (7,8),(1,2)
+ ((1,2),(7,8),(5,6),(3,-4)) | (7,8),(1,-4)
+ ((0,0))                    | (0,0),(0,0)
+ ((0,1),(0,1))              | (0,1),(0,1)
+(7 rows)
 
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
+-- To path
+SELECT f1, f1::path FROM POLYGON_TBL;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(7 rows)
+
+-- Same as polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 ~= p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(9 rows)
+
+-- Contained by polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <@ p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(12 rows)
+
+-- Contains polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 @> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(12 rows)
+
+-- Overlap with polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 && p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(25 rows)
+
+-- Left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 << p2.f1;
+      f1       |             f1             
+---------------+----------------------------
+ ((0,0))       | ((3,1),(3,3),(1,0))
+ ((0,0))       | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))       | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))       | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1)) | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1)) | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1)) | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1)) | ((1,2),(7,8),(5,6),(3,-4))
+(8 rows)
+
+-- Overlap of left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &< p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))                    | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1))              | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(32 rows)
+
+-- Right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 >> p2.f1;
+             f1             |      f1       
+----------------------------+---------------
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((0,1),(0,1))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1))
+(8 rows)
+
+-- Overlap of right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((2,0),(2,4),(0,0))        | ((0,1),(0,1))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((0,1),(0,1))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((3,1),(3,3),(1,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(37 rows)
+
+-- Below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <<| p2.f1;
+      f1       |            f1             
+---------------+---------------------------
+ ((0,0))       | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))       | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))       | ((0,1),(0,1))
+ ((0,1),(0,1)) | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1)) | ((7,8),(5,6),(3,4),(1,2))
+(5 rows)
+
+-- Overlap or below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &<| p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))                    | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1))              | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(31 rows)
 
+-- Above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |>> p2.f1;
+            f1             |      f1       
+---------------------------+---------------
+ ((1,2),(3,4),(5,6),(7,8)) | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8)) | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2)) | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2)) | ((0,1),(0,1))
+ ((0,1),(0,1))             | ((0,0))
+(5 rows)
+
+-- Overlap or above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |&> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((3,1),(3,3),(1,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(32 rows)
+
+-- Distance to polygon
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2;
+ERROR:  function "poly_distance" not implemented
 --
 -- Circles
 --
 SELECT '' AS six, circle(f1, 50.0)
    FROM POINT_TBL;
- six |     circle      
------+-----------------
+ six |         circle         
+-----+------------------------
      | <(0,0),50>
      | <(-10,0),50>
      | <(-3,4),50>
      | <(5.1,34.5),50>
      | <(-5,-12),50>
+     | <(1e-300,-1e-300),50>
+     | <(1e+300,Infinity),50>
+     | <(NaN,NaN),50>
      | <(10,10),50>
-(6 rows)
+(9 rows)
 
 SELECT '' AS four, circle(f1)
    FROM BOX_TBL;
- four |        circle         
-------+-----------------------
+ four |         circle         
+------+------------------------
       | <(1,1),1.41421356237>
       | <(2,2),1.41421356237>
+      | <(-5,-4),6.7082039325>
       | <(2.5,3),0.5>
       | <(3,3),0>
-(4 rows)
+(5 rows)
 
 SELECT '' AS two, circle(f1)
    FROM POLYGON_TBL
@@ -530,34 +3949,942 @@ SELECT '' AS two, circle(f1)
 -----+-----------------------------------------------
      | <(1.33333333333,1.33333333333),2.04168905064>
      | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
+     | <(4,5),2.82842712475>
+     | <(4,5),2.82842712475>
+     | <(4,3),4.80664375676>
+(5 rows)
 
 SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
    FROM CIRCLE_TBL c1, POINT_TBL p1
    WHERE (p1.f1 <-> c1.f1) > 0
    ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
+ twentyfour |     circle     |       point       |   distance    
+------------+----------------+-------------------+---------------
+            | <(1,2),3>      | (-3,4)            |   1.472135955
+            | <(5,1),3>      | (0,0)             | 2.09901951359
+            | <(5,1),3>      | (1e-300,-1e-300)  | 2.09901951359
+            | <(5,1),3>      | (-3,4)            | 5.54400374532
+            | <(3,5),0>      | (0,0)             | 5.83095189485
+            | <(3,5),0>      | (1e-300,-1e-300)  | 5.83095189485
+            | <(3,5),0>      | (-3,4)            |  6.0827625303
+            | <(1,3),5>      | (-10,0)           | 6.40175425099
+            | <(1,3),5>      | (10,10)           | 6.40175425099
+            | <(5,1),3>      | (10,10)           | 7.29563014099
+            | <(1,2),3>      | (-10,0)           |  8.1803398875
+            | <(3,5),0>      | (10,10)           | 8.60232526704
+            | <(1,2),3>      | (10,10)           | 9.04159457879
+            | <(1,3),5>      | (-5,-12)          | 11.1554944214
+            | <(5,1),3>      | (-10,0)           | 12.0332963784
+            | <(1,2),3>      | (-5,-12)          | 12.2315462117
+            | <(5,1),3>      | (-5,-12)          | 13.4012194669
+            | <(3,5),0>      | (-10,0)           | 13.9283882772
+            | <(3,5),0>      | (-5,-12)          | 18.7882942281
+            | <(1,3),5>      | (5.1,34.5)        | 26.7657047773
+            | <(3,5),0>      | (5.1,34.5)        | 29.5746513082
+            | <(1,2),3>      | (5.1,34.5)        | 29.7575945393
+            | <(5,1),3>      | (5.1,34.5)        | 30.5001492534
+            | <(100,200),10> | (5.1,34.5)        | 180.778038568
+            | <(100,200),10> | (10,10)           | 200.237960416
+            | <(100,200),10> | (-3,4)            | 211.415898255
+            | <(100,200),10> | (0,0)             |  213.60679775
+            | <(100,200),10> | (1e-300,-1e-300)  |  213.60679775
+            | <(100,200),10> | (-10,0)           |  218.25424421
+            | <(100,200),10> | (-5,-12)          | 226.577682802
+            | <(3,5),0>      | (1e+300,Infinity) |      Infinity
+            | <(1,2),3>      | (1e+300,Infinity) |      Infinity
+            | <(5,1),3>      | (1e+300,Infinity) |      Infinity
+            | <(1,3),5>      | (1e+300,Infinity) |      Infinity
+            | <(100,200),10> | (1e+300,Infinity) |      Infinity
+            | <(1,2),100>    | (1e+300,Infinity) |      Infinity
+            | <(100,1),115>  | (1e+300,Infinity) |      Infinity
+            | <(3,5),0>      | (NaN,NaN)         |           NaN
+            | <(1,2),3>      | (NaN,NaN)         |           NaN
+            | <(5,1),3>      | (NaN,NaN)         |           NaN
+            | <(1,3),5>      | (NaN,NaN)         |           NaN
+            | <(100,200),10> | (NaN,NaN)         |           NaN
+            | <(1,2),100>    | (NaN,NaN)         |           NaN
+            | <(100,1),115>  | (NaN,NaN)         |           NaN
+            | <(3,5),NaN>    | (-10,0)           |           NaN
+            | <(3,5),NaN>    | (-5,-12)          |           NaN
+            | <(3,5),NaN>    | (-3,4)            |           NaN
+            | <(3,5),NaN>    | (0,0)             |           NaN
+            | <(3,5),NaN>    | (1e-300,-1e-300)  |           NaN
+            | <(3,5),NaN>    | (5.1,34.5)        |           NaN
+            | <(3,5),NaN>    | (10,10)           |           NaN
+            | <(3,5),NaN>    | (1e+300,Infinity) |           NaN
+            | <(3,5),NaN>    | (NaN,NaN)         |           NaN
+(53 rows)
+
+-- To polygon
+SELECT f1, f1::polygon FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+       f1       |                                                                                                          f1                                                                                                          
+----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ <(5,1),3>      | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
+ <(1,2),100>    | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
+ <(1,3),5>      | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
+ <(1,2),3>      | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
+ <(100,200),10> | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
+ <(100,1),115>  | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
+(6 rows)
+
+-- To polygon with less points
+SELECT f1, polygon(8, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+       f1       |                                                                             polygon                                                                              
+----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ <(5,1),3>      | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
+ <(1,2),100>    | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
+ <(1,3),5>      | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
+ <(1,2),3>      | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
+ <(100,200),10> | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
+ <(100,1),115>  | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
+(6 rows)
+
+-- Too less points error
+SELECT f1, polygon(1, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+ERROR:  must request at least 2 points
+-- Zero radius error
+SELECT f1, polygon(10, f1) FROM CIRCLE_TBL WHERE f1 < '<(0,0),1>';
+ERROR:  cannot convert circle with radius zero to polygon
+-- Same as circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 ~= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+ <(3,5),NaN>    | <(3,5),0>
+ <(3,5),NaN>    | <(3,5),NaN>
+(9 rows)
+
+-- Overlap with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 && c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,1),115>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(100,1),115>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(33 rows)
+
+-- Overlap or left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &< c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(28 rows)
+
+-- Left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 << c2.f1;
+    f1     |       f1       
+-----------+----------------
+ <(5,1),3> | <(100,200),10>
+ <(1,3),5> | <(100,200),10>
+ <(1,2),3> | <(100,200),10>
+ <(3,5),0> | <(100,200),10>
+(4 rows)
+
+-- Right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >> c2.f1;
+       f1       |    f1     
+----------------+-----------
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(3,5),0>
+(4 rows)
+
+-- Overlap or right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(28 rows)
+
+-- Contained by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <@ c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(17 rows)
+
+-- Contain by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 @> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(3,5),0>
+(17 rows)
+
+-- Below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <<| c2.f1;
+      f1       |       f1       
+---------------+----------------
+ <(5,1),3>     | <(100,200),10>
+ <(5,1),3>     | <(3,5),0>
+ <(1,2),100>   | <(100,200),10>
+ <(1,3),5>     | <(100,200),10>
+ <(1,2),3>     | <(100,200),10>
+ <(100,1),115> | <(100,200),10>
+ <(3,5),0>     | <(100,200),10>
+(7 rows)
+
+-- Above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |>> c2.f1;
+       f1       |      f1       
+----------------+---------------
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(3,5),0>      | <(5,1),3>
+(7 rows)
+
+-- Overlap or below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &<| c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Overlap or above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |&> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 = c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(9 rows)
+
+-- Area not equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 != c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(40 rows)
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 > c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(3,5),0>
+(20 rows)
+
+-- Area less than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area greater than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Add point
+SELECT c.f1, p.f1, c.f1 + p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |        ?column?         
+----------------+-------------------+-------------------------
+ <(5,1),3>      | (0,0)             | <(5,1),3>
+ <(1,2),100>    | (0,0)             | <(1,2),100>
+ <(1,3),5>      | (0,0)             | <(1,3),5>
+ <(1,2),3>      | (0,0)             | <(1,2),3>
+ <(100,200),10> | (0,0)             | <(100,200),10>
+ <(100,1),115>  | (0,0)             | <(100,1),115>
+ <(3,5),0>      | (0,0)             | <(3,5),0>
+ <(3,5),NaN>    | (0,0)             | <(3,5),NaN>
+ <(5,1),3>      | (-10,0)           | <(-5,1),3>
+ <(1,2),100>    | (-10,0)           | <(-9,2),100>
+ <(1,3),5>      | (-10,0)           | <(-9,3),5>
+ <(1,2),3>      | (-10,0)           | <(-9,2),3>
+ <(100,200),10> | (-10,0)           | <(90,200),10>
+ <(100,1),115>  | (-10,0)           | <(90,1),115>
+ <(3,5),0>      | (-10,0)           | <(-7,5),0>
+ <(3,5),NaN>    | (-10,0)           | <(-7,5),NaN>
+ <(5,1),3>      | (-3,4)            | <(2,5),3>
+ <(1,2),100>    | (-3,4)            | <(-2,6),100>
+ <(1,3),5>      | (-3,4)            | <(-2,7),5>
+ <(1,2),3>      | (-3,4)            | <(-2,6),3>
+ <(100,200),10> | (-3,4)            | <(97,204),10>
+ <(100,1),115>  | (-3,4)            | <(97,5),115>
+ <(3,5),0>      | (-3,4)            | <(0,9),0>
+ <(3,5),NaN>    | (-3,4)            | <(0,9),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(10.1,35.5),3>
+ <(1,2),100>    | (5.1,34.5)        | <(6.1,36.5),100>
+ <(1,3),5>      | (5.1,34.5)        | <(6.1,37.5),5>
+ <(1,2),3>      | (5.1,34.5)        | <(6.1,36.5),3>
+ <(100,200),10> | (5.1,34.5)        | <(105.1,234.5),10>
+ <(100,1),115>  | (5.1,34.5)        | <(105.1,35.5),115>
+ <(3,5),0>      | (5.1,34.5)        | <(8.1,39.5),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(8.1,39.5),NaN>
+ <(5,1),3>      | (-5,-12)          | <(0,-11),3>
+ <(1,2),100>    | (-5,-12)          | <(-4,-10),100>
+ <(1,3),5>      | (-5,-12)          | <(-4,-9),5>
+ <(1,2),3>      | (-5,-12)          | <(-4,-10),3>
+ <(100,200),10> | (-5,-12)          | <(95,188),10>
+ <(100,1),115>  | (-5,-12)          | <(95,-11),115>
+ <(3,5),0>      | (-5,-12)          | <(-2,-7),0>
+ <(3,5),NaN>    | (-5,-12)          | <(-2,-7),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(5,1),3>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(1,2),100>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(1,3),5>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(1,2),3>
+ <(100,200),10> | (1e-300,-1e-300)  | <(100,200),10>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(100,1),115>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(3,5),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(3,5),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(1e+300,Infinity),3>
+ <(1,2),100>    | (1e+300,Infinity) | <(1e+300,Infinity),100>
+ <(1,3),5>      | (1e+300,Infinity) | <(1e+300,Infinity),5>
+ <(1,2),3>      | (1e+300,Infinity) | <(1e+300,Infinity),3>
+ <(100,200),10> | (1e+300,Infinity) | <(1e+300,Infinity),10>
+ <(100,1),115>  | (1e+300,Infinity) | <(1e+300,Infinity),115>
+ <(3,5),0>      | (1e+300,Infinity) | <(1e+300,Infinity),0>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(1e+300,Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),100>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),5>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),10>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),115>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),0>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(15,11),3>
+ <(1,2),100>    | (10,10)           | <(11,12),100>
+ <(1,3),5>      | (10,10)           | <(11,13),5>
+ <(1,2),3>      | (10,10)           | <(11,12),3>
+ <(100,200),10> | (10,10)           | <(110,210),10>
+ <(100,1),115>  | (10,10)           | <(110,11),115>
+ <(3,5),0>      | (10,10)           | <(13,15),0>
+ <(3,5),NaN>    | (10,10)           | <(13,15),NaN>
+(72 rows)
+
+-- Subtract point
+SELECT c.f1, p.f1, c.f1 - p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |         ?column?          
+----------------+-------------------+---------------------------
+ <(5,1),3>      | (0,0)             | <(5,1),3>
+ <(1,2),100>    | (0,0)             | <(1,2),100>
+ <(1,3),5>      | (0,0)             | <(1,3),5>
+ <(1,2),3>      | (0,0)             | <(1,2),3>
+ <(100,200),10> | (0,0)             | <(100,200),10>
+ <(100,1),115>  | (0,0)             | <(100,1),115>
+ <(3,5),0>      | (0,0)             | <(3,5),0>
+ <(3,5),NaN>    | (0,0)             | <(3,5),NaN>
+ <(5,1),3>      | (-10,0)           | <(15,1),3>
+ <(1,2),100>    | (-10,0)           | <(11,2),100>
+ <(1,3),5>      | (-10,0)           | <(11,3),5>
+ <(1,2),3>      | (-10,0)           | <(11,2),3>
+ <(100,200),10> | (-10,0)           | <(110,200),10>
+ <(100,1),115>  | (-10,0)           | <(110,1),115>
+ <(3,5),0>      | (-10,0)           | <(13,5),0>
+ <(3,5),NaN>    | (-10,0)           | <(13,5),NaN>
+ <(5,1),3>      | (-3,4)            | <(8,-3),3>
+ <(1,2),100>    | (-3,4)            | <(4,-2),100>
+ <(1,3),5>      | (-3,4)            | <(4,-1),5>
+ <(1,2),3>      | (-3,4)            | <(4,-2),3>
+ <(100,200),10> | (-3,4)            | <(103,196),10>
+ <(100,1),115>  | (-3,4)            | <(103,-3),115>
+ <(3,5),0>      | (-3,4)            | <(6,1),0>
+ <(3,5),NaN>    | (-3,4)            | <(6,1),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(-0.1,-33.5),3>
+ <(1,2),100>    | (5.1,34.5)        | <(-4.1,-32.5),100>
+ <(1,3),5>      | (5.1,34.5)        | <(-4.1,-31.5),5>
+ <(1,2),3>      | (5.1,34.5)        | <(-4.1,-32.5),3>
+ <(100,200),10> | (5.1,34.5)        | <(94.9,165.5),10>
+ <(100,1),115>  | (5.1,34.5)        | <(94.9,-33.5),115>
+ <(3,5),0>      | (5.1,34.5)        | <(-2.1,-29.5),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(-2.1,-29.5),NaN>
+ <(5,1),3>      | (-5,-12)          | <(10,13),3>
+ <(1,2),100>    | (-5,-12)          | <(6,14),100>
+ <(1,3),5>      | (-5,-12)          | <(6,15),5>
+ <(1,2),3>      | (-5,-12)          | <(6,14),3>
+ <(100,200),10> | (-5,-12)          | <(105,212),10>
+ <(100,1),115>  | (-5,-12)          | <(105,13),115>
+ <(3,5),0>      | (-5,-12)          | <(8,17),0>
+ <(3,5),NaN>    | (-5,-12)          | <(8,17),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(5,1),3>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(1,2),100>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(1,3),5>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(1,2),3>
+ <(100,200),10> | (1e-300,-1e-300)  | <(100,200),10>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(100,1),115>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(3,5),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(3,5),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(-1e+300,-Infinity),3>
+ <(1,2),100>    | (1e+300,Infinity) | <(-1e+300,-Infinity),100>
+ <(1,3),5>      | (1e+300,Infinity) | <(-1e+300,-Infinity),5>
+ <(1,2),3>      | (1e+300,Infinity) | <(-1e+300,-Infinity),3>
+ <(100,200),10> | (1e+300,Infinity) | <(-1e+300,-Infinity),10>
+ <(100,1),115>  | (1e+300,Infinity) | <(-1e+300,-Infinity),115>
+ <(3,5),0>      | (1e+300,Infinity) | <(-1e+300,-Infinity),0>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(-1e+300,-Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),100>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),5>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),10>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),115>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),0>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(-5,-9),3>
+ <(1,2),100>    | (10,10)           | <(-9,-8),100>
+ <(1,3),5>      | (10,10)           | <(-9,-7),5>
+ <(1,2),3>      | (10,10)           | <(-9,-8),3>
+ <(100,200),10> | (10,10)           | <(90,190),10>
+ <(100,1),115>  | (10,10)           | <(90,-9),115>
+ <(3,5),0>      | (10,10)           | <(-7,-5),0>
+ <(3,5),NaN>    | (10,10)           | <(-7,-5),NaN>
+(72 rows)
+
+-- Multiply with point
+SELECT c.f1, p.f1, c.f1 * p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |                  ?column?                  
+----------------+-------------------+--------------------------------------------
+ <(5,1),3>      | (0,0)             | <(0,0),0>
+ <(1,2),100>    | (0,0)             | <(0,0),0>
+ <(1,3),5>      | (0,0)             | <(0,0),0>
+ <(1,2),3>      | (0,0)             | <(0,0),0>
+ <(100,200),10> | (0,0)             | <(0,0),0>
+ <(100,1),115>  | (0,0)             | <(0,0),0>
+ <(3,5),0>      | (0,0)             | <(0,0),0>
+ <(3,5),NaN>    | (0,0)             | <(0,0),NaN>
+ <(5,1),3>      | (-10,0)           | <(-50,-10),30>
+ <(1,2),100>    | (-10,0)           | <(-10,-20),1000>
+ <(1,3),5>      | (-10,0)           | <(-10,-30),50>
+ <(1,2),3>      | (-10,0)           | <(-10,-20),30>
+ <(100,200),10> | (-10,0)           | <(-1000,-2000),100>
+ <(100,1),115>  | (-10,0)           | <(-1000,-10),1150>
+ <(3,5),0>      | (-10,0)           | <(-30,-50),0>
+ <(3,5),NaN>    | (-10,0)           | <(-30,-50),NaN>
+ <(5,1),3>      | (-3,4)            | <(-19,17),15>
+ <(1,2),100>    | (-3,4)            | <(-11,-2),500>
+ <(1,3),5>      | (-3,4)            | <(-15,-5),25>
+ <(1,2),3>      | (-3,4)            | <(-11,-2),15>
+ <(100,200),10> | (-3,4)            | <(-1100,-200),50>
+ <(100,1),115>  | (-3,4)            | <(-304,397),575>
+ <(3,5),0>      | (-3,4)            | <(-29,-3),0>
+ <(3,5),NaN>    | (-3,4)            | <(-29,-3),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(-9,177.6),104.624758064>
+ <(1,2),100>    | (5.1,34.5)        | <(-63.9,44.7),3487.49193547>
+ <(1,3),5>      | (5.1,34.5)        | <(-98.4,49.8),174.374596774>
+ <(1,2),3>      | (5.1,34.5)        | <(-63.9,44.7),104.624758064>
+ <(100,200),10> | (5.1,34.5)        | <(-6390,4470),348.749193547>
+ <(100,1),115>  | (5.1,34.5)        | <(475.5,3455.1),4010.6157258>
+ <(3,5),0>      | (5.1,34.5)        | <(-157.2,129),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(-157.2,129),NaN>
+ <(5,1),3>      | (-5,-12)          | <(-13,-65),39>
+ <(1,2),100>    | (-5,-12)          | <(19,-22),1300>
+ <(1,3),5>      | (-5,-12)          | <(31,-27),65>
+ <(1,2),3>      | (-5,-12)          | <(19,-22),39>
+ <(100,200),10> | (-5,-12)          | <(1900,-2200),130>
+ <(100,1),115>  | (-5,-12)          | <(-488,-1205),1495>
+ <(3,5),0>      | (-5,-12)          | <(45,-61),0>
+ <(3,5),NaN>    | (-5,-12)          | <(45,-61),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(6e-300,-4e-300),4.24264068712e-300>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(3e-300,1e-300),1.41421356237e-298>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(4e-300,2e-300),7.07106781187e-300>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(3e-300,1e-300),4.24264068712e-300>
+ <(100,200),10> | (1e-300,-1e-300)  | <(3e-298,1e-298),1.41421356237e-299>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(1.01e-298,-9.9e-299),1.62634559673e-298>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(8e-300,2e-300),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(8e-300,2e-300),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,2),100>    | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,3),5>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,2),3>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(100,200),10> | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(100,1),115>  | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(3,5),0>      | (1e+300,Infinity) | <(-Infinity,Infinity),NaN>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(-Infinity,Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(40,60),42.4264068712>
+ <(1,2),100>    | (10,10)           | <(-10,30),1414.21356237>
+ <(1,3),5>      | (10,10)           | <(-20,40),70.7106781187>
+ <(1,2),3>      | (10,10)           | <(-10,30),42.4264068712>
+ <(100,200),10> | (10,10)           | <(-1000,3000),141.421356237>
+ <(100,1),115>  | (10,10)           | <(990,1010),1626.34559673>
+ <(3,5),0>      | (10,10)           | <(-20,80),0>
+ <(3,5),NaN>    | (10,10)           | <(-20,80),NaN>
+(72 rows)
+
+-- Divide by point
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+       f1       |     f1     |                       ?column?                       
+----------------+------------+------------------------------------------------------
+ <(5,1),3>      | (5.1,34.5) | <(0.0493315573973,-0.137635045138),0.0860217042937>
+ <(5,1),3>      | (10,10)    | <(0.3,-0.2),0.212132034356>
+ <(1,2),100>    | (5.1,34.5) | <(0.0609244733856,-0.0199792807459),2.86739014312>
+ <(1,2),100>    | (10,10)    | <(0.15,0.05),7.07106781187>
+ <(1,3),5>      | (5.1,34.5) | <(0.0892901188891,-0.0157860983671),0.143369507156>
+ <(1,3),5>      | (10,10)    | <(0.2,0.1),0.353553390593>
+ <(1,2),3>      | (5.1,34.5) | <(0.0609244733856,-0.0199792807459),0.0860217042937>
+ <(1,2),3>      | (10,10)    | <(0.15,0.05),0.212132034356>
+ <(100,200),10> | (5.1,34.5) | <(6.09244733856,-1.99792807459),0.286739014312>
+ <(100,200),10> | (10,10)    | <(15,5),0.707106781187>
+ <(100,1),115>  | (5.1,34.5) | <(0.44768388338,-2.83237136796),3.29749866459>
+ <(100,1),115>  | (10,10)    | <(5.05,-4.95),8.13172798365>
+ <(3,5),0>      | (5.1,34.5) | <(0.154407774653,-0.0641310246164),0>
+ <(3,5),0>      | (10,10)    | <(0.4,0.1),0>
+ <(3,5),NaN>    | (5.1,34.5) | <(0.154407774653,-0.0641310246164),NaN>
+ <(3,5),NaN>    | (10,10)    | <(0.4,0.1),NaN>
+(16 rows)
+
+-- Overflow error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] > 1000;
+ERROR:  value out of range: overflow
+-- Division by 0 error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to polygon
+SELECT c.f1, p.f1, c.f1 <-> p.f1 FROM CIRCLE_TBL c, POLYGON_TBL p;
+       f1       |             f1             |    ?column?    
+----------------+----------------------------+----------------
+ <(5,1),3>      | ((2,0),(2,4),(0,0))        |              0
+ <(5,1),3>      | ((3,1),(3,3),(1,0))        |              0
+ <(5,1),3>      | ((1,2),(3,4),(5,6),(7,8))  | 0.535533905933
+ <(5,1),3>      | ((7,8),(5,6),(3,4),(1,2))  | 0.535533905933
+ <(5,1),3>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(5,1),3>      | ((0,0))                    |  2.09901951359
+ <(5,1),3>      | ((0,1),(0,1))              |              2
+ <(1,2),100>    | ((2,0),(2,4),(0,0))        |              0
+ <(1,2),100>    | ((3,1),(3,3),(1,0))        |              0
+ <(1,2),100>    | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,2),100>    | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,2),100>    | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,2),100>    | ((0,0))                    |              0
+ <(1,2),100>    | ((0,1),(0,1))              |              0
+ <(1,3),5>      | ((2,0),(2,4),(0,0))        |              0
+ <(1,3),5>      | ((3,1),(3,3),(1,0))        |              0
+ <(1,3),5>      | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,3),5>      | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,3),5>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,3),5>      | ((0,0))                    |              0
+ <(1,3),5>      | ((0,1),(0,1))              |              0
+ <(1,2),3>      | ((2,0),(2,4),(0,0))        |              0
+ <(1,2),3>      | ((3,1),(3,3),(1,0))        |              0
+ <(1,2),3>      | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,2),3>      | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,2),3>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,2),3>      | ((0,0))                    |              0
+ <(1,2),3>      | ((0,1),(0,1))              |              0
+ <(100,200),10> | ((2,0),(2,4),(0,0))        |  209.134661795
+ <(100,200),10> | ((3,1),(3,3),(1,0))        |  209.585974051
+ <(100,200),10> | ((1,2),(3,4),(5,6),(7,8))  |  203.337760371
+ <(100,200),10> | ((7,8),(5,6),(3,4),(1,2))  |  203.337760371
+ <(100,200),10> | ((1,2),(7,8),(5,6),(3,-4)) |  203.337760371
+ <(100,200),10> | ((0,0))                    |   213.60679775
+ <(100,200),10> | ((0,1),(0,1))              |  212.712819568
+ <(100,1),115>  | ((2,0),(2,4),(0,0))        |              0
+ <(100,1),115>  | ((3,1),(3,3),(1,0))        |              0
+ <(100,1),115>  | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(100,1),115>  | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(100,1),115>  | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(100,1),115>  | ((0,0))                    |              0
+ <(100,1),115>  | ((0,1),(0,1))              |              0
+ <(3,5),0>      | ((2,0),(2,4),(0,0))        |  1.41421356237
+ <(3,5),0>      | ((3,1),(3,3),(1,0))        |              2
+ <(3,5),0>      | ((1,2),(3,4),(5,6),(7,8))  | 0.707106781187
+ <(3,5),0>      | ((7,8),(5,6),(3,4),(1,2))  | 0.707106781187
+ <(3,5),0>      | ((1,2),(7,8),(5,6),(3,-4)) | 0.707106781187
+ <(3,5),0>      | ((0,0))                    |  5.83095189485
+ <(3,5),0>      | ((0,1),(0,1))              |              5
+ <(3,5),NaN>    | ((2,0),(2,4),(0,0))        |            NaN
+ <(3,5),NaN>    | ((3,1),(3,3),(1,0))        |            NaN
+ <(3,5),NaN>    | ((1,2),(3,4),(5,6),(7,8))  |            NaN
+ <(3,5),NaN>    | ((7,8),(5,6),(3,4),(1,2))  |            NaN
+ <(3,5),NaN>    | ((1,2),(7,8),(5,6),(3,-4)) |            NaN
+ <(3,5),NaN>    | ((0,0))                    |            NaN
+ <(3,5),NaN>    | ((0,1),(0,1))              |            NaN
+(56 rows)
 
diff --git a/src/test/regress/expected/geometry_1.out b/src/test/regress/expected/geometry_1.out
index 3b92e23059..48f4aa8638 100644
--- a/src/test/regress/expected/geometry_1.out
+++ b/src/test/regress/expected/geometry_1.out
@@ -13,9 +13,10 @@ SELECT '' AS four, center(f1) AS center
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, (@@ f1) AS center
    FROM BOX_TBL;
@@ -23,9 +24,10 @@ SELECT '' AS four, (@@ f1) AS center
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS six, point(f1) AS center
    FROM CIRCLE_TBL;
@@ -37,7 +39,9 @@ SELECT '' AS six, point(f1) AS center
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS six, (@@ f1) AS center
    FROM CIRCLE_TBL;
@@ -49,7 +53,9 @@ SELECT '' AS six, (@@ f1) AS center
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS two, (@@ f1) AS center
    FROM POLYGON_TBL
@@ -58,27 +64,32 @@ SELECT '' AS two, (@@ f1) AS center
 -----+-------------------------------
      | (1.33333333333,1.33333333333)
      | (2.33333333333,1.33333333333)
-(2 rows)
+     | (4,5)
+     | (4,5)
+     | (4,3)
+(5 rows)
 
 -- "is horizontal" function
 SELECT '' AS two, p1.f1
    FROM POINT_TBL p1
    WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 -- "is horizontal" operator
 SELECT '' AS two, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 -- "is vertical" function
 SELECT '' AS one, p1.f1
@@ -98,6 +109,1453 @@ SELECT '' AS one, p1.f1
      | (5.1,34.5)
 (1 row)
 
+-- Slope
+SELECT p1.f1, p2.f1, slope(p1.f1, p2.f1) FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |       slope        
+-------------------+-------------------+--------------------
+ (0,0)             | (0,0)             | 1.79769313486e+308
+ (0,0)             | (-10,0)           |                  0
+ (0,0)             | (-3,4)            |     -1.33333333333
+ (0,0)             | (5.1,34.5)        |      6.76470588235
+ (0,0)             | (-5,-12)          |                2.4
+ (0,0)             | (1e-300,-1e-300)  | 1.79769313486e+308
+ (0,0)             | (1e+300,Infinity) |           Infinity
+ (0,0)             | (NaN,NaN)         |                NaN
+ (0,0)             | (10,10)           |                  1
+ (-10,0)           | (0,0)             |                  0
+ (-10,0)           | (-10,0)           | 1.79769313486e+308
+ (-10,0)           | (-3,4)            |     0.571428571429
+ (-10,0)           | (5.1,34.5)        |      2.28476821192
+ (-10,0)           | (-5,-12)          |               -2.4
+ (-10,0)           | (1e-300,-1e-300)  |                  0
+ (-10,0)           | (1e+300,Infinity) |           Infinity
+ (-10,0)           | (NaN,NaN)         |                NaN
+ (-10,0)           | (10,10)           |                0.5
+ (-3,4)            | (0,0)             |     -1.33333333333
+ (-3,4)            | (-10,0)           |     0.571428571429
+ (-3,4)            | (-3,4)            | 1.79769313486e+308
+ (-3,4)            | (5.1,34.5)        |      3.76543209877
+ (-3,4)            | (-5,-12)          |                  8
+ (-3,4)            | (1e-300,-1e-300)  |     -1.33333333333
+ (-3,4)            | (1e+300,Infinity) |           Infinity
+ (-3,4)            | (NaN,NaN)         |                NaN
+ (-3,4)            | (10,10)           |     0.461538461538
+ (5.1,34.5)        | (0,0)             |      6.76470588235
+ (5.1,34.5)        | (-10,0)           |      2.28476821192
+ (5.1,34.5)        | (-3,4)            |      3.76543209877
+ (5.1,34.5)        | (5.1,34.5)        | 1.79769313486e+308
+ (5.1,34.5)        | (-5,-12)          |      4.60396039604
+ (5.1,34.5)        | (1e-300,-1e-300)  |      6.76470588235
+ (5.1,34.5)        | (1e+300,Infinity) |           Infinity
+ (5.1,34.5)        | (NaN,NaN)         |                NaN
+ (5.1,34.5)        | (10,10)           |                 -5
+ (-5,-12)          | (0,0)             |                2.4
+ (-5,-12)          | (-10,0)           |               -2.4
+ (-5,-12)          | (-3,4)            |                  8
+ (-5,-12)          | (5.1,34.5)        |      4.60396039604
+ (-5,-12)          | (-5,-12)          | 1.79769313486e+308
+ (-5,-12)          | (1e-300,-1e-300)  |                2.4
+ (-5,-12)          | (1e+300,Infinity) |           Infinity
+ (-5,-12)          | (NaN,NaN)         |                NaN
+ (-5,-12)          | (10,10)           |      1.46666666667
+ (1e-300,-1e-300)  | (0,0)             | 1.79769313486e+308
+ (1e-300,-1e-300)  | (-10,0)           |                  0
+ (1e-300,-1e-300)  | (-3,4)            |     -1.33333333333
+ (1e-300,-1e-300)  | (5.1,34.5)        |      6.76470588235
+ (1e-300,-1e-300)  | (-5,-12)          |                2.4
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | 1.79769313486e+308
+ (1e-300,-1e-300)  | (1e+300,Infinity) |           Infinity
+ (1e-300,-1e-300)  | (NaN,NaN)         |                NaN
+ (1e-300,-1e-300)  | (10,10)           |                  1
+ (1e+300,Infinity) | (0,0)             |           Infinity
+ (1e+300,Infinity) | (-10,0)           |           Infinity
+ (1e+300,Infinity) | (-3,4)            |           Infinity
+ (1e+300,Infinity) | (5.1,34.5)        |           Infinity
+ (1e+300,Infinity) | (-5,-12)          |           Infinity
+ (1e+300,Infinity) | (1e-300,-1e-300)  |           Infinity
+ (1e+300,Infinity) | (1e+300,Infinity) | 1.79769313486e+308
+ (1e+300,Infinity) | (NaN,NaN)         |                NaN
+ (1e+300,Infinity) | (10,10)           |           Infinity
+ (NaN,NaN)         | (0,0)             |                NaN
+ (NaN,NaN)         | (-10,0)           |                NaN
+ (NaN,NaN)         | (-3,4)            |                NaN
+ (NaN,NaN)         | (5.1,34.5)        |                NaN
+ (NaN,NaN)         | (-5,-12)          |                NaN
+ (NaN,NaN)         | (1e-300,-1e-300)  |                NaN
+ (NaN,NaN)         | (1e+300,Infinity) |                NaN
+ (NaN,NaN)         | (NaN,NaN)         |                NaN
+ (NaN,NaN)         | (10,10)           |                NaN
+ (10,10)           | (0,0)             |                  1
+ (10,10)           | (-10,0)           |                0.5
+ (10,10)           | (-3,4)            |     0.461538461538
+ (10,10)           | (5.1,34.5)        |                 -5
+ (10,10)           | (-5,-12)          |      1.46666666667
+ (10,10)           | (1e-300,-1e-300)  |                  1
+ (10,10)           | (1e+300,Infinity) |           Infinity
+ (10,10)           | (NaN,NaN)         |                NaN
+ (10,10)           | (10,10)           | 1.79769313486e+308
+(81 rows)
+
+-- Add point
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |     ?column?      
+-------------------+-------------------+-------------------
+ (0,0)             | (0,0)             | (0,0)
+ (0,0)             | (-10,0)           | (-10,0)
+ (0,0)             | (-3,4)            | (-3,4)
+ (0,0)             | (5.1,34.5)        | (5.1,34.5)
+ (0,0)             | (-5,-12)          | (-5,-12)
+ (0,0)             | (1e-300,-1e-300)  | (1e-300,-1e-300)
+ (0,0)             | (1e+300,Infinity) | (1e+300,Infinity)
+ (0,0)             | (NaN,NaN)         | (NaN,NaN)
+ (0,0)             | (10,10)           | (10,10)
+ (-10,0)           | (0,0)             | (-10,0)
+ (-10,0)           | (-10,0)           | (-20,0)
+ (-10,0)           | (-3,4)            | (-13,4)
+ (-10,0)           | (5.1,34.5)        | (-4.9,34.5)
+ (-10,0)           | (-5,-12)          | (-15,-12)
+ (-10,0)           | (1e-300,-1e-300)  | (-10,-1e-300)
+ (-10,0)           | (1e+300,Infinity) | (1e+300,Infinity)
+ (-10,0)           | (NaN,NaN)         | (NaN,NaN)
+ (-10,0)           | (10,10)           | (0,10)
+ (-3,4)            | (0,0)             | (-3,4)
+ (-3,4)            | (-10,0)           | (-13,4)
+ (-3,4)            | (-3,4)            | (-6,8)
+ (-3,4)            | (5.1,34.5)        | (2.1,38.5)
+ (-3,4)            | (-5,-12)          | (-8,-8)
+ (-3,4)            | (1e-300,-1e-300)  | (-3,4)
+ (-3,4)            | (1e+300,Infinity) | (1e+300,Infinity)
+ (-3,4)            | (NaN,NaN)         | (NaN,NaN)
+ (-3,4)            | (10,10)           | (7,14)
+ (5.1,34.5)        | (0,0)             | (5.1,34.5)
+ (5.1,34.5)        | (-10,0)           | (-4.9,34.5)
+ (5.1,34.5)        | (-3,4)            | (2.1,38.5)
+ (5.1,34.5)        | (5.1,34.5)        | (10.2,69)
+ (5.1,34.5)        | (-5,-12)          | (0.1,22.5)
+ (5.1,34.5)        | (1e-300,-1e-300)  | (5.1,34.5)
+ (5.1,34.5)        | (1e+300,Infinity) | (1e+300,Infinity)
+ (5.1,34.5)        | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5)        | (10,10)           | (15.1,44.5)
+ (-5,-12)          | (0,0)             | (-5,-12)
+ (-5,-12)          | (-10,0)           | (-15,-12)
+ (-5,-12)          | (-3,4)            | (-8,-8)
+ (-5,-12)          | (5.1,34.5)        | (0.1,22.5)
+ (-5,-12)          | (-5,-12)          | (-10,-24)
+ (-5,-12)          | (1e-300,-1e-300)  | (-5,-12)
+ (-5,-12)          | (1e+300,Infinity) | (1e+300,Infinity)
+ (-5,-12)          | (NaN,NaN)         | (NaN,NaN)
+ (-5,-12)          | (10,10)           | (5,-2)
+ (1e-300,-1e-300)  | (0,0)             | (1e-300,-1e-300)
+ (1e-300,-1e-300)  | (-10,0)           | (-10,-1e-300)
+ (1e-300,-1e-300)  | (-3,4)            | (-3,4)
+ (1e-300,-1e-300)  | (5.1,34.5)        | (5.1,34.5)
+ (1e-300,-1e-300)  | (-5,-12)          | (-5,-12)
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | (2e-300,-2e-300)
+ (1e-300,-1e-300)  | (1e+300,Infinity) | (1e+300,Infinity)
+ (1e-300,-1e-300)  | (NaN,NaN)         | (NaN,NaN)
+ (1e-300,-1e-300)  | (10,10)           | (10,10)
+ (1e+300,Infinity) | (0,0)             | (1e+300,Infinity)
+ (1e+300,Infinity) | (-10,0)           | (1e+300,Infinity)
+ (1e+300,Infinity) | (-3,4)            | (1e+300,Infinity)
+ (1e+300,Infinity) | (5.1,34.5)        | (1e+300,Infinity)
+ (1e+300,Infinity) | (-5,-12)          | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e-300,-1e-300)  | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e+300,Infinity) | (2e+300,Infinity)
+ (1e+300,Infinity) | (NaN,NaN)         | (NaN,NaN)
+ (1e+300,Infinity) | (10,10)           | (1e+300,Infinity)
+ (NaN,NaN)         | (0,0)             | (NaN,NaN)
+ (NaN,NaN)         | (-10,0)           | (NaN,NaN)
+ (NaN,NaN)         | (-3,4)            | (NaN,NaN)
+ (NaN,NaN)         | (5.1,34.5)        | (NaN,NaN)
+ (NaN,NaN)         | (-5,-12)          | (NaN,NaN)
+ (NaN,NaN)         | (1e-300,-1e-300)  | (NaN,NaN)
+ (NaN,NaN)         | (1e+300,Infinity) | (NaN,NaN)
+ (NaN,NaN)         | (NaN,NaN)         | (NaN,NaN)
+ (NaN,NaN)         | (10,10)           | (NaN,NaN)
+ (10,10)           | (0,0)             | (10,10)
+ (10,10)           | (-10,0)           | (0,10)
+ (10,10)           | (-3,4)            | (7,14)
+ (10,10)           | (5.1,34.5)        | (15.1,44.5)
+ (10,10)           | (-5,-12)          | (5,-2)
+ (10,10)           | (1e-300,-1e-300)  | (10,10)
+ (10,10)           | (1e+300,Infinity) | (1e+300,Infinity)
+ (10,10)           | (NaN,NaN)         | (NaN,NaN)
+ (10,10)           | (10,10)           | (20,20)
+(81 rows)
+
+-- Subtract point
+SELECT p1.f1, p2.f1, p1.f1 - p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |      ?column?       
+-------------------+-------------------+---------------------
+ (0,0)             | (0,0)             | (0,0)
+ (0,0)             | (-10,0)           | (10,0)
+ (0,0)             | (-3,4)            | (3,-4)
+ (0,0)             | (5.1,34.5)        | (-5.1,-34.5)
+ (0,0)             | (-5,-12)          | (5,12)
+ (0,0)             | (1e-300,-1e-300)  | (-1e-300,1e-300)
+ (0,0)             | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (0,0)             | (NaN,NaN)         | (NaN,NaN)
+ (0,0)             | (10,10)           | (-10,-10)
+ (-10,0)           | (0,0)             | (-10,0)
+ (-10,0)           | (-10,0)           | (0,0)
+ (-10,0)           | (-3,4)            | (-7,-4)
+ (-10,0)           | (5.1,34.5)        | (-15.1,-34.5)
+ (-10,0)           | (-5,-12)          | (-5,12)
+ (-10,0)           | (1e-300,-1e-300)  | (-10,1e-300)
+ (-10,0)           | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-10,0)           | (NaN,NaN)         | (NaN,NaN)
+ (-10,0)           | (10,10)           | (-20,-10)
+ (-3,4)            | (0,0)             | (-3,4)
+ (-3,4)            | (-10,0)           | (7,4)
+ (-3,4)            | (-3,4)            | (0,0)
+ (-3,4)            | (5.1,34.5)        | (-8.1,-30.5)
+ (-3,4)            | (-5,-12)          | (2,16)
+ (-3,4)            | (1e-300,-1e-300)  | (-3,4)
+ (-3,4)            | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-3,4)            | (NaN,NaN)         | (NaN,NaN)
+ (-3,4)            | (10,10)           | (-13,-6)
+ (5.1,34.5)        | (0,0)             | (5.1,34.5)
+ (5.1,34.5)        | (-10,0)           | (15.1,34.5)
+ (5.1,34.5)        | (-3,4)            | (8.1,30.5)
+ (5.1,34.5)        | (5.1,34.5)        | (0,0)
+ (5.1,34.5)        | (-5,-12)          | (10.1,46.5)
+ (5.1,34.5)        | (1e-300,-1e-300)  | (5.1,34.5)
+ (5.1,34.5)        | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (5.1,34.5)        | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5)        | (10,10)           | (-4.9,24.5)
+ (-5,-12)          | (0,0)             | (-5,-12)
+ (-5,-12)          | (-10,0)           | (5,-12)
+ (-5,-12)          | (-3,4)            | (-2,-16)
+ (-5,-12)          | (5.1,34.5)        | (-10.1,-46.5)
+ (-5,-12)          | (-5,-12)          | (0,0)
+ (-5,-12)          | (1e-300,-1e-300)  | (-5,-12)
+ (-5,-12)          | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-5,-12)          | (NaN,NaN)         | (NaN,NaN)
+ (-5,-12)          | (10,10)           | (-15,-22)
+ (1e-300,-1e-300)  | (0,0)             | (1e-300,-1e-300)
+ (1e-300,-1e-300)  | (-10,0)           | (10,-1e-300)
+ (1e-300,-1e-300)  | (-3,4)            | (3,-4)
+ (1e-300,-1e-300)  | (5.1,34.5)        | (-5.1,-34.5)
+ (1e-300,-1e-300)  | (-5,-12)          | (5,12)
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | (0,0)
+ (1e-300,-1e-300)  | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (1e-300,-1e-300)  | (NaN,NaN)         | (NaN,NaN)
+ (1e-300,-1e-300)  | (10,10)           | (-10,-10)
+ (1e+300,Infinity) | (0,0)             | (1e+300,Infinity)
+ (1e+300,Infinity) | (-10,0)           | (1e+300,Infinity)
+ (1e+300,Infinity) | (-3,4)            | (1e+300,Infinity)
+ (1e+300,Infinity) | (5.1,34.5)        | (1e+300,Infinity)
+ (1e+300,Infinity) | (-5,-12)          | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e-300,-1e-300)  | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e+300,Infinity) | (0,NaN)
+ (1e+300,Infinity) | (NaN,NaN)         | (NaN,NaN)
+ (1e+300,Infinity) | (10,10)           | (1e+300,Infinity)
+ (NaN,NaN)         | (0,0)             | (NaN,NaN)
+ (NaN,NaN)         | (-10,0)           | (NaN,NaN)
+ (NaN,NaN)         | (-3,4)            | (NaN,NaN)
+ (NaN,NaN)         | (5.1,34.5)        | (NaN,NaN)
+ (NaN,NaN)         | (-5,-12)          | (NaN,NaN)
+ (NaN,NaN)         | (1e-300,-1e-300)  | (NaN,NaN)
+ (NaN,NaN)         | (1e+300,Infinity) | (NaN,NaN)
+ (NaN,NaN)         | (NaN,NaN)         | (NaN,NaN)
+ (NaN,NaN)         | (10,10)           | (NaN,NaN)
+ (10,10)           | (0,0)             | (10,10)
+ (10,10)           | (-10,0)           | (20,10)
+ (10,10)           | (-3,4)            | (13,6)
+ (10,10)           | (5.1,34.5)        | (4.9,-24.5)
+ (10,10)           | (-5,-12)          | (15,22)
+ (10,10)           | (1e-300,-1e-300)  | (10,10)
+ (10,10)           | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (10,10)           | (NaN,NaN)         | (NaN,NaN)
+ (10,10)           | (10,10)           | (0,0)
+(81 rows)
+
+-- Multiply with point
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+     f1     |        f1         |       ?column?        
+------------+-------------------+-----------------------
+ (5.1,34.5) | (0,0)             | (0,0)
+ (10,10)    | (0,0)             | (0,0)
+ (5.1,34.5) | (-10,0)           | (-51,-345)
+ (10,10)    | (-10,0)           | (-100,-100)
+ (5.1,34.5) | (-3,4)            | (-153.3,-83.1)
+ (10,10)    | (-3,4)            | (-70,10)
+ (5.1,34.5) | (5.1,34.5)        | (-1164.24,351.9)
+ (10,10)    | (5.1,34.5)        | (-294,396)
+ (5.1,34.5) | (-5,-12)          | (388.5,-233.7)
+ (10,10)    | (-5,-12)          | (70,-170)
+ (5.1,34.5) | (1e-300,-1e-300)  | (3.96e-299,2.94e-299)
+ (10,10)    | (1e-300,-1e-300)  | (2e-299,0)
+ (5.1,34.5) | (1e+300,Infinity) | (-Infinity,Infinity)
+ (10,10)    | (1e+300,Infinity) | (-Infinity,Infinity)
+ (5.1,34.5) | (NaN,NaN)         | (NaN,NaN)
+ (10,10)    | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5) | (10,10)           | (-294,396)
+ (10,10)    | (10,10)           | (0,200)
+(18 rows)
+
+-- Underflow error
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] < 1;
+ERROR:  value out of range: underflow
+-- Divide by point
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] BETWEEN 1 AND 1000;
+        f1         |     f1     |                 ?column?                  
+-------------------+------------+-------------------------------------------
+ (0,0)             | (5.1,34.5) | (0,0)
+ (0,0)             | (10,10)    | (0,0)
+ (-10,0)           | (5.1,34.5) | (-0.0419318237877,0.283656455034)
+ (-10,0)           | (10,10)    | (-0.5,0.5)
+ (-3,4)            | (5.1,34.5) | (0.100883034877,0.101869666025)
+ (-3,4)            | (10,10)    | (0.05,0.35)
+ (5.1,34.5)        | (5.1,34.5) | (1,0)
+ (5.1,34.5)        | (10,10)    | (1.98,1.47)
+ (-5,-12)          | (5.1,34.5) | (-0.361353657935,0.0915100389719)
+ (-5,-12)          | (10,10)    | (-0.85,-0.35)
+ (1e-300,-1e-300)  | (5.1,34.5) | (-2.41724631247e-302,-3.25588278822e-302)
+ (1e-300,-1e-300)  | (10,10)    | (0,-1e-301)
+ (1e+300,Infinity) | (5.1,34.5) | (Infinity,Infinity)
+ (1e+300,Infinity) | (10,10)    | (Infinity,Infinity)
+ (NaN,NaN)         | (5.1,34.5) | (NaN,NaN)
+ (NaN,NaN)         | (10,10)    | (NaN,NaN)
+ (10,10)           | (5.1,34.5) | (0.325588278822,-0.241724631247)
+ (10,10)           | (10,10)    | (1,0)
+(18 rows)
+
+-- Overflow error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] > 1000;
+ERROR:  value out of range: overflow
+-- Division by 0 error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to line
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LINE_TBL l;
+        f1         |                   s                   |      ?column?      
+-------------------+---------------------------------------+--------------------
+ (0,0)             | {0,-1,5}                              |                  5
+ (0,0)             | {1,0,5}                               |                  5
+ (0,0)             | {0,3,0}                               |                  0
+ (0,0)             | {1,-1,0}                              |                  0
+ (0,0)             | {-0.4,-1,-6}                          |      5.57086014531
+ (0,0)             | {-0.000184615384615,-1,15.3846153846} |      15.3846151224
+ (0,0)             | {3,NaN,5}                             |                NaN
+ (0,0)             | {NaN,NaN,NaN}                         |                NaN
+ (0,0)             | {0,-1,3}                              |                  3
+ (0,0)             | {-1,0,3}                              |                  3
+ (-10,0)           | {0,-1,5}                              |                  5
+ (-10,0)           | {1,0,5}                               |                  5
+ (-10,0)           | {0,3,0}                               |                  0
+ (-10,0)           | {1,-1,0}                              |      7.07106781187
+ (-10,0)           | {-0.4,-1,-6}                          |      1.85695338177
+ (-10,0)           | {-0.000184615384615,-1,15.3846153846} |      15.3864612763
+ (-10,0)           | {3,NaN,5}                             |                NaN
+ (-10,0)           | {NaN,NaN,NaN}                         |                NaN
+ (-10,0)           | {0,-1,3}                              |                  3
+ (-10,0)           | {-1,0,3}                              |                 13
+ (-3,4)            | {0,-1,5}                              |                  1
+ (-3,4)            | {1,0,5}                               |                  2
+ (-3,4)            | {0,3,0}                               |                  4
+ (-3,4)            | {1,-1,0}                              |      4.94974746831
+ (-3,4)            | {-0.4,-1,-6}                          |      8.17059487979
+ (-3,4)            | {-0.000184615384615,-1,15.3846153846} |      11.3851690368
+ (-3,4)            | {3,NaN,5}                             |                NaN
+ (-3,4)            | {NaN,NaN,NaN}                         |                NaN
+ (-3,4)            | {0,-1,3}                              |                  1
+ (-3,4)            | {-1,0,3}                              |                  6
+ (5.1,34.5)        | {0,-1,5}                              |               29.5
+ (5.1,34.5)        | {1,0,5}                               |               10.1
+ (5.1,34.5)        | {0,3,0}                               |               34.5
+ (5.1,34.5)        | {1,-1,0}                              |      20.7889393669
+ (5.1,34.5)        | {-0.4,-1,-6}                          |      39.4973984303
+ (5.1,34.5)        | {-0.000184615384615,-1,15.3846153846} |      19.1163258281
+ (5.1,34.5)        | {3,NaN,5}                             |                NaN
+ (5.1,34.5)        | {NaN,NaN,NaN}                         |                NaN
+ (5.1,34.5)        | {0,-1,3}                              |               31.5
+ (5.1,34.5)        | {-1,0,3}                              |                2.1
+ (-5,-12)          | {0,-1,5}                              |                 17
+ (-5,-12)          | {1,0,5}                               |                  0
+ (-5,-12)          | {0,3,0}                               |                 12
+ (-5,-12)          | {1,-1,0}                              |      4.94974746831
+ (-5,-12)          | {-0.4,-1,-6}                          |      7.42781352708
+ (-5,-12)          | {-0.000184615384615,-1,15.3846153846} |      27.3855379948
+ (-5,-12)          | {3,NaN,5}                             |                NaN
+ (-5,-12)          | {NaN,NaN,NaN}                         |                NaN
+ (-5,-12)          | {0,-1,3}                              |                 15
+ (-5,-12)          | {-1,0,3}                              |                  8
+ (1e-300,-1e-300)  | {0,-1,5}                              |                  5
+ (1e-300,-1e-300)  | {1,0,5}                               |                  5
+ (1e-300,-1e-300)  | {0,3,0}                               |             1e-300
+ (1e-300,-1e-300)  | {1,-1,0}                              | 1.41421356237e-300
+ (1e-300,-1e-300)  | {-0.4,-1,-6}                          |      5.57086014531
+ (1e-300,-1e-300)  | {-0.000184615384615,-1,15.3846153846} |      15.3846151224
+ (1e-300,-1e-300)  | {3,NaN,5}                             |                NaN
+ (1e-300,-1e-300)  | {NaN,NaN,NaN}                         |                NaN
+ (1e-300,-1e-300)  | {0,-1,3}                              |                  3
+ (1e-300,-1e-300)  | {-1,0,3}                              |                  3
+ (1e+300,Infinity) | {0,-1,5}                              |           Infinity
+ (1e+300,Infinity) | {1,0,5}                               |                NaN
+ (1e+300,Infinity) | {0,3,0}                               |           Infinity
+ (1e+300,Infinity) | {1,-1,0}                              |           Infinity
+ (1e+300,Infinity) | {-0.4,-1,-6}                          |           Infinity
+ (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} |           Infinity
+ (1e+300,Infinity) | {3,NaN,5}                             |                NaN
+ (1e+300,Infinity) | {NaN,NaN,NaN}                         |                NaN
+ (1e+300,Infinity) | {0,-1,3}                              |           Infinity
+ (1e+300,Infinity) | {-1,0,3}                              |                NaN
+ (NaN,NaN)         | {0,-1,5}                              |                NaN
+ (NaN,NaN)         | {1,0,5}                               |                NaN
+ (NaN,NaN)         | {0,3,0}                               |                NaN
+ (NaN,NaN)         | {1,-1,0}                              |                NaN
+ (NaN,NaN)         | {-0.4,-1,-6}                          |                NaN
+ (NaN,NaN)         | {-0.000184615384615,-1,15.3846153846} |                NaN
+ (NaN,NaN)         | {3,NaN,5}                             |                NaN
+ (NaN,NaN)         | {NaN,NaN,NaN}                         |                NaN
+ (NaN,NaN)         | {0,-1,3}                              |                NaN
+ (NaN,NaN)         | {-1,0,3}                              |                NaN
+ (10,10)           | {0,-1,5}                              |                  5
+ (10,10)           | {1,0,5}                               |                 15
+ (10,10)           | {0,3,0}                               |                 10
+ (10,10)           | {1,-1,0}                              |                  0
+ (10,10)           | {-0.4,-1,-6}                          |      18.5695338177
+ (10,10)           | {-0.000184615384615,-1,15.3846153846} |      5.38276913903
+ (10,10)           | {3,NaN,5}                             |                NaN
+ (10,10)           | {NaN,NaN,NaN}                         |                NaN
+ (10,10)           | {0,-1,3}                              |                  7
+ (10,10)           | {-1,0,3}                              |                  7
+(90 rows)
+
+-- Distance to line segment
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LSEG_TBL l;
+        f1         |               s               |      ?column?      
+-------------------+-------------------------------+--------------------
+ (0,0)             | [(1,2),(3,4)]                 |       2.2360679775
+ (0,0)             | [(0,0),(6,6)]                 |                  0
+ (0,0)             | [(10,-10),(-3,-4)]            |      4.88901207039
+ (0,0)             | [(-1000000,200),(300000,-40)] |      15.3846151224
+ (0,0)             | [(11,22),(33,44)]             |      24.5967477525
+ (0,0)             | [(-10,2),(-10,3)]             |      10.1980390272
+ (0,0)             | [(0,-20),(30,-20)]            |                 20
+ (0,0)             | [(NaN,1),(NaN,90)]            |                NaN
+ (-10,0)           | [(1,2),(3,4)]                 |      11.1803398875
+ (-10,0)           | [(0,0),(6,6)]                 |                 10
+ (-10,0)           | [(10,-10),(-3,-4)]            |       8.0622577483
+ (-10,0)           | [(-1000000,200),(300000,-40)] |      15.3864612763
+ (-10,0)           | [(11,22),(33,44)]             |      30.4138126515
+ (-10,0)           | [(-10,2),(-10,3)]             |                  2
+ (-10,0)           | [(0,-20),(30,-20)]            |       22.360679775
+ (-10,0)           | [(NaN,1),(NaN,90)]            |                NaN
+ (-3,4)            | [(1,2),(3,4)]                 |        4.472135955
+ (-3,4)            | [(0,0),(6,6)]                 |      4.94974746831
+ (-3,4)            | [(10,-10),(-3,-4)]            |                  8
+ (-3,4)            | [(-1000000,200),(300000,-40)] |      11.3851690367
+ (-3,4)            | [(11,22),(33,44)]             |       22.803508502
+ (-3,4)            | [(-10,2),(-10,3)]             |      7.07106781187
+ (-3,4)            | [(0,-20),(30,-20)]            |      24.1867732449
+ (-3,4)            | [(NaN,1),(NaN,90)]            |                NaN
+ (5.1,34.5)        | [(1,2),(3,4)]                 |      30.5722096028
+ (5.1,34.5)        | [(0,0),(6,6)]                 |      28.5142069853
+ (5.1,34.5)        | [(10,-10),(-3,-4)]            |      39.3428519556
+ (5.1,34.5)        | [(-1000000,200),(300000,-40)] |      19.1163258281
+ (5.1,34.5)        | [(11,22),(33,44)]             |      13.0107647738
+ (5.1,34.5)        | [(-10,2),(-10,3)]             |       34.932220084
+ (5.1,34.5)        | [(0,-20),(30,-20)]            |               54.5
+ (5.1,34.5)        | [(NaN,1),(NaN,90)]            |                NaN
+ (-5,-12)          | [(1,2),(3,4)]                 |      15.2315462117
+ (-5,-12)          | [(0,0),(6,6)]                 |                 13
+ (-5,-12)          | [(10,-10),(-3,-4)]            |      8.10179143093
+ (-5,-12)          | [(-1000000,200),(300000,-40)] |      27.3855379949
+ (-5,-12)          | [(11,22),(33,44)]             |      37.5765884561
+ (-5,-12)          | [(-10,2),(-10,3)]             |      14.8660687473
+ (-5,-12)          | [(0,-20),(30,-20)]            |      9.43398113206
+ (-5,-12)          | [(NaN,1),(NaN,90)]            |                NaN
+ (1e-300,-1e-300)  | [(1,2),(3,4)]                 |       2.2360679775
+ (1e-300,-1e-300)  | [(0,0),(6,6)]                 | 1.41421356237e-300
+ (1e-300,-1e-300)  | [(10,-10),(-3,-4)]            |      4.88901207039
+ (1e-300,-1e-300)  | [(-1000000,200),(300000,-40)] |      15.3846151224
+ (1e-300,-1e-300)  | [(11,22),(33,44)]             |      24.5967477525
+ (1e-300,-1e-300)  | [(-10,2),(-10,3)]             |      10.1980390272
+ (1e-300,-1e-300)  | [(0,-20),(30,-20)]            |                 20
+ (1e-300,-1e-300)  | [(NaN,1),(NaN,90)]            |                NaN
+ (1e+300,Infinity) | [(1,2),(3,4)]                 |           Infinity
+ (1e+300,Infinity) | [(0,0),(6,6)]                 |           Infinity
+ (1e+300,Infinity) | [(10,-10),(-3,-4)]            |           Infinity
+ (1e+300,Infinity) | [(-1000000,200),(300000,-40)] |           Infinity
+ (1e+300,Infinity) | [(11,22),(33,44)]             |           Infinity
+ (1e+300,Infinity) | [(-10,2),(-10,3)]             |           Infinity
+ (1e+300,Infinity) | [(0,-20),(30,-20)]            |           Infinity
+ (1e+300,Infinity) | [(NaN,1),(NaN,90)]            |           Infinity
+ (NaN,NaN)         | [(1,2),(3,4)]                 |                NaN
+ (NaN,NaN)         | [(0,0),(6,6)]                 |                NaN
+ (NaN,NaN)         | [(10,-10),(-3,-4)]            |                NaN
+ (NaN,NaN)         | [(-1000000,200),(300000,-40)] |                NaN
+ (NaN,NaN)         | [(11,22),(33,44)]             |                NaN
+ (NaN,NaN)         | [(-10,2),(-10,3)]             |                NaN
+ (NaN,NaN)         | [(0,-20),(30,-20)]            |                NaN
+ (NaN,NaN)         | [(NaN,1),(NaN,90)]            |                NaN
+ (10,10)           | [(1,2),(3,4)]                 |      9.21954445729
+ (10,10)           | [(0,0),(6,6)]                 |      5.65685424949
+ (10,10)           | [(10,-10),(-3,-4)]            |        18.15918769
+ (10,10)           | [(-1000000,200),(300000,-40)] |      5.38276913904
+ (10,10)           | [(11,22),(33,44)]             |      12.0415945788
+ (10,10)           | [(-10,2),(-10,3)]             |      21.1896201004
+ (10,10)           | [(0,-20),(30,-20)]            |                 30
+ (10,10)           | [(NaN,1),(NaN,90)]            |                NaN
+(72 rows)
+
+-- Distance to box
+SELECT p.f1, b.f1, p.f1 <-> b.f1 FROM POINT_TBL p, BOX_TBL b;
+        f1         |         f1          |      ?column?      
+-------------------+---------------------+--------------------
+ (0,0)             | (2,2),(0,0)         |                  0
+ (0,0)             | (3,3),(1,1)         |      1.41421356237
+ (0,0)             | (-2,2),(-8,-10)     |                  2
+ (0,0)             | (2.5,3.5),(2.5,2.5) |      3.53553390593
+ (0,0)             | (3,3),(3,3)         |      4.24264068712
+ (-10,0)           | (2,2),(0,0)         |                 10
+ (-10,0)           | (3,3),(1,1)         |      11.0453610172
+ (-10,0)           | (-2,2),(-8,-10)     |                  2
+ (-10,0)           | (2.5,3.5),(2.5,2.5) |       12.747548784
+ (-10,0)           | (3,3),(3,3)         |      13.3416640641
+ (-3,4)            | (2,2),(0,0)         |      3.60555127546
+ (-3,4)            | (3,3),(1,1)         |      4.12310562562
+ (-3,4)            | (-2,2),(-8,-10)     |                  2
+ (-3,4)            | (2.5,3.5),(2.5,2.5) |      5.52268050859
+ (-3,4)            | (3,3),(3,3)         |       6.0827625303
+ (5.1,34.5)        | (2,2),(0,0)         |      32.6475113906
+ (5.1,34.5)        | (3,3),(1,1)         |      31.5699223946
+ (5.1,34.5)        | (-2,2),(-8,-10)     |      33.2664996656
+ (5.1,34.5)        | (2.5,3.5),(2.5,2.5) |       31.108841187
+ (5.1,34.5)        | (3,3),(3,3)         |      31.5699223946
+ (-5,-12)          | (2,2),(0,0)         |                 13
+ (-5,-12)          | (3,3),(1,1)         |      14.3178210633
+ (-5,-12)          | (-2,2),(-8,-10)     |                  2
+ (-5,-12)          | (2.5,3.5),(2.5,2.5) |      16.3248277173
+ (-5,-12)          | (3,3),(3,3)         |                 17
+ (1e-300,-1e-300)  | (2,2),(0,0)         | 1.41421356237e-300
+ (1e-300,-1e-300)  | (3,3),(1,1)         |      1.41421356237
+ (1e-300,-1e-300)  | (-2,2),(-8,-10)     |                  2
+ (1e-300,-1e-300)  | (2.5,3.5),(2.5,2.5) |      3.53553390593
+ (1e-300,-1e-300)  | (3,3),(3,3)         |      4.24264068712
+ (1e+300,Infinity) | (2,2),(0,0)         |           Infinity
+ (1e+300,Infinity) | (3,3),(1,1)         |           Infinity
+ (1e+300,Infinity) | (-2,2),(-8,-10)     |           Infinity
+ (1e+300,Infinity) | (2.5,3.5),(2.5,2.5) |           Infinity
+ (1e+300,Infinity) | (3,3),(3,3)         |           Infinity
+ (NaN,NaN)         | (2,2),(0,0)         |                NaN
+ (NaN,NaN)         | (3,3),(1,1)         |                NaN
+ (NaN,NaN)         | (-2,2),(-8,-10)     |                NaN
+ (NaN,NaN)         | (2.5,3.5),(2.5,2.5) |                NaN
+ (NaN,NaN)         | (3,3),(3,3)         |                NaN
+ (10,10)           | (2,2),(0,0)         |       11.313708499
+ (10,10)           | (3,3),(1,1)         |      9.89949493661
+ (10,10)           | (-2,2),(-8,-10)     |      14.4222051019
+ (10,10)           | (2.5,3.5),(2.5,2.5) |      9.92471662064
+ (10,10)           | (3,3),(3,3)         |      9.89949493661
+(45 rows)
+
+-- Distance to path
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, PATH_TBL p1;
+        f1         |            f1             |      ?column?      
+-------------------+---------------------------+--------------------
+ (0,0)             | [(1,2),(3,4)]             |       2.2360679775
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | [(0,0),(3,0),(4,5),(1,6)] |                  0
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | [(1,2),(3,4)]             |       2.2360679775
+ (0,0)             | ((10,20))                 |       22.360679775
+ (0,0)             | [(11,12),(13,14)]         |      16.2788205961
+ (0,0)             | ((11,12),(13,14))         |      16.2788205961
+ (-10,0)           | [(1,2),(3,4)]             |      11.1803398875
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | [(0,0),(3,0),(4,5),(1,6)] |                 10
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | [(1,2),(3,4)]             |      11.1803398875
+ (-10,0)           | ((10,20))                 |      28.2842712475
+ (-10,0)           | [(11,12),(13,14)]         |      24.1867732449
+ (-10,0)           | ((11,12),(13,14))         |      24.1867732449
+ (-3,4)            | [(1,2),(3,4)]             |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | [(0,0),(3,0),(4,5),(1,6)] |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | [(1,2),(3,4)]             |        4.472135955
+ (-3,4)            | ((10,20))                 |      20.6155281281
+ (-3,4)            | [(11,12),(13,14)]         |      16.1245154966
+ (-3,4)            | ((11,12),(13,14))         |      16.1245154966
+ (5.1,34.5)        | [(1,2),(3,4)]             |      30.5722096028
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | [(0,0),(3,0),(4,5),(1,6)] |       28.793402022
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | [(1,2),(3,4)]             |      30.5722096028
+ (5.1,34.5)        | ((10,20))                 |      15.3055545473
+ (5.1,34.5)        | [(11,12),(13,14)]         |      21.9695243462
+ (5.1,34.5)        | ((11,12),(13,14))         |      21.9695243462
+ (-5,-12)          | [(1,2),(3,4)]             |      15.2315462117
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | [(0,0),(3,0),(4,5),(1,6)] |                 13
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | [(1,2),(3,4)]             |      15.2315462117
+ (-5,-12)          | ((10,20))                 |      35.3411940941
+ (-5,-12)          | [(11,12),(13,14)]         |      28.8444102037
+ (-5,-12)          | ((11,12),(13,14))         |      28.8444102037
+ (1e-300,-1e-300)  | [(1,2),(3,4)]             |       2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | [(0,0),(3,0),(4,5),(1,6)] | 1.41421356237e-300
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | [(1,2),(3,4)]             |       2.2360679775
+ (1e-300,-1e-300)  | ((10,20))                 |       22.360679775
+ (1e-300,-1e-300)  | [(11,12),(13,14)]         |      16.2788205961
+ (1e-300,-1e-300)  | ((11,12),(13,14))         |      16.2788205961
+ (1e+300,Infinity) | [(1,2),(3,4)]             |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | [(0,0),(3,0),(4,5),(1,6)] |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | [(1,2),(3,4)]             |           Infinity
+ (1e+300,Infinity) | ((10,20))                 |           Infinity
+ (1e+300,Infinity) | [(11,12),(13,14)]         |           Infinity
+ (1e+300,Infinity) | ((11,12),(13,14))         |           Infinity
+ (NaN,NaN)         | [(1,2),(3,4)]             |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | [(0,0),(3,0),(4,5),(1,6)] |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | [(1,2),(3,4)]             |                NaN
+ (NaN,NaN)         | ((10,20))                 |                NaN
+ (NaN,NaN)         | [(11,12),(13,14)]         |                NaN
+ (NaN,NaN)         | ((11,12),(13,14))         |                NaN
+ (10,10)           | [(1,2),(3,4)]             |      9.21954445729
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | [(0,0),(3,0),(4,5),(1,6)] |      7.81024967591
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | [(1,2),(3,4)]             |      9.21954445729
+ (10,10)           | ((10,20))                 |                 10
+ (10,10)           | [(11,12),(13,14)]         |       2.2360679775
+ (10,10)           | ((11,12),(13,14))         |       2.2360679775
+(81 rows)
+
+-- Distance to polygon
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, POLYGON_TBL p1;
+        f1         |             f1             |   ?column?    
+-------------------+----------------------------+---------------
+ (0,0)             | ((2,0),(2,4),(0,0))        |             0
+ (0,0)             | ((3,1),(3,3),(1,0))        |             1
+ (0,0)             | ((1,2),(3,4),(5,6),(7,8))  |  2.2360679775
+ (0,0)             | ((7,8),(5,6),(3,4),(1,2))  |  2.2360679775
+ (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | 1.58113883008
+ (0,0)             | ((0,0))                    |             0
+ (0,0)             | ((0,1),(0,1))              |             1
+ (-10,0)           | ((2,0),(2,4),(0,0))        |            10
+ (-10,0)           | ((3,1),(3,3),(1,0))        |            11
+ (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | 11.1803398875
+ (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | 11.1803398875
+ (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | 11.1803398875
+ (-10,0)           | ((0,0))                    |            10
+ (-10,0)           | ((0,1),(0,1))              | 10.0498756211
+ (-3,4)            | ((2,0),(2,4),(0,0))        |   4.472135955
+ (-3,4)            | ((3,1),(3,3),(1,0))        | 5.54700196225
+ (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  |   4.472135955
+ (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  |   4.472135955
+ (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) |   4.472135955
+ (-3,4)            | ((0,0))                    |             5
+ (-3,4)            | ((0,1),(0,1))              | 4.24264068712
+ (5.1,34.5)        | ((2,0),(2,4),(0,0))        | 30.6571362002
+ (5.1,34.5)        | ((3,1),(3,3),(1,0))        | 31.5699223946
+ (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | 26.5680258958
+ (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | 26.5680258958
+ (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | 26.5680258958
+ (5.1,34.5)        | ((0,0))                    | 34.8749193547
+ (5.1,34.5)        | ((0,1),(0,1))              | 33.8859853037
+ (-5,-12)          | ((2,0),(2,4),(0,0))        |            13
+ (-5,-12)          | ((3,1),(3,3),(1,0))        |  13.416407865
+ (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | 15.2315462117
+ (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | 15.2315462117
+ (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) |  11.313708499
+ (-5,-12)          | ((0,0))                    |            13
+ (-5,-12)          | ((0,1),(0,1))              | 13.9283882772
+ (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        |             0
+ (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        |             1
+ (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  |  2.2360679775
+ (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  |  2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | 1.58113883008
+ (1e-300,-1e-300)  | ((0,0))                    |             0
+ (1e-300,-1e-300)  | ((0,1),(0,1))              |             1
+ (1e+300,Infinity) | ((2,0),(2,4),(0,0))        |      Infinity
+ (1e+300,Infinity) | ((3,1),(3,3),(1,0))        |      Infinity
+ (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  |      Infinity
+ (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  |      Infinity
+ (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) |      Infinity
+ (1e+300,Infinity) | ((0,0))                    |      Infinity
+ (1e+300,Infinity) | ((0,1),(0,1))              |      Infinity
+ (NaN,NaN)         | ((2,0),(2,4),(0,0))        |             0
+ (NaN,NaN)         | ((3,1),(3,3),(1,0))        |             0
+ (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  |             0
+ (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  |             0
+ (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) |             0
+ (NaN,NaN)         | ((0,0))                    |             0
+ (NaN,NaN)         | ((0,1),(0,1))              |             0
+ (10,10)           | ((2,0),(2,4),(0,0))        |            10
+ (10,10)           | ((3,1),(3,3),(1,0))        | 9.89949493661
+ (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | 3.60555127546
+ (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | 3.60555127546
+ (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | 3.60555127546
+ (10,10)           | ((0,0))                    | 14.1421356237
+ (10,10)           | ((0,1),(0,1))              | 13.4536240471
+(63 rows)
+
+-- Closest point to line
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LINE_TBL l;
+        f1         |                   s                   |             ?column?             
+-------------------+---------------------------------------+----------------------------------
+ (0,0)             | {0,-1,5}                              | (0,5)
+ (0,0)             | {1,0,5}                               | (-5,0)
+ (0,0)             | {0,3,0}                               | (0,0)
+ (0,0)             | {1,-1,0}                              | (0,0)
+ (0,0)             | {-0.4,-1,-6}                          | (-2.06896551724,-5.1724137931)
+ (0,0)             | {-0.000184615384615,-1,15.3846153846} | (0.00284023658959,15.3846148603)
+ (0,0)             | {3,NaN,5}                             | 
+ (0,0)             | {NaN,NaN,NaN}                         | 
+ (0,0)             | {0,-1,3}                              | (0,3)
+ (0,0)             | {-1,0,3}                              | (3,0)
+ (-10,0)           | {0,-1,5}                              | (-10,5)
+ (-10,0)           | {1,0,5}                               | (-5,0)
+ (-10,0)           | {0,3,0}                               | (-10,0)
+ (-10,0)           | {1,-1,0}                              | (-5,-5)
+ (-10,0)           | {-0.4,-1,-6}                          | (-10.6896551724,-1.72413793103)
+ (-10,0)           | {-0.000184615384615,-1,15.3846153846} | (-9.99715942258,15.386461014)
+ (-10,0)           | {3,NaN,5}                             | 
+ (-10,0)           | {NaN,NaN,NaN}                         | 
+ (-10,0)           | {0,-1,3}                              | (-10,3)
+ (-10,0)           | {-1,0,3}                              | (3,0)
+ (-3,4)            | {0,-1,5}                              | (-3,5)
+ (-3,4)            | {1,0,5}                               | (-5,4)
+ (-3,4)            | {0,3,0}                               | (-3,0)
+ (-3,4)            | {1,-1,0}                              | (0.5,0.5)
+ (-3,4)            | {-0.4,-1,-6}                          | (-6.03448275862,-3.58620689655)
+ (-3,4)            | {-0.000184615384615,-1,15.3846153846} | (-2.99789812268,15.3851688427)
+ (-3,4)            | {3,NaN,5}                             | 
+ (-3,4)            | {NaN,NaN,NaN}                         | 
+ (-3,4)            | {0,-1,3}                              | (-3,3)
+ (-3,4)            | {-1,0,3}                              | (3,4)
+ (5.1,34.5)        | {0,-1,5}                              | (5.1,5)
+ (5.1,34.5)        | {1,0,5}                               | (-5,34.5)
+ (5.1,34.5)        | {0,3,0}                               | (5.1,0)
+ (5.1,34.5)        | {1,-1,0}                              | (19.8,19.8)
+ (5.1,34.5)        | {-0.4,-1,-6}                          | (-9.56896551724,-2.1724137931)
+ (5.1,34.5)        | {-0.000184615384615,-1,15.3846153846} | (5.09647083221,15.3836744977)
+ (5.1,34.5)        | {3,NaN,5}                             | 
+ (5.1,34.5)        | {NaN,NaN,NaN}                         | 
+ (5.1,34.5)        | {0,-1,3}                              | (5.1,3)
+ (5.1,34.5)        | {-1,0,3}                              | (3,34.5)
+ (-5,-12)          | {0,-1,5}                              | (-5,5)
+ (-5,-12)          | {1,0,5}                               | (-5,-12)
+ (-5,-12)          | {0,3,0}                               | (-5,0)
+ (-5,-12)          | {1,-1,0}                              | (-8.5,-8.5)
+ (-5,-12)          | {-0.4,-1,-6}                          | (-2.24137931034,-5.10344827586)
+ (-5,-12)          | {-0.000184615384615,-1,15.3846153846} | (-4.99494420846,15.3855375282)
+ (-5,-12)          | {3,NaN,5}                             | 
+ (-5,-12)          | {NaN,NaN,NaN}                         | 
+ (-5,-12)          | {0,-1,3}                              | (-5,3)
+ (-5,-12)          | {-1,0,3}                              | (3,-12)
+ (1e-300,-1e-300)  | {0,-1,5}                              | (1e-300,5)
+ (1e-300,-1e-300)  | {1,0,5}                               | (-5,-1e-300)
+ (1e-300,-1e-300)  | {0,3,0}                               | (1e-300,0)
+ (1e-300,-1e-300)  | {1,-1,0}                              | (0,0)
+ (1e-300,-1e-300)  | {-0.4,-1,-6}                          | (-2.06896551724,-5.1724137931)
+ (1e-300,-1e-300)  | {-0.000184615384615,-1,15.3846153846} | (0.00284023658959,15.3846148603)
+ (1e-300,-1e-300)  | {3,NaN,5}                             | 
+ (1e-300,-1e-300)  | {NaN,NaN,NaN}                         | 
+ (1e-300,-1e-300)  | {0,-1,3}                              | (1e-300,3)
+ (1e-300,-1e-300)  | {-1,0,3}                              | (3,-1e-300)
+ (1e+300,Infinity) | {0,-1,5}                              | (1e+300,5)
+ (1e+300,Infinity) | {1,0,5}                               | 
+ (1e+300,Infinity) | {0,3,0}                               | (1e+300,0)
+ (1e+300,Infinity) | {1,-1,0}                              | (Infinity,NaN)
+ (1e+300,Infinity) | {-0.4,-1,-6}                          | (-Infinity,NaN)
+ (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} | (-Infinity,NaN)
+ (1e+300,Infinity) | {3,NaN,5}                             | 
+ (1e+300,Infinity) | {NaN,NaN,NaN}                         | 
+ (1e+300,Infinity) | {0,-1,3}                              | (1e+300,3)
+ (1e+300,Infinity) | {-1,0,3}                              | 
+ (NaN,NaN)         | {0,-1,5}                              | 
+ (NaN,NaN)         | {1,0,5}                               | 
+ (NaN,NaN)         | {0,3,0}                               | 
+ (NaN,NaN)         | {1,-1,0}                              | 
+ (NaN,NaN)         | {-0.4,-1,-6}                          | 
+ (NaN,NaN)         | {-0.000184615384615,-1,15.3846153846} | 
+ (NaN,NaN)         | {3,NaN,5}                             | 
+ (NaN,NaN)         | {NaN,NaN,NaN}                         | 
+ (NaN,NaN)         | {0,-1,3}                              | 
+ (NaN,NaN)         | {-1,0,3}                              | 
+ (10,10)           | {0,-1,5}                              | (10,5)
+ (10,10)           | {1,0,5}                               | (-5,10)
+ (10,10)           | {0,3,0}                               | (10,0)
+ (10,10)           | {1,-1,0}                              | (10,10)
+ (10,10)           | {-0.4,-1,-6}                          | (3.10344827586,-7.24137931034)
+ (10,10)           | {-0.000184615384615,-1,15.3846153846} | (10.000993742,15.3827690473)
+ (10,10)           | {3,NaN,5}                             | 
+ (10,10)           | {NaN,NaN,NaN}                         | 
+ (10,10)           | {0,-1,3}                              | (10,3)
+ (10,10)           | {-1,0,3}                              | (3,10)
+(90 rows)
+
+-- Closest point to line segment
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LSEG_TBL l;
+        f1         |               s               |             ?column?             
+-------------------+-------------------------------+----------------------------------
+ (0,0)             | [(1,2),(3,4)]                 | (1,2)
+ (0,0)             | [(0,0),(6,6)]                 | (0,0)
+ (0,0)             | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ (0,0)             | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
+ (0,0)             | [(11,22),(33,44)]             | (11,22)
+ (0,0)             | [(-10,2),(-10,3)]             | (-10,2)
+ (0,0)             | [(0,-20),(30,-20)]            | (0,-20)
+ (0,0)             | [(NaN,1),(NaN,90)]            | 
+ (-10,0)           | [(1,2),(3,4)]                 | (1,2)
+ (-10,0)           | [(0,0),(6,6)]                 | (0,0)
+ (-10,0)           | [(10,-10),(-3,-4)]            | (-3,-4)
+ (-10,0)           | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
+ (-10,0)           | [(11,22),(33,44)]             | (11,22)
+ (-10,0)           | [(-10,2),(-10,3)]             | (-10,2)
+ (-10,0)           | [(0,-20),(30,-20)]            | (0,-20)
+ (-10,0)           | [(NaN,1),(NaN,90)]            | 
+ (-3,4)            | [(1,2),(3,4)]                 | (1,2)
+ (-3,4)            | [(0,0),(6,6)]                 | (0.5,0.5)
+ (-3,4)            | [(10,-10),(-3,-4)]            | (-3,-4)
+ (-3,4)            | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
+ (-3,4)            | [(11,22),(33,44)]             | (11,22)
+ (-3,4)            | [(-10,2),(-10,3)]             | (-10,3)
+ (-3,4)            | [(0,-20),(30,-20)]            | (0,-20)
+ (-3,4)            | [(NaN,1),(NaN,90)]            | 
+ (5.1,34.5)        | [(1,2),(3,4)]                 | (3,4)
+ (5.1,34.5)        | [(0,0),(6,6)]                 | (6,6)
+ (5.1,34.5)        | [(10,-10),(-3,-4)]            | (-3,-4)
+ (5.1,34.5)        | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
+ (5.1,34.5)        | [(11,22),(33,44)]             | (14.3,25.3)
+ (5.1,34.5)        | [(-10,2),(-10,3)]             | (-10,3)
+ (5.1,34.5)        | [(0,-20),(30,-20)]            | (5.1,-20)
+ (5.1,34.5)        | [(NaN,1),(NaN,90)]            | 
+ (-5,-12)          | [(1,2),(3,4)]                 | (1,2)
+ (-5,-12)          | [(0,0),(6,6)]                 | (0,0)
+ (-5,-12)          | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
+ (-5,-12)          | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
+ (-5,-12)          | [(11,22),(33,44)]             | (11,22)
+ (-5,-12)          | [(-10,2),(-10,3)]             | (-10,2)
+ (-5,-12)          | [(0,-20),(30,-20)]            | (0,-20)
+ (-5,-12)          | [(NaN,1),(NaN,90)]            | 
+ (1e-300,-1e-300)  | [(1,2),(3,4)]                 | (1,2)
+ (1e-300,-1e-300)  | [(0,0),(6,6)]                 | (0,0)
+ (1e-300,-1e-300)  | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ (1e-300,-1e-300)  | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
+ (1e-300,-1e-300)  | [(11,22),(33,44)]             | (11,22)
+ (1e-300,-1e-300)  | [(-10,2),(-10,3)]             | (-10,2)
+ (1e-300,-1e-300)  | [(0,-20),(30,-20)]            | (0,-20)
+ (1e-300,-1e-300)  | [(NaN,1),(NaN,90)]            | 
+ (1e+300,Infinity) | [(1,2),(3,4)]                 | (3,4)
+ (1e+300,Infinity) | [(0,0),(6,6)]                 | (6,6)
+ (1e+300,Infinity) | [(10,-10),(-3,-4)]            | (-3,-4)
+ (1e+300,Infinity) | [(-1000000,200),(300000,-40)] | (300000,-40)
+ (1e+300,Infinity) | [(11,22),(33,44)]             | (33,44)
+ (1e+300,Infinity) | [(-10,2),(-10,3)]             | (-10,3)
+ (1e+300,Infinity) | [(0,-20),(30,-20)]            | (30,-20)
+ (1e+300,Infinity) | [(NaN,1),(NaN,90)]            | (NaN,90)
+ (NaN,NaN)         | [(1,2),(3,4)]                 | 
+ (NaN,NaN)         | [(0,0),(6,6)]                 | 
+ (NaN,NaN)         | [(10,-10),(-3,-4)]            | 
+ (NaN,NaN)         | [(-1000000,200),(300000,-40)] | 
+ (NaN,NaN)         | [(11,22),(33,44)]             | 
+ (NaN,NaN)         | [(-10,2),(-10,3)]             | 
+ (NaN,NaN)         | [(0,-20),(30,-20)]            | 
+ (NaN,NaN)         | [(NaN,1),(NaN,90)]            | 
+ (10,10)           | [(1,2),(3,4)]                 | (3,4)
+ (10,10)           | [(0,0),(6,6)]                 | (6,6)
+ (10,10)           | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
+ (10,10)           | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
+ (10,10)           | [(11,22),(33,44)]             | (11,22)
+ (10,10)           | [(-10,2),(-10,3)]             | (-10,3)
+ (10,10)           | [(0,-20),(30,-20)]            | (10,-20)
+ (10,10)           | [(NaN,1),(NaN,90)]            | 
+(72 rows)
+
+-- Closest point to box
+SELECT p.f1, b.f1, p.f1 ## b.f1 FROM POINT_TBL p, BOX_TBL b;
+        f1         |         f1          |   ?column?   
+-------------------+---------------------+--------------
+ (0,0)             | (2,2),(0,0)         | (0,0)
+ (0,0)             | (3,3),(1,1)         | (1,1)
+ (0,0)             | (-2,2),(-8,-10)     | (-2,0)
+ (0,0)             | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (0,0)             | (3,3),(3,3)         | (3,3)
+ (-10,0)           | (2,2),(0,0)         | (0,0)
+ (-10,0)           | (3,3),(1,1)         | (1,1)
+ (-10,0)           | (-2,2),(-8,-10)     | (-8,0)
+ (-10,0)           | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (-10,0)           | (3,3),(3,3)         | (3,3)
+ (-3,4)            | (2,2),(0,0)         | (0,2)
+ (-3,4)            | (3,3),(1,1)         | (1,3)
+ (-3,4)            | (-2,2),(-8,-10)     | (-3,2)
+ (-3,4)            | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (-3,4)            | (3,3),(3,3)         | (3,3)
+ (5.1,34.5)        | (2,2),(0,0)         | (2,2)
+ (5.1,34.5)        | (3,3),(1,1)         | (3,3)
+ (5.1,34.5)        | (-2,2),(-8,-10)     | (-2,2)
+ (5.1,34.5)        | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (5.1,34.5)        | (3,3),(3,3)         | (3,3)
+ (-5,-12)          | (2,2),(0,0)         | (0,0)
+ (-5,-12)          | (3,3),(1,1)         | (1,1)
+ (-5,-12)          | (-2,2),(-8,-10)     | (-5,-10)
+ (-5,-12)          | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (-5,-12)          | (3,3),(3,3)         | (3,3)
+ (1e-300,-1e-300)  | (2,2),(0,0)         | (0,0)
+ (1e-300,-1e-300)  | (3,3),(1,1)         | (1,1)
+ (1e-300,-1e-300)  | (-2,2),(-8,-10)     | (-2,-1e-300)
+ (1e-300,-1e-300)  | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (1e-300,-1e-300)  | (3,3),(3,3)         | (3,3)
+ (1e+300,Infinity) | (2,2),(0,0)         | (0,2)
+ (1e+300,Infinity) | (3,3),(1,1)         | (1,3)
+ (1e+300,Infinity) | (-2,2),(-8,-10)     | (-8,2)
+ (1e+300,Infinity) | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (1e+300,Infinity) | (3,3),(3,3)         | (3,3)
+ (NaN,NaN)         | (2,2),(0,0)         | 
+ (NaN,NaN)         | (3,3),(1,1)         | 
+ (NaN,NaN)         | (-2,2),(-8,-10)     | 
+ (NaN,NaN)         | (2.5,3.5),(2.5,2.5) | 
+ (NaN,NaN)         | (3,3),(3,3)         | 
+ (10,10)           | (2,2),(0,0)         | (2,2)
+ (10,10)           | (3,3),(1,1)         | (3,3)
+ (10,10)           | (-2,2),(-8,-10)     | (-2,2)
+ (10,10)           | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (10,10)           | (3,3),(3,3)         | (3,3)
+(45 rows)
+
+-- On line
+SELECT p.f1, l.s FROM POINT_TBL p, LINE_TBL l WHERE p.f1 <@ l.s;
+        f1        |    s     
+------------------+----------
+ (0,0)            | {0,3,0}
+ (0,0)            | {1,-1,0}
+ (-10,0)          | {0,3,0}
+ (-5,-12)         | {1,0,5}
+ (1e-300,-1e-300) | {0,3,0}
+ (1e-300,-1e-300) | {1,-1,0}
+ (10,10)          | {1,-1,0}
+(7 rows)
+
+-- On line segment
+SELECT p.f1, l.s FROM POINT_TBL p, LSEG_TBL l WHERE p.f1 <@ l.s;
+        f1        |       s       
+------------------+---------------
+ (0,0)            | [(0,0),(6,6)]
+ (1e-300,-1e-300) | [(0,0),(6,6)]
+(2 rows)
+
+-- On path
+SELECT p.f1, p1.f1 FROM POINT_TBL p, PATH_TBL p1 WHERE p.f1 <@ p1.f1;
+        f1        |            f1             
+------------------+---------------------------
+ (0,0)            | [(0,0),(3,0),(4,5),(1,6)]
+ (1e-300,-1e-300) | [(0,0),(3,0),(4,5),(1,6)]
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((10,20))
+ (NaN,NaN)        | ((11,12),(13,14))
+(7 rows)
+
+--
+-- Lines
+--
+-- Vertical
+SELECT s FROM LINE_TBL WHERE ?| s;
+    s     
+----------
+ {1,0,5}
+ {-1,0,3}
+(2 rows)
+
+-- Horizontal
+SELECT s FROM LINE_TBL WHERE ?- s;
+    s     
+----------
+ {0,-1,5}
+ {0,3,0}
+ {0,-1,3}
+(3 rows)
+
+-- Same as line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s = l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {0,-1,5}
+ {1,0,5}                               | {1,0,5}
+ {0,3,0}                               | {0,3,0}
+ {1,-1,0}                              | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846}
+ {3,NaN,5}                             | {3,NaN,5}
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}
+ {0,-1,3}                              | {0,-1,3}
+ {-1,0,3}                              | {-1,0,3}
+(10 rows)
+
+-- Parallel to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?|| l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {0,-1,5}
+ {0,-1,5}                              | {0,3,0}
+ {0,-1,5}                              | {0,-1,3}
+ {1,0,5}                               | {1,0,5}
+ {1,0,5}                               | {-1,0,3}
+ {0,3,0}                               | {0,-1,5}
+ {0,3,0}                               | {0,3,0}
+ {0,3,0}                               | {0,-1,3}
+ {1,-1,0}                              | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,3}                              | {0,-1,5}
+ {0,-1,3}                              | {0,3,0}
+ {0,-1,3}                              | {0,-1,3}
+ {-1,0,3}                              | {1,0,5}
+ {-1,0,3}                              | {-1,0,3}
+(16 rows)
+
+-- Perpendicular to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?-| l2.s;
+    s     |    s     
+----------+----------
+ {0,-1,5} | {1,0,5}
+ {0,-1,5} | {-1,0,3}
+ {1,0,5}  | {0,-1,5}
+ {1,0,5}  | {0,3,0}
+ {1,0,5}  | {0,-1,3}
+ {0,3,0}  | {1,0,5}
+ {0,3,0}  | {-1,0,3}
+ {0,-1,3} | {1,0,5}
+ {0,-1,3} | {-1,0,3}
+ {-1,0,3} | {0,-1,5}
+ {-1,0,3} | {0,3,0}
+ {-1,0,3} | {0,-1,3}
+(12 rows)
+
+-- Distance to line
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2;
+                   s                   |                   s                   | ?column? 
+---------------------------------------+---------------------------------------+----------
+ {0,-1,5}                              | {0,-1,5}                              |        0
+ {0,-1,5}                              | {1,0,5}                               |        0
+ {0,-1,5}                              | {0,3,0}                               |        5
+ {0,-1,5}                              | {1,-1,0}                              |        0
+ {0,-1,5}                              | {-0.4,-1,-6}                          |        0
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,-1,5}                              | {3,NaN,5}                             |        0
+ {0,-1,5}                              | {NaN,NaN,NaN}                         |        0
+ {0,-1,5}                              | {0,-1,3}                              |        2
+ {0,-1,5}                              | {-1,0,3}                              |        0
+ {1,0,5}                               | {0,-1,5}                              |        0
+ {1,0,5}                               | {1,0,5}                               |        0
+ {1,0,5}                               | {0,3,0}                               |        0
+ {1,0,5}                               | {1,-1,0}                              |        0
+ {1,0,5}                               | {-0.4,-1,-6}                          |        0
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846} |        0
+ {1,0,5}                               | {3,NaN,5}                             |        0
+ {1,0,5}                               | {NaN,NaN,NaN}                         |        0
+ {1,0,5}                               | {0,-1,3}                              |        0
+ {1,0,5}                               | {-1,0,3}                              |        8
+ {0,3,0}                               | {0,-1,5}                              |        5
+ {0,3,0}                               | {1,0,5}                               |        0
+ {0,3,0}                               | {0,3,0}                               |        0
+ {0,3,0}                               | {1,-1,0}                              |        0
+ {0,3,0}                               | {-0.4,-1,-6}                          |        0
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,3,0}                               | {3,NaN,5}                             |        0
+ {0,3,0}                               | {NaN,NaN,NaN}                         |        0
+ {0,3,0}                               | {0,-1,3}                              |        3
+ {0,3,0}                               | {-1,0,3}                              |        0
+ {1,-1,0}                              | {0,-1,5}                              |        0
+ {1,-1,0}                              | {1,0,5}                               |        0
+ {1,-1,0}                              | {0,3,0}                               |        0
+ {1,-1,0}                              | {1,-1,0}                              |        0
+ {1,-1,0}                              | {-0.4,-1,-6}                          |        0
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {1,-1,0}                              | {3,NaN,5}                             |        0
+ {1,-1,0}                              | {NaN,NaN,NaN}                         |        0
+ {1,-1,0}                              | {0,-1,3}                              |        0
+ {1,-1,0}                              | {-1,0,3}                              |        0
+ {-0.4,-1,-6}                          | {0,-1,5}                              |        0
+ {-0.4,-1,-6}                          | {1,0,5}                               |        0
+ {-0.4,-1,-6}                          | {0,3,0}                               |        0
+ {-0.4,-1,-6}                          | {1,-1,0}                              |        0
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}                          |        0
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846} |        0
+ {-0.4,-1,-6}                          | {3,NaN,5}                             |        0
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}                         |        0
+ {-0.4,-1,-6}                          | {0,-1,3}                              |        0
+ {-0.4,-1,-6}                          | {-1,0,3}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}                               |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}                               |        0
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}                          |        0
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} |        0
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}                             |        0
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}                         |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}                              |        0
+ {3,NaN,5}                             | {0,-1,5}                              |        0
+ {3,NaN,5}                             | {1,0,5}                               |        0
+ {3,NaN,5}                             | {0,3,0}                               |        0
+ {3,NaN,5}                             | {1,-1,0}                              |        0
+ {3,NaN,5}                             | {-0.4,-1,-6}                          |        0
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846} |        0
+ {3,NaN,5}                             | {3,NaN,5}                             |        0
+ {3,NaN,5}                             | {NaN,NaN,NaN}                         |        0
+ {3,NaN,5}                             | {0,-1,3}                              |        0
+ {3,NaN,5}                             | {-1,0,3}                              |        0
+ {NaN,NaN,NaN}                         | {0,-1,5}                              |        0
+ {NaN,NaN,NaN}                         | {1,0,5}                               |        0
+ {NaN,NaN,NaN}                         | {0,3,0}                               |        0
+ {NaN,NaN,NaN}                         | {1,-1,0}                              |        0
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}                          |        0
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846} |        0
+ {NaN,NaN,NaN}                         | {3,NaN,5}                             |        0
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}                         |        0
+ {NaN,NaN,NaN}                         | {0,-1,3}                              |        0
+ {NaN,NaN,NaN}                         | {-1,0,3}                              |        0
+ {0,-1,3}                              | {0,-1,5}                              |        2
+ {0,-1,3}                              | {1,0,5}                               |        0
+ {0,-1,3}                              | {0,3,0}                               |        3
+ {0,-1,3}                              | {1,-1,0}                              |        0
+ {0,-1,3}                              | {-0.4,-1,-6}                          |        0
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,-1,3}                              | {3,NaN,5}                             |        0
+ {0,-1,3}                              | {NaN,NaN,NaN}                         |        0
+ {0,-1,3}                              | {0,-1,3}                              |        0
+ {0,-1,3}                              | {-1,0,3}                              |        0
+ {-1,0,3}                              | {0,-1,5}                              |        0
+ {-1,0,3}                              | {1,0,5}                               |        8
+ {-1,0,3}                              | {0,3,0}                               |        0
+ {-1,0,3}                              | {1,-1,0}                              |        0
+ {-1,0,3}                              | {-0.4,-1,-6}                          |        0
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {-1,0,3}                              | {3,NaN,5}                             |        0
+ {-1,0,3}                              | {NaN,NaN,NaN}                         |        0
+ {-1,0,3}                              | {0,-1,3}                              |        0
+ {-1,0,3}                              | {-1,0,3}                              |        0
+(100 rows)
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LINE_TBL l, BOX_TBL b;
+ERROR:  function "dist_lb" not implemented
+-- Intersect with line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?# l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {1,0,5}
+ {0,-1,5}                              | {1,-1,0}
+ {0,-1,5}                              | {-0.4,-1,-6}
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,5}                              | {3,NaN,5}
+ {0,-1,5}                              | {NaN,NaN,NaN}
+ {0,-1,5}                              | {-1,0,3}
+ {1,0,5}                               | {0,-1,5}
+ {1,0,5}                               | {0,3,0}
+ {1,0,5}                               | {1,-1,0}
+ {1,0,5}                               | {-0.4,-1,-6}
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846}
+ {1,0,5}                               | {3,NaN,5}
+ {1,0,5}                               | {NaN,NaN,NaN}
+ {1,0,5}                               | {0,-1,3}
+ {0,3,0}                               | {1,0,5}
+ {0,3,0}                               | {1,-1,0}
+ {0,3,0}                               | {-0.4,-1,-6}
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846}
+ {0,3,0}                               | {3,NaN,5}
+ {0,3,0}                               | {NaN,NaN,NaN}
+ {0,3,0}                               | {-1,0,3}
+ {1,-1,0}                              | {0,-1,5}
+ {1,-1,0}                              | {1,0,5}
+ {1,-1,0}                              | {0,3,0}
+ {1,-1,0}                              | {-0.4,-1,-6}
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846}
+ {1,-1,0}                              | {3,NaN,5}
+ {1,-1,0}                              | {NaN,NaN,NaN}
+ {1,-1,0}                              | {0,-1,3}
+ {1,-1,0}                              | {-1,0,3}
+ {-0.4,-1,-6}                          | {0,-1,5}
+ {-0.4,-1,-6}                          | {1,0,5}
+ {-0.4,-1,-6}                          | {0,3,0}
+ {-0.4,-1,-6}                          | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846}
+ {-0.4,-1,-6}                          | {3,NaN,5}
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}
+ {-0.4,-1,-6}                          | {0,-1,3}
+ {-0.4,-1,-6}                          | {-1,0,3}
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}
+ {3,NaN,5}                             | {0,-1,5}
+ {3,NaN,5}                             | {1,0,5}
+ {3,NaN,5}                             | {0,3,0}
+ {3,NaN,5}                             | {1,-1,0}
+ {3,NaN,5}                             | {-0.4,-1,-6}
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846}
+ {3,NaN,5}                             | {3,NaN,5}
+ {3,NaN,5}                             | {NaN,NaN,NaN}
+ {3,NaN,5}                             | {0,-1,3}
+ {3,NaN,5}                             | {-1,0,3}
+ {NaN,NaN,NaN}                         | {0,-1,5}
+ {NaN,NaN,NaN}                         | {1,0,5}
+ {NaN,NaN,NaN}                         | {0,3,0}
+ {NaN,NaN,NaN}                         | {1,-1,0}
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846}
+ {NaN,NaN,NaN}                         | {3,NaN,5}
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}
+ {NaN,NaN,NaN}                         | {0,-1,3}
+ {NaN,NaN,NaN}                         | {-1,0,3}
+ {0,-1,3}                              | {1,0,5}
+ {0,-1,3}                              | {1,-1,0}
+ {0,-1,3}                              | {-0.4,-1,-6}
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,3}                              | {3,NaN,5}
+ {0,-1,3}                              | {NaN,NaN,NaN}
+ {0,-1,3}                              | {-1,0,3}
+ {-1,0,3}                              | {0,-1,5}
+ {-1,0,3}                              | {0,3,0}
+ {-1,0,3}                              | {1,-1,0}
+ {-1,0,3}                              | {-0.4,-1,-6}
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846}
+ {-1,0,3}                              | {3,NaN,5}
+ {-1,0,3}                              | {NaN,NaN,NaN}
+ {-1,0,3}                              | {0,-1,3}
+(84 rows)
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LINE_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+      s       |         f1          
+--------------+---------------------
+ {1,0,5}      | (-2,2),(-8,-10)
+ {0,3,0}      | (2,2),(0,0)
+ {0,3,0}      | (-2,2),(-8,-10)
+ {1,-1,0}     | (2,2),(0,0)
+ {1,-1,0}     | (3,3),(1,1)
+ {1,-1,0}     | (-2,2),(-8,-10)
+ {1,-1,0}     | (2.5,3.5),(2.5,2.5)
+ {1,-1,0}     | (3,3),(3,3)
+ {-0.4,-1,-6} | (-2,2),(-8,-10)
+ {0,-1,3}     | (3,3),(1,1)
+ {0,-1,3}     | (2.5,3.5),(2.5,2.5)
+ {0,-1,3}     | (3,3),(3,3)
+ {-1,0,3}     | (3,3),(1,1)
+(13 rows)
+
+-- Intersection point with line
+SELECT l1.s, l2.s, l1.s # l2.s FROM LINE_TBL l1, LINE_TBL l2;
+                   s                   |                   s                   |             ?column?              
+---------------------------------------+---------------------------------------+------------------------------------
+ {0,-1,5}                              | {0,-1,5}                              | 
+ {0,-1,5}                              | {1,0,5}                               | (-5,5)
+ {0,-1,5}                              | {0,3,0}                               | 
+ {0,-1,5}                              | {1,-1,0}                              | (5,5)
+ {0,-1,5}                              | {-0.4,-1,-6}                          | (-27.5,5)
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846} | (56250,5)
+ {0,-1,5}                              | {3,NaN,5}                             | (NaN,NaN)
+ {0,-1,5}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,-1,5}                              | {0,-1,3}                              | 
+ {0,-1,5}                              | {-1,0,3}                              | (3,5)
+ {1,0,5}                               | {0,-1,5}                              | (-5,5)
+ {1,0,5}                               | {1,0,5}                               | 
+ {1,0,5}                               | {0,3,0}                               | (-5,0)
+ {1,0,5}                               | {1,-1,0}                              | (-5,-5)
+ {1,0,5}                               | {-0.4,-1,-6}                          | (-5,-4)
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846} | (-5,15.3855384615)
+ {1,0,5}                               | {3,NaN,5}                             | (NaN,NaN)
+ {1,0,5}                               | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {1,0,5}                               | {0,-1,3}                              | (-5,3)
+ {1,0,5}                               | {-1,0,3}                              | 
+ {0,3,0}                               | {0,-1,5}                              | 
+ {0,3,0}                               | {1,0,5}                               | (-5,0)
+ {0,3,0}                               | {0,3,0}                               | 
+ {0,3,0}                               | {1,-1,0}                              | (0,0)
+ {0,3,0}                               | {-0.4,-1,-6}                          | (-15,0)
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846} | (83333.3333333,0)
+ {0,3,0}                               | {3,NaN,5}                             | (NaN,NaN)
+ {0,3,0}                               | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,3,0}                               | {0,-1,3}                              | 
+ {0,3,0}                               | {-1,0,3}                              | (3,0)
+ {1,-1,0}                              | {0,-1,5}                              | (5,5)
+ {1,-1,0}                              | {1,0,5}                               | (-5,-5)
+ {1,-1,0}                              | {0,3,0}                               | (0,0)
+ {1,-1,0}                              | {1,-1,0}                              | 
+ {1,-1,0}                              | {-0.4,-1,-6}                          | (-4.28571428571,-4.28571428571)
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846} | (15.3817756722,15.3817756722)
+ {1,-1,0}                              | {3,NaN,5}                             | (NaN,NaN)
+ {1,-1,0}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {1,-1,0}                              | {0,-1,3}                              | (3,3)
+ {1,-1,0}                              | {-1,0,3}                              | (3,3)
+ {-0.4,-1,-6}                          | {0,-1,5}                              | (-27.5,5)
+ {-0.4,-1,-6}                          | {1,0,5}                               | (-5,-4)
+ {-0.4,-1,-6}                          | {0,3,0}                               | (-15,0)
+ {-0.4,-1,-6}                          | {1,-1,0}                              | (-4.28571428571,-4.28571428571)
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}                          | 
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846} | (-53.4862244113,15.3944897645)
+ {-0.4,-1,-6}                          | {3,NaN,5}                             | (NaN,NaN)
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-0.4,-1,-6}                          | {0,-1,3}                              | (-22.5,3)
+ {-0.4,-1,-6}                          | {-1,0,3}                              | (3,-7.2)
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}                              | (56250,5)
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}                               | (-5,15.3855384615)
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}                               | (83333.3333333,-1.7763568394e-015)
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}                              | (15.3817756722,15.3817756722)
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}                          | (-53.4862244113,15.3944897645)
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} | 
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}                             | (NaN,NaN)
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}                              | (67083.3333333,3)
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}                              | (3,15.3840615385)
+ {3,NaN,5}                             | {0,-1,5}                              | (NaN,NaN)
+ {3,NaN,5}                             | {1,0,5}                               | (NaN,NaN)
+ {3,NaN,5}                             | {0,3,0}                               | (NaN,NaN)
+ {3,NaN,5}                             | {1,-1,0}                              | (NaN,NaN)
+ {3,NaN,5}                             | {-0.4,-1,-6}                          | (NaN,NaN)
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ {3,NaN,5}                             | {3,NaN,5}                             | (NaN,NaN)
+ {3,NaN,5}                             | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {3,NaN,5}                             | {0,-1,3}                              | (NaN,NaN)
+ {3,NaN,5}                             | {-1,0,3}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,-1,5}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {1,0,5}                               | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,3,0}                               | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {1,-1,0}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}                          | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {3,NaN,5}                             | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,-1,3}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-1,0,3}                              | (NaN,NaN)
+ {0,-1,3}                              | {0,-1,5}                              | 
+ {0,-1,3}                              | {1,0,5}                               | (-5,3)
+ {0,-1,3}                              | {0,3,0}                               | 
+ {0,-1,3}                              | {1,-1,0}                              | (3,3)
+ {0,-1,3}                              | {-0.4,-1,-6}                          | (-22.5,3)
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846} | (67083.3333333,3)
+ {0,-1,3}                              | {3,NaN,5}                             | (NaN,NaN)
+ {0,-1,3}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,-1,3}                              | {0,-1,3}                              | 
+ {0,-1,3}                              | {-1,0,3}                              | (3,3)
+ {-1,0,3}                              | {0,-1,5}                              | (3,5)
+ {-1,0,3}                              | {1,0,5}                               | 
+ {-1,0,3}                              | {0,3,0}                               | (3,0)
+ {-1,0,3}                              | {1,-1,0}                              | (3,3)
+ {-1,0,3}                              | {-0.4,-1,-6}                          | (3,-7.2)
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846} | (3,15.3840615385)
+ {-1,0,3}                              | {3,NaN,5}                             | (NaN,NaN)
+ {-1,0,3}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-1,0,3}                              | {0,-1,3}                              | (3,3)
+ {-1,0,3}                              | {-1,0,3}                              | 
+(100 rows)
+
+-- Closest point to line segment
+SELECT l.s, l1.s, l.s ## l1.s FROM LINE_TBL l, LSEG_TBL l1;
+                   s                   |               s               |             ?column?              
+---------------------------------------+-------------------------------+------------------------------------
+ {0,-1,5}                              | [(1,2),(3,4)]                 | (3,4)
+ {0,-1,5}                              | [(0,0),(6,6)]                 | (5,5)
+ {0,-1,5}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,-1,5}                              | [(-1000000,200),(300000,-40)] | (56250,5)
+ {0,-1,5}                              | [(11,22),(33,44)]             | (11,22)
+ {0,-1,5}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {0,-1,5}                              | [(0,-20),(30,-20)]            | 
+ {0,-1,5}                              | [(NaN,1),(NaN,90)]            | 
+ {1,0,5}                               | [(1,2),(3,4)]                 | (1,2)
+ {1,0,5}                               | [(0,0),(6,6)]                 | (0,0)
+ {1,0,5}                               | [(10,-10),(-3,-4)]            | (-3,-4)
+ {1,0,5}                               | [(-1000000,200),(300000,-40)] | (-5,15.3855384615)
+ {1,0,5}                               | [(11,22),(33,44)]             | (11,22)
+ {1,0,5}                               | [(-10,2),(-10,3)]             | 
+ {1,0,5}                               | [(0,-20),(30,-20)]            | (0,-20)
+ {1,0,5}                               | [(NaN,1),(NaN,90)]            | 
+ {0,3,0}                               | [(1,2),(3,4)]                 | (1,2)
+ {0,3,0}                               | [(0,0),(6,6)]                 | (0,0)
+ {0,3,0}                               | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,3,0}                               | [(-1000000,200),(300000,-40)] | (83333.3333333,-1.7763568394e-015)
+ {0,3,0}                               | [(11,22),(33,44)]             | (11,22)
+ {0,3,0}                               | [(-10,2),(-10,3)]             | (-10,2)
+ {0,3,0}                               | [(0,-20),(30,-20)]            | 
+ {0,3,0}                               | [(NaN,1),(NaN,90)]            | 
+ {1,-1,0}                              | [(1,2),(3,4)]                 | 
+ {1,-1,0}                              | [(0,0),(6,6)]                 | 
+ {1,-1,0}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {1,-1,0}                              | [(-1000000,200),(300000,-40)] | (15.3817756722,15.3817756722)
+ {1,-1,0}                              | [(11,22),(33,44)]             | 
+ {1,-1,0}                              | [(-10,2),(-10,3)]             | (-10,2)
+ {1,-1,0}                              | [(0,-20),(30,-20)]            | (0,-20)
+ {1,-1,0}                              | [(NaN,1),(NaN,90)]            | 
+ {-0.4,-1,-6}                          | [(1,2),(3,4)]                 | (1,2)
+ {-0.4,-1,-6}                          | [(0,0),(6,6)]                 | (0,0)
+ {-0.4,-1,-6}                          | [(10,-10),(-3,-4)]            | (10,-10)
+ {-0.4,-1,-6}                          | [(-1000000,200),(300000,-40)] | (-53.4862244113,15.3944897645)
+ {-0.4,-1,-6}                          | [(11,22),(33,44)]             | (11,22)
+ {-0.4,-1,-6}                          | [(-10,2),(-10,3)]             | (-10,2)
+ {-0.4,-1,-6}                          | [(0,-20),(30,-20)]            | (30,-20)
+ {-0.4,-1,-6}                          | [(NaN,1),(NaN,90)]            | 
+ {-0.000184615384615,-1,15.3846153846} | [(1,2),(3,4)]                 | (3,4)
+ {-0.000184615384615,-1,15.3846153846} | [(0,0),(6,6)]                 | (6,6)
+ {-0.000184615384615,-1,15.3846153846} | [(10,-10),(-3,-4)]            | (-3,-4)
+ {-0.000184615384615,-1,15.3846153846} | [(-1000000,200),(300000,-40)] | 
+ {-0.000184615384615,-1,15.3846153846} | [(11,22),(33,44)]             | (11,22)
+ {-0.000184615384615,-1,15.3846153846} | [(-10,2),(-10,3)]             | (-10,3)
+ {-0.000184615384615,-1,15.3846153846} | [(0,-20),(30,-20)]            | (30,-20)
+ {-0.000184615384615,-1,15.3846153846} | [(NaN,1),(NaN,90)]            | 
+ {3,NaN,5}                             | [(1,2),(3,4)]                 | 
+ {3,NaN,5}                             | [(0,0),(6,6)]                 | 
+ {3,NaN,5}                             | [(10,-10),(-3,-4)]            | 
+ {3,NaN,5}                             | [(-1000000,200),(300000,-40)] | 
+ {3,NaN,5}                             | [(11,22),(33,44)]             | 
+ {3,NaN,5}                             | [(-10,2),(-10,3)]             | 
+ {3,NaN,5}                             | [(0,-20),(30,-20)]            | 
+ {3,NaN,5}                             | [(NaN,1),(NaN,90)]            | 
+ {NaN,NaN,NaN}                         | [(1,2),(3,4)]                 | 
+ {NaN,NaN,NaN}                         | [(0,0),(6,6)]                 | 
+ {NaN,NaN,NaN}                         | [(10,-10),(-3,-4)]            | 
+ {NaN,NaN,NaN}                         | [(-1000000,200),(300000,-40)] | 
+ {NaN,NaN,NaN}                         | [(11,22),(33,44)]             | 
+ {NaN,NaN,NaN}                         | [(-10,2),(-10,3)]             | 
+ {NaN,NaN,NaN}                         | [(0,-20),(30,-20)]            | 
+ {NaN,NaN,NaN}                         | [(NaN,1),(NaN,90)]            | 
+ {0,-1,3}                              | [(1,2),(3,4)]                 | (2,3)
+ {0,-1,3}                              | [(0,0),(6,6)]                 | (3,3)
+ {0,-1,3}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,-1,3}                              | [(-1000000,200),(300000,-40)] | (67083.3333333,3)
+ {0,-1,3}                              | [(11,22),(33,44)]             | (11,22)
+ {0,-1,3}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {0,-1,3}                              | [(0,-20),(30,-20)]            | 
+ {0,-1,3}                              | [(NaN,1),(NaN,90)]            | 
+ {-1,0,3}                              | [(1,2),(3,4)]                 | (3,4)
+ {-1,0,3}                              | [(0,0),(6,6)]                 | (3,3)
+ {-1,0,3}                              | [(10,-10),(-3,-4)]            | (3,-6.76923076923)
+ {-1,0,3}                              | [(-1000000,200),(300000,-40)] | (3,15.3840615385)
+ {-1,0,3}                              | [(11,22),(33,44)]             | (11,22)
+ {-1,0,3}                              | [(-10,2),(-10,3)]             | 
+ {-1,0,3}                              | [(0,-20),(30,-20)]            | (3,-20)
+ {-1,0,3}                              | [(NaN,1),(NaN,90)]            | 
+(80 rows)
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LINE_TBL l, BOX_TBL b;
+ERROR:  function "close_lb" not implemented
 --
 -- Line segments
 --
@@ -108,42 +1566,728 @@ ERROR:  operator does not exist: lseg # point
 LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
                                            ^
 HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
+-- Length
+SELECT s, @-@ s FROM LSEG_TBL;
+               s               |   ?column?    
+-------------------------------+---------------
+ [(1,2),(3,4)]                 | 2.82842712475
+ [(0,0),(6,6)]                 | 8.48528137424
+ [(10,-10),(-3,-4)]            | 14.3178210633
+ [(-1000000,200),(300000,-40)] | 1300000.02215
+ [(11,22),(33,44)]             | 31.1126983722
+ [(-10,2),(-10,3)]             |             1
+ [(0,-20),(30,-20)]            |            30
+ [(NaN,1),(NaN,90)]            |           NaN
+(8 rows)
+
+-- Vertical
+SELECT s FROM LSEG_TBL WHERE ?| s;
+         s         
+-------------------
+ [(-10,2),(-10,3)]
+(1 row)
+
+-- Horizontal
+SELECT s FROM LSEG_TBL WHERE ?- s;
+         s          
+--------------------
+ [(0,-20),(30,-20)]
+(1 row)
+
+-- Center
+SELECT s, @@ s FROM LSEG_TBL;
+               s               |   ?column?   
+-------------------------------+--------------
+ [(1,2),(3,4)]                 | (2,3)
+ [(0,0),(6,6)]                 | (3,3)
+ [(10,-10),(-3,-4)]            | (3.5,-7)
+ [(-1000000,200),(300000,-40)] | (-350000,80)
+ [(11,22),(33,44)]             | (22,33)
+ [(-10,2),(-10,3)]             | (-10,2.5)
+ [(0,-20),(30,-20)]            | (15,-20)
+ [(NaN,1),(NaN,90)]            | (NaN,45.5)
+(8 rows)
+
+-- To point
+SELECT s, s::point FROM LSEG_TBL;
+               s               |      s       
+-------------------------------+--------------
+ [(1,2),(3,4)]                 | (2,3)
+ [(0,0),(6,6)]                 | (3,3)
+ [(10,-10),(-3,-4)]            | (3.5,-7)
+ [(-1000000,200),(300000,-40)] | (-350000,80)
+ [(11,22),(33,44)]             | (22,33)
+ [(-10,2),(-10,3)]             | (-10,2.5)
+ [(0,-20),(30,-20)]            | (15,-20)
+ [(NaN,1),(NaN,90)]            | (NaN,45.5)
+(8 rows)
+
+-- Has points less than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s < l2.s;
+         s          |               s               
+--------------------+-------------------------------
+ [(1,2),(3,4)]      | [(0,0),(6,6)]
+ [(1,2),(3,4)]      | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]      | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]      | [(11,22),(33,44)]
+ [(1,2),(3,4)]      | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]      | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]      | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]      | [(11,22),(33,44)]
+ [(0,0),(6,6)]      | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)] | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)] | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]  | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]  | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]  | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]  | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]  | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]  | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]  | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)] | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)] | [(11,22),(33,44)]
+(21 rows)
+
+-- Has points less than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s <= l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(28 rows)
+
+-- Has points equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s = l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]
+(8 rows)
+
+-- Has points greater than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s >= l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(28 rows)
+
+-- Has points greater than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s > l2.s;
+               s               |         s          
+-------------------------------+--------------------
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+(21 rows)
+
+-- Has points not equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s != l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)]
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]
+(56 rows)
+
+-- Parallel with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?|| l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(13 rows)
+
+-- Perpendicular with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?-| l2.s;
+         s          |         s          
+--------------------+--------------------
+ [(-10,2),(-10,3)]  | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)] | [(-10,2),(-10,3)]
+(2 rows)
+
+-- Distance to line
+SELECT l.s, l1.s, l.s <-> l1.s FROM LSEG_TBL l, LINE_TBL l1;
+               s               |                   s                   |    ?column?    
+-------------------------------+---------------------------------------+----------------
+ [(1,2),(3,4)]                 | {0,-1,5}                              |              1
+ [(0,0),(6,6)]                 | {0,-1,5}                              |              0
+ [(10,-10),(-3,-4)]            | {0,-1,5}                              |              9
+ [(-1000000,200),(300000,-40)] | {0,-1,5}                              |              0
+ [(11,22),(33,44)]             | {0,-1,5}                              |             17
+ [(-10,2),(-10,3)]             | {0,-1,5}                              |              2
+ [(0,-20),(30,-20)]            | {0,-1,5}                              |             25
+ [(NaN,1),(NaN,90)]            | {0,-1,5}                              |            NaN
+ [(1,2),(3,4)]                 | {1,0,5}                               |              6
+ [(0,0),(6,6)]                 | {1,0,5}                               |              5
+ [(10,-10),(-3,-4)]            | {1,0,5}                               |              2
+ [(-1000000,200),(300000,-40)] | {1,0,5}                               |              0
+ [(11,22),(33,44)]             | {1,0,5}                               |             16
+ [(-10,2),(-10,3)]             | {1,0,5}                               |              5
+ [(0,-20),(30,-20)]            | {1,0,5}                               |              5
+ [(NaN,1),(NaN,90)]            | {1,0,5}                               |            NaN
+ [(1,2),(3,4)]                 | {0,3,0}                               |              2
+ [(0,0),(6,6)]                 | {0,3,0}                               |              0
+ [(10,-10),(-3,-4)]            | {0,3,0}                               |              4
+ [(-1000000,200),(300000,-40)] | {0,3,0}                               |              0
+ [(11,22),(33,44)]             | {0,3,0}                               |             22
+ [(-10,2),(-10,3)]             | {0,3,0}                               |              2
+ [(0,-20),(30,-20)]            | {0,3,0}                               |             20
+ [(NaN,1),(NaN,90)]            | {0,3,0}                               |            NaN
+ [(1,2),(3,4)]                 | {1,-1,0}                              | 0.707106781187
+ [(0,0),(6,6)]                 | {1,-1,0}                              |              0
+ [(10,-10),(-3,-4)]            | {1,-1,0}                              | 0.707106781187
+ [(-1000000,200),(300000,-40)] | {1,-1,0}                              |              0
+ [(11,22),(33,44)]             | {1,-1,0}                              |  7.77817459305
+ [(-10,2),(-10,3)]             | {1,-1,0}                              |  8.48528137424
+ [(0,-20),(30,-20)]            | {1,-1,0}                              |  14.1421356237
+ [(NaN,1),(NaN,90)]            | {1,-1,0}                              |            NaN
+ [(1,2),(3,4)]                 | {-0.4,-1,-6}                          |  7.79920420344
+ [(0,0),(6,6)]                 | {-0.4,-1,-6}                          |  5.57086014531
+ [(10,-10),(-3,-4)]            | {-0.4,-1,-6}                          |              0
+ [(-1000000,200),(300000,-40)] | {-0.4,-1,-6}                          |              0
+ [(11,22),(33,44)]             | {-0.4,-1,-6}                          |  30.0826447847
+ [(-10,2),(-10,3)]             | {-0.4,-1,-6}                          |  3.71390676354
+ [(0,-20),(30,-20)]            | {-0.4,-1,-6}                          |  1.85695338177
+ [(NaN,1),(NaN,90)]            | {-0.4,-1,-6}                          |            NaN
+ [(1,2),(3,4)]                 | {-0.000184615384615,-1,15.3846153846} |  11.3840613445
+ [(0,0),(6,6)]                 | {-0.000184615384615,-1,15.3846153846} |   9.3835075324
+ [(10,-10),(-3,-4)]            | {-0.000184615384615,-1,15.3846153846} |  19.3851689004
+ [(-1000000,200),(300000,-40)] | {-0.000184615384615,-1,15.3846153846} |              0
+ [(11,22),(33,44)]             | {-0.000184615384615,-1,15.3846153846} |  6.61741527185
+ [(-10,2),(-10,3)]             | {-0.000184615384615,-1,15.3846153846} |  12.3864613274
+ [(0,-20),(30,-20)]            | {-0.000184615384615,-1,15.3846153846} |  35.3790763202
+ [(NaN,1),(NaN,90)]            | {-0.000184615384615,-1,15.3846153846} |            NaN
+ [(1,2),(3,4)]                 | {3,NaN,5}                             |            NaN
+ [(0,0),(6,6)]                 | {3,NaN,5}                             |            NaN
+ [(10,-10),(-3,-4)]            | {3,NaN,5}                             |            NaN
+ [(-1000000,200),(300000,-40)] | {3,NaN,5}                             |            NaN
+ [(11,22),(33,44)]             | {3,NaN,5}                             |            NaN
+ [(-10,2),(-10,3)]             | {3,NaN,5}                             |            NaN
+ [(0,-20),(30,-20)]            | {3,NaN,5}                             |            NaN
+ [(NaN,1),(NaN,90)]            | {3,NaN,5}                             |            NaN
+ [(1,2),(3,4)]                 | {NaN,NaN,NaN}                         |            NaN
+ [(0,0),(6,6)]                 | {NaN,NaN,NaN}                         |            NaN
+ [(10,-10),(-3,-4)]            | {NaN,NaN,NaN}                         |            NaN
+ [(-1000000,200),(300000,-40)] | {NaN,NaN,NaN}                         |            NaN
+ [(11,22),(33,44)]             | {NaN,NaN,NaN}                         |            NaN
+ [(-10,2),(-10,3)]             | {NaN,NaN,NaN}                         |            NaN
+ [(0,-20),(30,-20)]            | {NaN,NaN,NaN}                         |            NaN
+ [(NaN,1),(NaN,90)]            | {NaN,NaN,NaN}                         |            NaN
+ [(1,2),(3,4)]                 | {0,-1,3}                              |              0
+ [(0,0),(6,6)]                 | {0,-1,3}                              |              0
+ [(10,-10),(-3,-4)]            | {0,-1,3}                              |              7
+ [(-1000000,200),(300000,-40)] | {0,-1,3}                              |              0
+ [(11,22),(33,44)]             | {0,-1,3}                              |             19
+ [(-10,2),(-10,3)]             | {0,-1,3}                              |              0
+ [(0,-20),(30,-20)]            | {0,-1,3}                              |             23
+ [(NaN,1),(NaN,90)]            | {0,-1,3}                              |            NaN
+ [(1,2),(3,4)]                 | {-1,0,3}                              |              0
+ [(0,0),(6,6)]                 | {-1,0,3}                              |              0
+ [(10,-10),(-3,-4)]            | {-1,0,3}                              |              0
+ [(-1000000,200),(300000,-40)] | {-1,0,3}                              |              0
+ [(11,22),(33,44)]             | {-1,0,3}                              |              8
+ [(-10,2),(-10,3)]             | {-1,0,3}                              |             13
+ [(0,-20),(30,-20)]            | {-1,0,3}                              |              0
+ [(NaN,1),(NaN,90)]            | {-1,0,3}                              |            NaN
+(80 rows)
+
+-- Distance to line segment
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               |    ?column?    
+-------------------------------+-------------------------------+----------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 |              0
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 0.707106781187
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            |  7.12398901685
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] |  11.3840613445
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             |  19.6977156036
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             |             11
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            |             22
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            |            NaN
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 0.707106781187
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 |              0
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            |  4.88901207039
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] |   9.3835075324
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             |  16.7630546142
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             |  10.1980390272
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            |             20
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            |            NaN
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 |  7.12398901685
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 |  4.88901207039
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            |              0
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] |  19.3851689004
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             |  29.4737584815
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             |  9.21954445729
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            |             10
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            |            NaN
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 |  11.3840613445
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 |   9.3835075324
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            |  19.3851689004
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] |              0
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             |  6.61741527185
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             |  12.3864613274
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            |  35.3790763202
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            |            NaN
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 |  19.6977156036
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 |  16.7630546142
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            |  29.4737584815
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] |  6.61741527185
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             |              0
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             |   28.319604517
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            |             42
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            |            NaN
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 |             11
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 |  10.1980390272
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            |  9.21954445729
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] |  12.3864613274
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             |   28.319604517
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             |              0
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            |  24.1660919472
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            |            NaN
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 |             22
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 |             20
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            |             10
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] |  35.3790763202
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             |             42
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             |  24.1660919472
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            |              0
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 |            NaN
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 |            NaN
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] |            NaN
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             |            NaN
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             |            NaN
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            |            NaN
+(64 rows)
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LSEG_TBL l, BOX_TBL b;
+               s               |         f1          |    ?column?    
+-------------------------------+---------------------+----------------
+ [(1,2),(3,4)]                 | (2,2),(0,0)         |              0
+ [(1,2),(3,4)]                 | (3,3),(1,1)         |              0
+ [(1,2),(3,4)]                 | (-2,2),(-8,-10)     |              3
+ [(1,2),(3,4)]                 | (2.5,3.5),(2.5,2.5) |              0
+ [(1,2),(3,4)]                 | (3,3),(3,3)         | 0.707106781187
+ [(0,0),(6,6)]                 | (2,2),(0,0)         |              0
+ [(0,0),(6,6)]                 | (3,3),(1,1)         |              0
+ [(0,0),(6,6)]                 | (-2,2),(-8,-10)     |              2
+ [(0,0),(6,6)]                 | (2.5,3.5),(2.5,2.5) |              0
+ [(0,0),(6,6)]                 | (3,3),(3,3)         |              0
+ [(10,-10),(-3,-4)]            | (2,2),(0,0)         |  4.88901207039
+ [(10,-10),(-3,-4)]            | (3,3),(1,1)         |  6.21602963235
+ [(10,-10),(-3,-4)]            | (-2,2),(-8,-10)     |              0
+ [(10,-10),(-3,-4)]            | (2.5,3.5),(2.5,2.5) |  8.20655597529
+ [(10,-10),(-3,-4)]            | (3,3),(3,3)         |  8.87006475627
+ [(-1000000,200),(300000,-40)] | (2,2),(0,0)         |  13.3842459258
+ [(-1000000,200),(300000,-40)] | (3,3),(1,1)         |  12.3840613274
+ [(-1000000,200),(300000,-40)] | (-2,2),(-8,-10)     |  13.3849843873
+ [(-1000000,200),(300000,-40)] | (2.5,3.5),(2.5,2.5) |  11.8841536436
+ [(-1000000,200),(300000,-40)] | (3,3),(3,3)         |  12.3840613274
+ [(11,22),(33,44)]             | (2,2),(0,0)         |  21.9317121995
+ [(11,22),(33,44)]             | (3,3),(1,1)         |  20.6155281281
+ [(11,22),(33,44)]             | (-2,2),(-8,-10)     |  23.8537208838
+ [(11,22),(33,44)]             | (2.5,3.5),(2.5,2.5) |  20.3592730715
+ [(11,22),(33,44)]             | (3,3),(3,3)         |  20.6155281281
+ [(-10,2),(-10,3)]             | (2,2),(0,0)         |             10
+ [(-10,2),(-10,3)]             | (3,3),(1,1)         |             11
+ [(-10,2),(-10,3)]             | (-2,2),(-8,-10)     |              2
+ [(-10,2),(-10,3)]             | (2.5,3.5),(2.5,2.5) |           12.5
+ [(-10,2),(-10,3)]             | (3,3),(3,3)         |             13
+ [(0,-20),(30,-20)]            | (2,2),(0,0)         |             20
+ [(0,-20),(30,-20)]            | (3,3),(1,1)         |             21
+ [(0,-20),(30,-20)]            | (-2,2),(-8,-10)     |  10.1980390272
+ [(0,-20),(30,-20)]            | (2.5,3.5),(2.5,2.5) |           22.5
+ [(0,-20),(30,-20)]            | (3,3),(3,3)         |             23
+ [(NaN,1),(NaN,90)]            | (2,2),(0,0)         |            NaN
+ [(NaN,1),(NaN,90)]            | (3,3),(1,1)         |            NaN
+ [(NaN,1),(NaN,90)]            | (-2,2),(-8,-10)     |            NaN
+ [(NaN,1),(NaN,90)]            | (2.5,3.5),(2.5,2.5) |            NaN
+ [(NaN,1),(NaN,90)]            | (3,3),(3,3)         |            NaN
+(40 rows)
+
+-- Intersect with line segment
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s ?# l1.s;
+               s               |      s       
+-------------------------------+--------------
+ [(0,0),(6,6)]                 | {0,-1,5}
+ [(-1000000,200),(300000,-40)] | {0,-1,5}
+ [(-1000000,200),(300000,-40)] | {1,0,5}
+ [(0,0),(6,6)]                 | {0,3,0}
+ [(-1000000,200),(300000,-40)] | {0,3,0}
+ [(-1000000,200),(300000,-40)] | {1,-1,0}
+ [(10,-10),(-3,-4)]            | {-0.4,-1,-6}
+ [(-1000000,200),(300000,-40)] | {-0.4,-1,-6}
+ [(1,2),(3,4)]                 | {0,-1,3}
+ [(0,0),(6,6)]                 | {0,-1,3}
+ [(-1000000,200),(300000,-40)] | {0,-1,3}
+ [(-10,2),(-10,3)]             | {0,-1,3}
+ [(1,2),(3,4)]                 | {-1,0,3}
+ [(0,0),(6,6)]                 | {-1,0,3}
+ [(10,-10),(-3,-4)]            | {-1,0,3}
+ [(-1000000,200),(300000,-40)] | {-1,0,3}
+ [(0,-20),(30,-20)]            | {-1,0,3}
+(17 rows)
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+         s          |         f1          
+--------------------+---------------------
+ [(1,2),(3,4)]      | (2,2),(0,0)
+ [(1,2),(3,4)]      | (3,3),(1,1)
+ [(1,2),(3,4)]      | (2.5,3.5),(2.5,2.5)
+ [(0,0),(6,6)]      | (2,2),(0,0)
+ [(0,0),(6,6)]      | (3,3),(1,1)
+ [(0,0),(6,6)]      | (2.5,3.5),(2.5,2.5)
+ [(0,0),(6,6)]      | (3,3),(3,3)
+ [(10,-10),(-3,-4)] | (-2,2),(-8,-10)
+(8 rows)
+
+-- Intersection point with line segment
+SELECT l1.s, l2.s, l1.s # l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               | ?column? 
+-------------------------------+-------------------------------+----------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 | 
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            | 
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] | 
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             | 
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             | 
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            | 
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            | 
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 | 
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            | 
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] | 
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             | 
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             | 
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            | 
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            | 
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 | 
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 | 
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            | 
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] | 
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             | 
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             | 
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            | 
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            | 
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 | 
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 | 
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            | 
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] | 
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             | 
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             | 
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            | 
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            | 
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 | 
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 | 
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            | 
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] | 
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             | 
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             | 
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            | 
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            | 
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 | 
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 | 
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            | 
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] | 
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             | 
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             | 
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            | 
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            | 
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 | 
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 | 
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            | 
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] | 
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             | 
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             | 
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            | 
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            | 
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 | 
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 | 
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            | 
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] | 
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             | 
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             | 
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            | 
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            | 
+(64 rows)
+
+-- Closest point to line
+SELECT l.s, l1.s, l.s ## l1.s FROM LSEG_TBL l, LINE_TBL l1;
+ERROR:  function "close_sl" not implemented
+-- Closest point to line segment
+SELECT l1.s, l2.s, l1.s ## l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               |            ?column?             
+-------------------------------+-------------------------------+---------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 | 
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            | (-1.98536585366,-4.46829268293)
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] | (3.00210167283,15.3840611505)
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             | 
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             | (-10,2)
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            | (1,-20)
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            | 
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 | 
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] | (6.00173233982,15.3835073725)
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             | 
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             | (-10,2)
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            | (0,-20)
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            | 
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 | (1,2)
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 | (0,0)
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            | 
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] | (-2.99642119965,15.3851685701)
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             | (11,22)
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             | (-10,2)
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            | (10,-20)
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            | 
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 | (3,4)
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 | (6,6)
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            | (-3,-4)
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] | 
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             | (11,22)
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             | (-10,3)
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            | (30,-20)
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            | 
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 | 
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 | 
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            | (-1.3512195122,-4.76097560976)
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] | (10.9987783234,15.3825848409)
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             | 
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             | (-10,3)
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            | (11,-20)
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            | 
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 | (1,2)
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 | (0,0)
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            | (-3,-4)
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] | (-9.99771326872,15.3864611163)
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             | (11,22)
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             | 
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            | (0,-20)
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            | 
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 | (1,2)
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 | (0,0)
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            | (10,-10)
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] | (30.0065315217,15.3790757173)
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             | (11,22)
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             | (-10,2)
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            | 
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            | 
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 | 
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 | 
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            | 
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] | 
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             | 
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             | 
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            | 
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            | 
+(64 rows)
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LSEG_TBL l, BOX_TBL b;
+               s               |         f1          |  ?column?   
+-------------------------------+---------------------+-------------
+ [(1,2),(3,4)]                 | (2,2),(0,0)         | (1,2)
+ [(1,2),(3,4)]                 | (3,3),(1,1)         | (1.5,2.5)
+ [(1,2),(3,4)]                 | (-2,2),(-8,-10)     | (-2,2)
+ [(1,2),(3,4)]                 | (2.5,3.5),(2.5,2.5) | (2.25,3.25)
+ [(1,2),(3,4)]                 | (3,3),(3,3)         | (3,3)
+ [(0,0),(6,6)]                 | (2,2),(0,0)         | (1,1)
+ [(0,0),(6,6)]                 | (3,3),(1,1)         | (2,2)
+ [(0,0),(6,6)]                 | (-2,2),(-8,-10)     | (-2,0)
+ [(0,0),(6,6)]                 | (2.5,3.5),(2.5,2.5) | (2.75,2.75)
+ [(0,0),(6,6)]                 | (3,3),(3,3)         | (3,3)
+ [(10,-10),(-3,-4)]            | (2,2),(0,0)         | (0,0)
+ [(10,-10),(-3,-4)]            | (3,3),(1,1)         | (1,1)
+ [(10,-10),(-3,-4)]            | (-2,2),(-8,-10)     | (-3,-4)
+ [(10,-10),(-3,-4)]            | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ [(10,-10),(-3,-4)]            | (3,3),(3,3)         | (3,3)
+ [(-1000000,200),(300000,-40)] | (2,2),(0,0)         | (2,2)
+ [(-1000000,200),(300000,-40)] | (3,3),(1,1)         | (3,3)
+ [(-1000000,200),(300000,-40)] | (-2,2),(-8,-10)     | (-2,2)
+ [(-1000000,200),(300000,-40)] | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ [(-1000000,200),(300000,-40)] | (3,3),(3,3)         | (3,3)
+ [(11,22),(33,44)]             | (2,2),(0,0)         | (2,2)
+ [(11,22),(33,44)]             | (3,3),(1,1)         | (3,3)
+ [(11,22),(33,44)]             | (-2,2),(-8,-10)     | (-2,2)
+ [(11,22),(33,44)]             | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ [(11,22),(33,44)]             | (3,3),(3,3)         | (3,3)
+ [(-10,2),(-10,3)]             | (2,2),(0,0)         | (0,2)
+ [(-10,2),(-10,3)]             | (3,3),(1,1)         | (1,2)
+ [(-10,2),(-10,3)]             | (-2,2),(-8,-10)     | (-8,2)
+ [(-10,2),(-10,3)]             | (2.5,3.5),(2.5,2.5) | (2.5,3)
+ [(-10,2),(-10,3)]             | (3,3),(3,3)         | (3,3)
+ [(0,-20),(30,-20)]            | (2,2),(0,0)         | (0,0)
+ [(0,-20),(30,-20)]            | (3,3),(1,1)         | (1,1)
+ [(0,-20),(30,-20)]            | (-2,2),(-8,-10)     | (-2,-10)
+ [(0,-20),(30,-20)]            | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ [(0,-20),(30,-20)]            | (3,3),(3,3)         | (3,3)
+ [(NaN,1),(NaN,90)]            | (2,2),(0,0)         | 
+ [(NaN,1),(NaN,90)]            | (3,3),(1,1)         | 
+ [(NaN,1),(NaN,90)]            | (-2,2),(-8,-10)     | 
+ [(NaN,1),(NaN,90)]            | (2.5,3.5),(2.5,2.5) | 
+ [(NaN,1),(NaN,90)]            | (3,3),(3,3)         | 
+(40 rows)
+
+-- On line
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s <@ l1.s;
+               s               |                   s                   
+-------------------------------+---------------------------------------
+ [(0,0),(6,6)]                 | {1,-1,0}
+ [(-1000000,200),(300000,-40)] | {-0.000184615384615,-1,15.3846153846}
+(2 rows)
+
+-- On box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s <@ b.f1;
+ s | f1 
+---+----
+(0 rows)
 
 --
 -- Boxes
@@ -157,138 +2301,176 @@ SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
      | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
      | (107.071067812,207.071067812),(92.9289321881,192.928932188)
      | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
+     | (3,5),(3,5)
+     | (NaN,NaN),(NaN,NaN)
+(8 rows)
 
 -- translation
 SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
+ twentyfour |             translation             
+------------+-------------------------------------
             | (2,2),(0,0)
             | (3,3),(1,1)
+            | (-2,2),(-8,-10)
             | (2.5,3.5),(2.5,2.5)
             | (3,3),(3,3)
             | (-8,2),(-10,0)
             | (-7,3),(-9,1)
+            | (-12,2),(-18,-10)
             | (-7.5,3.5),(-7.5,2.5)
             | (-7,3),(-7,3)
             | (-1,6),(-3,4)
             | (0,7),(-2,5)
+            | (-5,6),(-11,-6)
             | (-0.5,7.5),(-0.5,6.5)
             | (0,7),(0,7)
             | (7.1,36.5),(5.1,34.5)
             | (8.1,37.5),(6.1,35.5)
+            | (3.1,36.5),(-2.9,24.5)
             | (7.6,38),(7.6,37)
             | (8.1,37.5),(8.1,37.5)
             | (-3,-10),(-5,-12)
             | (-2,-9),(-4,-11)
+            | (-7,-10),(-13,-22)
             | (-2.5,-8.5),(-2.5,-9.5)
             | (-2,-9),(-2,-9)
+            | (2,2),(1e-300,-1e-300)
+            | (3,3),(1,1)
+            | (-2,2),(-8,-10)
+            | (2.5,3.5),(2.5,2.5)
+            | (3,3),(3,3)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
             | (12,12),(10,10)
             | (13,13),(11,11)
+            | (8,12),(2,0)
             | (12.5,13.5),(12.5,12.5)
             | (13,13),(13,13)
-(24 rows)
+(45 rows)
 
 SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
+ twentyfour |               translation               
+------------+-----------------------------------------
             | (2,2),(0,0)
             | (3,3),(1,1)
+            | (-2,2),(-8,-10)
             | (2.5,3.5),(2.5,2.5)
             | (3,3),(3,3)
             | (12,2),(10,0)
             | (13,3),(11,1)
+            | (8,2),(2,-10)
             | (12.5,3.5),(12.5,2.5)
             | (13,3),(13,3)
             | (5,-2),(3,-4)
             | (6,-1),(4,-3)
+            | (1,-2),(-5,-14)
             | (5.5,-0.5),(5.5,-1.5)
             | (6,-1),(6,-1)
             | (-3.1,-32.5),(-5.1,-34.5)
             | (-2.1,-31.5),(-4.1,-33.5)
+            | (-7.1,-32.5),(-13.1,-44.5)
             | (-2.6,-31),(-2.6,-32)
             | (-2.1,-31.5),(-2.1,-31.5)
             | (7,14),(5,12)
             | (8,15),(6,13)
+            | (3,14),(-3,2)
             | (7.5,15.5),(7.5,14.5)
             | (8,15),(8,15)
+            | (2,2),(-1e-300,1e-300)
+            | (3,3),(1,1)
+            | (-2,2),(-8,-10)
+            | (2.5,3.5),(2.5,2.5)
+            | (3,3),(3,3)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
             | (-8,-8),(-10,-10)
             | (-7,-7),(-9,-9)
+            | (-12,-8),(-18,-20)
             | (-7.5,-6.5),(-7.5,-7.5)
             | (-7,-7),(-7,-7)
-(24 rows)
+(45 rows)
 
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
-
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,0),(-0.2,-0.2)
-        | (0.08,0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
+-- Multiply with point
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+         f1          |     f1     |          ?column?           
+---------------------+------------+-----------------------------
+ (2,2),(0,0)         | (5.1,34.5) | (0,79.2),(-58.8,0)
+ (2,2),(0,0)         | (10,10)    | (0,40),(0,0)
+ (3,3),(1,1)         | (5.1,34.5) | (-29.4,118.8),(-88.2,39.6)
+ (3,3),(1,1)         | (10,10)    | (0,60),(0,20)
+ (-2,2),(-8,-10)     | (5.1,34.5) | (304.2,-58.8),(-79.2,-327)
+ (-2,2),(-8,-10)     | (10,10)    | (20,0),(-40,-180)
+ (2.5,3.5),(2.5,2.5) | (5.1,34.5) | (-73.5,104.1),(-108,99)
+ (2.5,3.5),(2.5,2.5) | (10,10)    | (0,60),(-10,50)
+ (3,3),(3,3)         | (5.1,34.5) | (-88.2,118.8),(-88.2,118.8)
+ (3,3),(3,3)         | (10,10)    | (0,60),(0,60)
+(10 rows)
+
+-- Overflow error
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] > 1000;
+         f1          |        f1         |                  ?column?                  
+---------------------+-------------------+--------------------------------------------
+ (2,2),(0,0)         | (1e+300,Infinity) | (NaN,NaN),(-Infinity,Infinity)
+ (2,2),(0,0)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (3,3),(1,1)         | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (3,3),(1,1)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (-2,2),(-8,-10)     | (1e+300,Infinity) | (Infinity,-Infinity),(-Infinity,-Infinity)
+ (-2,2),(-8,-10)     | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (2.5,3.5),(2.5,2.5) | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (2.5,3.5),(2.5,2.5) | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (3,3),(3,3)         | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (3,3),(3,3)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+(10 rows)
+
+-- Divide by point
+SELECT b.f1, p.f1, b.f1 / p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+         f1          |     f1     |                               ?column?                               
+---------------------+------------+----------------------------------------------------------------------
+ (2,2),(0,0)         | (5.1,34.5) | (0.0651176557644,0),(0,-0.0483449262493)
+ (2,2),(0,0)         | (10,10)    | (0.2,0),(0,0)
+ (3,3),(1,1)         | (5.1,34.5) | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
+ (3,3),(1,1)         | (10,10)    | (0.3,0),(0.1,0)
+ (-2,2),(-8,-10)     | (5.1,34.5) | (0.0483449262493,0.18499334024),(-0.317201914064,0.0651176557644)
+ (-2,2),(-8,-10)     | (10,10)    | (0,0.2),(-0.9,-0.1)
+ (2.5,3.5),(2.5,2.5) | (5.1,34.5) | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
+ (2.5,3.5),(2.5,2.5) | (10,10)    | (0.3,0.05),(0.25,0)
+ (3,3),(3,3)         | (5.1,34.5) | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
+ (3,3),(3,3)         | (10,10)    | (0.3,0),(0.3,0)
+(10 rows)
 
+-- To box
 SELECT f1::box
 	FROM POINT_TBL;
-          f1           
------------------------
+                 f1                  
+-------------------------------------
  (0,0),(0,0)
  (-10,0),(-10,0)
  (-3,4),(-3,4)
  (5.1,34.5),(5.1,34.5)
  (-5,-12),(-5,-12)
+ (1e-300,-1e-300),(1e-300,-1e-300)
+ (1e+300,Infinity),(1e+300,Infinity)
+ (NaN,NaN),(NaN,NaN)
  (10,10),(10,10)
-(6 rows)
+(9 rows)
 
 SELECT bound_box(a.f1, b.f1)
 	FROM BOX_TBL a, BOX_TBL b;
@@ -296,76 +2478,935 @@ SELECT bound_box(a.f1, b.f1)
 ---------------------
  (2,2),(0,0)
  (3,3),(0,0)
+ (2,2),(-8,-10)
  (2.5,3.5),(0,0)
  (3,3),(0,0)
  (3,3),(0,0)
  (3,3),(1,1)
+ (3,3),(-8,-10)
  (3,3.5),(1,1)
  (3,3),(1,1)
+ (2,2),(-8,-10)
+ (3,3),(-8,-10)
+ (-2,2),(-8,-10)
+ (2.5,3.5),(-8,-10)
+ (3,3),(-8,-10)
  (2.5,3.5),(0,0)
  (3,3.5),(1,1)
+ (2.5,3.5),(-8,-10)
  (2.5,3.5),(2.5,2.5)
  (3,3.5),(2.5,2.5)
  (3,3),(0,0)
  (3,3),(1,1)
+ (3,3),(-8,-10)
  (3,3.5),(2.5,2.5)
  (3,3),(3,3)
-(16 rows)
+(25 rows)
+
+-- Below box
+SELECT b1.f1, b2.f1, b1.f1 <^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          | ?column? 
+---------------------+---------------------+----------
+ (2,2),(0,0)         | (2,2),(0,0)         | f
+ (2,2),(0,0)         | (3,3),(1,1)         | f
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | f
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | t
+ (2,2),(0,0)         | (3,3),(3,3)         | t
+ (3,3),(1,1)         | (2,2),(0,0)         | f
+ (3,3),(1,1)         | (3,3),(1,1)         | f
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | f
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(1,1)         | (3,3),(3,3)         | t
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | f
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | f
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | f
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | t
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | t
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | f
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | f
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | f
+ (3,3),(3,3)         | (2,2),(0,0)         | f
+ (3,3),(3,3)         | (3,3),(1,1)         | f
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | f
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(3,3)         | (3,3),(3,3)         | t
+(25 rows)
+
+-- Above box
+SELECT b1.f1, b2.f1, b1.f1 >^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          | ?column? 
+---------------------+---------------------+----------
+ (2,2),(0,0)         | (2,2),(0,0)         | f
+ (2,2),(0,0)         | (3,3),(1,1)         | f
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | f
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | f
+ (2,2),(0,0)         | (3,3),(3,3)         | f
+ (3,3),(1,1)         | (2,2),(0,0)         | f
+ (3,3),(1,1)         | (3,3),(1,1)         | f
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | f
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(1,1)         | (3,3),(3,3)         | f
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | f
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | f
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | f
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | f
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | f
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | t
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | f
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | t
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | f
+ (3,3),(3,3)         | (2,2),(0,0)         | t
+ (3,3),(3,3)         | (3,3),(1,1)         | t
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | t
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(3,3)         | (3,3),(3,3)         | t
+(25 rows)
+
+-- Intersection point with box
+SELECT b1.f1, b2.f1, b1.f1 # b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          |      ?column?       
+---------------------+---------------------+---------------------
+ (2,2),(0,0)         | (2,2),(0,0)         | (2,2),(0,0)
+ (2,2),(0,0)         | (3,3),(1,1)         | (2,2),(1,1)
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | 
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | 
+ (2,2),(0,0)         | (3,3),(3,3)         | 
+ (3,3),(1,1)         | (2,2),(0,0)         | (2,2),(1,1)
+ (3,3),(1,1)         | (3,3),(1,1)         | (3,3),(1,1)
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | 
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | (2.5,3),(2.5,2.5)
+ (3,3),(1,1)         | (3,3),(3,3)         | (3,3),(3,3)
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | 
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | 
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | (-2,2),(-8,-10)
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | 
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | 
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | 
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | (2.5,3),(2.5,2.5)
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | 
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5)
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | 
+ (3,3),(3,3)         | (2,2),(0,0)         | 
+ (3,3),(3,3)         | (3,3),(1,1)         | (3,3),(3,3)
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | 
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | 
+ (3,3),(3,3)         | (3,3),(3,3)         | (3,3),(3,3)
+(25 rows)
+
+-- Diagonal
+SELECT f1, diagonal(f1) FROM BOX_TBL;
+         f1          |       diagonal        
+---------------------+-----------------------
+ (2,2),(0,0)         | [(2,2),(0,0)]
+ (3,3),(1,1)         | [(3,3),(1,1)]
+ (-2,2),(-8,-10)     | [(-2,2),(-8,-10)]
+ (2.5,3.5),(2.5,2.5) | [(2.5,3.5),(2.5,2.5)]
+ (3,3),(3,3)         | [(3,3),(3,3)]
+(5 rows)
+
+-- Distance to box
+SELECT b1.f1, b2.f1, b1.f1 <-> b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          |   ?column?    
+---------------------+---------------------+---------------
+ (2,2),(0,0)         | (2,2),(0,0)         |             0
+ (2,2),(0,0)         | (3,3),(1,1)         | 1.41421356237
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | 7.81024967591
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) |           2.5
+ (2,2),(0,0)         | (3,3),(3,3)         | 2.82842712475
+ (3,3),(1,1)         | (2,2),(0,0)         | 1.41421356237
+ (3,3),(1,1)         | (3,3),(1,1)         |             0
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | 9.21954445729
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | 1.11803398875
+ (3,3),(1,1)         | (3,3),(3,3)         | 1.41421356237
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | 7.81024967591
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | 9.21954445729
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     |             0
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | 10.2591422643
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | 10.6301458127
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         |           2.5
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | 1.11803398875
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | 10.2591422643
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) |             0
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         |           0.5
+ (3,3),(3,3)         | (2,2),(0,0)         | 2.82842712475
+ (3,3),(3,3)         | (3,3),(1,1)         | 1.41421356237
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | 10.6301458127
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) |           0.5
+ (3,3),(3,3)         | (3,3),(3,3)         |             0
+(25 rows)
 
 --
 -- Paths
 --
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
+-- Points
+SELECT f1, npoints(f1) FROM PATH_TBL;
+            f1             | npoints 
+---------------------------+---------
+ [(1,2),(3,4)]             |       2
+ ((1,2),(3,4))             |       2
+ [(0,0),(3,0),(4,5),(1,6)] |       4
+ ((1,2),(3,4))             |       2
+ ((1,2),(3,4))             |       2
+ [(1,2),(3,4)]             |       2
+ ((10,20))                 |       1
+ [(11,12),(13,14)]         |       2
+ ((11,12),(13,14))         |       2
+(9 rows)
 
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
+-- Area
+SELECT f1, area(f1) FROM PATH_TBL;
+            f1             | area 
+---------------------------+------
+ [(1,2),(3,4)]             |     
+ ((1,2),(3,4))             |    0
+ [(0,0),(3,0),(4,5),(1,6)] |     
+ ((1,2),(3,4))             |    0
+ ((1,2),(3,4))             |    0
+ [(1,2),(3,4)]             |     
+ ((10,20))                 |    0
+ [(11,12),(13,14)]         |     
+ ((11,12),(13,14))         |    0
+(9 rows)
 
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
+-- Length
+SELECT f1, @-@ f1 FROM PATH_TBL;
+            f1             |   ?column?    
+---------------------------+---------------
+ [(1,2),(3,4)]             | 2.82842712475
+ ((1,2),(3,4))             | 5.65685424949
+ [(0,0),(3,0),(4,5),(1,6)] | 11.2612971738
+ ((1,2),(3,4))             | 5.65685424949
+ ((1,2),(3,4))             | 5.65685424949
+ [(1,2),(3,4)]             | 2.82842712475
+ ((10,20))                 |             0
+ [(11,12),(13,14)]         | 2.82842712475
+ ((11,12),(13,14))         | 5.65685424949
+(9 rows)
 
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
+-- Center
+SELECT f1, @@ f1 FROM PATH_TBL;
+ERROR:  function "path_center" not implemented
+-- To polygon
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isclosed(f1);
+        f1         |        f1         
+-------------------+-------------------
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((10,20))         | ((10,20))
+ ((11,12),(13,14)) | ((11,12),(13,14))
+(5 rows)
+
+-- Open path cannot be converted to polygon error
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isopen(f1);
+ERROR:  open path cannot be converted to polygon
+-- Has points less than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 < p2.f1;
+        f1         |            f1             
+-------------------+---------------------------
+ [(1,2),(3,4)]     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]     | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))         | [(1,2),(3,4)]
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | [(1,2),(3,4)]
+ ((10,20))         | [(11,12),(13,14)]
+ ((10,20))         | ((11,12),(13,14))
+ [(11,12),(13,14)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((11,12),(13,14)) | [(0,0),(3,0),(4,5),(1,6)]
+(15 rows)
+
+-- Has points less than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 <= p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | [(1,2),(3,4)]
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | [(1,2),(3,4)]
+ ((10,20))                 | ((10,20))
+ ((10,20))                 | [(11,12),(13,14)]
+ ((10,20))                 | ((11,12),(13,14))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(66 rows)
+
+-- Has points equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 = p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | ((10,20))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(51 rows)
+
+-- Has points greater than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 >= p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | ((10,20))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((10,20))
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((10,20))
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(66 rows)
+
+-- Has points greater than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 > p2.f1;
+            f1             |        f1         
+---------------------------+-------------------
+ [(1,2),(3,4)]             | ((10,20))
+ ((1,2),(3,4))             | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | ((10,20))
+ [(1,2),(3,4)]             | ((10,20))
+ [(11,12),(13,14)]         | ((10,20))
+ ((11,12),(13,14))         | ((10,20))
+(15 rows)
+
+-- Add path
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+            f1             |            f1             |                     ?column?                      
+---------------------------+---------------------------+---------------------------------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4),(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))                 | 
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         | [(1,2),(3,4),(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6),(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6),(0,0),(3,0),(4,5),(1,6)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6),(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))                 | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6),(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4),(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))                 | 
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         | [(1,2),(3,4),(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))         | 
+ ((10,20))                 | [(1,2),(3,4)]             | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | [(1,2),(3,4)]             | 
+ ((10,20))                 | ((10,20))                 | 
+ ((10,20))                 | [(11,12),(13,14)]         | 
+ ((10,20))                 | ((11,12),(13,14))         | 
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             | [(11,12),(13,14),(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14),(0,0),(3,0),(4,5),(1,6)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             | [(11,12),(13,14),(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((10,20))                 | 
+ [(11,12),(13,14)]         | [(11,12),(13,14)]         | [(11,12),(13,14),(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))         | 
+ ((11,12),(13,14))         | [(1,2),(3,4)]             | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | [(1,2),(3,4)]             | 
+ ((11,12),(13,14))         | ((10,20))                 | 
+ ((11,12),(13,14))         | [(11,12),(13,14)]         | 
+ ((11,12),(13,14))         | ((11,12),(13,14))         | 
+(81 rows)
+
+-- Add point
+SELECT p.f1, p1.f1, p.f1 + p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                                 ?column?                                  
+---------------------------+-------------------+---------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((10,20))                 | (0,0)             | ((10,20))
+ [(11,12),(13,14)]         | (0,0)             | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (0,0)             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (-10,0)           | [(-9,2),(-7,4)]
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(-10,0),(-7,0),(-6,5),(-9,6)]
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ [(1,2),(3,4)]             | (-10,0)           | [(-9,2),(-7,4)]
+ ((10,20))                 | (-10,0)           | ((0,20))
+ [(11,12),(13,14)]         | (-10,0)           | [(1,12),(3,14)]
+ ((11,12),(13,14))         | (-10,0)           | ((1,12),(3,14))
+ [(1,2),(3,4)]             | (-3,4)            | [(-2,6),(0,8)]
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(-3,4),(0,4),(1,9),(-2,10)]
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ [(1,2),(3,4)]             | (-3,4)            | [(-2,6),(0,8)]
+ ((10,20))                 | (-3,4)            | ((7,24))
+ [(11,12),(13,14)]         | (-3,4)            | [(8,16),(10,18)]
+ ((11,12),(13,14))         | (-3,4)            | ((8,16),(10,18))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(6.1,36.5),(8.1,38.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(5.1,34.5),(8.1,34.5),(9.1,39.5),(6.1,40.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(6.1,36.5),(8.1,38.5)]
+ ((10,20))                 | (5.1,34.5)        | ((15.1,54.5))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(16.1,46.5),(18.1,48.5)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((16.1,46.5),(18.1,48.5))
+ [(1,2),(3,4)]             | (-5,-12)          | [(-4,-10),(-2,-8)]
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(-5,-12),(-2,-12),(-1,-7),(-4,-6)]
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ [(1,2),(3,4)]             | (-5,-12)          | [(-4,-10),(-2,-8)]
+ ((10,20))                 | (-5,-12)          | ((5,8))
+ [(11,12),(13,14)]         | (-5,-12)          | [(6,0),(8,2)]
+ ((11,12),(13,14))         | (-5,-12)          | ((6,0),(8,2))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(1e-300,-1e-300),(3,-1e-300),(4,5),(1,6)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((10,20))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity),(1e+300,Infinity),(1e+300,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((1e+300,Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(11,12),(13,14)]
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(10,10),(13,10),(14,15),(11,16)]
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (10,10)           | [(11,12),(13,14)]
+ ((10,20))                 | (10,10)           | ((20,30))
+ [(11,12),(13,14)]         | (10,10)           | [(21,22),(23,24)]
+ ((11,12),(13,14))         | (10,10)           | ((21,22),(23,24))
+(81 rows)
+
+-- Subtract point
+SELECT p.f1, p1.f1, p.f1 - p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                                     ?column?                                      
+---------------------------+-------------------+-----------------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((10,20))                 | (0,0)             | ((10,20))
+ [(11,12),(13,14)]         | (0,0)             | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (0,0)             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (-10,0)           | [(11,2),(13,4)]
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(10,0),(13,0),(14,5),(11,6)]
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ [(1,2),(3,4)]             | (-10,0)           | [(11,2),(13,4)]
+ ((10,20))                 | (-10,0)           | ((20,20))
+ [(11,12),(13,14)]         | (-10,0)           | [(21,12),(23,14)]
+ ((11,12),(13,14))         | (-10,0)           | ((21,12),(23,14))
+ [(1,2),(3,4)]             | (-3,4)            | [(4,-2),(6,0)]
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(3,-4),(6,-4),(7,1),(4,2)]
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ [(1,2),(3,4)]             | (-3,4)            | [(4,-2),(6,0)]
+ ((10,20))                 | (-3,4)            | ((13,16))
+ [(11,12),(13,14)]         | (-3,4)            | [(14,8),(16,10)]
+ ((11,12),(13,14))         | (-3,4)            | ((14,8),(16,10))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-4.1,-32.5),(-2.1,-30.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(-5.1,-34.5),(-2.1,-34.5),(-1.1,-29.5),(-4.1,-28.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-4.1,-32.5),(-2.1,-30.5)]
+ ((10,20))                 | (5.1,34.5)        | ((4.9,-14.5))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(5.9,-22.5),(7.9,-20.5)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((5.9,-22.5),(7.9,-20.5))
+ [(1,2),(3,4)]             | (-5,-12)          | [(6,14),(8,16)]
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(5,12),(8,12),(9,17),(6,18)]
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ [(1,2),(3,4)]             | (-5,-12)          | [(6,14),(8,16)]
+ ((10,20))                 | (-5,-12)          | ((15,32))
+ [(11,12),(13,14)]         | (-5,-12)          | [(16,24),(18,26)]
+ ((11,12),(13,14))         | (-5,-12)          | ((16,24),(18,26))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(-1e-300,1e-300),(3,1e-300),(4,5),(1,6)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((10,20))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity),(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((-1e+300,-Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(-9,-8),(-7,-6)]
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(-10,-10),(-7,-10),(-6,-5),(-9,-4)]
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ [(1,2),(3,4)]             | (10,10)           | [(-9,-8),(-7,-6)]
+ ((10,20))                 | (10,10)           | ((0,10))
+ [(11,12),(13,14)]         | (10,10)           | [(1,2),(3,4)]
+ ((11,12),(13,14))         | (10,10)           | ((1,2),(3,4))
+(81 rows)
+
+-- Multiply with point
+SELECT p.f1, p1.f1, p.f1 * p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                               ?column?                               
+---------------------------+-------------------+----------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(0,0),(0,0)]
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(0,0),(0,0),(0,0)]
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ [(1,2),(3,4)]             | (0,0)             | [(0,0),(0,0)]
+ ((10,20))                 | (0,0)             | ((0,0))
+ [(11,12),(13,14)]         | (0,0)             | [(0,0),(0,0)]
+ ((11,12),(13,14))         | (0,0)             | ((0,0),(0,0))
+ [(1,2),(3,4)]             | (-10,0)           | [(-10,-20),(-30,-40)]
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(0,0),(-30,0),(-40,-50),(-10,-60)]
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ [(1,2),(3,4)]             | (-10,0)           | [(-10,-20),(-30,-40)]
+ ((10,20))                 | (-10,0)           | ((-100,-200))
+ [(11,12),(13,14)]         | (-10,0)           | [(-110,-120),(-130,-140)]
+ ((11,12),(13,14))         | (-10,0)           | ((-110,-120),(-130,-140))
+ [(1,2),(3,4)]             | (-3,4)            | [(-11,-2),(-25,0)]
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(0,0),(-9,12),(-32,1),(-27,-14)]
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ [(1,2),(3,4)]             | (-3,4)            | [(-11,-2),(-25,0)]
+ ((10,20))                 | (-3,4)            | ((-110,-20))
+ [(11,12),(13,14)]         | (-3,4)            | [(-81,8),(-95,10)]
+ ((11,12),(13,14))         | (-3,4)            | ((-81,8),(-95,10))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-63.9,44.7),(-122.7,123.9)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(0,0),(15.3,103.5),(-152.1,163.5),(-201.9,65.1)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-63.9,44.7),(-122.7,123.9)]
+ ((10,20))                 | (5.1,34.5)        | ((-639,447))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(-357.9,440.7),(-416.7,519.9)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((-357.9,440.7),(-416.7,519.9))
+ [(1,2),(3,4)]             | (-5,-12)          | [(19,-22),(33,-56)]
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(0,0),(-15,-36),(40,-73),(67,-42)]
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ [(1,2),(3,4)]             | (-5,-12)          | [(19,-22),(33,-56)]
+ ((10,20))                 | (-5,-12)          | ((190,-220))
+ [(11,12),(13,14)]         | (-5,-12)          | [(89,-192),(103,-226)]
+ ((11,12),(13,14))         | (-5,-12)          | ((89,-192),(103,-226))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(3e-300,1e-300),(7e-300,1e-300)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(0,0),(3e-300,-3e-300),(9e-300,1e-300),(7e-300,5e-300)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(3e-300,1e-300),(7e-300,1e-300)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((3e-299,1e-299))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(2.3e-299,1e-300),(2.7e-299,1e-300)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((2.3e-299,1e-300),(2.7e-299,1e-300))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(NaN,NaN),(NaN,Infinity),(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((-Infinity,Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(-10,30),(-10,70)]
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(0,0),(30,30),(-10,90),(-50,70)]
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ [(1,2),(3,4)]             | (10,10)           | [(-10,30),(-10,70)]
+ ((10,20))                 | (10,10)           | ((-100,300))
+ [(11,12),(13,14)]         | (10,10)           | [(-10,230),(-10,270)]
+ ((11,12),(13,14))         | (10,10)           | ((-10,230),(-10,270))
+(81 rows)
+
+-- Divide by point
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+            f1             |     f1     |                                                    ?column?                                                     
+---------------------------+------------+-----------------------------------------------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (5.1,34.5) | [(0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952)]
+ [(1,2),(3,4)]             | (10,10)    | [(0.15,0.05),(0.35,0.05)]
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5) | [(0,0),(0.0125795471363,-0.0850969365103),(0.158600957032,-0.0924966701199),(0.174387055399,-0.00320655123082)]
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)    | [(0,0),(0.15,-0.15),(0.45,0.05),(0.35,0.25)]
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ [(1,2),(3,4)]             | (5.1,34.5) | [(0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952)]
+ [(1,2),(3,4)]             | (10,10)    | [(0.15,0.05),(0.35,0.05)]
+ ((10,20))                 | (5.1,34.5) | ((0.609244733856,-0.199792807459))
+ ((10,20))                 | (10,10)    | ((1.5,0.5))
+ [(11,12),(13,14)]         | (5.1,34.5) | [(0.386512752208,-0.261703911993),(0.451630407972,-0.310048838242)]
+ [(11,12),(13,14)]         | (10,10)    | [(1.15,0.05),(1.35,0.05)]
+ ((11,12),(13,14))         | (5.1,34.5) | ((0.386512752208,-0.261703911993),(0.451630407972,-0.310048838242))
+ ((11,12),(13,14))         | (10,10)    | ((1.15,0.05),(1.35,0.05))
+(18 rows)
+
+-- Division by 0 error
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to path
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+            f1             |            f1             |    ?column?    
+---------------------------+---------------------------+----------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((10,20))                 |  17.4642491966
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         |   11.313708499
+ [(1,2),(3,4)]             | ((11,12),(13,14))         |   11.313708499
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)] |              0
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))                 |  16.1554944214
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]         |  9.89949493661
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))         |  9.89949493661
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((10,20))                 |  17.4642491966
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         |   11.313708499
+ [(1,2),(3,4)]             | ((11,12),(13,14))         |   11.313708499
+ ((10,20))                 | [(1,2),(3,4)]             |  17.4642491966
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)] |  16.1554944214
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | [(1,2),(3,4)]             |  17.4642491966
+ ((10,20))                 | ((10,20))                 |              0
+ ((10,20))                 | [(11,12),(13,14)]         |   6.7082039325
+ ((10,20))                 | ((11,12),(13,14))         |   6.7082039325
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             |   11.313708499
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)] |  9.89949493661
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             |   11.313708499
+ [(11,12),(13,14)]         | ((10,20))                 |   6.7082039325
+ [(11,12),(13,14)]         | [(11,12),(13,14)]         |              0
+ [(11,12),(13,14)]         | ((11,12),(13,14))         |              0
+ ((11,12),(13,14))         | [(1,2),(3,4)]             |   11.313708499
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)] |  9.89949493661
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | [(1,2),(3,4)]             |   11.313708499
+ ((11,12),(13,14))         | ((10,20))                 |   6.7082039325
+ ((11,12),(13,14))         | [(11,12),(13,14)]         |              0
+ ((11,12),(13,14))         | ((11,12),(13,14))         |              0
+(81 rows)
 
 --
 -- Polygons
@@ -373,73 +3414,154 @@ SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
 -- containment
 SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
    FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
+ twentyfour |        f1         |             f1             | contains 
+------------+-------------------+----------------------------+----------
+            | (0,0)             | ((2,0),(2,4),(0,0))        | t
+            | (0,0)             | ((3,1),(3,3),(1,0))        | f
+            | (0,0)             | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (0,0)             | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (0,0)             | ((0,0))                    | t
+            | (0,0)             | ((0,1),(0,1))              | f
+            | (-10,0)           | ((2,0),(2,4),(0,0))        | f
+            | (-10,0)           | ((3,1),(3,3),(1,0))        | f
+            | (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-10,0)           | ((0,0))                    | f
+            | (-10,0)           | ((0,1),(0,1))              | f
+            | (-3,4)            | ((2,0),(2,4),(0,0))        | f
+            | (-3,4)            | ((3,1),(3,3),(1,0))        | f
+            | (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-3,4)            | ((0,0))                    | f
+            | (-3,4)            | ((0,1),(0,1))              | f
+            | (5.1,34.5)        | ((2,0),(2,4),(0,0))        | f
+            | (5.1,34.5)        | ((3,1),(3,3),(1,0))        | f
+            | (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (5.1,34.5)        | ((0,0))                    | f
+            | (5.1,34.5)        | ((0,1),(0,1))              | f
+            | (-5,-12)          | ((2,0),(2,4),(0,0))        | f
+            | (-5,-12)          | ((3,1),(3,3),(1,0))        | f
+            | (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-5,-12)          | ((0,0))                    | f
+            | (-5,-12)          | ((0,1),(0,1))              | f
+            | (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        | t
+            | (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        | f
+            | (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e-300,-1e-300)  | ((0,0))                    | t
+            | (1e-300,-1e-300)  | ((0,1),(0,1))              | f
+            | (1e+300,Infinity) | ((2,0),(2,4),(0,0))        | f
+            | (1e+300,Infinity) | ((3,1),(3,3),(1,0))        | f
+            | (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e+300,Infinity) | ((0,0))                    | f
+            | (1e+300,Infinity) | ((0,1),(0,1))              | f
+            | (NaN,NaN)         | ((2,0),(2,4),(0,0))        | t
+            | (NaN,NaN)         | ((3,1),(3,3),(1,0))        | t
+            | (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  | t
+            | (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  | t
+            | (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) | t
+            | (NaN,NaN)         | ((0,0))                    | t
+            | (NaN,NaN)         | ((0,1),(0,1))              | t
+            | (10,10)           | ((2,0),(2,4),(0,0))        | f
+            | (10,10)           | ((3,1),(3,3),(1,0))        | f
+            | (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (10,10)           | ((0,0))                    | f
+            | (10,10)           | ((0,1),(0,1))              | f
+(63 rows)
 
 SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
    FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
+ twentyfour |        f1         |             f1             | contained 
+------------+-------------------+----------------------------+-----------
+            | (0,0)             | ((2,0),(2,4),(0,0))        | t
+            | (0,0)             | ((3,1),(3,3),(1,0))        | f
+            | (0,0)             | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (0,0)             | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (0,0)             | ((0,0))                    | t
+            | (0,0)             | ((0,1),(0,1))              | f
+            | (-10,0)           | ((2,0),(2,4),(0,0))        | f
+            | (-10,0)           | ((3,1),(3,3),(1,0))        | f
+            | (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-10,0)           | ((0,0))                    | f
+            | (-10,0)           | ((0,1),(0,1))              | f
+            | (-3,4)            | ((2,0),(2,4),(0,0))        | f
+            | (-3,4)            | ((3,1),(3,3),(1,0))        | f
+            | (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-3,4)            | ((0,0))                    | f
+            | (-3,4)            | ((0,1),(0,1))              | f
+            | (5.1,34.5)        | ((2,0),(2,4),(0,0))        | f
+            | (5.1,34.5)        | ((3,1),(3,3),(1,0))        | f
+            | (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (5.1,34.5)        | ((0,0))                    | f
+            | (5.1,34.5)        | ((0,1),(0,1))              | f
+            | (-5,-12)          | ((2,0),(2,4),(0,0))        | f
+            | (-5,-12)          | ((3,1),(3,3),(1,0))        | f
+            | (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-5,-12)          | ((0,0))                    | f
+            | (-5,-12)          | ((0,1),(0,1))              | f
+            | (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        | t
+            | (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        | f
+            | (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e-300,-1e-300)  | ((0,0))                    | t
+            | (1e-300,-1e-300)  | ((0,1),(0,1))              | f
+            | (1e+300,Infinity) | ((2,0),(2,4),(0,0))        | f
+            | (1e+300,Infinity) | ((3,1),(3,3),(1,0))        | f
+            | (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e+300,Infinity) | ((0,0))                    | f
+            | (1e+300,Infinity) | ((0,1),(0,1))              | f
+            | (NaN,NaN)         | ((2,0),(2,4),(0,0))        | t
+            | (NaN,NaN)         | ((3,1),(3,3),(1,0))        | t
+            | (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  | t
+            | (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  | t
+            | (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) | t
+            | (NaN,NaN)         | ((0,0))                    | t
+            | (NaN,NaN)         | ((0,1),(0,1))              | t
+            | (10,10)           | ((2,0),(2,4),(0,0))        | f
+            | (10,10)           | ((3,1),(3,3),(1,0))        | f
+            | (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (10,10)           | ((0,0))                    | f
+            | (10,10)           | ((0,1),(0,1))              | f
+(63 rows)
 
 SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
    FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
+ four | npoints |          polygon           
+------+---------+----------------------------
       |       3 | ((2,0),(2,4),(0,0))
       |       3 | ((3,1),(3,3),(1,0))
+      |       4 | ((1,2),(3,4),(5,6),(7,8))
+      |       4 | ((7,8),(5,6),(3,4),(1,2))
+      |       4 | ((1,2),(7,8),(5,6),(3,-4))
       |       1 | ((0,0))
       |       2 | ((0,1),(0,1))
-(4 rows)
+(7 rows)
 
 SELECT '' AS four, polygon(f1)
    FROM BOX_TBL;
@@ -447,9 +3569,10 @@ SELECT '' AS four, polygon(f1)
 ------+-------------------------------------------
       | ((0,0),(0,2),(2,2),(2,0))
       | ((1,1),(1,3),(3,3),(3,1))
+      | ((-8,-10),(-8,2),(-2,2),(-2,-10))
       | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
       | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, polygon(f1)
    FROM PATH_TBL WHERE isclosed(f1);
@@ -458,8 +3581,9 @@ SELECT '' AS four, polygon(f1)
       | ((1,2),(3,4))
       | ((1,2),(3,4))
       | ((1,2),(3,4))
+      | ((10,20))
       | ((11,12),(13,14))
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
    FROM PATH_TBL
@@ -472,56 +3596,351 @@ SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
       | [(11,12),(13,14)]         | ((11,12),(13,14))
 (4 rows)
 
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
+-- To box
+SELECT f1, f1::box FROM POLYGON_TBL;
+             f1             |      f1      
+----------------------------+--------------
+ ((2,0),(2,4),(0,0))        | (2,4),(0,0)
+ ((3,1),(3,3),(1,0))        | (3,3),(1,0)
+ ((1,2),(3,4),(5,6),(7,8))  | (7,8),(1,2)
+ ((7,8),(5,6),(3,4),(1,2))  | (7,8),(1,2)
+ ((1,2),(7,8),(5,6),(3,-4)) | (7,8),(1,-4)
+ ((0,0))                    | (0,0),(0,0)
+ ((0,1),(0,1))              | (0,1),(0,1)
+(7 rows)
 
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
+-- To path
+SELECT f1, f1::path FROM POLYGON_TBL;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(7 rows)
+
+-- Same as polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 ~= p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(9 rows)
+
+-- Contained by polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <@ p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(12 rows)
+
+-- Contains polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 @> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(12 rows)
+
+-- Overlap with polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 && p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(25 rows)
+
+-- Left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 << p2.f1;
+      f1       |             f1             
+---------------+----------------------------
+ ((0,0))       | ((3,1),(3,3),(1,0))
+ ((0,0))       | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))       | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))       | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1)) | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1)) | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1)) | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1)) | ((1,2),(7,8),(5,6),(3,-4))
+(8 rows)
+
+-- Overlap of left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &< p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))                    | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1))              | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(32 rows)
+
+-- Right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 >> p2.f1;
+             f1             |      f1       
+----------------------------+---------------
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((0,1),(0,1))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1))
+(8 rows)
+
+-- Overlap of right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((2,0),(2,4),(0,0))        | ((0,1),(0,1))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((0,1),(0,1))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((3,1),(3,3),(1,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(37 rows)
+
+-- Below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <<| p2.f1;
+      f1       |            f1             
+---------------+---------------------------
+ ((0,0))       | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))       | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))       | ((0,1),(0,1))
+ ((0,1),(0,1)) | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1)) | ((7,8),(5,6),(3,4),(1,2))
+(5 rows)
+
+-- Overlap or below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &<| p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))                    | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1))              | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(31 rows)
 
+-- Above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |>> p2.f1;
+            f1             |      f1       
+---------------------------+---------------
+ ((1,2),(3,4),(5,6),(7,8)) | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8)) | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2)) | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2)) | ((0,1),(0,1))
+ ((0,1),(0,1))             | ((0,0))
+(5 rows)
+
+-- Overlap or above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |&> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((3,1),(3,3),(1,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(32 rows)
+
+-- Distance to polygon
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2;
+ERROR:  function "poly_distance" not implemented
 --
 -- Circles
 --
 SELECT '' AS six, circle(f1, 50.0)
    FROM POINT_TBL;
- six |     circle      
------+-----------------
+ six |         circle         
+-----+------------------------
      | <(0,0),50>
      | <(-10,0),50>
      | <(-3,4),50>
      | <(5.1,34.5),50>
      | <(-5,-12),50>
+     | <(1e-300,-1e-300),50>
+     | <(1e+300,Infinity),50>
+     | <(NaN,NaN),50>
      | <(10,10),50>
-(6 rows)
+(9 rows)
 
 SELECT '' AS four, circle(f1)
    FROM BOX_TBL;
- four |        circle         
-------+-----------------------
+ four |         circle         
+------+------------------------
       | <(1,1),1.41421356237>
       | <(2,2),1.41421356237>
+      | <(-5,-4),6.7082039325>
       | <(2.5,3),0.5>
       | <(3,3),0>
-(4 rows)
+(5 rows)
 
 SELECT '' AS two, circle(f1)
    FROM POLYGON_TBL
@@ -530,34 +3949,942 @@ SELECT '' AS two, circle(f1)
 -----+-----------------------------------------------
      | <(1.33333333333,1.33333333333),2.04168905064>
      | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
+     | <(4,5),2.82842712475>
+     | <(4,5),2.82842712475>
+     | <(4,3),4.80664375676>
+(5 rows)
 
 SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
    FROM CIRCLE_TBL c1, POINT_TBL p1
    WHERE (p1.f1 <-> c1.f1) > 0
    ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
+ twentyfour |     circle     |       point       |   distance    
+------------+----------------+-------------------+---------------
+            | <(1,2),3>      | (-3,4)            |   1.472135955
+            | <(5,1),3>      | (0,0)             | 2.09901951359
+            | <(5,1),3>      | (1e-300,-1e-300)  | 2.09901951359
+            | <(5,1),3>      | (-3,4)            | 5.54400374532
+            | <(3,5),0>      | (0,0)             | 5.83095189485
+            | <(3,5),0>      | (1e-300,-1e-300)  | 5.83095189485
+            | <(3,5),0>      | (-3,4)            |  6.0827625303
+            | <(1,3),5>      | (-10,0)           | 6.40175425099
+            | <(1,3),5>      | (10,10)           | 6.40175425099
+            | <(5,1),3>      | (10,10)           | 7.29563014099
+            | <(1,2),3>      | (-10,0)           |  8.1803398875
+            | <(3,5),0>      | (10,10)           | 8.60232526704
+            | <(1,2),3>      | (10,10)           | 9.04159457879
+            | <(1,3),5>      | (-5,-12)          | 11.1554944214
+            | <(5,1),3>      | (-10,0)           | 12.0332963784
+            | <(1,2),3>      | (-5,-12)          | 12.2315462117
+            | <(5,1),3>      | (-5,-12)          | 13.4012194669
+            | <(3,5),0>      | (-10,0)           | 13.9283882772
+            | <(3,5),0>      | (-5,-12)          | 18.7882942281
+            | <(1,3),5>      | (5.1,34.5)        | 26.7657047773
+            | <(3,5),0>      | (5.1,34.5)        | 29.5746513082
+            | <(1,2),3>      | (5.1,34.5)        | 29.7575945393
+            | <(5,1),3>      | (5.1,34.5)        | 30.5001492534
+            | <(100,200),10> | (5.1,34.5)        | 180.778038568
+            | <(100,200),10> | (10,10)           | 200.237960416
+            | <(100,200),10> | (-3,4)            | 211.415898255
+            | <(100,200),10> | (0,0)             |  213.60679775
+            | <(100,200),10> | (1e-300,-1e-300)  |  213.60679775
+            | <(100,200),10> | (-10,0)           |  218.25424421
+            | <(100,200),10> | (-5,-12)          | 226.577682802
+            | <(3,5),0>      | (1e+300,Infinity) |      Infinity
+            | <(1,2),3>      | (1e+300,Infinity) |      Infinity
+            | <(5,1),3>      | (1e+300,Infinity) |      Infinity
+            | <(1,3),5>      | (1e+300,Infinity) |      Infinity
+            | <(100,200),10> | (1e+300,Infinity) |      Infinity
+            | <(1,2),100>    | (1e+300,Infinity) |      Infinity
+            | <(100,1),115>  | (1e+300,Infinity) |      Infinity
+            | <(3,5),0>      | (NaN,NaN)         |           NaN
+            | <(1,2),3>      | (NaN,NaN)         |           NaN
+            | <(5,1),3>      | (NaN,NaN)         |           NaN
+            | <(1,3),5>      | (NaN,NaN)         |           NaN
+            | <(100,200),10> | (NaN,NaN)         |           NaN
+            | <(1,2),100>    | (NaN,NaN)         |           NaN
+            | <(100,1),115>  | (NaN,NaN)         |           NaN
+            | <(3,5),NaN>    | (-10,0)           |           NaN
+            | <(3,5),NaN>    | (-5,-12)          |           NaN
+            | <(3,5),NaN>    | (-3,4)            |           NaN
+            | <(3,5),NaN>    | (0,0)             |           NaN
+            | <(3,5),NaN>    | (1e-300,-1e-300)  |           NaN
+            | <(3,5),NaN>    | (5.1,34.5)        |           NaN
+            | <(3,5),NaN>    | (10,10)           |           NaN
+            | <(3,5),NaN>    | (1e+300,Infinity) |           NaN
+            | <(3,5),NaN>    | (NaN,NaN)         |           NaN
+(53 rows)
+
+-- To polygon
+SELECT f1, f1::polygon FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+       f1       |                                                                                                          f1                                                                                                          
+----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ <(5,1),3>      | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
+ <(1,2),100>    | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
+ <(1,3),5>      | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
+ <(1,2),3>      | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
+ <(100,200),10> | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
+ <(100,1),115>  | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
+(6 rows)
+
+-- To polygon with less points
+SELECT f1, polygon(8, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+       f1       |                                                                             polygon                                                                              
+----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ <(5,1),3>      | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
+ <(1,2),100>    | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
+ <(1,3),5>      | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
+ <(1,2),3>      | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
+ <(100,200),10> | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
+ <(100,1),115>  | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
+(6 rows)
+
+-- Too less points error
+SELECT f1, polygon(1, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+ERROR:  must request at least 2 points
+-- Zero radius error
+SELECT f1, polygon(10, f1) FROM CIRCLE_TBL WHERE f1 < '<(0,0),1>';
+ERROR:  cannot convert circle with radius zero to polygon
+-- Same as circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 ~= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+ <(3,5),NaN>    | <(3,5),0>
+ <(3,5),NaN>    | <(3,5),NaN>
+(9 rows)
+
+-- Overlap with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 && c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,1),115>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(100,1),115>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(33 rows)
+
+-- Overlap or left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &< c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(28 rows)
+
+-- Left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 << c2.f1;
+    f1     |       f1       
+-----------+----------------
+ <(5,1),3> | <(100,200),10>
+ <(1,3),5> | <(100,200),10>
+ <(1,2),3> | <(100,200),10>
+ <(3,5),0> | <(100,200),10>
+(4 rows)
+
+-- Right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >> c2.f1;
+       f1       |    f1     
+----------------+-----------
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(3,5),0>
+(4 rows)
+
+-- Overlap or right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(28 rows)
+
+-- Contained by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <@ c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(17 rows)
+
+-- Contain by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 @> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(3,5),0>
+(17 rows)
+
+-- Below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <<| c2.f1;
+      f1       |       f1       
+---------------+----------------
+ <(5,1),3>     | <(100,200),10>
+ <(5,1),3>     | <(3,5),0>
+ <(1,2),100>   | <(100,200),10>
+ <(1,3),5>     | <(100,200),10>
+ <(1,2),3>     | <(100,200),10>
+ <(100,1),115> | <(100,200),10>
+ <(3,5),0>     | <(100,200),10>
+(7 rows)
+
+-- Above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |>> c2.f1;
+       f1       |      f1       
+----------------+---------------
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(3,5),0>      | <(5,1),3>
+(7 rows)
+
+-- Overlap or below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &<| c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Overlap or above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |&> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 = c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(9 rows)
+
+-- Area not equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 != c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(40 rows)
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 > c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(3,5),0>
+(20 rows)
+
+-- Area less than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area greater than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Add point
+SELECT c.f1, p.f1, c.f1 + p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |        ?column?         
+----------------+-------------------+-------------------------
+ <(5,1),3>      | (0,0)             | <(5,1),3>
+ <(1,2),100>    | (0,0)             | <(1,2),100>
+ <(1,3),5>      | (0,0)             | <(1,3),5>
+ <(1,2),3>      | (0,0)             | <(1,2),3>
+ <(100,200),10> | (0,0)             | <(100,200),10>
+ <(100,1),115>  | (0,0)             | <(100,1),115>
+ <(3,5),0>      | (0,0)             | <(3,5),0>
+ <(3,5),NaN>    | (0,0)             | <(3,5),NaN>
+ <(5,1),3>      | (-10,0)           | <(-5,1),3>
+ <(1,2),100>    | (-10,0)           | <(-9,2),100>
+ <(1,3),5>      | (-10,0)           | <(-9,3),5>
+ <(1,2),3>      | (-10,0)           | <(-9,2),3>
+ <(100,200),10> | (-10,0)           | <(90,200),10>
+ <(100,1),115>  | (-10,0)           | <(90,1),115>
+ <(3,5),0>      | (-10,0)           | <(-7,5),0>
+ <(3,5),NaN>    | (-10,0)           | <(-7,5),NaN>
+ <(5,1),3>      | (-3,4)            | <(2,5),3>
+ <(1,2),100>    | (-3,4)            | <(-2,6),100>
+ <(1,3),5>      | (-3,4)            | <(-2,7),5>
+ <(1,2),3>      | (-3,4)            | <(-2,6),3>
+ <(100,200),10> | (-3,4)            | <(97,204),10>
+ <(100,1),115>  | (-3,4)            | <(97,5),115>
+ <(3,5),0>      | (-3,4)            | <(0,9),0>
+ <(3,5),NaN>    | (-3,4)            | <(0,9),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(10.1,35.5),3>
+ <(1,2),100>    | (5.1,34.5)        | <(6.1,36.5),100>
+ <(1,3),5>      | (5.1,34.5)        | <(6.1,37.5),5>
+ <(1,2),3>      | (5.1,34.5)        | <(6.1,36.5),3>
+ <(100,200),10> | (5.1,34.5)        | <(105.1,234.5),10>
+ <(100,1),115>  | (5.1,34.5)        | <(105.1,35.5),115>
+ <(3,5),0>      | (5.1,34.5)        | <(8.1,39.5),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(8.1,39.5),NaN>
+ <(5,1),3>      | (-5,-12)          | <(0,-11),3>
+ <(1,2),100>    | (-5,-12)          | <(-4,-10),100>
+ <(1,3),5>      | (-5,-12)          | <(-4,-9),5>
+ <(1,2),3>      | (-5,-12)          | <(-4,-10),3>
+ <(100,200),10> | (-5,-12)          | <(95,188),10>
+ <(100,1),115>  | (-5,-12)          | <(95,-11),115>
+ <(3,5),0>      | (-5,-12)          | <(-2,-7),0>
+ <(3,5),NaN>    | (-5,-12)          | <(-2,-7),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(5,1),3>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(1,2),100>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(1,3),5>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(1,2),3>
+ <(100,200),10> | (1e-300,-1e-300)  | <(100,200),10>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(100,1),115>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(3,5),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(3,5),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(1e+300,Infinity),3>
+ <(1,2),100>    | (1e+300,Infinity) | <(1e+300,Infinity),100>
+ <(1,3),5>      | (1e+300,Infinity) | <(1e+300,Infinity),5>
+ <(1,2),3>      | (1e+300,Infinity) | <(1e+300,Infinity),3>
+ <(100,200),10> | (1e+300,Infinity) | <(1e+300,Infinity),10>
+ <(100,1),115>  | (1e+300,Infinity) | <(1e+300,Infinity),115>
+ <(3,5),0>      | (1e+300,Infinity) | <(1e+300,Infinity),0>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(1e+300,Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),100>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),5>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),10>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),115>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),0>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(15,11),3>
+ <(1,2),100>    | (10,10)           | <(11,12),100>
+ <(1,3),5>      | (10,10)           | <(11,13),5>
+ <(1,2),3>      | (10,10)           | <(11,12),3>
+ <(100,200),10> | (10,10)           | <(110,210),10>
+ <(100,1),115>  | (10,10)           | <(110,11),115>
+ <(3,5),0>      | (10,10)           | <(13,15),0>
+ <(3,5),NaN>    | (10,10)           | <(13,15),NaN>
+(72 rows)
+
+-- Subtract point
+SELECT c.f1, p.f1, c.f1 - p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |         ?column?          
+----------------+-------------------+---------------------------
+ <(5,1),3>      | (0,0)             | <(5,1),3>
+ <(1,2),100>    | (0,0)             | <(1,2),100>
+ <(1,3),5>      | (0,0)             | <(1,3),5>
+ <(1,2),3>      | (0,0)             | <(1,2),3>
+ <(100,200),10> | (0,0)             | <(100,200),10>
+ <(100,1),115>  | (0,0)             | <(100,1),115>
+ <(3,5),0>      | (0,0)             | <(3,5),0>
+ <(3,5),NaN>    | (0,0)             | <(3,5),NaN>
+ <(5,1),3>      | (-10,0)           | <(15,1),3>
+ <(1,2),100>    | (-10,0)           | <(11,2),100>
+ <(1,3),5>      | (-10,0)           | <(11,3),5>
+ <(1,2),3>      | (-10,0)           | <(11,2),3>
+ <(100,200),10> | (-10,0)           | <(110,200),10>
+ <(100,1),115>  | (-10,0)           | <(110,1),115>
+ <(3,5),0>      | (-10,0)           | <(13,5),0>
+ <(3,5),NaN>    | (-10,0)           | <(13,5),NaN>
+ <(5,1),3>      | (-3,4)            | <(8,-3),3>
+ <(1,2),100>    | (-3,4)            | <(4,-2),100>
+ <(1,3),5>      | (-3,4)            | <(4,-1),5>
+ <(1,2),3>      | (-3,4)            | <(4,-2),3>
+ <(100,200),10> | (-3,4)            | <(103,196),10>
+ <(100,1),115>  | (-3,4)            | <(103,-3),115>
+ <(3,5),0>      | (-3,4)            | <(6,1),0>
+ <(3,5),NaN>    | (-3,4)            | <(6,1),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(-0.1,-33.5),3>
+ <(1,2),100>    | (5.1,34.5)        | <(-4.1,-32.5),100>
+ <(1,3),5>      | (5.1,34.5)        | <(-4.1,-31.5),5>
+ <(1,2),3>      | (5.1,34.5)        | <(-4.1,-32.5),3>
+ <(100,200),10> | (5.1,34.5)        | <(94.9,165.5),10>
+ <(100,1),115>  | (5.1,34.5)        | <(94.9,-33.5),115>
+ <(3,5),0>      | (5.1,34.5)        | <(-2.1,-29.5),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(-2.1,-29.5),NaN>
+ <(5,1),3>      | (-5,-12)          | <(10,13),3>
+ <(1,2),100>    | (-5,-12)          | <(6,14),100>
+ <(1,3),5>      | (-5,-12)          | <(6,15),5>
+ <(1,2),3>      | (-5,-12)          | <(6,14),3>
+ <(100,200),10> | (-5,-12)          | <(105,212),10>
+ <(100,1),115>  | (-5,-12)          | <(105,13),115>
+ <(3,5),0>      | (-5,-12)          | <(8,17),0>
+ <(3,5),NaN>    | (-5,-12)          | <(8,17),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(5,1),3>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(1,2),100>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(1,3),5>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(1,2),3>
+ <(100,200),10> | (1e-300,-1e-300)  | <(100,200),10>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(100,1),115>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(3,5),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(3,5),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(-1e+300,-Infinity),3>
+ <(1,2),100>    | (1e+300,Infinity) | <(-1e+300,-Infinity),100>
+ <(1,3),5>      | (1e+300,Infinity) | <(-1e+300,-Infinity),5>
+ <(1,2),3>      | (1e+300,Infinity) | <(-1e+300,-Infinity),3>
+ <(100,200),10> | (1e+300,Infinity) | <(-1e+300,-Infinity),10>
+ <(100,1),115>  | (1e+300,Infinity) | <(-1e+300,-Infinity),115>
+ <(3,5),0>      | (1e+300,Infinity) | <(-1e+300,-Infinity),0>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(-1e+300,-Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),100>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),5>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),10>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),115>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),0>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(-5,-9),3>
+ <(1,2),100>    | (10,10)           | <(-9,-8),100>
+ <(1,3),5>      | (10,10)           | <(-9,-7),5>
+ <(1,2),3>      | (10,10)           | <(-9,-8),3>
+ <(100,200),10> | (10,10)           | <(90,190),10>
+ <(100,1),115>  | (10,10)           | <(90,-9),115>
+ <(3,5),0>      | (10,10)           | <(-7,-5),0>
+ <(3,5),NaN>    | (10,10)           | <(-7,-5),NaN>
+(72 rows)
+
+-- Multiply with point
+SELECT c.f1, p.f1, c.f1 * p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |                  ?column?                  
+----------------+-------------------+--------------------------------------------
+ <(5,1),3>      | (0,0)             | <(0,0),0>
+ <(1,2),100>    | (0,0)             | <(0,0),0>
+ <(1,3),5>      | (0,0)             | <(0,0),0>
+ <(1,2),3>      | (0,0)             | <(0,0),0>
+ <(100,200),10> | (0,0)             | <(0,0),0>
+ <(100,1),115>  | (0,0)             | <(0,0),0>
+ <(3,5),0>      | (0,0)             | <(0,0),0>
+ <(3,5),NaN>    | (0,0)             | <(0,0),NaN>
+ <(5,1),3>      | (-10,0)           | <(-50,-10),30>
+ <(1,2),100>    | (-10,0)           | <(-10,-20),1000>
+ <(1,3),5>      | (-10,0)           | <(-10,-30),50>
+ <(1,2),3>      | (-10,0)           | <(-10,-20),30>
+ <(100,200),10> | (-10,0)           | <(-1000,-2000),100>
+ <(100,1),115>  | (-10,0)           | <(-1000,-10),1150>
+ <(3,5),0>      | (-10,0)           | <(-30,-50),0>
+ <(3,5),NaN>    | (-10,0)           | <(-30,-50),NaN>
+ <(5,1),3>      | (-3,4)            | <(-19,17),15>
+ <(1,2),100>    | (-3,4)            | <(-11,-2),500>
+ <(1,3),5>      | (-3,4)            | <(-15,-5),25>
+ <(1,2),3>      | (-3,4)            | <(-11,-2),15>
+ <(100,200),10> | (-3,4)            | <(-1100,-200),50>
+ <(100,1),115>  | (-3,4)            | <(-304,397),575>
+ <(3,5),0>      | (-3,4)            | <(-29,-3),0>
+ <(3,5),NaN>    | (-3,4)            | <(-29,-3),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(-9,177.6),104.624758064>
+ <(1,2),100>    | (5.1,34.5)        | <(-63.9,44.7),3487.49193547>
+ <(1,3),5>      | (5.1,34.5)        | <(-98.4,49.8),174.374596774>
+ <(1,2),3>      | (5.1,34.5)        | <(-63.9,44.7),104.624758064>
+ <(100,200),10> | (5.1,34.5)        | <(-6390,4470),348.749193547>
+ <(100,1),115>  | (5.1,34.5)        | <(475.5,3455.1),4010.6157258>
+ <(3,5),0>      | (5.1,34.5)        | <(-157.2,129),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(-157.2,129),NaN>
+ <(5,1),3>      | (-5,-12)          | <(-13,-65),39>
+ <(1,2),100>    | (-5,-12)          | <(19,-22),1300>
+ <(1,3),5>      | (-5,-12)          | <(31,-27),65>
+ <(1,2),3>      | (-5,-12)          | <(19,-22),39>
+ <(100,200),10> | (-5,-12)          | <(1900,-2200),130>
+ <(100,1),115>  | (-5,-12)          | <(-488,-1205),1495>
+ <(3,5),0>      | (-5,-12)          | <(45,-61),0>
+ <(3,5),NaN>    | (-5,-12)          | <(45,-61),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(6e-300,-4e-300),4.24264068712e-300>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(3e-300,1e-300),1.41421356237e-298>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(4e-300,2e-300),7.07106781187e-300>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(3e-300,1e-300),4.24264068712e-300>
+ <(100,200),10> | (1e-300,-1e-300)  | <(3e-298,1e-298),1.41421356237e-299>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(1.01e-298,-9.9e-299),1.62634559673e-298>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(8e-300,2e-300),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(8e-300,2e-300),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,2),100>    | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,3),5>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,2),3>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(100,200),10> | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(100,1),115>  | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(3,5),0>      | (1e+300,Infinity) | <(-Infinity,Infinity),NaN>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(-Infinity,Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(40,60),42.4264068712>
+ <(1,2),100>    | (10,10)           | <(-10,30),1414.21356237>
+ <(1,3),5>      | (10,10)           | <(-20,40),70.7106781187>
+ <(1,2),3>      | (10,10)           | <(-10,30),42.4264068712>
+ <(100,200),10> | (10,10)           | <(-1000,3000),141.421356237>
+ <(100,1),115>  | (10,10)           | <(990,1010),1626.34559673>
+ <(3,5),0>      | (10,10)           | <(-20,80),0>
+ <(3,5),NaN>    | (10,10)           | <(-20,80),NaN>
+(72 rows)
+
+-- Divide by point
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+       f1       |     f1     |                       ?column?                       
+----------------+------------+------------------------------------------------------
+ <(5,1),3>      | (5.1,34.5) | <(0.0493315573973,-0.137635045138),0.0860217042937>
+ <(5,1),3>      | (10,10)    | <(0.3,-0.2),0.212132034356>
+ <(1,2),100>    | (5.1,34.5) | <(0.0609244733856,-0.0199792807459),2.86739014312>
+ <(1,2),100>    | (10,10)    | <(0.15,0.05),7.07106781187>
+ <(1,3),5>      | (5.1,34.5) | <(0.0892901188891,-0.0157860983671),0.143369507156>
+ <(1,3),5>      | (10,10)    | <(0.2,0.1),0.353553390593>
+ <(1,2),3>      | (5.1,34.5) | <(0.0609244733856,-0.0199792807459),0.0860217042937>
+ <(1,2),3>      | (10,10)    | <(0.15,0.05),0.212132034356>
+ <(100,200),10> | (5.1,34.5) | <(6.09244733856,-1.99792807459),0.286739014312>
+ <(100,200),10> | (10,10)    | <(15,5),0.707106781187>
+ <(100,1),115>  | (5.1,34.5) | <(0.44768388338,-2.83237136796),3.29749866459>
+ <(100,1),115>  | (10,10)    | <(5.05,-4.95),8.13172798365>
+ <(3,5),0>      | (5.1,34.5) | <(0.154407774653,-0.0641310246164),0>
+ <(3,5),0>      | (10,10)    | <(0.4,0.1),0>
+ <(3,5),NaN>    | (5.1,34.5) | <(0.154407774653,-0.0641310246164),NaN>
+ <(3,5),NaN>    | (10,10)    | <(0.4,0.1),NaN>
+(16 rows)
+
+-- Overflow error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] > 1000;
+ERROR:  value out of range: overflow
+-- Division by 0 error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to polygon
+SELECT c.f1, p.f1, c.f1 <-> p.f1 FROM CIRCLE_TBL c, POLYGON_TBL p;
+       f1       |             f1             |    ?column?    
+----------------+----------------------------+----------------
+ <(5,1),3>      | ((2,0),(2,4),(0,0))        |              0
+ <(5,1),3>      | ((3,1),(3,3),(1,0))        |              0
+ <(5,1),3>      | ((1,2),(3,4),(5,6),(7,8))  | 0.535533905933
+ <(5,1),3>      | ((7,8),(5,6),(3,4),(1,2))  | 0.535533905933
+ <(5,1),3>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(5,1),3>      | ((0,0))                    |  2.09901951359
+ <(5,1),3>      | ((0,1),(0,1))              |              2
+ <(1,2),100>    | ((2,0),(2,4),(0,0))        |              0
+ <(1,2),100>    | ((3,1),(3,3),(1,0))        |              0
+ <(1,2),100>    | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,2),100>    | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,2),100>    | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,2),100>    | ((0,0))                    |              0
+ <(1,2),100>    | ((0,1),(0,1))              |              0
+ <(1,3),5>      | ((2,0),(2,4),(0,0))        |              0
+ <(1,3),5>      | ((3,1),(3,3),(1,0))        |              0
+ <(1,3),5>      | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,3),5>      | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,3),5>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,3),5>      | ((0,0))                    |              0
+ <(1,3),5>      | ((0,1),(0,1))              |              0
+ <(1,2),3>      | ((2,0),(2,4),(0,0))        |              0
+ <(1,2),3>      | ((3,1),(3,3),(1,0))        |              0
+ <(1,2),3>      | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,2),3>      | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,2),3>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,2),3>      | ((0,0))                    |              0
+ <(1,2),3>      | ((0,1),(0,1))              |              0
+ <(100,200),10> | ((2,0),(2,4),(0,0))        |  209.134661795
+ <(100,200),10> | ((3,1),(3,3),(1,0))        |  209.585974051
+ <(100,200),10> | ((1,2),(3,4),(5,6),(7,8))  |  203.337760371
+ <(100,200),10> | ((7,8),(5,6),(3,4),(1,2))  |  203.337760371
+ <(100,200),10> | ((1,2),(7,8),(5,6),(3,-4)) |  203.337760371
+ <(100,200),10> | ((0,0))                    |   213.60679775
+ <(100,200),10> | ((0,1),(0,1))              |  212.712819568
+ <(100,1),115>  | ((2,0),(2,4),(0,0))        |              0
+ <(100,1),115>  | ((3,1),(3,3),(1,0))        |              0
+ <(100,1),115>  | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(100,1),115>  | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(100,1),115>  | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(100,1),115>  | ((0,0))                    |              0
+ <(100,1),115>  | ((0,1),(0,1))              |              0
+ <(3,5),0>      | ((2,0),(2,4),(0,0))        |  1.41421356237
+ <(3,5),0>      | ((3,1),(3,3),(1,0))        |              2
+ <(3,5),0>      | ((1,2),(3,4),(5,6),(7,8))  | 0.707106781187
+ <(3,5),0>      | ((7,8),(5,6),(3,4),(1,2))  | 0.707106781187
+ <(3,5),0>      | ((1,2),(7,8),(5,6),(3,-4)) | 0.707106781187
+ <(3,5),0>      | ((0,0))                    |  5.83095189485
+ <(3,5),0>      | ((0,1),(0,1))              |              5
+ <(3,5),NaN>    | ((2,0),(2,4),(0,0))        |            NaN
+ <(3,5),NaN>    | ((3,1),(3,3),(1,0))        |            NaN
+ <(3,5),NaN>    | ((1,2),(3,4),(5,6),(7,8))  |            NaN
+ <(3,5),NaN>    | ((7,8),(5,6),(3,4),(1,2))  |            NaN
+ <(3,5),NaN>    | ((1,2),(7,8),(5,6),(3,-4)) |            NaN
+ <(3,5),NaN>    | ((0,0))                    |            NaN
+ <(3,5),NaN>    | ((0,1),(0,1))              |            NaN
+(56 rows)
 
diff --git a/src/test/regress/expected/geometry_2.out b/src/test/regress/expected/geometry_2.out
deleted file mode 100644
index 5a922bcd3f..0000000000
--- a/src/test/regress/expected/geometry_2.out
+++ /dev/null
@@ -1,563 +0,0 @@
---
--- GEOMETRY
---
--- Back off displayed precision a little bit to reduce platform-to-platform
--- variation in results.
-SET extra_float_digits TO -3;
---
--- Points
---
-SELECT '' AS four, center(f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS four, (@@ f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS six, point(f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS six, (@@ f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS two, (@@ f1) AS center
-   FROM POLYGON_TBL
-   WHERE (# f1) > 2;
- two |            center             
------+-------------------------------
-     | (1.33333333333,1.33333333333)
-     | (2.33333333333,1.33333333333)
-(2 rows)
-
--- "is horizontal" function
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is horizontal" operator
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is vertical" function
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE isvertical(p1.f1, point '(5.1,34.5)');
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
--- "is vertical" operator
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?| point '(5.1,34.5)';
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
---
--- Line segments
---
--- intersection
-SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-   FROM LSEG_TBL l, POINT_TBL p;
-ERROR:  operator does not exist: lseg # point
-LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-                                           ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
-
---
--- Boxes
---
-SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
- six |                              box                               
------+----------------------------------------------------------------
-     | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
-     | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
-     | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
-     | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
-     | (107.071067812,207.071067812),(92.9289321881,192.928932188)
-     | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
-
--- translation
-SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (-8,2),(-10,0)
-            | (-7,3),(-9,1)
-            | (-7.5,3.5),(-7.5,2.5)
-            | (-7,3),(-7,3)
-            | (-1,6),(-3,4)
-            | (0,7),(-2,5)
-            | (-0.5,7.5),(-0.5,6.5)
-            | (0,7),(0,7)
-            | (7.1,36.5),(5.1,34.5)
-            | (8.1,37.5),(6.1,35.5)
-            | (7.6,38),(7.6,37)
-            | (8.1,37.5),(8.1,37.5)
-            | (-3,-10),(-5,-12)
-            | (-2,-9),(-4,-11)
-            | (-2.5,-8.5),(-2.5,-9.5)
-            | (-2,-9),(-2,-9)
-            | (12,12),(10,10)
-            | (13,13),(11,11)
-            | (12.5,13.5),(12.5,12.5)
-            | (13,13),(13,13)
-(24 rows)
-
-SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (12,2),(10,0)
-            | (13,3),(11,1)
-            | (12.5,3.5),(12.5,2.5)
-            | (13,3),(13,3)
-            | (5,-2),(3,-4)
-            | (6,-1),(4,-3)
-            | (5.5,-0.5),(5.5,-1.5)
-            | (6,-1),(6,-1)
-            | (-3.1,-32.5),(-5.1,-34.5)
-            | (-2.1,-31.5),(-4.1,-33.5)
-            | (-2.6,-31),(-2.6,-32)
-            | (-2.1,-31.5),(-2.1,-31.5)
-            | (7,14),(5,12)
-            | (8,15),(6,13)
-            | (7.5,15.5),(7.5,14.5)
-            | (8,15),(8,15)
-            | (-8,-8),(-10,-10)
-            | (-7,-7),(-9,-9)
-            | (-7.5,-6.5),(-7.5,-7.5)
-            | (-7,-7),(-7,-7)
-(24 rows)
-
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (-0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (-0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,-0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
-
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,-0),(-0.2,-0.2)
-        | (0.08,-0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (-0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
-
-SELECT f1::box
-	FROM POINT_TBL;
-          f1           
------------------------
- (0,0),(0,0)
- (-10,0),(-10,0)
- (-3,4),(-3,4)
- (5.1,34.5),(5.1,34.5)
- (-5,-12),(-5,-12)
- (10,10),(10,10)
-(6 rows)
-
-SELECT bound_box(a.f1, b.f1)
-	FROM BOX_TBL a, BOX_TBL b;
-      bound_box      
----------------------
- (2,2),(0,0)
- (3,3),(0,0)
- (2.5,3.5),(0,0)
- (3,3),(0,0)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(1,1)
- (3,3),(1,1)
- (2.5,3.5),(0,0)
- (3,3.5),(1,1)
- (2.5,3.5),(2.5,2.5)
- (3,3.5),(2.5,2.5)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(2.5,2.5)
- (3,3),(3,3)
-(16 rows)
-
---
--- Paths
---
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
-
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
-
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
-
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
-
---
--- Polygons
---
--- containment
-SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
-   FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
-      |       3 | ((2,0),(2,4),(0,0))
-      |       3 | ((3,1),(3,3),(1,0))
-      |       1 | ((0,0))
-      |       2 | ((0,1),(0,1))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM BOX_TBL;
- four |                  polygon                  
-------+-------------------------------------------
-      | ((0,0),(0,2),(2,2),(2,0))
-      | ((1,1),(1,3),(3,3),(3,1))
-      | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
-      | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM PATH_TBL WHERE isclosed(f1);
- four |      polygon      
-------+-------------------
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((11,12),(13,14))
-(4 rows)
-
-SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
-   FROM PATH_TBL
-   WHERE isopen(f1);
- four |         open_path         |          polygon          
-------+---------------------------+---------------------------
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(11,12),(13,14)]         | ((11,12),(13,14))
-(4 rows)
-
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
-
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
-
---
--- Circles
---
-SELECT '' AS six, circle(f1, 50.0)
-   FROM POINT_TBL;
- six |     circle      
------+-----------------
-     | <(0,0),50>
-     | <(-10,0),50>
-     | <(-3,4),50>
-     | <(5.1,34.5),50>
-     | <(-5,-12),50>
-     | <(10,10),50>
-(6 rows)
-
-SELECT '' AS four, circle(f1)
-   FROM BOX_TBL;
- four |        circle         
-------+-----------------------
-      | <(1,1),1.41421356237>
-      | <(2,2),1.41421356237>
-      | <(2.5,3),0.5>
-      | <(3,3),0>
-(4 rows)
-
-SELECT '' AS two, circle(f1)
-   FROM POLYGON_TBL
-   WHERE (# f1) >= 3;
- two |                    circle                     
------+-----------------------------------------------
-     | <(1.33333333333,1.33333333333),2.04168905064>
-     | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
-
-SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
-   FROM CIRCLE_TBL c1, POINT_TBL p1
-   WHERE (p1.f1 <-> c1.f1) > 0
-   ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
-
diff --git a/src/test/regress/expected/line.out b/src/test/regress/expected/line.out
index f20abdc430..bf780daa2c 100644
--- a/src/test/regress/expected/line.out
+++ b/src/test/regress/expected/line.out
@@ -4,24 +4,43 @@
 --
 --DROP TABLE LINE_TBL;
 CREATE TABLE LINE_TBL (s line);
-INSERT INTO LINE_TBL VALUES ('{1,-1,1}');
-INSERT INTO LINE_TBL VALUES ('(0,0),(6,6)');
+INSERT INTO LINE_TBL VALUES ('{0,-1,5}');	-- A == 0
+INSERT INTO LINE_TBL VALUES ('{1,0,5}');	-- B == 0
+INSERT INTO LINE_TBL VALUES ('{0,3,0}');	-- A == C == 0
+INSERT INTO LINE_TBL VALUES (' (0,0), (6,6)');
 INSERT INTO LINE_TBL VALUES ('10,-10 ,-5,-4');
 INSERT INTO LINE_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LINE_TBL VALUES ('(11,22,33,44)');
-INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
-ERROR:  invalid line specification: must be two distinct points
-LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
-                                     ^
+INSERT INTO LINE_TBL VALUES ('{3,NaN,5}');
+INSERT INTO LINE_TBL VALUES ('{NaN,NaN,NaN}');
 -- horizontal
 INSERT INTO LINE_TBL VALUES ('[(1,3),(2,3)]');
 -- vertical
-INSERT INTO LINE_TBL VALUES ('[(3,1),(3,2)]');
+INSERT INTO LINE_TBL VALUES (line(point '(3,1)', point '(3,2)'));
 -- bad values for parser testing
+INSERT INTO LINE_TBL VALUES ('{}');
+ERROR:  invalid input syntax for type line: "{}"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{}');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0');
+ERROR:  invalid input syntax for type line: "{0"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0,0}');
+ERROR:  invalid input syntax for type line: "{0,0}"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0}');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0,0,1');
+ERROR:  invalid input syntax for type line: "{0,0,1"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1');
+                                     ^
 INSERT INTO LINE_TBL VALUES ('{0,0,1}');
 ERROR:  invalid line specification: A and B cannot both be zero
 LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1}');
                                      ^
+INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
+ERROR:  invalid input syntax for type line: "{0,0,1} x"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
+                                     ^
 INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
 ERROR:  invalid input syntax for type line: "(3asdf,2 ,3,4r2)"
 LINE 1: INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
@@ -38,234 +57,31 @@ INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
 ERROR:  invalid input syntax for type line: "[(1,2),(3,4)"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
                                      ^
+INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
+ERROR:  invalid line specification: must be two distinct points
+LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
+                                     ^
+INSERT INTO LINE_TBL VALUES (line(point '(1,0)', point '(1,0)'));
+ERROR:  invalid line specification: must be two distinct points
 select * from LINE_TBL;
                       s                      
 ---------------------------------------------
- {1,-1,1}
+ {0,-1,5}
+ {1,0,5}
+ {0,3,0}
  {1,-1,0}
  {-0.4,-1,-6}
  {-0.000184615384615385,-1,15.3846153846154}
- {1,-1,11}
+ {3,NaN,5}
+ {NaN,NaN,NaN}
  {0,-1,3}
  {-1,0,3}
-(7 rows)
-
--- functions and operators
-SELECT * FROM LINE_TBL WHERE (s <-> line '[(1,2),(3,4)]') < 10;
-                      s                      
----------------------------------------------
- {1,-1,1}
- {1,-1,0}
- {-0.4,-1,-6}
- {-0.000184615384615385,-1,15.3846153846154}
- {1,-1,11}
- {0,-1,3}
- {-1,0,3}
-(7 rows)
-
-SELECT * FROM LINE_TBL WHERE (point '(0.1,0.1)' <-> s) < 1;
-    s     
-----------
- {1,-1,1}
- {1,-1,0}
-(2 rows)
-
-SELECT * FROM LINE_TBL WHERE (lseg '[(0.1,0.1),(0.2,0.2)]' <-> s) < 1;
-    s     
-----------
- {1,-1,1}
- {1,-1,0}
-(2 rows)
-
-SELECT line '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
- ?column? 
-----------
-        2
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
- ?column? 
-----------
-        2
-(1 row)
-
-SELECT point '(-1,1)' <-> line '[(-3,0),(-4,0)]';
- ?column? 
-----------
-        1
-(1 row)
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(2,0),(0,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# box '(0,0,2,2)';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(3,0),(4,1)]' ?# box '(0,0,2,2)';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(1,1)' <@ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT point '(1,1)' <@ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(1,1)' @ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT point '(1,1)' @ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT lseg '[(1,1),(2,2)]' <@ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' <@ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT lseg '[(1,1),(2,2)]' @ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' @ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(0,1)' ## line '[(0,0),(1,1)]';
- ?column?  
------------
- (0.5,0.5)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ## lseg '[(1,0),(2,0)]';
- ?column? 
-----------
- (1,0)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(2,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(1,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(2,1)]';
- ?column? 
-----------
- 
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(1,1)]';
- ?column? 
-----------
- (1,1)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(2,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,0)]' ?-| line '[(0,0),(0,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?-| line '[(1,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT ?- line '[(0,0),(1,0)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT ?- line '[(0,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT ?| line '[(0,0),(0,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT ?| line '[(0,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line(point '(1,2)', point '(3,4)');
-   line   
-----------
- {1,-1,1}
-(1 row)
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,5)]';  -- true
- ?column? 
-----------
- t
-(1 row)
+(10 rows)
 
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,4)]';  -- false
- ?column? 
-----------
- f
+select '{nan, 1, nan}'::line = '{nan, 1, nan}'::line as true,
+	   '{nan, 1, nan}'::line = '{nan, 2, nan}'::line as false;
+ true | false 
+------+-------
+ t    | f
 (1 row)
 
diff --git a/src/test/regress/expected/lseg.out b/src/test/regress/expected/lseg.out
index bba1f3ee80..7e878b5577 100644
--- a/src/test/regress/expected/lseg.out
+++ b/src/test/regress/expected/lseg.out
@@ -8,7 +8,10 @@ INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('(0,0),(6,6)');
 INSERT INTO LSEG_TBL VALUES ('10,-10 ,-3,-4');
 INSERT INTO LSEG_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LSEG_TBL VALUES ('(11,22,33,44)');
+INSERT INTO LSEG_TBL VALUES (lseg(point(11, 22), point(33,44)));
+INSERT INTO LSEG_TBL VALUES ('[(-10,2),(-10,3)]');	-- vertical
+INSERT INTO LSEG_TBL VALUES ('[(0,-20),(30,-20)]');	-- horizontal
+INSERT INTO LSEG_TBL VALUES ('[(NaN,1),(NaN,90)]');	-- NaN
 -- bad values for parser testing
 INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
 ERROR:  invalid input syntax for type lseg: "(3asdf,2 ,3,4r2)"
@@ -34,19 +37,8 @@ select * from LSEG_TBL;
  [(10,-10),(-3,-4)]
  [(-1000000,200),(300000,-40)]
  [(11,22),(33,44)]
-(5 rows)
-
-SELECT * FROM LSEG_TBL WHERE s <= lseg '[(1,2),(3,4)]';
-       s       
----------------
- [(1,2),(3,4)]
-(1 row)
-
-SELECT * FROM LSEG_TBL WHERE (s <-> lseg '[(1,2),(3,4)]') < 10;
-         s          
---------------------
- [(1,2),(3,4)]
- [(0,0),(6,6)]
- [(10,-10),(-3,-4)]
-(3 rows)
+ [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]
+ [(NaN,1),(NaN,90)]
+(8 rows)
 
diff --git a/src/test/regress/expected/path.out b/src/test/regress/expected/path.out
index 08d6d61dda..bd6e467752 100644
--- a/src/test/regress/expected/path.out
+++ b/src/test/regress/expected/path.out
@@ -4,14 +4,19 @@
 --DROP TABLE PATH_TBL;
 CREATE TABLE PATH_TBL (f1 path);
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)]');
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
-INSERT INTO PATH_TBL VALUES ('[(0,0),(3,0),(4,5),(1,6)]');
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
-INSERT INTO PATH_TBL VALUES ('1,2 ,3,4');
-INSERT INTO PATH_TBL VALUES ('[1,2,3, 4]');
-INSERT INTO PATH_TBL VALUES ('[11,12,13,14]');
-INSERT INTO PATH_TBL VALUES ('(11,12,13,14)');
+INSERT INTO PATH_TBL VALUES (' ( ( 1 , 2 ) , ( 3 , 4 ) ) ');
+INSERT INTO PATH_TBL VALUES ('[ (0,0),(3,0),(4,5),(1,6) ]');
+INSERT INTO PATH_TBL VALUES ('((1,2) ,(3,4 ))');
+INSERT INTO PATH_TBL VALUES ('1,2 ,3,4 ');
+INSERT INTO PATH_TBL VALUES (' [1,2,3, 4] ');
+INSERT INTO PATH_TBL VALUES ('((10,20))');	-- Only one point
+INSERT INTO PATH_TBL VALUES ('[ 11,12,13,14 ]');
+INSERT INTO PATH_TBL VALUES ('( 11,12,13,14) ');
 -- bad values for parser testing
+INSERT INTO PATH_TBL VALUES ('[]');
+ERROR:  invalid input syntax for type path: "[]"
+LINE 1: INSERT INTO PATH_TBL VALUES ('[]');
+                                     ^
 INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
 ERROR:  invalid input syntax for type path: "[(,2),(3,4)]"
 LINE 1: INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
@@ -20,19 +25,14 @@ INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
 ERROR:  invalid input syntax for type path: "[(1,2),(3,4)"
 LINE 1: INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
                                      ^
-SELECT f1 FROM PATH_TBL;
-            f1             
----------------------------
- [(1,2),(3,4)]
- ((1,2),(3,4))
- [(0,0),(3,0),(4,5),(1,6)]
- ((1,2),(3,4))
- ((1,2),(3,4))
- [(1,2),(3,4)]
- [(11,12),(13,14)]
- ((11,12),(13,14))
-(8 rows)
-
+INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+ERROR:  invalid input syntax for type path: "(1,2,3,4"
+LINE 1: INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+                                     ^
+INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
+ERROR:  invalid input syntax for type path: "(1,2),(3,4)]"
+LINE 1: INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
+                                     ^
 SELECT '' AS count, f1 AS open_path FROM PATH_TBL WHERE isopen(f1);
  count |         open_path         
 -------+---------------------------
@@ -48,8 +48,9 @@ SELECT '' AS count, f1 AS closed_path FROM PATH_TBL WHERE isclosed(f1);
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
+       | ((10,20))
        | ((11,12),(13,14))
-(4 rows)
+(5 rows)
 
 SELECT '' AS count, pclose(f1) AS closed_path FROM PATH_TBL;
  count |        closed_path        
@@ -60,9 +61,10 @@ SELECT '' AS count, pclose(f1) AS closed_path FROM PATH_TBL;
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
+       | ((10,20))
        | ((11,12),(13,14))
        | ((11,12),(13,14))
-(8 rows)
+(9 rows)
 
 SELECT '' AS count, popen(f1) AS open_path FROM PATH_TBL;
  count |         open_path         
@@ -73,7 +75,8 @@ SELECT '' AS count, popen(f1) AS open_path FROM PATH_TBL;
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
+       | [(10,20)]
        | [(11,12),(13,14)]
        | [(11,12),(13,14)]
-(8 rows)
+(9 rows)
 
diff --git a/src/test/regress/expected/point.out b/src/test/regress/expected/point.out
index bfc0962749..c18e865370 100644
--- a/src/test/regress/expected/point.out
+++ b/src/test/regress/expected/point.out
@@ -7,6 +7,9 @@ INSERT INTO POINT_TBL(f1) VALUES ('(-10.0,0.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-3.0,4.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(5.1, 34.5)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-5.0,-12.0)');
+INSERT INTO POINT_TBL(f1) VALUES ('(1e-300,-1e-300)');	-- To underflow
+INSERT INTO POINT_TBL(f1) VALUES ('(1e+300,Inf)');		-- To overflow
+INSERT INTO POINT_TBL(f1) VALUES (' ( Nan , NaN ) ');
 -- bad format points
 INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
 ERROR:  invalid input syntax for type point: "asdfasdf"
@@ -17,20 +20,31 @@ INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
 ERROR:  invalid input syntax for type point: "(10.0 10.0)"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
                                           ^
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+ERROR:  invalid input syntax for type point: "(10.0, 10.0) x"
+LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+                                          ^
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
 ERROR:  invalid input syntax for type point: "(10.0,10.0"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
                                           ^
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');	-- Out of range
+ERROR:  "1e+500" is out of range for type double precision
+LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');
+                                          ^
 SELECT '' AS six, * FROM POINT_TBL;
- six |     f1     
------+------------
+ six |        f1         
+-----+-------------------
      | (0,0)
      | (-10,0)
      | (-3,4)
      | (5.1,34.5)
      | (-5,-12)
+     | (1e-300,-1e-300)
+     | (1e+300,Infinity)
+     | (NaN,NaN)
      | (10,10)
-(6 rows)
+(9 rows)
 
 -- left of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE p.f1 << '(0.0, 0.0)';
@@ -92,158 +106,268 @@ SELECT '' AS three, p.* FROM POINT_TBL p
 
 SELECT '' AS three, p.* FROM POINT_TBL p
    WHERE not p.f1 <@ box '(0,0,100,100)';
- three |    f1    
--------+----------
+ three |        f1         
+-------+-------------------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
-(3 rows)
+       | (1e-300,-1e-300)
+       | (1e+300,Infinity)
+       | (NaN,NaN)
+(6 rows)
 
 SELECT '' AS two, p.* FROM POINT_TBL p
    WHERE p.f1 <@ path '[(0,0),(-10,0),(-10,10)]';
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 SELECT '' AS three, p.* FROM POINT_TBL p
    WHERE not box '(0,0,100,100)' @> p.f1;
- three |    f1    
--------+----------
+ three |        f1         
+-------+-------------------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
-(3 rows)
+       | (1e-300,-1e-300)
+       | (1e+300,Infinity)
+       | (NaN,NaN)
+(6 rows)
 
 SELECT '' AS six, p.f1, p.f1 <-> point '(0,0)' AS dist
    FROM POINT_TBL p
    ORDER BY dist;
- six |     f1     |       dist       
------+------------+------------------
-     | (0,0)      |                0
-     | (-3,4)     |                5
-     | (-10,0)    |               10
-     | (-5,-12)   |               13
-     | (10,10)    |  14.142135623731
-     | (5.1,34.5) | 34.8749193547455
-(6 rows)
+ six |        f1         |         dist         
+-----+-------------------+----------------------
+     | (0,0)             |                    0
+     | (1e-300,-1e-300)  | 1.4142135623731e-300
+     | (-3,4)            |                    5
+     | (-10,0)           |                   10
+     | (-5,-12)          |                   13
+     | (10,10)           |      14.142135623731
+     | (5.1,34.5)        |     34.8749193547455
+     | (1e+300,Infinity) |             Infinity
+     | (NaN,NaN)         |                  NaN
+(9 rows)
 
 SELECT '' AS thirtysix, p1.f1 AS point1, p2.f1 AS point2, p1.f1 <-> p2.f1 AS dist
    FROM POINT_TBL p1, POINT_TBL p2
    ORDER BY dist, p1.f1[0], p2.f1[0];
- thirtysix |   point1   |   point2   |       dist       
------------+------------+------------+------------------
-           | (-10,0)    | (-10,0)    |                0
-           | (-5,-12)   | (-5,-12)   |                0
-           | (-3,4)     | (-3,4)     |                0
-           | (0,0)      | (0,0)      |                0
-           | (5.1,34.5) | (5.1,34.5) |                0
-           | (10,10)    | (10,10)    |                0
-           | (-3,4)     | (0,0)      |                5
-           | (0,0)      | (-3,4)     |                5
-           | (-10,0)    | (-3,4)     | 8.06225774829855
-           | (-3,4)     | (-10,0)    | 8.06225774829855
-           | (-10,0)    | (0,0)      |               10
-           | (0,0)      | (-10,0)    |               10
-           | (-10,0)    | (-5,-12)   |               13
-           | (-5,-12)   | (-10,0)    |               13
-           | (-5,-12)   | (0,0)      |               13
-           | (0,0)      | (-5,-12)   |               13
-           | (0,0)      | (10,10)    |  14.142135623731
-           | (10,10)    | (0,0)      |  14.142135623731
-           | (-3,4)     | (10,10)    | 14.3178210632764
-           | (10,10)    | (-3,4)     | 14.3178210632764
-           | (-5,-12)   | (-3,4)     | 16.1245154965971
-           | (-3,4)     | (-5,-12)   | 16.1245154965971
-           | (-10,0)    | (10,10)    | 22.3606797749979
-           | (10,10)    | (-10,0)    | 22.3606797749979
-           | (5.1,34.5) | (10,10)    | 24.9851956166046
-           | (10,10)    | (5.1,34.5) | 24.9851956166046
-           | (-5,-12)   | (10,10)    | 26.6270539113887
-           | (10,10)    | (-5,-12)   | 26.6270539113887
-           | (-3,4)     | (5.1,34.5) | 31.5572495632937
-           | (5.1,34.5) | (-3,4)     | 31.5572495632937
-           | (0,0)      | (5.1,34.5) | 34.8749193547455
-           | (5.1,34.5) | (0,0)      | 34.8749193547455
-           | (-10,0)    | (5.1,34.5) | 37.6597928831267
-           | (5.1,34.5) | (-10,0)    | 37.6597928831267
-           | (-5,-12)   | (5.1,34.5) | 47.5842410888311
-           | (5.1,34.5) | (-5,-12)   | 47.5842410888311
-(36 rows)
+ thirtysix |      point1       |      point2       |         dist         
+-----------+-------------------+-------------------+----------------------
+           | (-10,0)           | (-10,0)           |                    0
+           | (-5,-12)          | (-5,-12)          |                    0
+           | (-3,4)            | (-3,4)            |                    0
+           | (0,0)             | (0,0)             |                    0
+           | (1e-300,-1e-300)  | (1e-300,-1e-300)  |                    0
+           | (5.1,34.5)        | (5.1,34.5)        |                    0
+           | (10,10)           | (10,10)           |                    0
+           | (0,0)             | (1e-300,-1e-300)  | 1.4142135623731e-300
+           | (1e-300,-1e-300)  | (0,0)             | 1.4142135623731e-300
+           | (-3,4)            | (0,0)             |                    5
+           | (-3,4)            | (1e-300,-1e-300)  |                    5
+           | (0,0)             | (-3,4)            |                    5
+           | (1e-300,-1e-300)  | (-3,4)            |                    5
+           | (-10,0)           | (-3,4)            |     8.06225774829855
+           | (-3,4)            | (-10,0)           |     8.06225774829855
+           | (-10,0)           | (0,0)             |                   10
+           | (-10,0)           | (1e-300,-1e-300)  |                   10
+           | (0,0)             | (-10,0)           |                   10
+           | (1e-300,-1e-300)  | (-10,0)           |                   10
+           | (-10,0)           | (-5,-12)          |                   13
+           | (-5,-12)          | (-10,0)           |                   13
+           | (-5,-12)          | (0,0)             |                   13
+           | (-5,-12)          | (1e-300,-1e-300)  |                   13
+           | (0,0)             | (-5,-12)          |                   13
+           | (1e-300,-1e-300)  | (-5,-12)          |                   13
+           | (0,0)             | (10,10)           |      14.142135623731
+           | (1e-300,-1e-300)  | (10,10)           |      14.142135623731
+           | (10,10)           | (0,0)             |      14.142135623731
+           | (10,10)           | (1e-300,-1e-300)  |      14.142135623731
+           | (-3,4)            | (10,10)           |     14.3178210632764
+           | (10,10)           | (-3,4)            |     14.3178210632764
+           | (-5,-12)          | (-3,4)            |     16.1245154965971
+           | (-3,4)            | (-5,-12)          |     16.1245154965971
+           | (-10,0)           | (10,10)           |     22.3606797749979
+           | (10,10)           | (-10,0)           |     22.3606797749979
+           | (5.1,34.5)        | (10,10)           |     24.9851956166046
+           | (10,10)           | (5.1,34.5)        |     24.9851956166046
+           | (-5,-12)          | (10,10)           |     26.6270539113887
+           | (10,10)           | (-5,-12)          |     26.6270539113887
+           | (-3,4)            | (5.1,34.5)        |     31.5572495632937
+           | (5.1,34.5)        | (-3,4)            |     31.5572495632937
+           | (0,0)             | (5.1,34.5)        |     34.8749193547455
+           | (1e-300,-1e-300)  | (5.1,34.5)        |     34.8749193547455
+           | (5.1,34.5)        | (0,0)             |     34.8749193547455
+           | (5.1,34.5)        | (1e-300,-1e-300)  |     34.8749193547455
+           | (-10,0)           | (5.1,34.5)        |     37.6597928831267
+           | (5.1,34.5)        | (-10,0)           |     37.6597928831267
+           | (-5,-12)          | (5.1,34.5)        |     47.5842410888311
+           | (5.1,34.5)        | (-5,-12)          |     47.5842410888311
+           | (-10,0)           | (1e+300,Infinity) |             Infinity
+           | (-5,-12)          | (1e+300,Infinity) |             Infinity
+           | (-3,4)            | (1e+300,Infinity) |             Infinity
+           | (0,0)             | (1e+300,Infinity) |             Infinity
+           | (1e-300,-1e-300)  | (1e+300,Infinity) |             Infinity
+           | (5.1,34.5)        | (1e+300,Infinity) |             Infinity
+           | (10,10)           | (1e+300,Infinity) |             Infinity
+           | (1e+300,Infinity) | (-10,0)           |             Infinity
+           | (1e+300,Infinity) | (-5,-12)          |             Infinity
+           | (1e+300,Infinity) | (-3,4)            |             Infinity
+           | (1e+300,Infinity) | (0,0)             |             Infinity
+           | (1e+300,Infinity) | (1e-300,-1e-300)  |             Infinity
+           | (1e+300,Infinity) | (5.1,34.5)        |             Infinity
+           | (1e+300,Infinity) | (10,10)           |             Infinity
+           | (-10,0)           | (NaN,NaN)         |                  NaN
+           | (-5,-12)          | (NaN,NaN)         |                  NaN
+           | (-3,4)            | (NaN,NaN)         |                  NaN
+           | (0,0)             | (NaN,NaN)         |                  NaN
+           | (1e-300,-1e-300)  | (NaN,NaN)         |                  NaN
+           | (5.1,34.5)        | (NaN,NaN)         |                  NaN
+           | (10,10)           | (NaN,NaN)         |                  NaN
+           | (1e+300,Infinity) | (1e+300,Infinity) |                  NaN
+           | (1e+300,Infinity) | (NaN,NaN)         |                  NaN
+           | (NaN,NaN)         | (-10,0)           |                  NaN
+           | (NaN,NaN)         | (-5,-12)          |                  NaN
+           | (NaN,NaN)         | (-3,4)            |                  NaN
+           | (NaN,NaN)         | (0,0)             |                  NaN
+           | (NaN,NaN)         | (1e-300,-1e-300)  |                  NaN
+           | (NaN,NaN)         | (5.1,34.5)        |                  NaN
+           | (NaN,NaN)         | (10,10)           |                  NaN
+           | (NaN,NaN)         | (1e+300,Infinity) |                  NaN
+           | (NaN,NaN)         | (NaN,NaN)         |                  NaN
+(81 rows)
 
 SELECT '' AS thirty, p1.f1 AS point1, p2.f1 AS point2
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3;
- thirty |   point1   |   point2   
---------+------------+------------
-        | (0,0)      | (-10,0)
-        | (0,0)      | (-3,4)
-        | (0,0)      | (5.1,34.5)
-        | (0,0)      | (-5,-12)
-        | (0,0)      | (10,10)
-        | (-10,0)    | (0,0)
-        | (-10,0)    | (-3,4)
-        | (-10,0)    | (5.1,34.5)
-        | (-10,0)    | (-5,-12)
-        | (-10,0)    | (10,10)
-        | (-3,4)     | (0,0)
-        | (-3,4)     | (-10,0)
-        | (-3,4)     | (5.1,34.5)
-        | (-3,4)     | (-5,-12)
-        | (-3,4)     | (10,10)
-        | (5.1,34.5) | (0,0)
-        | (5.1,34.5) | (-10,0)
-        | (5.1,34.5) | (-3,4)
-        | (5.1,34.5) | (-5,-12)
-        | (5.1,34.5) | (10,10)
-        | (-5,-12)   | (0,0)
-        | (-5,-12)   | (-10,0)
-        | (-5,-12)   | (-3,4)
-        | (-5,-12)   | (5.1,34.5)
-        | (-5,-12)   | (10,10)
-        | (10,10)    | (0,0)
-        | (10,10)    | (-10,0)
-        | (10,10)    | (-3,4)
-        | (10,10)    | (5.1,34.5)
-        | (10,10)    | (-5,-12)
-(30 rows)
+ thirty |      point1       |      point2       
+--------+-------------------+-------------------
+        | (0,0)             | (-10,0)
+        | (0,0)             | (-3,4)
+        | (0,0)             | (5.1,34.5)
+        | (0,0)             | (-5,-12)
+        | (0,0)             | (1e+300,Infinity)
+        | (0,0)             | (NaN,NaN)
+        | (0,0)             | (10,10)
+        | (-10,0)           | (0,0)
+        | (-10,0)           | (-3,4)
+        | (-10,0)           | (5.1,34.5)
+        | (-10,0)           | (-5,-12)
+        | (-10,0)           | (1e-300,-1e-300)
+        | (-10,0)           | (1e+300,Infinity)
+        | (-10,0)           | (NaN,NaN)
+        | (-10,0)           | (10,10)
+        | (-3,4)            | (0,0)
+        | (-3,4)            | (-10,0)
+        | (-3,4)            | (5.1,34.5)
+        | (-3,4)            | (-5,-12)
+        | (-3,4)            | (1e-300,-1e-300)
+        | (-3,4)            | (1e+300,Infinity)
+        | (-3,4)            | (NaN,NaN)
+        | (-3,4)            | (10,10)
+        | (5.1,34.5)        | (0,0)
+        | (5.1,34.5)        | (-10,0)
+        | (5.1,34.5)        | (-3,4)
+        | (5.1,34.5)        | (-5,-12)
+        | (5.1,34.5)        | (1e-300,-1e-300)
+        | (5.1,34.5)        | (1e+300,Infinity)
+        | (5.1,34.5)        | (NaN,NaN)
+        | (5.1,34.5)        | (10,10)
+        | (-5,-12)          | (0,0)
+        | (-5,-12)          | (-10,0)
+        | (-5,-12)          | (-3,4)
+        | (-5,-12)          | (5.1,34.5)
+        | (-5,-12)          | (1e-300,-1e-300)
+        | (-5,-12)          | (1e+300,Infinity)
+        | (-5,-12)          | (NaN,NaN)
+        | (-5,-12)          | (10,10)
+        | (1e-300,-1e-300)  | (-10,0)
+        | (1e-300,-1e-300)  | (-3,4)
+        | (1e-300,-1e-300)  | (5.1,34.5)
+        | (1e-300,-1e-300)  | (-5,-12)
+        | (1e-300,-1e-300)  | (1e+300,Infinity)
+        | (1e-300,-1e-300)  | (NaN,NaN)
+        | (1e-300,-1e-300)  | (10,10)
+        | (1e+300,Infinity) | (0,0)
+        | (1e+300,Infinity) | (-10,0)
+        | (1e+300,Infinity) | (-3,4)
+        | (1e+300,Infinity) | (5.1,34.5)
+        | (1e+300,Infinity) | (-5,-12)
+        | (1e+300,Infinity) | (1e-300,-1e-300)
+        | (1e+300,Infinity) | (1e+300,Infinity)
+        | (1e+300,Infinity) | (NaN,NaN)
+        | (1e+300,Infinity) | (10,10)
+        | (NaN,NaN)         | (0,0)
+        | (NaN,NaN)         | (-10,0)
+        | (NaN,NaN)         | (-3,4)
+        | (NaN,NaN)         | (5.1,34.5)
+        | (NaN,NaN)         | (-5,-12)
+        | (NaN,NaN)         | (1e-300,-1e-300)
+        | (NaN,NaN)         | (1e+300,Infinity)
+        | (NaN,NaN)         | (NaN,NaN)
+        | (NaN,NaN)         | (10,10)
+        | (10,10)           | (0,0)
+        | (10,10)           | (-10,0)
+        | (10,10)           | (-3,4)
+        | (10,10)           | (5.1,34.5)
+        | (10,10)           | (-5,-12)
+        | (10,10)           | (1e-300,-1e-300)
+        | (10,10)           | (1e+300,Infinity)
+        | (10,10)           | (NaN,NaN)
+(72 rows)
 
 -- put distance result into output to allow sorting with GEQ optimizer - tgl 97/05/10
 SELECT '' AS fifteen, p1.f1 AS point1, p2.f1 AS point2, (p1.f1 <-> p2.f1) AS distance
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3 and p1.f1 << p2.f1
    ORDER BY distance, p1.f1[0], p2.f1[0];
- fifteen |   point1   |   point2   |     distance     
----------+------------+------------+------------------
-         | (-3,4)     | (0,0)      |                5
-         | (-10,0)    | (-3,4)     | 8.06225774829855
-         | (-10,0)    | (0,0)      |               10
-         | (-10,0)    | (-5,-12)   |               13
-         | (-5,-12)   | (0,0)      |               13
-         | (0,0)      | (10,10)    |  14.142135623731
-         | (-3,4)     | (10,10)    | 14.3178210632764
-         | (-5,-12)   | (-3,4)     | 16.1245154965971
-         | (-10,0)    | (10,10)    | 22.3606797749979
-         | (5.1,34.5) | (10,10)    | 24.9851956166046
-         | (-5,-12)   | (10,10)    | 26.6270539113887
-         | (-3,4)     | (5.1,34.5) | 31.5572495632937
-         | (0,0)      | (5.1,34.5) | 34.8749193547455
-         | (-10,0)    | (5.1,34.5) | 37.6597928831267
-         | (-5,-12)   | (5.1,34.5) | 47.5842410888311
-(15 rows)
+ fifteen |      point1      |      point2       |     distance     
+---------+------------------+-------------------+------------------
+         | (-3,4)           | (0,0)             |                5
+         | (-3,4)           | (1e-300,-1e-300)  |                5
+         | (-10,0)          | (-3,4)            | 8.06225774829855
+         | (-10,0)          | (0,0)             |               10
+         | (-10,0)          | (1e-300,-1e-300)  |               10
+         | (-10,0)          | (-5,-12)          |               13
+         | (-5,-12)         | (0,0)             |               13
+         | (-5,-12)         | (1e-300,-1e-300)  |               13
+         | (0,0)            | (10,10)           |  14.142135623731
+         | (1e-300,-1e-300) | (10,10)           |  14.142135623731
+         | (-3,4)           | (10,10)           | 14.3178210632764
+         | (-5,-12)         | (-3,4)            | 16.1245154965971
+         | (-10,0)          | (10,10)           | 22.3606797749979
+         | (5.1,34.5)       | (10,10)           | 24.9851956166046
+         | (-5,-12)         | (10,10)           | 26.6270539113887
+         | (-3,4)           | (5.1,34.5)        | 31.5572495632937
+         | (0,0)            | (5.1,34.5)        | 34.8749193547455
+         | (1e-300,-1e-300) | (5.1,34.5)        | 34.8749193547455
+         | (-10,0)          | (5.1,34.5)        | 37.6597928831267
+         | (-5,-12)         | (5.1,34.5)        | 47.5842410888311
+         | (-10,0)          | (1e+300,Infinity) |         Infinity
+         | (-5,-12)         | (1e+300,Infinity) |         Infinity
+         | (-3,4)           | (1e+300,Infinity) |         Infinity
+         | (0,0)            | (1e+300,Infinity) |         Infinity
+         | (1e-300,-1e-300) | (1e+300,Infinity) |         Infinity
+         | (5.1,34.5)       | (1e+300,Infinity) |         Infinity
+         | (10,10)          | (1e+300,Infinity) |         Infinity
+(27 rows)
 
 -- put distance result into output to allow sorting with GEQ optimizer - tgl 97/05/10
 SELECT '' AS three, p1.f1 AS point1, p2.f1 AS point2, (p1.f1 <-> p2.f1) AS distance
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3 and p1.f1 << p2.f1 and p1.f1 >^ p2.f1
    ORDER BY distance;
- three |   point1   |  point2  |     distance     
--------+------------+----------+------------------
-       | (-3,4)     | (0,0)    |                5
-       | (-10,0)    | (-5,-12) |               13
-       | (5.1,34.5) | (10,10)  | 24.9851956166046
-(3 rows)
+ three |   point1   |      point2      |     distance     
+-------+------------+------------------+------------------
+       | (-3,4)     | (0,0)            |                5
+       | (-3,4)     | (1e-300,-1e-300) |                5
+       | (-10,0)    | (-5,-12)         |               13
+       | (5.1,34.5) | (10,10)          | 24.9851956166046
+(4 rows)
 
 -- Test that GiST indexes provide same behavior as sequential scan
 CREATE TEMP TABLE point_gist_tbl(f1 point);
diff --git a/src/test/regress/expected/polygon.out b/src/test/regress/expected/polygon.out
index 4a1f60427a..be5f76bf9d 100644
--- a/src/test/regress/expected/polygon.out
+++ b/src/test/regress/expected/polygon.out
@@ -6,6 +6,9 @@
 CREATE TABLE POLYGON_TBL(f1 polygon);
 INSERT INTO POLYGON_TBL(f1) VALUES ('(2.0,0.0),(2.0,4.0),(0.0,0.0)');
 INSERT INTO POLYGON_TBL(f1) VALUES ('(3.0,1.0),(3.0,3.0),(1.0,0.0)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(3,4),(5,6),(7,8)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(7,8),(5,6),(3,4),(1,2)'); -- Reverse
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(7,8),(5,6),(3,-4)');
 -- degenerate polygons
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,0.0)');
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,1.0),(0.0,1.0)');
@@ -31,201 +34,16 @@ ERROR:  invalid input syntax for type polygon: "asdf"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
                                             ^
 SELECT '' AS four, * FROM POLYGON_TBL;
- four |         f1          
-------+---------------------
+ four |             f1             
+------+----------------------------
       | ((2,0),(2,4),(0,0))
       | ((3,1),(3,3),(1,0))
+      | ((1,2),(3,4),(5,6),(7,8))
+      | ((7,8),(5,6),(3,4),(1,2))
+      | ((1,2),(7,8),(5,6),(3,-4))
       | ((0,0))
       | ((0,1),(0,1))
-(4 rows)
-
--- overlap
-SELECT '' AS three, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 && '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- three |         f1          
--------+---------------------
-       | ((2,0),(2,4),(0,0))
-       | ((3,1),(3,3),(1,0))
-(2 rows)
-
--- left overlap
-SELECT '' AS four, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &< '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- four |         f1          
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
-
--- right overlap
-SELECT '' AS two, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- two |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- left of
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 << '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |      f1       
------+---------------
-     | ((0,0))
-     | ((0,1),(0,1))
-(2 rows)
-
--- right of
-SELECT '' AS zero, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 >> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- zero | f1 
-------+----
-(0 rows)
-
--- contained
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- same
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- contains
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
---
--- polygon logic
---
--- left of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- left overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
- true 
-------
- f
-(1 row)
-
--- right overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' &> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- right of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' >> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- contained in
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- contains
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((0,4),(6,4),(3,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
-SELECT '((1,1),(1,4),(5,4),(5,3),(2,3),(2,2),(5,2),(5,1))'::polygon @> '((3,2),(3,3),(4,3),(4,2))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((0,0),(0,3),(3,3),(3,0))'::polygon @> '((2,1),(2,2),(3,2),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
--- same
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' && polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
- true 
-------
- t
-(1 row)
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon && '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
-SELECT '((1,4),(1,1),(4,1),(4,2),(2,2),(2,4),(1,4))'::polygon && '((3,3),(4,3),(4,4),(3,4),(3,3))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((200,800),(800,800),(800,200),(200,200))' &&  '(1000,1000,0,0)'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
--- distance from a point
-SELECT	'(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
-	'(1,1)'::point <-> '((0,0),(2,2),(1,3))'::polygon as on_segment,
-	'(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;
- on_corner | on_segment | inside |   near_corner   | near_segment 
------------+------------+--------+-----------------+--------------
-         0 |          0 |      0 | 1.4142135623731 |          3.2
-(1 row)
+(7 rows)
 
 --
 -- Test the SP-GiST index
diff --git a/src/test/regress/sql/box.sql b/src/test/regress/sql/box.sql
index 135ac108eb..6710fc90f5 100644
--- a/src/test/regress/sql/box.sql
+++ b/src/test/regress/sql/box.sql
@@ -25,6 +25,9 @@ INSERT INTO BOX_TBL (f1) VALUES ('(2.0,2.0,0.0,0.0)');
 
 INSERT INTO BOX_TBL (f1) VALUES ('(1.0,1.0,3.0,3.0)');
 
+INSERT INTO BOX_TBL (f1) VALUES ('((-8, 2), (-2, -10))');
+
+
 -- degenerate cases where the box is a line or a point
 -- note that lines and points boxes all have zero area
 INSERT INTO BOX_TBL (f1) VALUES ('(2.5, 2.5, 2.5,3.5)');
@@ -34,6 +37,12 @@ INSERT INTO BOX_TBL (f1) VALUES ('(3.0, 3.0,3.0,3.0)');
 -- badly formatted box inputs
 INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
 
+INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+
 INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
 
 
diff --git a/src/test/regress/sql/circle.sql b/src/test/regress/sql/circle.sql
index c0284b2b59..46c96e1400 100644
--- a/src/test/regress/sql/circle.sql
+++ b/src/test/regress/sql/circle.sql
@@ -14,12 +14,20 @@ INSERT INTO CIRCLE_TBL VALUES ('((1,2),3)');
 
 INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10>');
 
-INSERT INTO CIRCLE_TBL VALUES ('<(100,1),115>');
+INSERT INTO CIRCLE_TBL VALUES (' < ( 100 , 1 ) , 115 > ');
+
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),0>');	-- Zero radius
+
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),NaN>');	-- NaN radius
 
 -- bad values
 
 INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
 
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+
 INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
 
 INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
diff --git a/src/test/regress/sql/geometry.sql b/src/test/regress/sql/geometry.sql
index 1429ee772a..ce98b3e90c 100644
--- a/src/test/regress/sql/geometry.sql
+++ b/src/test/regress/sql/geometry.sql
@@ -46,6 +46,103 @@ SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?| point '(5.1,34.5)';
 
+-- Slope
+SELECT p1.f1, p2.f1, slope(p1.f1, p2.f1) FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Add point
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Subtract point
+SELECT p1.f1, p2.f1, p1.f1 - p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Multiply with point
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+
+-- Underflow error
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] < 1;
+
+-- Divide by point
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] BETWEEN 1 AND 1000;
+
+-- Overflow error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] > 1000;
+
+-- Division by 0 error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1 ~= '(0,0)'::point;
+
+-- Distance to line
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LINE_TBL l;
+
+-- Distance to line segment
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LSEG_TBL l;
+
+-- Distance to box
+SELECT p.f1, b.f1, p.f1 <-> b.f1 FROM POINT_TBL p, BOX_TBL b;
+
+-- Distance to path
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, PATH_TBL p1;
+
+-- Distance to polygon
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, POLYGON_TBL p1;
+
+-- Closest point to line
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LINE_TBL l;
+
+-- Closest point to line segment
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LSEG_TBL l;
+
+-- Closest point to box
+SELECT p.f1, b.f1, p.f1 ## b.f1 FROM POINT_TBL p, BOX_TBL b;
+
+-- On line
+SELECT p.f1, l.s FROM POINT_TBL p, LINE_TBL l WHERE p.f1 <@ l.s;
+
+-- On line segment
+SELECT p.f1, l.s FROM POINT_TBL p, LSEG_TBL l WHERE p.f1 <@ l.s;
+
+-- On path
+SELECT p.f1, p1.f1 FROM POINT_TBL p, PATH_TBL p1 WHERE p.f1 <@ p1.f1;
+
+--
+-- Lines
+--
+
+-- Vertical
+SELECT s FROM LINE_TBL WHERE ?| s;
+
+-- Horizontal
+SELECT s FROM LINE_TBL WHERE ?- s;
+
+-- Same as line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s = l2.s;
+
+-- Parallel to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?|| l2.s;
+
+-- Perpendicular to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?-| l2.s;
+
+-- Distance to line
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2;
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LINE_TBL l, BOX_TBL b;
+
+-- Intersect with line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?# l2.s;
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LINE_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+
+-- Intersection point with line
+SELECT l1.s, l2.s, l1.s # l2.s FROM LINE_TBL l1, LINE_TBL l2;
+
+-- Closest point to line segment
+SELECT l.s, l1.s, l.s ## l1.s FROM LINE_TBL l, LSEG_TBL l1;
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LINE_TBL l, BOX_TBL b;
+
 --
 -- Line segments
 --
@@ -54,9 +151,77 @@ SELECT '' AS one, p1.f1
 SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
    FROM LSEG_TBL l, POINT_TBL p;
 
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
+-- Length
+SELECT s, @-@ s FROM LSEG_TBL;
+
+-- Vertical
+SELECT s FROM LSEG_TBL WHERE ?| s;
+
+-- Horizontal
+SELECT s FROM LSEG_TBL WHERE ?- s;
+
+-- Center
+SELECT s, @@ s FROM LSEG_TBL;
+
+-- To point
+SELECT s, s::point FROM LSEG_TBL;
+
+-- Has points less than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s < l2.s;
+
+-- Has points less than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s <= l2.s;
+
+-- Has points equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s = l2.s;
+
+-- Has points greater than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s >= l2.s;
+
+-- Has points greater than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s > l2.s;
+
+-- Has points not equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s != l2.s;
+
+-- Parallel with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?|| l2.s;
+
+-- Perpendicular with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?-| l2.s;
+
+-- Distance to line
+SELECT l.s, l1.s, l.s <-> l1.s FROM LSEG_TBL l, LINE_TBL l1;
+
+-- Distance to line segment
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LSEG_TBL l, BOX_TBL b;
+
+-- Intersect with line segment
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s ?# l1.s;
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+
+-- Intersection point with line segment
+SELECT l1.s, l2.s, l1.s # l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Closest point to line
+SELECT l.s, l1.s, l.s ## l1.s FROM LSEG_TBL l, LINE_TBL l1;
+
+-- Closest point to line segment
+SELECT l1.s, l2.s, l1.s ## l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LSEG_TBL l, BOX_TBL b;
+
+-- On line
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s <@ l1.s;
+
+-- On box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s <@ b.f1;
 
 --
 -- Boxes
@@ -71,35 +236,94 @@ SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
 SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
 
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
+-- Multiply with point
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+
+-- Overflow error
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] > 1000;
 
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
+-- Divide by point
+SELECT b.f1, p.f1, b.f1 / p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
 
+-- To box
 SELECT f1::box
 	FROM POINT_TBL;
 
 SELECT bound_box(a.f1, b.f1)
 	FROM BOX_TBL a, BOX_TBL b;
 
+-- Below box
+SELECT b1.f1, b2.f1, b1.f1 <^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Above box
+SELECT b1.f1, b2.f1, b1.f1 >^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Intersection point with box
+SELECT b1.f1, b2.f1, b1.f1 # b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Diagonal
+SELECT f1, diagonal(f1) FROM BOX_TBL;
+
+-- Distance to box
+SELECT b1.f1, b2.f1, b1.f1 <-> b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
 --
 -- Paths
 --
 
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
+-- Points
+SELECT f1, npoints(f1) FROM PATH_TBL;
+
+-- Area
+SELECT f1, area(f1) FROM PATH_TBL;
 
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
+-- Length
+SELECT f1, @-@ f1 FROM PATH_TBL;
 
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
+-- Center
+SELECT f1, @@ f1 FROM PATH_TBL;
+
+-- To polygon
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isclosed(f1);
+
+-- Open path cannot be converted to polygon error
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isopen(f1);
+
+-- Has points less than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 < p2.f1;
+
+-- Has points less than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 <= p2.f1;
+
+-- Has points equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 = p2.f1;
+
+-- Has points greater than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 >= p2.f1;
+
+-- Has points greater than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 > p2.f1;
+
+-- Add path
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+
+-- Add point
+SELECT p.f1, p1.f1, p.f1 + p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+
+-- Subtract point
+SELECT p.f1, p1.f1, p.f1 - p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+
+-- Multiply with point
+SELECT p.f1, p1.f1, p.f1 * p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+
+-- Divide by point
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1[0] BETWEEN 1 AND 1000;
 
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
+-- Division by 0 error
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1 ~= '(0,0)'::point;
+
+-- Distance to path
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
 
 --
 -- Polygons
@@ -125,13 +349,50 @@ SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
    FROM PATH_TBL
    WHERE isopen(f1);
 
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
+-- To box
+SELECT f1, f1::box FROM POLYGON_TBL;
 
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
+-- To path
+SELECT f1, f1::path FROM POLYGON_TBL;
+
+-- Same as polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 ~= p2.f1;
+
+-- Contained by polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <@ p2.f1;
+
+-- Contains polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 @> p2.f1;
+
+-- Overlap with polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 && p2.f1;
+
+-- Left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 << p2.f1;
+
+-- Overlap of left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &< p2.f1;
+
+-- Right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 >> p2.f1;
+
+-- Overlap of right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &> p2.f1;
+
+-- Below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <<| p2.f1;
+
+-- Overlap or below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &<| p2.f1;
+
+-- Above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |>> p2.f1;
+
+-- Overlap or above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |&> p2.f1;
+
+-- Distance to polygon
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2;
 
 --
 -- Circles
@@ -151,3 +412,96 @@ SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS d
    FROM CIRCLE_TBL c1, POINT_TBL p1
    WHERE (p1.f1 <-> c1.f1) > 0
    ORDER BY distance, area(c1.f1), p1.f1[0];
+
+-- To polygon
+SELECT f1, f1::polygon FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+
+-- To polygon with less points
+SELECT f1, polygon(8, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+
+-- Too less points error
+SELECT f1, polygon(1, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+
+-- Zero radius error
+SELECT f1, polygon(10, f1) FROM CIRCLE_TBL WHERE f1 < '<(0,0),1>';
+
+-- Same as circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 ~= c2.f1;
+
+-- Overlap with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 && c2.f1;
+
+-- Overlap or left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &< c2.f1;
+
+-- Left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 << c2.f1;
+
+-- Right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >> c2.f1;
+
+-- Overlap or right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &> c2.f1;
+
+-- Contained by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <@ c2.f1;
+
+-- Contain by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 @> c2.f1;
+
+-- Below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <<| c2.f1;
+
+-- Above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |>> c2.f1;
+
+-- Overlap or below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &<| c2.f1;
+
+-- Overlap or above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |&> c2.f1;
+
+-- Area equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 = c2.f1;
+
+-- Area not equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 != c2.f1;
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 > c2.f1;
+
+-- Area less than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <= c2.f1;
+
+-- Area greater than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >= c2.f1;
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+
+-- Add point
+SELECT c.f1, p.f1, c.f1 + p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Subtract point
+SELECT c.f1, p.f1, c.f1 - p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Multiply with point
+SELECT c.f1, p.f1, c.f1 * p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Divide by point
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+
+-- Overflow error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] > 1000;
+
+-- Division by 0 error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1 ~= '(0,0)'::point;
+
+-- Distance to polygon
+SELECT c.f1, p.f1, c.f1 <-> p.f1 FROM CIRCLE_TBL c, POLYGON_TBL p;
diff --git a/src/test/regress/sql/line.sql b/src/test/regress/sql/line.sql
index 94067b0cee..f589ffecc8 100644
--- a/src/test/regress/sql/line.sql
+++ b/src/test/regress/sql/line.sql
@@ -6,82 +6,37 @@
 --DROP TABLE LINE_TBL;
 CREATE TABLE LINE_TBL (s line);
 
-INSERT INTO LINE_TBL VALUES ('{1,-1,1}');
-INSERT INTO LINE_TBL VALUES ('(0,0),(6,6)');
+INSERT INTO LINE_TBL VALUES ('{0,-1,5}');	-- A == 0
+INSERT INTO LINE_TBL VALUES ('{1,0,5}');	-- B == 0
+INSERT INTO LINE_TBL VALUES ('{0,3,0}');	-- A == C == 0
+INSERT INTO LINE_TBL VALUES (' (0,0), (6,6)');
 INSERT INTO LINE_TBL VALUES ('10,-10 ,-5,-4');
 INSERT INTO LINE_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LINE_TBL VALUES ('(11,22,33,44)');
 
-INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
+INSERT INTO LINE_TBL VALUES ('{3,NaN,5}');
+INSERT INTO LINE_TBL VALUES ('{NaN,NaN,NaN}');
 
 -- horizontal
 INSERT INTO LINE_TBL VALUES ('[(1,3),(2,3)]');
 -- vertical
-INSERT INTO LINE_TBL VALUES ('[(3,1),(3,2)]');
+INSERT INTO LINE_TBL VALUES (line(point '(3,1)', point '(3,2)'));
 
 -- bad values for parser testing
+INSERT INTO LINE_TBL VALUES ('{}');
+INSERT INTO LINE_TBL VALUES ('{0');
+INSERT INTO LINE_TBL VALUES ('{0,0}');
+INSERT INTO LINE_TBL VALUES ('{0,0,1');
 INSERT INTO LINE_TBL VALUES ('{0,0,1}');
+INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
 INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
 INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
 INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
 INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
+INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
 
-select * from LINE_TBL;
-
-
--- functions and operators
-
-SELECT * FROM LINE_TBL WHERE (s <-> line '[(1,2),(3,4)]') < 10;
-
-SELECT * FROM LINE_TBL WHERE (point '(0.1,0.1)' <-> s) < 1;
-
-SELECT * FROM LINE_TBL WHERE (lseg '[(0.1,0.1),(0.2,0.2)]' <-> s) < 1;
-
-SELECT line '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
-SELECT lseg '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
-SELECT point '(-1,1)' <-> line '[(-3,0),(-4,0)]';
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(2,0),(0,2)]';  -- true
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(0,0),(1,0)]';  -- false
-
-SELECT line '[(0,0),(1,1)]' ?# box '(0,0,2,2)';  -- true
-SELECT line '[(3,0),(4,1)]' ?# box '(0,0,2,2)';  -- false
-
-SELECT point '(1,1)' <@ line '[(0,0),(2,2)]';  -- true
-SELECT point '(1,1)' <@ line '[(0,0),(1,0)]';  -- false
-
-SELECT point '(1,1)' @ line '[(0,0),(2,2)]';  -- true
-SELECT point '(1,1)' @ line '[(0,0),(1,0)]';  -- false
+INSERT INTO LINE_TBL VALUES (line(point '(1,0)', point '(1,0)'));
 
-SELECT lseg '[(1,1),(2,2)]' <@ line '[(0,0),(2,2)]';  -- true
-SELECT lseg '[(1,1),(2,1)]' <@ line '[(0,0),(1,0)]';  -- false
-
-SELECT lseg '[(1,1),(2,2)]' @ line '[(0,0),(2,2)]';  -- true
-SELECT lseg '[(1,1),(2,1)]' @ line '[(0,0),(1,0)]';  -- false
-
-SELECT point '(0,1)' ## line '[(0,0),(1,1)]';
-
-SELECT line '[(0,0),(1,1)]' ## lseg '[(1,0),(2,0)]';
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(2,1)]';  -- false
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(1,1)]';  -- true
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(2,1)]';
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(1,1)]';
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(2,1)]';  -- true
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(1,1)]';  -- false
-
-SELECT line '[(0,0),(1,0)]' ?-| line '[(0,0),(0,1)]';  -- true
-SELECT line '[(0,0),(1,1)]' ?-| line '[(1,0),(1,1)]';  -- false
-
-SELECT ?- line '[(0,0),(1,0)]';  -- true
-SELECT ?- line '[(0,0),(1,1)]';  -- false
-
-SELECT ?| line '[(0,0),(0,1)]';  -- true
-SELECT ?| line '[(0,0),(1,1)]';  -- false
-
-SELECT line(point '(1,2)', point '(3,4)');
+select * from LINE_TBL;
 
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,5)]';  -- true
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,4)]';  -- false
+select '{nan, 1, nan}'::line = '{nan, 1, nan}'::line as true,
+	   '{nan, 1, nan}'::line = '{nan, 2, nan}'::line as false;
diff --git a/src/test/regress/sql/lseg.sql b/src/test/regress/sql/lseg.sql
index 07c5a29e0a..f266ca3e09 100644
--- a/src/test/regress/sql/lseg.sql
+++ b/src/test/regress/sql/lseg.sql
@@ -10,7 +10,10 @@ INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('(0,0),(6,6)');
 INSERT INTO LSEG_TBL VALUES ('10,-10 ,-3,-4');
 INSERT INTO LSEG_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LSEG_TBL VALUES ('(11,22,33,44)');
+INSERT INTO LSEG_TBL VALUES (lseg(point(11, 22), point(33,44)));
+INSERT INTO LSEG_TBL VALUES ('[(-10,2),(-10,3)]');	-- vertical
+INSERT INTO LSEG_TBL VALUES ('[(0,-20),(30,-20)]');	-- horizontal
+INSERT INTO LSEG_TBL VALUES ('[(NaN,1),(NaN,90)]');	-- NaN
 
 -- bad values for parser testing
 INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
@@ -19,7 +22,3 @@ INSERT INTO LSEG_TBL VALUES ('[(,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)');
 
 select * from LSEG_TBL;
-
-SELECT * FROM LSEG_TBL WHERE s <= lseg '[(1,2),(3,4)]';
-
-SELECT * FROM LSEG_TBL WHERE (s <-> lseg '[(1,2),(3,4)]') < 10;
diff --git a/src/test/regress/sql/path.sql b/src/test/regress/sql/path.sql
index 7e69b539ad..318decf974 100644
--- a/src/test/regress/sql/path.sql
+++ b/src/test/regress/sql/path.sql
@@ -8,26 +8,32 @@ CREATE TABLE PATH_TBL (f1 path);
 
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)]');
 
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
+INSERT INTO PATH_TBL VALUES (' ( ( 1 , 2 ) , ( 3 , 4 ) ) ');
 
-INSERT INTO PATH_TBL VALUES ('[(0,0),(3,0),(4,5),(1,6)]');
+INSERT INTO PATH_TBL VALUES ('[ (0,0),(3,0),(4,5),(1,6) ]');
 
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
+INSERT INTO PATH_TBL VALUES ('((1,2) ,(3,4 ))');
 
-INSERT INTO PATH_TBL VALUES ('1,2 ,3,4');
+INSERT INTO PATH_TBL VALUES ('1,2 ,3,4 ');
 
-INSERT INTO PATH_TBL VALUES ('[1,2,3, 4]');
+INSERT INTO PATH_TBL VALUES (' [1,2,3, 4] ');
 
-INSERT INTO PATH_TBL VALUES ('[11,12,13,14]');
+INSERT INTO PATH_TBL VALUES ('((10,20))');	-- Only one point
 
-INSERT INTO PATH_TBL VALUES ('(11,12,13,14)');
+INSERT INTO PATH_TBL VALUES ('[ 11,12,13,14 ]');
+
+INSERT INTO PATH_TBL VALUES ('( 11,12,13,14) ');
 
 -- bad values for parser testing
+INSERT INTO PATH_TBL VALUES ('[]');
+
 INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
 
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
 
-SELECT f1 FROM PATH_TBL;
+INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+
+INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
 
 SELECT '' AS count, f1 AS open_path FROM PATH_TBL WHERE isopen(f1);
 
diff --git a/src/test/regress/sql/point.sql b/src/test/regress/sql/point.sql
index 63a803a809..a209f3bfeb 100644
--- a/src/test/regress/sql/point.sql
+++ b/src/test/regress/sql/point.sql
@@ -14,6 +14,12 @@ INSERT INTO POINT_TBL(f1) VALUES ('(5.1, 34.5)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-5.0,-12.0)');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(1e-300,-1e-300)');	-- To underflow
+
+INSERT INTO POINT_TBL(f1) VALUES ('(1e+300,Inf)');		-- To overflow
+
+INSERT INTO POINT_TBL(f1) VALUES (' ( Nan , NaN ) ');
+
 -- bad format points
 INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
 
@@ -21,8 +27,12 @@ INSERT INTO POINT_TBL(f1) VALUES ('10.0,10.0');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');	-- Out of range
+
 
 SELECT '' AS six, * FROM POINT_TBL;
 
diff --git a/src/test/regress/sql/polygon.sql b/src/test/regress/sql/polygon.sql
index 7e8cb08cd8..d3d2fe3457 100644
--- a/src/test/regress/sql/polygon.sql
+++ b/src/test/regress/sql/polygon.sql
@@ -11,6 +11,10 @@ INSERT INTO POLYGON_TBL(f1) VALUES ('(2.0,0.0),(2.0,4.0),(0.0,0.0)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(3.0,1.0),(3.0,3.0),(1.0,0.0)');
 
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(3,4),(5,6),(7,8)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(7,8),(5,6),(3,4),(1,2)'); -- Reverse
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(7,8),(5,6),(3,-4)');
+
 -- degenerate polygons
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,0.0)');
 
@@ -30,93 +34,6 @@ INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
 
 SELECT '' AS four, * FROM POLYGON_TBL;
 
--- overlap
-SELECT '' AS three, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 && '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- left overlap
-SELECT '' AS four, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &< '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- right overlap
-SELECT '' AS two, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- left of
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 << '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- right of
-SELECT '' AS zero, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 >> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- contained
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- same
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- contains
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
---
--- polygon logic
---
--- left of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- left overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
-
--- right overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' &> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- right of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' >> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- contained in
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- contains
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "false";
-
-SELECT '((0,4),(6,4),(3,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
-
-SELECT '((1,1),(1,4),(5,4),(5,3),(2,3),(2,2),(5,2),(5,1))'::polygon @> '((3,2),(3,3),(4,3),(4,2))'::polygon AS "false";
-
-SELECT '((0,0),(0,3),(3,3),(3,0))'::polygon @> '((2,1),(2,2),(3,2),(3,1))'::polygon AS "true";
-
--- same
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' && polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon && '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
-
-SELECT '((1,4),(1,1),(4,1),(4,2),(2,2),(2,4),(1,4))'::polygon && '((3,3),(4,3),(4,4),(3,4),(3,3))'::polygon AS "false";
-SELECT '((200,800),(800,800),(800,200),(200,200))' &&  '(1000,1000,0,0)'::polygon AS "true";
-
--- distance from a point
-SELECT	'(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
-	'(1,1)'::point <-> '((0,0),(2,2),(1,3))'::polygon as on_segment,
-	'(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
 --
-- 
2.13.6

0005-Check-for-float-0-after-multiplications-and-division.patchtext/x-patch; name=0005-Check-for-float-0-after-multiplications-and-division.patchDownload
From edc8d6fa7cd9e552fc4d33f732af0ee22764e086 Mon Sep 17 00:00:00 2001
From: Tomas Vondra <tomas@2ndquadrant.com>
Date: Thu, 26 Jul 2018 16:16:38 +0200
Subject: [PATCH 5/6] Check for float -0 after multiplications and divisions

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com
---
 src/include/utils/float.h | 26 ++++++++++++++++++++------
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/src/include/utils/float.h b/src/include/utils/float.h
index 0e8483c930..e359d8a3d4 100644
--- a/src/include/utils/float.h
+++ b/src/include/utils/float.h
@@ -216,11 +216,14 @@ float8_mi(const float8 val1, const float8 val2)
 static inline float4
 float4_mul(const float4 val1, const float4 val2)
 {
+	const bool	zero_is_valid = val1 == 0.0f || val2 == 0.0f;
 	float4		result;
 
 	result = val1 * val2;
-	check_float4_val(result, isinf(val1) || isinf(val2),
-					 val1 == 0.0f || val2 == 0.0f);
+	check_float4_val(result, isinf(val1) || isinf(val2), zero_is_valid);
+
+	if (zero_is_valid && unlikely(result == -0.0f))
+		result = 0.0f;
 
 	return result;
 }
@@ -228,11 +231,14 @@ float4_mul(const float4 val1, const float4 val2)
 static inline float8
 float8_mul(const float8 val1, const float8 val2)
 {
+	const bool	zero_is_valid = val1 == 0.0 || val2 == 0.0;
 	float8		result;
 
 	result = val1 * val2;
-	check_float8_val(result, isinf(val1) || isinf(val2),
-					 val1 == 0.0 || val2 == 0.0);
+	check_float8_val(result, isinf(val1) || isinf(val2), zero_is_valid);
+
+	if (zero_is_valid && unlikely(result == -0.0))
+		result = 0.0;
 
 	return result;
 }
@@ -240,6 +246,7 @@ float8_mul(const float8 val1, const float8 val2)
 static inline float4
 float4_div(const float4 val1, const float4 val2)
 {
+	const bool	zero_is_valid = val1 == 0.0f;
 	float4		result;
 
 	if (val2 == 0.0f)
@@ -248,7 +255,10 @@ float4_div(const float4 val1, const float4 val2)
 				 errmsg("division by zero")));
 
 	result = val1 / val2;
-	check_float4_val(result, isinf(val1) || isinf(val2), val1 == 0.0f);
+	check_float4_val(result, isinf(val1) || isinf(val2), zero_is_valid);
+
+	if (zero_is_valid && unlikely(result == -0.0f))
+		result = 0.0f;
 
 	return result;
 }
@@ -256,6 +266,7 @@ float4_div(const float4 val1, const float4 val2)
 static inline float8
 float8_div(const float8 val1, const float8 val2)
 {
+	const bool	zero_is_valid = val1 == 0.0;
 	float8		result;
 
 	if (val2 == 0.0)
@@ -264,7 +275,10 @@ float8_div(const float8 val1, const float8 val2)
 				 errmsg("division by zero")));
 
 	result = val1 / val2;
-	check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
+	check_float8_val(result, isinf(val1) || isinf(val2), zero_is_valid);
+
+	if (zero_is_valid && unlikely(result == -0.0))
+		result = 0.0;
 
 	return result;
 }
-- 
2.13.6

0004-Fix-obvious-problems-around-the-line-datatype.patchtext/x-patch; name=0004-Fix-obvious-problems-around-the-line-datatype.patchDownload
From 5e5e5bcabe37d5ed5951169b04422c0fa724c81f Mon Sep 17 00:00:00 2001
From: Tomas Vondra <tomas@2ndquadrant.com>
Date: Thu, 26 Jul 2018 15:43:00 +0200
Subject: [PATCH 4/6] Fix obvious problems around the line datatype

I have noticed some line operators retuning wrong results, and Tom Lane
spotted similar problems on more places.  Source history reveals that
during 1990s, the internal format of the line datatype is changed, but
most functions haven't got the hint.  The fixes include:

* Reject invalid specification A=B=0 on receive
* Reject same points on line_construct_pp()
* Fix perpendicular operator when negative values are involved
* Avoid division by zero on perpendicular operator
* Fix intersection and distance operators when neither A nor B are 1
* Return NULL for closest point when objects are parallel
* Check whether closest point of line segments is the intersection point
* Fix closest point of line segments being on the wrong segment

The changes are also aiming make line operators more symmetric and less
sensitive to floating point precision loss.  The EPSILON interferes with
every minor change in different ways.  It is hard to guess which
behaviour is more expected, but we can assume threating both sides of
the operators more equally is more expected.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com

Parallel discussions:

* https://www.postgresql.org/message-id/CAE2gYzw_-z%3DV2kh8QqFjenu%3D8MJXzOP44wRW%3DAzzeamrmTT1%3DQ%40mail.gmail.com
* https://www.postgresql.org/message-id/20180201.205138.34583581.horiguchi.kyotaro@lab.ntt.co.jp
---
 src/backend/utils/adt/geo_ops.c | 153 +++++++++++++++++++++++++++-------------
 1 file changed, 103 insertions(+), 50 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 314e442f2e..a72a9a28c9 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -48,6 +48,7 @@ static int	point_inside(Point *p, int npts, Point *plist);
 
 /* Routines for lines */
 static inline void line_construct(LINE *result, Point *pt, float8 m);
+static inline float8 line_sl(LINE *line);
 static inline float8 line_invsl(LINE *line);
 static bool	line_interpt_line(Point *result, LINE *l1, LINE *l2);
 static bool line_contain_point(LINE *line, Point *point);
@@ -980,6 +981,11 @@ line_recv(PG_FUNCTION_ARGS)
 	line->B = pq_getmsgfloat8(buf);
 	line->C = pq_getmsgfloat8(buf);
 
+	if (FPzero(line->A) && FPzero(line->B))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("invalid line specification: A and B cannot both be zero")));
+
 	PG_RETURN_LINE_P(line);
 }
 
@@ -1037,6 +1043,11 @@ line_construct_pp(PG_FUNCTION_ARGS)
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 	LINE	   *result = (LINE *) palloc(sizeof(LINE));
 
+	if (point_eq_point(pt1, pt2))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("invalid line specification: must be two distinct points")));
+
 	line_construct(result, pt1, point_sl(pt1, pt2));
 
 	PG_RETURN_LINE_P(result);
@@ -1073,11 +1084,15 @@ line_perp(PG_FUNCTION_ARGS)
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
-	else if (FPzero(l1->B))
+	if (FPzero(l2->A))
+		PG_RETURN_BOOL(FPzero(l1->B));
+	if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
+	if (FPzero(l2->B))
+		PG_RETURN_BOOL(FPzero(l1->A));
 
-	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
-								   float8_mul(l1->B, l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->A),
+								   float8_mul(l1->B, l2->B)), -1.0));
 }
 
 Datum
@@ -1133,6 +1148,20 @@ line_eq(PG_FUNCTION_ARGS)
  *---------------------------------------------------------*/
 
 /*
+ * Return slope of the line
+ */
+static inline float8
+line_sl(LINE *line)
+{
+	if (FPzero(line->A))
+		return 0.0;
+	if (FPzero(line->B))
+		return DBL_MAX;
+	return float8_div(line->A, -line->B);
+}
+
+
+/*
  * Return inverse slope of the line
  */
 static inline float8
@@ -1154,16 +1183,21 @@ line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	float8		result;
-	Point		tmp;
+	float8		ratio;
 
 	if (line_interpt_line(NULL, l1, l2))	/* intersecting? */
 		PG_RETURN_FLOAT8(0.0);
-	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
-	point_construct(&tmp, 0.0, l1->C);
-	result = line_closept_point(NULL, l2, &tmp);
-	PG_RETURN_FLOAT8(result);
+
+	if (!FPzero(l1->A) && !isnan(l1->A) && !FPzero(l2->A) && !isnan(l2->A))
+		ratio = float8_div(l1->A, l2->A);
+	else if (!FPzero(l1->B) && !isnan(l1->B) && !FPzero(l2->B) && !isnan(l2->B))
+		ratio = float8_div(l1->B, l2->B);
+	else
+		ratio = 1.0;
+
+	PG_RETURN_FLOAT8(float8_div(fabs(float8_mi(l1->C,
+											   float8_mul(ratio, l2->C))),
+								HYPOT(l1->A, l1->B)));
 }
 
 /* line_interpt()
@@ -1204,27 +1238,30 @@ line_interpt_line(Point *result, LINE *l1, LINE *l2)
 	float8		x,
 				y;
 
-	if (FPzero(l1->B))			/* l1 vertical? */
+	if (!FPzero(l1->B))
 	{
-		if (FPzero(l2->B))		/* l2 vertical? */
+		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
 			return false;
 
-		x = l1->C;
-		y = float8_pl(float8_mul(l2->A, x), l2->C);
-	}
-	else if (FPzero(l2->B))		/* l2 vertical? */
-	{
-		x = l2->C;
-		y = float8_pl(float8_mul(l1->A, x), l1->C);
+		x = float8_div(float8_mi(float8_mul(l1->B, l2->C),
+								 float8_mul(l2->B, l1->C)),
+					   float8_mi(float8_mul(l1->A, l2->B),
+								 float8_mul(l2->A, l1->B)));
+		y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
 	}
-	else
+	else if (!FPzero(l2->B))
 	{
-		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
+		if (FPeq(l1->A, float8_mul(l2->A, float8_div(l1->B, l2->B))))
 			return false;
 
-		x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
-		y = float8_pl(float8_mul(l1->A, x), l1->C);
+		x = float8_div(float8_mi(float8_mul(l2->B, l1->C),
+								 float8_mul(l1->B, l2->C)),
+					   float8_mi(float8_mul(l2->A, l1->B),
+								 float8_mul(l1->A, l2->B)));
+		y = float8_div(-float8_pl(float8_mul(l2->A, x), l2->C), l2->B);
 	}
+	else
+		return false;
 
 	if (result != NULL)
 		point_construct(result, x, y);
@@ -2344,16 +2381,8 @@ dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
-	float8		result;
-
-	if (lseg_interpt_line(NULL, lseg, line))
-		result = 0.0;
-	else
-		/* XXX shouldn't we take the min not max? */
-		result = float8_max(line_closept_point(NULL, line, &lseg->p[0]),
-							line_closept_point(NULL, line, &lseg->p[1]));
 
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(lseg_closept_line(NULL, lseg, line));
 }
 
 /*
@@ -2541,19 +2570,26 @@ lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
 static float8
 line_closept_point(Point *result, LINE *line, Point *point)
 {
-	bool		retval;
-	Point       closept;
+	Point		closept;
 	LINE		tmp;
 
-	/* We drop a perpendicular to find the intersection point. */
+	/*
+	 * We drop a perpendicular to find the intersection point.  Ordinarily
+	 * we should always find it, but that can fail in the presence of NaN
+	 * coordinates, and perhaps even from simple roundoff issues.
+	 */
 	line_construct(&tmp, point, line_invsl(line));
-	retval = line_interpt_line(&closept, line, &tmp);
-	Assert(retval);		/* XXX: We need something better. */
+	if (!line_interpt_line(&closept, &tmp, line))
+	{
+		if (result != NULL)
+			*result = *point;
+
+		return get_float8_nan();
+	}
 
 	if (result != NULL)
 		*result = closept;
 
-	/* Then we calculate the distance between the points. */
 	return point_dt(&closept, point);
 }
 
@@ -2627,27 +2663,38 @@ lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
 	float8		dist,
 				d;
 
-	d = lseg_closept_point(NULL, l1, &l2->p[0]);
-	dist = d;
-	if (result != NULL)
-		*result = l2->p[0];
+	/* First, we handle the case when the line segments are intersecting. */
+	if (lseg_interpt_lseg(result, l1, l2))
+		return 0.0;
 
-	d = lseg_closept_point(NULL, l1, &l2->p[1]);
+	/*
+	 * Then, we find the closest points from the endpoints of the second
+	 * line segment, and keep the closest one.
+	 */
+	dist = lseg_closept_point(result, l1, &l2->p[0]);
+	d = lseg_closept_point(&point, l1, &l2->p[1]);
 	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
-			*result = l2->p[1];
+			*result = point;
 	}
 
-	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[0]), dist))
-		d = lseg_closept_point(result, l1, &point);
-
-	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[1]), dist))
-		d = lseg_closept_point(result, l1, &point);
-
+	/* The closest point can still be one of the endpoints, so we test them. */
+	d = lseg_closept_point(NULL, l2, &l1->p[0]);
+	if (float8_lt(d, dist))
+	{
+		dist = d;
+		if (result != NULL)
+			*result = l1->p[0];
+	}
+	d = lseg_closept_point(NULL, l2, &l1->p[1]);
 	if (float8_lt(d, dist))
+	{
 		dist = d;
+		if (result != NULL)
+			*result = l1->p[1];
+	}
 
 	return dist;
 }
@@ -2659,6 +2706,9 @@ close_lseg(PG_FUNCTION_ARGS)
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
+	if (lseg_sl(l1) == lseg_sl(l2))
+		PG_RETURN_NULL();
+
 	result = (Point *) palloc(sizeof(Point));
 
 	if (isnan(lseg_closept_lseg(result, l2, l1)))
@@ -2833,6 +2883,9 @@ close_ls(PG_FUNCTION_ARGS)
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
+	if (lseg_sl(lseg) == line_sl(line))
+		PG_RETURN_NULL();
+
 	result = (Point *) palloc(sizeof(Point));
 
 	if (isnan(lseg_closept_line(result, lseg, line)))
-- 
2.13.6

0003-Use-the-built-in-float-datatype-to-implement-geometr.patchtext/x-patch; name=0003-Use-the-built-in-float-datatype-to-implement-geometr.patchDownload
From 20c1d6645eff82fc54cfb905795044f59ab7916c Mon Sep 17 00:00:00 2001
From: Tomas Vondra <tomas@2ndquadrant.com>
Date: Thu, 26 Jul 2018 15:14:36 +0200
Subject: [PATCH 3/6] Use the built-in float datatype to implement geometric
 types

This patch makes the geometric operators and functions use the exported
function of the float datatype.  The main reason of doing so is to check
for underflow and overflow, and to handle NaNs consciously.

The float datatypes consider NaNs to be equal and greater than any
non-NaN.  This change considers NaNs equal only for the equality
operators.  The placement operators, contains, overlaps, left/right of
etc. continues to return false when NaNs are involved.  We don't need
to worry about them being considered greater than any-NaN because there
aren't any basic comparison operators like less/greater than for the
geometric datatypes.

All changes can be summarised as:

* Check for underflow and overflow
* Check for division by zero
* Let the objects with NaN values to be the same
* Return NULL when the distance is NaN for all closest point operators
* Favour not-NaN over NaN where it makes sense

The patch also replaces all occurrences of "double" as "float8".  They
are the same, but were randomly spread on the same file.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com

Parallel discussions: https://www.postgresql.org/message-id/28685.1468246504%40sss.pgh.pa.us
---
 src/backend/access/gist/gistproc.c |  90 +++----
 src/backend/utils/adt/geo_ops.c    | 501 ++++++++++++++++++++-----------------
 src/backend/utils/adt/geo_spgist.c |  28 +--
 src/include/utils/geo_decls.h      |  19 +-
 4 files changed, 341 insertions(+), 297 deletions(-)

diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index d6ce5ccf6c..895cf2d473 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -55,7 +55,7 @@ rt_box_union(BOX *n, const BOX *a, const BOX *b)
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 size_box(const BOX *box)
 {
 	/*
@@ -76,20 +76,21 @@ size_box(const BOX *box)
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
-	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
+	return float8_mul(float8_mi(box->high.x, box->low.x),
+					  float8_mi(box->high.y, box->low.y));
 }
 
 /*
  * Return amount by which the union of the two boxes is larger than
  * the original BOX's area.  The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 box_penalty(const BOX *original, const BOX *new)
 {
 	BOX			unionbox;
 
 	rt_box_union(&unionbox, original, new);
-	return size_box(&unionbox) - size_box(original);
+	return float8_mi(size_box(&unionbox), size_box(original));
 }
 
 /*
@@ -263,7 +264,7 @@ typedef struct
 	/* Index of entry in the initial array */
 	int			index;
 	/* Delta between penalties of entry insertion into different groups */
-	double		delta;
+	float8		delta;
 } CommonEntry;
 
 /*
@@ -279,13 +280,13 @@ typedef struct
 
 	bool		first;			/* true if no split was selected yet */
 
-	double		leftUpper;		/* upper bound of left interval */
-	double		rightLower;		/* lower bound of right interval */
+	float8		leftUpper;		/* upper bound of left interval */
+	float8		rightLower;		/* lower bound of right interval */
 
 	float4		ratio;
 	float4		overlap;
 	int			dim;			/* axis of this split */
-	double		range;			/* width of general MBR projection to the
+	float8		range;			/* width of general MBR projection to the
 								 * selected axis */
 } ConsiderSplitContext;
 
@@ -294,7 +295,7 @@ typedef struct
  */
 typedef struct
 {
-	double		lower,
+	float8		lower,
 				upper;
 } SplitInterval;
 
@@ -304,7 +305,7 @@ typedef struct
 static int
 interval_cmp_lower(const void *i1, const void *i2)
 {
-	double		lower1 = ((const SplitInterval *) i1)->lower,
+	float8		lower1 = ((const SplitInterval *) i1)->lower,
 				lower2 = ((const SplitInterval *) i2)->lower;
 
 	return float8_cmp_internal(lower1, lower2);
@@ -316,7 +317,7 @@ interval_cmp_lower(const void *i1, const void *i2)
 static int
 interval_cmp_upper(const void *i1, const void *i2)
 {
-	double		upper1 = ((const SplitInterval *) i1)->upper,
+	float8		upper1 = ((const SplitInterval *) i1)->upper,
 				upper2 = ((const SplitInterval *) i2)->upper;
 
 	return float8_cmp_internal(upper1, upper2);
@@ -339,14 +340,14 @@ non_negative(float val)
  */
 static inline void
 g_box_consider_split(ConsiderSplitContext *context, int dimNum,
-					 double rightLower, int minLeftCount,
-					 double leftUpper, int maxLeftCount)
+					 float8 rightLower, int minLeftCount,
+					 float8 leftUpper, int maxLeftCount)
 {
 	int			leftCount,
 				rightCount;
 	float4		ratio,
 				overlap;
-	double		range;
+	float8		range;
 
 	/*
 	 * Calculate entries distribution ratio assuming most uniform distribution
@@ -369,8 +370,7 @@ g_box_consider_split(ConsiderSplitContext *context, int dimNum,
 	 * Ratio of split - quotient between size of lesser group and total
 	 * entries count.
 	 */
-	ratio = ((float4) Min(leftCount, rightCount)) /
-		((float4) context->entriesCount);
+	ratio = float4_div(Min(leftCount, rightCount), context->entriesCount);
 
 	if (ratio > LIMIT_RATIO)
 	{
@@ -384,11 +384,13 @@ g_box_consider_split(ConsiderSplitContext *context, int dimNum,
 		 * or less range with same overlap.
 		 */
 		if (dimNum == 0)
-			range = context->boundingBox.high.x - context->boundingBox.low.x;
+			range = float8_mi(context->boundingBox.high.x,
+							  context->boundingBox.low.x);
 		else
-			range = context->boundingBox.high.y - context->boundingBox.low.y;
+			range = float8_mi(context->boundingBox.high.y,
+							  context->boundingBox.low.y);
 
-		overlap = (leftUpper - rightLower) / range;
+		overlap = float8_div(float8_mi(leftUpper, rightLower), range);
 
 		/* If there is no previous selection, select this */
 		if (context->first)
@@ -531,7 +533,7 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 	context.first = true;		/* nothing selected yet */
 	for (dim = 0; dim < 2; dim++)
 	{
-		double		leftUpper,
+		float8		leftUpper,
 					rightLower;
 		int			i1,
 					i2;
@@ -728,7 +730,7 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 	 */
 	for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 	{
-		double		lower,
+		float8		lower,
 					upper;
 
 		/*
@@ -783,7 +785,7 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		 * Calculate minimum number of entries that must be placed in both
 		 * groups, to reach LIMIT_RATIO.
 		 */
-		int			m = ceil(LIMIT_RATIO * (double) nentries);
+		int			m = ceil(LIMIT_RATIO * (float8) nentries);
 
 		/*
 		 * Calculate delta between penalties of join "common entries" to
@@ -792,8 +794,8 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		for (i = 0; i < commonEntriesCount; i++)
 		{
 			box = DatumGetBoxP(entryvec->vector[commonEntries[i].index].key);
-			commonEntries[i].delta = Abs(box_penalty(leftBox, box) -
-										 box_penalty(rightBox, box));
+			commonEntries[i].delta = Abs(float8_mi(box_penalty(leftBox, box),
+												   box_penalty(rightBox, box)));
 		}
 
 		/*
@@ -1107,10 +1109,10 @@ gist_circle_compress(PG_FUNCTION_ARGS)
 		BOX		   *r;
 
 		r = (BOX *) palloc(sizeof(BOX));
-		r->high.x = in->center.x + in->radius;
-		r->low.x = in->center.x - in->radius;
-		r->high.y = in->center.y + in->radius;
-		r->low.y = in->center.y - in->radius;
+		r->high.x = float8_pl(in->center.x, in->radius);
+		r->low.x = float8_mi(in->center.x, in->radius);
+		r->high.y = float8_pl(in->center.y, in->radius);
+		r->low.y = float8_mi(in->center.y, in->radius);
 
 		retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
 		gistentryinit(*retval, PointerGetDatum(r),
@@ -1148,10 +1150,10 @@ gist_circle_consistent(PG_FUNCTION_ARGS)
 	 * rtree_internal_consistent even at leaf nodes.  (This works in part
 	 * because the index entries are bounding boxes not circles.)
 	 */
-	bbox.high.x = query->center.x + query->radius;
-	bbox.low.x = query->center.x - query->radius;
-	bbox.high.y = query->center.y + query->radius;
-	bbox.low.y = query->center.y - query->radius;
+	bbox.high.x = float8_pl(query->center.x, query->radius);
+	bbox.low.x = float8_mi(query->center.x, query->radius);
+	bbox.high.y = float8_pl(query->center.y, query->radius);
+	bbox.low.y = float8_mi(query->center.y, query->radius);
 
 	result = rtree_internal_consistent(DatumGetBoxP(entry->key),
 									   &bbox, strategy);
@@ -1216,10 +1218,10 @@ gist_point_fetch(PG_FUNCTION_ARGS)
 	DatumGetFloat8(DirectFunctionCall2(point_distance, \
 									   PointPGetDatum(p1), PointPGetDatum(p2)))
 
-static double
+static float8
 computeDistance(bool isLeaf, BOX *box, Point *point)
 {
-	double		result = 0.0;
+	float8		result = 0.0;
 
 	if (isLeaf)
 	{
@@ -1237,9 +1239,9 @@ computeDistance(bool isLeaf, BOX *box, Point *point)
 		/* point is over or below box */
 		Assert(box->low.y <= box->high.y);
 		if (point->y > box->high.y)
-			result = point->y - box->high.y;
+			result = float8_mi(point->y, box->high.y);
 		else if (point->y < box->low.y)
-			result = box->low.y - point->y;
+			result = float8_mi(box->low.y, point->y);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
@@ -1248,9 +1250,9 @@ computeDistance(bool isLeaf, BOX *box, Point *point)
 		/* point is to left or right of box */
 		Assert(box->low.x <= box->high.x);
 		if (point->x > box->high.x)
-			result = point->x - box->high.x;
+			result = float8_mi(point->x, box->high.x);
 		else if (point->x < box->low.x)
-			result = box->low.x - point->x;
+			result = float8_mi(box->low.x, point->x);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
@@ -1258,7 +1260,7 @@ computeDistance(bool isLeaf, BOX *box, Point *point)
 	{
 		/* closest point will be a vertex */
 		Point		p;
-		double		subresult;
+		float8		subresult;
 
 		result = point_point_distance(point, &box->low);
 
@@ -1449,7 +1451,7 @@ gist_point_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	switch (strategyGroup)
@@ -1478,11 +1480,11 @@ gist_point_distance(PG_FUNCTION_ARGS)
  * This is a lower bound estimate of distance from point to indexed geometric
  * type.
  */
-static double
+static float8
 gist_bbox_distance(GISTENTRY *entry, Datum query,
 				   StrategyNumber strategy, bool *recheck)
 {
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	/* Bounding box distance is always inexact. */
@@ -1512,7 +1514,7 @@ gist_circle_distance(PG_FUNCTION_ARGS)
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
@@ -1528,7 +1530,7 @@ gist_poly_distance(PG_FUNCTION_ARGS)
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 1fb2ff2603..314e442f2e 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -59,7 +59,7 @@ static inline float8 lseg_sl(LSEG *lseg);
 static inline float8 lseg_invsl(LSEG *lseg);
 static bool	lseg_interpt_line(Point *result, LSEG *lseg, LINE *line);
 static bool	lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2);
-static int	lseg_crossing(double x, double y, double px, double py);
+static int	lseg_crossing(float8 x, float8 y, float8 px, float8 py);
 static bool	lseg_contain_point(LSEG *lseg, Point *point);
 static float8 lseg_closept_point(Point *result, LSEG *lseg, Point *pt);
 static float8 lseg_closept_line(Point *result, LSEG *lseg, LINE *line);
@@ -69,9 +69,9 @@ static float8 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2);
 static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
 static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
-static double box_ar(BOX *box);
-static double box_ht(BOX *box);
-static double box_wd(BOX *box);
+static float8 box_ar(BOX *box);
+static float8 box_ht(BOX *box);
+static float8 box_wd(BOX *box);
 static bool box_contain_point(BOX *box, Point *point);
 static bool box_contain_box(BOX *box1, BOX *box2);
 static bool box_contain_lseg(BOX *box, LSEG *lseg);
@@ -80,7 +80,7 @@ static float8 box_closept_point(Point *result, BOX *box, Point *point);
 static float8 box_closept_lseg(Point *result, BOX *box, LSEG *lseg);
 
 /* Routines for circles */
-static double circle_ar(CIRCLE *circle);
+static float8 circle_ar(CIRCLE *circle);
 
 /* Routines for polygons */
 static void make_bound_box(POLYGON *poly);
@@ -91,10 +91,10 @@ static bool plist_same(int npts, Point *p1, Point *p2);
 static float8 dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 /* Routines for encoding and decoding */
-static double single_decode(char *num, char **endptr_p,
+static float8 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
-static void pair_decode(char *str, double *x, double *y, char **endptr_p,
+static void pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
@@ -146,7 +146,7 @@ static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
  *	and restore that order for text output - tgl 97/01/16
  */
 
-static double
+static float8
 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string)
 {
@@ -163,7 +163,7 @@ single_encode(float8 x, StringInfo str)
 }								/* single_encode() */
 
 static void
-pair_decode(char *str, double *x, double *y, char **endptr_p,
+pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string)
 {
 	bool		has_delim;
@@ -376,19 +376,19 @@ box_in(PG_FUNCTION_ARGS)
 	char	   *str = PG_GETARG_CSTRING(0);
 	BOX		   *box = (BOX *) palloc(sizeof(BOX));
 	bool		isopen;
-	double		x,
+	float8		x,
 				y;
 
 	path_decode(str, false, 2, &(box->high), &isopen, NULL, "box", str);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
@@ -416,7 +416,7 @@ box_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	BOX		   *box;
-	double		x,
+	float8		x,
 				y;
 
 	box = (BOX *) palloc(sizeof(BOX));
@@ -427,13 +427,13 @@ box_recv(PG_FUNCTION_ARGS)
 	box->low.y = pq_getmsgfloat8(buf);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
@@ -466,7 +466,7 @@ box_send(PG_FUNCTION_ARGS)
 static inline void
 box_construct(BOX *result, Point *pt1, Point *pt2)
 {
-	if (pt1->x > pt2->x)
+	if (float8_gt(pt1->x, pt2->x))
 	{
 		result->high.x = pt1->x;
 		result->low.x = pt2->x;
@@ -476,7 +476,7 @@ box_construct(BOX *result, Point *pt1, Point *pt2)
 		result->high.x = pt2->x;
 		result->low.x = pt1->x;
 	}
-	if (pt1->y > pt2->y)
+	if (float8_gt(pt1->y, pt2->y))
 	{
 		result->high.y = pt1->y;
 		result->low.y = pt2->y;
@@ -808,10 +808,10 @@ box_center(PG_FUNCTION_ARGS)
 
 /*		box_ar	-		returns the area of the box.
  */
-static double
+static float8
 box_ar(BOX *box)
 {
-	return box_wd(box) * box_ht(box);
+	return float8_mul(box_wd(box), box_ht(box));
 }
 
 
@@ -820,28 +820,28 @@ box_ar(BOX *box)
 static void
 box_cn(Point *center, BOX *box)
 {
-	center->x = (box->high.x + box->low.x) / 2.0;
-	center->y = (box->high.y + box->low.y) / 2.0;
+	center->x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	center->y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 }
 
 
 /*		box_wd	-		returns the width (length) of the box
  *								  (horizontal magnitude).
  */
-static double
+static float8
 box_wd(BOX *box)
 {
-	return box->high.x - box->low.x;
+	return float8_mi(box->high.x, box->low.x);
 }
 
 
 /*		box_ht	-		returns the height of the box
  *								  (vertical magnitude).
  */
-static double
+static float8
 box_ht(BOX *box)
 {
-	return box->high.y - box->low.y;
+	return float8_mi(box->high.y, box->low.y);
 }
 
 
@@ -865,10 +865,10 @@ box_intersect(PG_FUNCTION_ARGS)
 
 	result = (BOX *) palloc(sizeof(BOX));
 
-	result->high.x = Min(box1->high.x, box2->high.x);
-	result->low.x = Max(box1->low.x, box2->low.x);
-	result->high.y = Min(box1->high.y, box2->high.y);
-	result->low.y = Max(box1->low.y, box2->low.y);
+	result->high.x = float8_min(box1->high.x, box2->high.x);
+	result->low.x = float8_max(box1->low.x, box2->low.x);
+	result->high.y = float8_min(box1->high.y, box2->high.y);
+	result->low.y = float8_max(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(result);
 }
@@ -1014,8 +1014,8 @@ line_construct(LINE *result, Point *pt, float8 m)
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
-		result->A = -1;
-		result->B = 0;
+		result->A = -1.0;
+		result->B = 0.0;
 		result->C = pt->x;
 	}
 	else
@@ -1023,7 +1023,7 @@ line_construct(LINE *result, Point *pt, float8 m)
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
-		result->C = pt->y - m * pt->x;
+		result->C = float8_mi(pt->y, float8_mul(m, pt->x));
 	}
 }
 
@@ -1076,7 +1076,8 @@ line_perp(PG_FUNCTION_ARGS)
 	else if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
 
-	PG_RETURN_BOOL(FPeq(((l1->A * l2->B) / (l1->B * l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
+								   float8_mul(l1->B, l2->A)), -1.0));
 }
 
 Datum
@@ -1095,25 +1096,35 @@ line_horizontal(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(FPzero(line->A));
 }
 
+
+/*
+ * Check whether the two lines are the same
+ *
+ * We consider NaNs values to be equal to each other to let those lines
+ * to be found.
+ */
 Datum
 line_eq(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	double		k;
-
-	if (!FPzero(l2->A))
-		k = l1->A / l2->A;
-	else if (!FPzero(l2->B))
-		k = l1->B / l2->B;
-	else if (!FPzero(l2->C))
-		k = l1->C / l2->C;
+	float8		ratio;
+
+	if (!FPzero(l2->A) && !isnan(l2->A))
+		ratio = float8_div(l1->A, l2->A);
+	else if (!FPzero(l2->B) && !isnan(l2->B))
+		ratio = float8_div(l1->B, l2->B);
+	else if (!FPzero(l2->C) && !isnan(l2->C))
+		ratio = float8_div(l1->C, l2->C);
 	else
-		k = 1.0;
+		ratio = 1.0;
 
-	PG_RETURN_BOOL(FPeq(l1->A, k * l2->A) &&
-				   FPeq(l1->B, k * l2->B) &&
-				   FPeq(l1->C, k * l2->C));
+	PG_RETURN_BOOL((FPeq(l1->A, float8_mul(ratio, l2->A)) &&
+					FPeq(l1->B, float8_mul(ratio, l2->B)) &&
+					FPeq(l1->C, float8_mul(ratio, l2->C))) ||
+				   (float8_eq(l1->A, l2->A) &&
+					float8_eq(l1->B, l2->B) &&
+					float8_eq(l1->C, l2->C)));
 }
 
 
@@ -1131,7 +1142,7 @@ line_invsl(LINE *line)
 		return DBL_MAX;
 	if (FPzero(line->B))
 		return 0.0;
-	return line->B / line->A;
+	return float8_div(line->B, line->A);
 }
 
 
@@ -1149,7 +1160,7 @@ line_distance(PG_FUNCTION_ARGS)
 	if (line_interpt_line(NULL, l1, l2))	/* intersecting? */
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
+		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
 	point_construct(&tmp, 0.0, l1->C);
 	result = line_closept_point(NULL, l2, &tmp);
 	PG_RETURN_FLOAT8(result);
@@ -1182,11 +1193,15 @@ line_interpt(PG_FUNCTION_ARGS)
  * NOTE: If the lines are identical then we will find they are parallel
  * and report "no intersection".  This is a little weird, but since
  * there's no *unique* intersection, maybe it's appropriate behavior.
+ *
+ * If the lines have NaN constants, we will return true, and the intersection
+ * point would have NaN coordinates.  We shouldn't return false in this case
+ * because that would mean the lines are parallel.
  */
 static bool
 line_interpt_line(Point *result, LINE *l1, LINE *l2)
 {
-	double		x,
+	float8		x,
 				y;
 
 	if (FPzero(l1->B))			/* l1 vertical? */
@@ -1195,20 +1210,20 @@ line_interpt_line(Point *result, LINE *l1, LINE *l2)
 			return false;
 
 		x = l1->C;
-		y = (l2->A * x + l2->C);
+		y = float8_pl(float8_mul(l2->A, x), l2->C);
 	}
 	else if (FPzero(l2->B))		/* l2 vertical? */
 	{
 		x = l2->C;
-		y = (l1->A * x + l1->C);
+		y = float8_pl(float8_mul(l1->A, x), l1->C);
 	}
 	else
 	{
-		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
 			return false;
 
-		x = (l1->C - l2->C) / (l2->A - l1->A);
-		y = (l1->A * x + l1->C);
+		x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
+		y = float8_pl(float8_mul(l1->A, x), l1->C);
 	}
 
 	if (result != NULL)
@@ -1244,7 +1259,7 @@ Datum
 path_area(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P(0);
-	double		area = 0.0;
+	float8		area = 0.0;
 	int			i,
 				j;
 
@@ -1254,12 +1269,11 @@ path_area(PG_FUNCTION_ARGS)
 	for (i = 0; i < path->npts; i++)
 	{
 		j = (i + 1) % path->npts;
-		area += path->p[i].x * path->p[j].y;
-		area -= path->p[i].y * path->p[j].x;
+		area = float8_pl(area, float8_mul(path->p[i].x, path->p[j].y));
+		area = float8_mi(area, float8_mul(path->p[i].y, path->p[j].x));
 	}
 
-	area *= 0.5;
-	PG_RETURN_FLOAT8(area < 0.0 ? -area : area);
+	PG_RETURN_FLOAT8(float8_div(fabs(area), 2.0));
 }
 
 
@@ -1529,19 +1543,19 @@ path_inter(PG_FUNCTION_ARGS)
 	b1.high.y = b1.low.y = p1->p[0].y;
 	for (i = 1; i < p1->npts; i++)
 	{
-		b1.high.x = Max(p1->p[i].x, b1.high.x);
-		b1.high.y = Max(p1->p[i].y, b1.high.y);
-		b1.low.x = Min(p1->p[i].x, b1.low.x);
-		b1.low.y = Min(p1->p[i].y, b1.low.y);
+		b1.high.x = float8_max(p1->p[i].x, b1.high.x);
+		b1.high.y = float8_max(p1->p[i].y, b1.high.y);
+		b1.low.x = float8_min(p1->p[i].x, b1.low.x);
+		b1.low.y = float8_min(p1->p[i].y, b1.low.y);
 	}
 	b2.high.x = b2.low.x = p2->p[0].x;
 	b2.high.y = b2.low.y = p2->p[0].y;
 	for (i = 1; i < p2->npts; i++)
 	{
-		b2.high.x = Max(p2->p[i].x, b2.high.x);
-		b2.high.y = Max(p2->p[i].y, b2.high.y);
-		b2.low.x = Min(p2->p[i].x, b2.low.x);
-		b2.low.y = Min(p2->p[i].y, b2.low.y);
+		b2.high.x = float8_max(p2->p[i].x, b2.high.x);
+		b2.high.y = float8_max(p2->p[i].y, b2.high.y);
+		b2.low.x = float8_min(p2->p[i].x, b2.low.x);
+		b2.low.y = float8_min(p2->p[i].y, b2.low.y);
 	}
 	if (!box_ov(&b1, &b2))
 		PG_RETURN_BOOL(false);
@@ -1631,7 +1645,7 @@ path_distance(PG_FUNCTION_ARGS)
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
 			tmp = lseg_closept_lseg(NULL, &seg1, &seg2);
-			if (!have_min || tmp < min)
+			if (!have_min || float8_lt(tmp, min))
 			{
 				min = tmp;
 				have_min = true;
@@ -1670,7 +1684,7 @@ path_length(PG_FUNCTION_ARGS)
 			iprev = path->npts - 1; /* include the closure segment */
 		}
 
-		result += point_dt(&path->p[iprev], &path->p[i]);
+		result = float8_pl(result, point_dt(&path->p[iprev], &path->p[i]));
 	}
 
 	PG_RETURN_FLOAT8(result);
@@ -1830,10 +1844,18 @@ point_ne(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(!point_eq_point(pt1, pt2));
 }
 
+
+/*
+ * Check whether the two points are the same
+ *
+ * We consider NaNs coordinates to be equal to each other to let those points
+ * to be found.
+ */
 static inline bool
 point_eq_point(Point *pt1, Point *pt2)
 {
-	return FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y);
+	return ((FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y)) ||
+			(float8_eq(pt1->x, pt2->x) && float8_eq(pt1->y, pt2->y)));
 }
 
 
@@ -1853,7 +1875,7 @@ point_distance(PG_FUNCTION_ARGS)
 static inline float8
 point_dt(Point *pt1, Point *pt2)
 {
-	return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
+	return HYPOT(float8_mi(pt1->x, pt2->x), float8_mi(pt1->y, pt2->y));
 }
 
 Datum
@@ -1878,7 +1900,7 @@ point_sl(Point *pt1, Point *pt2)
 		return DBL_MAX;
 	if (FPeq(pt1->y, pt2->y))
 		return 0.0;
-	return (pt1->y - pt2->y) / (pt1->x - pt2->x);
+	return float8_div(float8_mi(pt1->y, pt2->y), float8_mi(pt1->x, pt2->x));
 }
 
 
@@ -1894,7 +1916,7 @@ point_invsl(Point *pt1, Point *pt2)
 		return 0.0;
 	if (FPeq(pt1->y, pt2->y))
 		return DBL_MAX;
-	return (pt1->x - pt2->x) / (pt2->y - pt1->y);
+	return float8_div(float8_mi(pt1->x, pt2->x), float8_mi(pt2->y, pt1->y));
 }
 
 
@@ -2168,8 +2190,8 @@ lseg_center(PG_FUNCTION_ARGS)
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
-	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
+	result->x = float8_div(float8_pl(lseg->p[0].x, lseg->p[1].x), 2.0);
+	result->y = float8_div(float8_pl(lseg->p[0].y, lseg->p[1].y), 2.0);
 
 	PG_RETURN_POINT_P(result);
 }
@@ -2292,7 +2314,7 @@ dist_ppath(PG_FUNCTION_ARGS)
 
 		statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
 		tmp = lseg_closept_point(NULL, &lseg, pt);
-		if (!have_min || tmp < result)
+		if (!have_min || float8_lt(tmp, result))
 		{
 			result = tmp;
 			have_min = true;
@@ -2322,19 +2344,14 @@ dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
-	float8		result,
-				d2;
+	float8		result;
 
 	if (lseg_interpt_line(NULL, lseg, line))
 		result = 0.0;
 	else
-	{
-		result = line_closept_point(NULL, line, &lseg->p[0]);
-		d2 = line_closept_point(NULL, line, &lseg->p[1]);
 		/* XXX shouldn't we take the min not max? */
-		if (d2 > result)
-			result = d2;
-	}
+		result = float8_max(line_closept_point(NULL, line, &lseg->p[0]),
+							line_closept_point(NULL, line, &lseg->p[1]));
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -2381,11 +2398,10 @@ dist_cpoly(PG_FUNCTION_ARGS)
 	float8		result;
 
 	/* calculate distance to center, and subtract radius */
-	result = dist_ppoly_internal(&circle->center, poly);
-
-	result -= circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(dist_ppoly_internal(&circle->center, poly),
+					   circle->radius);
+	if (result < 0.0)
+		result = 0.0;
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -2411,7 +2427,7 @@ dist_polyp(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT8(dist_ppoly_internal(point, poly));
 }
 
-static double
+static float8
 dist_ppoly_internal(Point *pt, POLYGON *poly)
 {
 	float8		result;
@@ -2448,7 +2464,7 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
 #ifdef GEODEBUG
 		printf("dist_ppoly_internal- segment %d distance is %f\n", (i + 1), d);
 #endif
-		if (d < result)
+		if (float8_lt(d, result))
 			result = d;
 	}
 
@@ -2550,7 +2566,8 @@ close_pl(PG_FUNCTION_ARGS)
 
 	result = (Point *) palloc(sizeof(Point));
 
-	line_closept_point(result, line, pt);
+	if (isnan(line_closept_point(result, line, pt)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
@@ -2607,8 +2624,8 @@ static float8
 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
 {
 	Point		point;
-	double		dist;
-	double		d;
+	float8		dist,
+				d;
 
 	d = lseg_closept_point(NULL, l1, &l2->p[0]);
 	dist = d;
@@ -2616,20 +2633,20 @@ lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
 		*result = l2->p[0];
 
 	d = lseg_closept_point(NULL, l1, &l2->p[1]);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = l2->p[1];
 	}
 
-	if (lseg_closept_point(&point, l2, &l1->p[0]) < dist)
+	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[0]), dist))
 		d = lseg_closept_point(result, l1, &point);
 
-	if (lseg_closept_point(&point, l2, &l1->p[1]) < dist)
+	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[1]), dist))
 		d = lseg_closept_point(result, l1, &point);
 
-	if (d < dist)
+	if (float8_lt(d, dist))
 		dist = d;
 
 	return dist;
@@ -2644,7 +2661,8 @@ close_lseg(PG_FUNCTION_ARGS)
 
 	result = (Point *) palloc(sizeof(Point));
 
-	lseg_closept_lseg(result, l2, l1);
+	if (isnan(lseg_closept_lseg(result, l2, l1)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
@@ -2659,11 +2677,11 @@ close_lseg(PG_FUNCTION_ARGS)
 static float8
 box_closept_point(Point *result, BOX *box, Point *pt)
 {
-	LSEG		lseg;
+	float8		dist,
+				d;
 	Point		point,
 				closept;
-	double		dist,
-				d;
+	LSEG		lseg;
 
 	if (box_contain_point(box, pt))
 	{
@@ -2681,7 +2699,7 @@ box_closept_point(Point *result, BOX *box, Point *pt)
 
 	statlseg_construct(&lseg, &box->high, &point);
 	d = lseg_closept_point(&closept, &lseg, pt);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
@@ -2692,7 +2710,7 @@ box_closept_point(Point *result, BOX *box, Point *pt)
 	point.y = box->low.y;
 	statlseg_construct(&lseg, &box->low, &point);
 	d = lseg_closept_point(&closept, &lseg, pt);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
@@ -2701,7 +2719,7 @@ box_closept_point(Point *result, BOX *box, Point *pt)
 
 	statlseg_construct(&lseg, &box->high, &point);
 	d = lseg_closept_point(&closept, &lseg, pt);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
@@ -2720,7 +2738,8 @@ close_pb(PG_FUNCTION_ARGS)
 
 	result = (Point *) palloc(sizeof(Point));
 
-	box_closept_point(result, box, pt);
+	if (isnan(box_closept_point(result, box, pt)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
@@ -2752,7 +2771,7 @@ close_sl(PG_FUNCTION_ARGS)
 
 	d1 = line_closept_point(NULL, line, &lseg->p[0]);
 	d2 = line_closept_point(NULL, line, &lseg->p[1]);
-	if (d1 < d2)
+	if (float8_lt(d1, d2))
 		*result = lseg->p[0];
 	else
 		*result = lseg->p[1];
@@ -2816,7 +2835,8 @@ close_ls(PG_FUNCTION_ARGS)
 
 	result = (Point *) palloc(sizeof(Point));
 
-	lseg_closept_line(result, lseg, line);
+	if (isnan(lseg_closept_line(result, lseg, line)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
@@ -2831,11 +2851,11 @@ close_ls(PG_FUNCTION_ARGS)
 static float8
 box_closept_lseg(Point *result, BOX *box, LSEG *lseg)
 {
+	float8		dist,
+				d;
 	Point		point,
 				closept;
 	LSEG		bseg;
-	double		dist,
-				d;
 
 	if (box_interpt_lseg(result, box, lseg))
 		return 0.0;
@@ -2848,7 +2868,7 @@ box_closept_lseg(Point *result, BOX *box, LSEG *lseg)
 
 	statlseg_construct(&bseg, &box->high, &point);
 	d = lseg_closept_lseg(&closept, &bseg, lseg);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
@@ -2859,7 +2879,7 @@ box_closept_lseg(Point *result, BOX *box, LSEG *lseg)
 	point.y = box->low.y;
 	statlseg_construct(&bseg, &box->low, &point);
 	d = lseg_closept_lseg(&closept, &bseg, lseg);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
@@ -2868,7 +2888,7 @@ box_closept_lseg(Point *result, BOX *box, LSEG *lseg)
 
 	statlseg_construct(&bseg, &box->high, &point);
 	d = lseg_closept_lseg(&closept, &bseg, lseg);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
@@ -2887,7 +2907,8 @@ close_sb(PG_FUNCTION_ARGS)
 
 	result = (Point *) palloc(sizeof(Point));
 
-	box_closept_lseg(result, box, lseg);
+	if (isnan(box_closept_lseg(result, box, lseg)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
@@ -2920,7 +2941,9 @@ close_lb(PG_FUNCTION_ARGS)
 static bool
 line_contain_point(LINE *line, Point *point)
 {
-	return FPzero(line->A * point->x + line->B * point->y + line->C);
+	return FPzero(float8_pl(float8_pl(float8_mul(line->A, point->x),
+									  float8_mul(line->B, point->y)),
+							line->C));
 }
 
 Datum
@@ -3001,7 +3024,7 @@ on_ppath(PG_FUNCTION_ARGS)
 	PATH	   *path = PG_GETARG_PATH_P(1);
 	int			i,
 				n;
-	double		a,
+	float8		a,
 				b;
 
 	/*-- OPEN --*/
@@ -3012,8 +3035,7 @@ on_ppath(PG_FUNCTION_ARGS)
 		for (i = 0; i < n; i++)
 		{
 			b = point_dt(pt, &path->p[i + 1]);
-			if (FPeq(a + b,
-					 point_dt(&path->p[i], &path->p[i + 1])))
+			if (FPeq(float8_pl(a, b), point_dt(&path->p[i], &path->p[i + 1])))
 				PG_RETURN_BOOL(true);
 			a = b;
 		}
@@ -3099,10 +3121,10 @@ box_interpt_lseg(Point *result, BOX *box, LSEG *lseg)
 	LSEG		bseg;
 	Point		point;
 
-	lbox.low.x = Min(lseg->p[0].x, lseg->p[1].x);
-	lbox.low.y = Min(lseg->p[0].y, lseg->p[1].y);
-	lbox.high.x = Max(lseg->p[0].x, lseg->p[1].x);
-	lbox.high.y = Max(lseg->p[0].y, lseg->p[1].y);
+	lbox.low.x = float8_min(lseg->p[0].x, lseg->p[1].x);
+	lbox.low.y = float8_min(lseg->p[0].y, lseg->p[1].y);
+	lbox.high.x = float8_max(lseg->p[0].x, lseg->p[1].x);
+	lbox.high.y = float8_max(lseg->p[0].y, lseg->p[1].y);
 
 	/* nothing close to overlap? then not going to intersect */
 	if (!box_ov(&lbox, box))
@@ -3209,7 +3231,7 @@ static void
 make_bound_box(POLYGON *poly)
 {
 	int			i;
-	double		x1,
+	float8		x1,
 				y1,
 				x2,
 				y2;
@@ -3220,13 +3242,13 @@ make_bound_box(POLYGON *poly)
 	y2 = y1 = poly->p[0].y;
 	for (i = 1; i < poly->npts; i++)
 	{
-		if (poly->p[i].x < x1)
+		if (float8_lt(poly->p[i].x, x1))
 			x1 = poly->p[i].x;
-		if (poly->p[i].x > x2)
+		if (float8_gt(poly->p[i].x, x2))
 			x2 = poly->p[i].x;
-		if (poly->p[i].y < y1)
+		if (float8_lt(poly->p[i].y, y1))
 			y1 = poly->p[i].y;
-		if (poly->p[i].y > y2)
+		if (float8_gt(poly->p[i].y, y2))
 			y2 = poly->p[i].y;
 	}
 
@@ -3739,8 +3761,8 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 		 * if X-intersection wasn't found  then check central point of tested
 		 * segment. In opposite case we already check all subsegments
 		 */
-		p.x = (t.p[0].x + t.p[1].x) / 2.0;
-		p.y = (t.p[0].y + t.p[1].y) / 2.0;
+		p.x = float8_div(float8_pl(t.p[0].x, t.p[1].x), 2.0);
+		p.y = float8_div(float8_pl(t.p[0].y, t.p[1].y), 2.0);
 
 		res = point_inside(&p, poly->npts, poly->p);
 	}
@@ -3880,8 +3902,8 @@ static inline void
 point_add_point(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x + pt2->x,
-					pt1->y + pt2->y);
+					float8_pl(pt1->x, pt2->x),
+					float8_pl(pt1->y, pt2->y));
 }
 
 Datum
@@ -3903,8 +3925,8 @@ static inline void
 point_sub_point(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x - pt2->x,
-					pt1->y - pt2->y);
+					float8_mi(pt1->x, pt2->x),
+					float8_mi(pt1->y, pt2->y));
 }
 
 Datum
@@ -3926,8 +3948,10 @@ static inline void
 point_mul_point(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					(pt1->x * pt2->x) - (pt1->y * pt2->y),
-					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+					float8_mi(float8_mul(pt1->x, pt2->x),
+							  float8_mul(pt1->y, pt2->y)),
+					float8_pl(float8_mul(pt1->x, pt2->y),
+							  float8_mul(pt1->y, pt2->x)));
 }
 
 Datum
@@ -3948,18 +3972,15 @@ point_mul(PG_FUNCTION_ARGS)
 static inline void
 point_div_point(Point *result, Point *pt1, Point *pt2)
 {
-	double		div;
-
-	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
+	float8		div;
 
-	if (div == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
+	div = float8_pl(float8_mul(pt2->x, pt2->x), float8_mul(pt2->y, pt2->y));
 
 	point_construct(result,
-					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
-					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+					float8_div(float8_pl(float8_mul(pt1->x, pt2->x),
+										 float8_mul(pt1->y, pt2->y)), div),
+					float8_div(float8_mi(float8_mul(pt1->y, pt2->x),
+										 float8_mul(pt1->x, pt2->y)), div));
 }
 
 Datum
@@ -4096,10 +4117,10 @@ boxes_bound_box(PG_FUNCTION_ARGS)
 
 	container = (BOX *) palloc(sizeof(BOX));
 
-	container->high.x = Max(box1->high.x, box2->high.x);
-	container->low.x = Min(box1->low.x, box2->low.x);
-	container->high.y = Max(box1->high.y, box2->high.y);
-	container->low.y = Min(box1->low.y, box2->low.y);
+	container->high.x = float8_max(box1->high.x, box2->high.x);
+	container->low.x = float8_min(box1->low.x, box2->low.x);
+	container->high.y = float8_max(box1->high.y, box2->high.y);
+	container->low.y = float8_min(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(container);
 }
@@ -4419,7 +4440,8 @@ circle_in(PG_FUNCTION_ARGS)
 		s++;
 
 	circle->radius = single_decode(s, &s, "circle", str);
-	if (circle->radius < 0)
+	/* We have to accept NaN. */
+	if (circle->radius < 0.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
@@ -4486,7 +4508,8 @@ circle_recv(PG_FUNCTION_ARGS)
 	circle->center.y = pq_getmsgfloat8(buf);
 	circle->radius = pq_getmsgfloat8(buf);
 
-	if (circle->radius < 0)
+	/* We have to accept NaN. */
+	if (circle->radius < 0.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
 				 errmsg("invalid radius in external \"circle\" value")));
@@ -4517,6 +4540,9 @@ circle_send(PG_FUNCTION_ARGS)
  *---------------------------------------------------------*/
 
 /*		circles identical?
+ *
+ * We consider NaNs values to be equal to each other to let those circles
+ * to be found.
  */
 Datum
 circle_same(PG_FUNCTION_ARGS)
@@ -4524,7 +4550,8 @@ circle_same(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPeq(circle1->radius, circle2->radius) &&
+	PG_RETURN_BOOL(((isnan(circle1->radius) && isnan(circle1->radius)) ||
+					FPeq(circle1->radius, circle2->radius)) &&
 				   point_eq_point(&circle1->center, &circle2->center));
 }
 
@@ -4537,7 +4564,7 @@ circle_overlap(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle1->radius + circle2->radius));
+						float8_pl(circle1->radius, circle2->radius)));
 }
 
 /*		circle_overleft -		is the right edge of circle1 at or left of
@@ -4549,8 +4576,8 @@ circle_overleft(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.x + circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_left		-		is circle1 strictly left of circle2?
@@ -4561,8 +4588,8 @@ circle_left(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.x + circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_right	-		is circle1 strictly right of circle2?
@@ -4573,8 +4600,8 @@ circle_right(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.x - circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_overright	-	is the left edge of circle1 at or right of
@@ -4586,8 +4613,8 @@ circle_overright(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.x - circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_contained		-		is circle1 contained by circle2?
@@ -4599,7 +4626,7 @@ circle_contained(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle2->radius - circle1->radius));
+						float8_mi(circle2->radius, circle1->radius)));
 }
 
 /*		circle_contain	-		does circle1 contain circle2?
@@ -4611,7 +4638,7 @@ circle_contain(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle1->radius - circle2->radius));
+						float8_mi(circle1->radius, circle2->radius)));
 }
 
 
@@ -4623,8 +4650,8 @@ circle_below(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.y + circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_above	-		is circle1 strictly above circle2?
@@ -4635,8 +4662,8 @@ circle_above(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.y - circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overbelow -		is the upper edge of circle1 at or below
@@ -4648,8 +4675,8 @@ circle_overbelow(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.y + circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overabove	-	is the lower edge of circle1 at or above
@@ -4661,8 +4688,8 @@ circle_overabove(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.y - circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 
@@ -4775,7 +4802,7 @@ circle_mul_pt(PG_FUNCTION_ARGS)
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_mul_point(&result->center, &circle->center, point);
-	result->radius = circle->radius * HYPOT(point->x, point->y);
+	result->radius = float8_mul(circle->radius, HYPOT(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
@@ -4790,7 +4817,7 @@ circle_div_pt(PG_FUNCTION_ARGS)
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_div_point(&result->center, &circle->center, point);
-	result->radius = circle->radius / HYPOT(point->x, point->y);
+	result->radius = float8_div(circle->radius, HYPOT(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
@@ -4814,7 +4841,7 @@ circle_diameter(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
-	PG_RETURN_FLOAT8(2 * circle->radius);
+	PG_RETURN_FLOAT8(float8_mul(circle->radius, 2.0));
 }
 
 
@@ -4839,10 +4866,11 @@ circle_distance(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(&circle1->center, &circle2->center) -
-		(circle1->radius + circle2->radius);
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(&circle1->center, &circle2->center),
+					   float8_pl(circle1->radius, circle2->radius));
+	if (result < 0.0)
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -4852,7 +4880,7 @@ circle_contain_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
 	PG_RETURN_BOOL(d <= circle->radius);
@@ -4864,7 +4892,7 @@ pt_contained_circle(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
 	PG_RETURN_BOOL(d <= circle->radius);
@@ -4881,9 +4909,11 @@ dist_pc(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center),
+					   circle->radius);
+	if (result < 0.0)
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -4897,9 +4927,10 @@ dist_cpoint(PG_FUNCTION_ARGS)
 	Point	   *point = PG_GETARG_POINT_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center), circle->radius);
+	if (result < 0.0)
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
@@ -4921,10 +4952,10 @@ circle_center(PG_FUNCTION_ARGS)
 
 /*		circle_ar		-		returns the area of the circle.
  */
-static double
+static float8
 circle_ar(CIRCLE *circle)
 {
-	return M_PI * (circle->radius * circle->radius);
+	return float8_mul(float8_mul(circle->radius, circle->radius), M_PI);
 }
 
 
@@ -4953,16 +4984,16 @@ circle_box(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	BOX		   *box;
-	double		delta;
+	float8		delta;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
-	delta = circle->radius / sqrt(2.0);
+	delta = float8_div(circle->radius, sqrt(2.0));
 
-	box->high.x = circle->center.x + delta;
-	box->low.x = circle->center.x - delta;
-	box->high.y = circle->center.y + delta;
-	box->low.y = circle->center.y - delta;
+	box->high.x = float8_pl(circle->center.x, delta);
+	box->low.x = float8_mi(circle->center.x, delta);
+	box->high.y = float8_pl(circle->center.y, delta);
+	box->low.y = float8_mi(circle->center.y, delta);
 
 	PG_RETURN_BOX_P(box);
 }
@@ -4978,8 +5009,8 @@ box_circle(PG_FUNCTION_ARGS)
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	circle->center.x = (box->high.x + box->low.x) / 2;
-	circle->center.y = (box->high.y + box->low.y) / 2;
+	circle->center.x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	circle->center.y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 
 	circle->radius = point_dt(&circle->center, &box->high);
 
@@ -4996,8 +5027,8 @@ circle_poly(PG_FUNCTION_ARGS)
 	int			base_size,
 				size;
 	int			i;
-	double		angle;
-	double		anglestep;
+	float8		angle;
+	float8		anglestep;
 
 	if (FPzero(circle->radius))
 		ereport(ERROR,
@@ -5022,13 +5053,16 @@ circle_poly(PG_FUNCTION_ARGS)
 	SET_VARSIZE(poly, size);
 	poly->npts = npts;
 
-	anglestep = (2.0 * M_PI) / npts;
+	anglestep = float8_div(2.0 * M_PI, npts);
 
 	for (i = 0; i < npts; i++)
 	{
-		angle = i * anglestep;
-		poly->p[i].x = circle->center.x - (circle->radius * cos(angle));
-		poly->p[i].y = circle->center.y + (circle->radius * sin(angle));
+		angle = float8_mul(anglestep, i);
+
+		poly->p[i].x = float8_mi(circle->center.x,
+								 float8_mul(circle->radius, cos(angle)));
+		poly->p[i].y = float8_pl(circle->center.y,
+								 float8_mul(circle->radius, sin(angle)));
 	}
 
 	make_bound_box(poly);
@@ -5057,12 +5091,13 @@ poly_to_circle(CIRCLE *result, POLYGON *poly)
 
 	for (i = 0; i < poly->npts; i++)
 		point_add_point(&result->center, &result->center, &poly->p[i]);
-	result->center.x /= poly->npts;
-	result->center.y /= poly->npts;
+	result->center.x = float8_div(result->center.x, poly->npts);
+	result->center.y = float8_div(result->center.y, poly->npts);
 
 	for (i = 0; i < poly->npts; i++)
-		result->radius += point_dt(&poly->p[i], &result->center);
-	result->radius /= poly->npts;
+		result->radius = float8_pl(result->radius,
+								   point_dt(&poly->p[i], &result->center));
+	result->radius = float8_div(result->radius, poly->npts);
 }
 
 Datum
@@ -5101,12 +5136,12 @@ poly_circle(PG_FUNCTION_ARGS)
 static int
 point_inside(Point *p, int npts, Point *plist)
 {
-	double		x0,
+	float8		x0,
 				y0;
-	double		prev_x,
+	float8		prev_x,
 				prev_y;
 	int			i = 0;
-	double		x,
+	float8		x,
 				y;
 	int			cross,
 				total_cross = 0;
@@ -5114,8 +5149,8 @@ point_inside(Point *p, int npts, Point *plist)
 	Assert(npts > 0);
 
 	/* compute first polygon point relative to single point */
-	x0 = plist[0].x - p->x;
-	y0 = plist[0].y - p->y;
+	x0 = float8_mi(plist[0].x, p->x);
+	y0 = float8_mi(plist[0].y, p->y);
 
 	prev_x = x0;
 	prev_y = y0;
@@ -5123,8 +5158,8 @@ point_inside(Point *p, int npts, Point *plist)
 	for (i = 1; i < npts; i++)
 	{
 		/* compute next polygon point relative to single point */
-		x = plist[i].x - p->x;
-		y = plist[i].y - p->y;
+		x = float8_mi(plist[i].x, p->x);
+		y = float8_mi(plist[i].y, p->y);
 
 		/* compute previous to current point crossing */
 		if ((cross = lseg_crossing(x, y, prev_x, prev_y)) == POINT_ON_POLYGON)
@@ -5156,9 +5191,9 @@ point_inside(Point *p, int npts, Point *plist)
  */
 
 static int
-lseg_crossing(double x, double y, double prev_x, double prev_y)
+lseg_crossing(float8 x, float8 y, float8 prev_x, float8 prev_y)
 {
-	double		z;
+	float8		z;
 	int			y_sign;
 
 	if (FPzero(y))
@@ -5169,42 +5204,47 @@ lseg_crossing(double x, double y, double prev_x, double prev_y)
 		{						/* x > 0 */
 			if (FPzero(prev_y)) /* y and prev_y are zero */
 				/* prev_x > 0? */
-				return FPgt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
-			return FPlt(prev_y, 0) ? 1 : -1;
+				return FPgt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
+			return FPlt(prev_y, 0.0) ? 1 : -1;
 		}
 		else
 		{						/* x < 0, x not on positive X axis */
 			if (FPzero(prev_y))
 				/* prev_x < 0? */
-				return FPlt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
+				return FPlt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
 			return 0;
 		}
 	}
 	else
 	{							/* y != 0 */
 		/* compute y crossing direction from previous point */
-		y_sign = FPgt(y, 0) ? 1 : -1;
+		y_sign = FPgt(y, 0.0) ? 1 : -1;
 
 		if (FPzero(prev_y))
 			/* previous point was on X axis, so new point is either off or on */
-			return FPlt(prev_x, 0) ? 0 : y_sign;
-		else if (FPgt(y_sign * prev_y, 0))
+			return FPlt(prev_x, 0.0) ? 0 : y_sign;
+		else if ((y_sign < 0 && FPlt(prev_y, 0.0)) ||
+				 (y_sign > 0 && FPgt(prev_y, 0.0)))
 			/* both above or below X axis */
 			return 0;			/* same sign */
 		else
 		{						/* y and prev_y cross X-axis */
-			if (FPge(x, 0) && FPgt(prev_x, 0))
+			if (FPge(x, 0.0) && FPgt(prev_x, 0.0))
 				/* both non-negative so cross positive X-axis */
 				return 2 * y_sign;
-			if (FPlt(x, 0) && FPle(prev_x, 0))
+			if (FPlt(x, 0.0) && FPle(prev_x, 0.0))
 				/* both non-positive so do not cross positive X-axis */
 				return 0;
 
 			/* x and y cross axises, see URL above point_inside() */
-			z = (x - prev_x) * y - (y - prev_y) * x;
+			z = float8_mi(float8_mul(float8_mi(x, prev_x), y),
+						  float8_mul(float8_mi(y, prev_y), x));
 			if (FPzero(z))
 				return POINT_ON_POLYGON;
-			return FPgt((y_sign * z), 0) ? 0 : 2 * y_sign;
+			if ((y_sign < 0 && FPlt(z, 0.0)) ||
+				(y_sign > 0 && FPgt(z, 0.0)))
+				return 0;
+			return 2 * y_sign;
 		}
 	}
 }
@@ -5288,10 +5328,11 @@ plist_same(int npts, Point *p1, Point *p2)
  * case of hypot(inf,nan) results in INF, and not NAN.
  *-----------------------------------------------------------------------
  */
-double
-pg_hypot(double x, double y)
+float8
+pg_hypot(float8 x, float8 y)
 {
-	double		yx;
+	float8		yx,
+				result;
 
 	/* Handle INF and NaN properly */
 	if (isinf(x) || isinf(y))
@@ -5307,7 +5348,7 @@ pg_hypot(double x, double y)
 	/* Swap x and y if needed to make x the larger one */
 	if (x < y)
 	{
-		double		temp = x;
+		float8		temp = x;
 
 		x = y;
 		y = temp;
@@ -5323,5 +5364,9 @@ pg_hypot(double x, double y)
 
 	/* Determine the hypotenuse */
 	yx = y / x;
-	return x * sqrt(1.0 + (yx * yx));
+	result = x * sqrt(1.0 + (yx * yx));
+
+	check_float8_val(result, false, false);
+
+	return result;
 }
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index fea36f361a..4aff973ef3 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -84,14 +84,14 @@
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
- * is going only going to be used in a place to effect the performance
+ * is only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
 compareDoubles(const void *a, const void *b)
 {
-	double		x = *(double *) a;
-	double		y = *(double *) b;
+	float8		x = *(float8 *) a;
+	float8		y = *(float8 *) b;
 
 	if (x == y)
 		return 0;
@@ -100,8 +100,8 @@ compareDoubles(const void *a, const void *b)
 
 typedef struct
 {
-	double		low;
-	double		high;
+	float8		low;
+	float8		high;
 } Range;
 
 typedef struct
@@ -175,7 +175,7 @@ static RectBox *
 initRectBox(void)
 {
 	RectBox    *rect_box = (RectBox *) palloc(sizeof(RectBox));
-	double		infinity = get_float8_infinity();
+	float8		infinity = get_float8_infinity();
 
 	rect_box->range_box_x.left.low = -infinity;
 	rect_box->range_box_x.left.high = infinity;
@@ -418,10 +418,10 @@ spg_box_quad_picksplit(PG_FUNCTION_ARGS)
 	BOX		   *centroid;
 	int			median,
 				i;
-	double	   *lowXs = palloc(sizeof(double) * in->nTuples);
-	double	   *highXs = palloc(sizeof(double) * in->nTuples);
-	double	   *lowYs = palloc(sizeof(double) * in->nTuples);
-	double	   *highYs = palloc(sizeof(double) * in->nTuples);
+	float8	   *lowXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *lowYs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highYs = palloc(sizeof(float8) * in->nTuples);
 
 	/* Calculate median of all 4D coordinates */
 	for (i = 0; i < in->nTuples; i++)
@@ -434,10 +434,10 @@ spg_box_quad_picksplit(PG_FUNCTION_ARGS)
 		highYs[i] = box->high.y;
 	}
 
-	qsort(lowXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(lowYs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highYs, in->nTuples, sizeof(double), compareDoubles);
+	qsort(lowXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(lowYs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highYs, in->nTuples, sizeof(float8), compareDoubles);
 
 	median = in->nTuples / 2;
 
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 0e066894cd..9f8505804e 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -8,9 +8,6 @@
  *
  * src/include/utils/geo_decls.h
  *
- * NOTE
- *	  These routines do *not* use the float types from adt/.
- *
  *	  XXX These routines were not written by a numerical analyst.
  *
  *	  XXX I have made some attempt to flesh out the operators
@@ -21,14 +18,14 @@
 #ifndef GEO_DECLS_H
 #define GEO_DECLS_H
 
-#include <math.h>
-
 #include "fmgr.h"
 
 /*--------------------------------------------------------------------
  * Useful floating point utilities and constants.
- *-------------------------------------------------------------------*/
-
+ *-------------------------------------------------------------------
+ *
+ * XXX: They are not NaN-aware.
+ */
 
 #define EPSILON					1.0E-06
 
@@ -57,7 +54,7 @@
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		x,
+	float8		x,
 				y;
 } Point;
 
@@ -89,7 +86,7 @@ typedef struct
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		A,
+	float8		A,
 				B,
 				C;
 } LINE;
@@ -124,7 +121,7 @@ typedef struct
 typedef struct
 {
 	Point		center;
-	double		radius;
+	float8		radius;
 } CIRCLE;
 
 /*
@@ -178,6 +175,6 @@ typedef struct
  * in geo_ops.c
  */
 
-extern double pg_hypot(double x, double y);
+extern float8 pg_hypot(float8 x, float8 y);
 
 #endif							/* GEO_DECLS_H */
-- 
2.13.6

#72Kyotaro HORIGUCHI
horiguchi.kyotaro@lab.ntt.co.jp
In reply to: Tomas Vondra (#71)
Re: [PATCH] Improve geometric types

Thank you for taking this.

At Thu, 26 Jul 2018 17:12:50 +0200, Tomas Vondra <tomas.vondra@2ndquadrant.com> wrote in <672f4c42-6742-c1ec-e9a4-1994b815acc7@2ndquadrant.com>

On 07/11/2018 07:13 PM, Emre Hasegeli wrote:

New versions are attached after the <float.h> patch got in. I noticed
tests failing on Windows [1] and added alternative .out file.
[1]
https://ci.appveyor.com/project/postgresql-cfbot/postgresql/build/1.0.5235

The version posted about two weeks ago is slightly broken - AFAICS the
float.h includes in geo_ops.c and gistproc.c need to be part of 0002,
not 0003. Attached is a version fixing that.

Barring objections, I'll get this committed over the next few days,
once I review all the individual parts once more. I'm planning to
commit the 6 parts separately, as submitted. No backpatching, as
discussed before.

+1 for no backpatching, and not merging into single big patch.

regards.

--
Kyotaro Horiguchi
NTT Open Source Software Center

#73Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Kyotaro HORIGUCHI (#72)
Re: [PATCH] Improve geometric types

On 07/27/2018 10:20 AM, Kyotaro HORIGUCHI wrote:

Thank you for taking this.

At Thu, 26 Jul 2018 17:12:50 +0200, Tomas Vondra <tomas.vondra@2ndquadrant.com> wrote in <672f4c42-6742-c1ec-e9a4-1994b815acc7@2ndquadrant.com>

On 07/11/2018 07:13 PM, Emre Hasegeli wrote:

New versions are attached after the <float.h> patch got in. I noticed
tests failing on Windows [1] and added alternative .out file.
[1]
https://ci.appveyor.com/project/postgresql-cfbot/postgresql/build/1.0.5235

The version posted about two weeks ago is slightly broken - AFAICS the
float.h includes in geo_ops.c and gistproc.c need to be part of 0002,
not 0003. Attached is a version fixing that.

Barring objections, I'll get this committed over the next few days,
once I review all the individual parts once more. I'm planning to
commit the 6 parts separately, as submitted. No backpatching, as
discussed before.

+1 for no backpatching, and not merging into single big patch.

I've committed the first two parts, after a review and testing.

As these two parts were primarily refactoring (and quite extensive),
this seems like a good place to wait if the buildfarm is happy with it.
If yes, I'll continue applying the patches that do fix/change the
behavior in various ways.

regards

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

#74Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Tomas Vondra (#73)
Re: [PATCH] Improve geometric types

On 07/29/2018 03:54 AM, Tomas Vondra wrote:

On 07/27/2018 10:20 AM, Kyotaro HORIGUCHI wrote:

Thank you for taking this.

At Thu, 26 Jul 2018 17:12:50 +0200, Tomas Vondra <tomas.vondra@2ndquadrant.com> wrote in <672f4c42-6742-c1ec-e9a4-1994b815acc7@2ndquadrant.com>

On 07/11/2018 07:13 PM, Emre Hasegeli wrote:

New versions are attached after the <float.h> patch got in. I noticed
tests failing on Windows [1] and added alternative .out file.
[1]
https://ci.appveyor.com/project/postgresql-cfbot/postgresql/build/1.0.5235

The version posted about two weeks ago is slightly broken - AFAICS the
float.h includes in geo_ops.c and gistproc.c need to be part of 0002,
not 0003. Attached is a version fixing that.

Barring objections, I'll get this committed over the next few days,
once I review all the individual parts once more. I'm planning to
commit the 6 parts separately, as submitted. No backpatching, as
discussed before.

+1 for no backpatching, and not merging into single big patch.

I've committed the first two parts, after a review and testing.

As these two parts were primarily refactoring (and quite extensive),
this seems like a good place to wait if the buildfarm is happy with it.
If yes, I'll continue applying the patches that do fix/change the
behavior in various ways.

Seems there's a couple of failures like this, so far:

*** 42,48 ****
                        s
  ---------------------------------------------
   {1,-1,1}
!  {1,-1,0}
   {-0.4,-1,-6}
   {-0.000184615384615385,-1,15.3846153846154}
   {1,-1,11}
--- 42,48 ----
                        s
  ---------------------------------------------
   {1,-1,1}
!  {1,-1,-0}
   {-0.4,-1,-6}
   {-0.000184615384615385,-1,15.3846153846154}
   {1,-1,11}
***************

It's always 0/-0 difference, and it's limited to power machines. I'll
try to get access to such system and see what's wrong.

regards

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

#75Thomas Munro
thomas.munro@enterprisedb.com
In reply to: Tomas Vondra (#74)
Re: [PATCH] Improve geometric types

On Sun, Jul 29, 2018 at 10:35 PM, Tomas Vondra
<tomas.vondra@2ndquadrant.com> wrote:

It's always 0/-0 difference, and it's limited to power machines. I'll
try to get access to such system and see what's wrong.

This is suspicious:

/* on some platforms, the preceding expression tends to produce -0 */
if (line->C == 0.0)
line->C = 0.0;

FWIW I tried this on our Linux/POWER8 box but it didn't show the problem.

--
Thomas Munro
http://www.enterprisedb.com

#76Thomas Munro
thomas.munro@enterprisedb.com
In reply to: Thomas Munro (#75)
Re: [PATCH] Improve geometric types

On Sun, Jul 29, 2018 at 10:57 PM, Thomas Munro
<thomas.munro@enterprisedb.com> wrote:

On Sun, Jul 29, 2018 at 10:35 PM, Tomas Vondra
<tomas.vondra@2ndquadrant.com> wrote:

It's always 0/-0 difference, and it's limited to power machines. I'll
try to get access to such system and see what's wrong.

This is suspicious:

/* on some platforms, the preceding expression tends to produce -0 */
if (line->C == 0.0)
line->C = 0.0;

I mean, it's suspiciously absent from the new line_construct()
function. It was introduced here:

commit 43fe90f66a0b200f6c32507428349afb45f661ca
Author: Tom Lane <tgl@sss.pgh.pa.us>
Date: Fri Oct 25 15:55:15 2013 -0400

Suppress -0 in the C field of lines computed by line_construct_pts().

It's not entirely clear why some PPC machines are generating -0 here, since
the underlying computation should be exactly 0 - 0. Perhaps there's some
wider-than-nominal-precision calculations happening? Anyway, the best way
to avoid platform-dependent results seems to be to explicitly reset -0 to
regular zero.

--
Thomas Munro
http://www.enterprisedb.com

#77Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Thomas Munro (#76)
Re: [PATCH] Improve geometric types

On 07/29/2018 01:28 PM, Thomas Munro wrote:

On Sun, Jul 29, 2018 at 10:57 PM, Thomas Munro
<thomas.munro@enterprisedb.com> wrote:

On Sun, Jul 29, 2018 at 10:35 PM, Tomas Vondra
<tomas.vondra@2ndquadrant.com> wrote:

It's always 0/-0 difference, and it's limited to power machines. I'll
try to get access to such system and see what's wrong.

This is suspicious:

/* on some platforms, the preceding expression tends to produce -0 */
if (line->C == 0.0)
line->C = 0.0;

I mean, it's suspiciously absent from the new line_construct()
function. It was introduced here:

commit 43fe90f66a0b200f6c32507428349afb45f661ca
Author: Tom Lane <tgl@sss.pgh.pa.us>
Date: Fri Oct 25 15:55:15 2013 -0400

Suppress -0 in the C field of lines computed by line_construct_pts().

It's not entirely clear why some PPC machines are generating -0 here, since
the underlying computation should be exactly 0 - 0. Perhaps there's some
wider-than-nominal-precision calculations happening? Anyway, the best way
to avoid platform-dependent results seems to be to explicitly reset -0 to
regular zero.

Hmm, I see. I think adding it to the else branch should do the trick,
then, I guess. But I'd be much happier if I could test it somewhere
before the commit.

regards

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

#78Jeff Janes
jeff.janes@gmail.com
In reply to: Tomas Vondra (#73)
Re: [PATCH] Improve geometric types

On Sat, Jul 28, 2018 at 9:54 PM, Tomas Vondra <tomas.vondra@2ndquadrant.com>
wrote:

I've committed the first two parts, after a review and testing.

I'm getting a compiler warning now:

geo_ops.c: In function 'line_closept_point':
geo_ops.c:2528:7: warning: variable 'retval' set but not used
[-Wunused-but-set-variable]
bool retval;

gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.10)

Cheers,

Jeff

Show quoted text

As these two parts were primarily refactoring (and quite extensive),
this seems like a good place to wait if the buildfarm is happy with it.
If yes, I'll continue applying the patches that do fix/change the
behavior in various ways.

regards

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

#79Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Jeff Janes (#78)
Re: [PATCH] Improve geometric types

On 07/29/2018 04:31 PM, Jeff Janes wrote:

On Sat, Jul 28, 2018 at 9:54 PM, Tomas Vondra
<tomas.vondra@2ndquadrant.com <mailto:tomas.vondra@2ndquadrant.com>> wrote:

I've committed the first two parts, after a review and testing.

I'm getting a compiler warning now:

geo_ops.c: In function 'line_closept_point':
geo_ops.c:2528:7: warning: variable 'retval' set but not used
[-Wunused-but-set-variable]
  bool  retval;
 

Yeah, the variable is apparently only used in an assert. Will fix.

regards

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

#80Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Tomas Vondra (#77)
1 attachment(s)
Re: [PATCH] Improve geometric types

On 07/29/2018 02:03 PM, Tomas Vondra wrote:

On 07/29/2018 01:28 PM, Thomas Munro wrote:

On Sun, Jul 29, 2018 at 10:57 PM, Thomas Munro
<thomas.munro@enterprisedb.com> wrote:

On Sun, Jul 29, 2018 at 10:35 PM, Tomas Vondra
<tomas.vondra@2ndquadrant.com> wrote:

It's always 0/-0 difference, and it's limited to power machines. I'll
try to get access to such system and see what's wrong.

This is suspicious:

/* on some platforms, the preceding expression tends to produce -0 */
if (line->C == 0.0)
line->C = 0.0;

I mean, it's suspiciously absent from the new line_construct()
function. It was introduced here:

commit 43fe90f66a0b200f6c32507428349afb45f661ca
Author: Tom Lane <tgl@sss.pgh.pa.us>
Date: Fri Oct 25 15:55:15 2013 -0400

Suppress -0 in the C field of lines computed by line_construct_pts().

It's not entirely clear why some PPC machines are generating -0 here, since
the underlying computation should be exactly 0 - 0. Perhaps there's some
wider-than-nominal-precision calculations happening? Anyway, the best way
to avoid platform-dependent results seems to be to explicitly reset -0 to
regular zero.

Hmm, I see. I think adding it to the else branch should do the trick,
then, I guess. But I'd be much happier if I could test it somewhere
before the commit.

FWIW I think this should fix it. Can someone with access to an affected
machine confirm?

regards

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

Attachments:

zero-handling.patchtext/x-patch; name=zero-handling.patchDownload
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 1fb2ff2603..fefb03ee86 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -1024,6 +1024,9 @@ line_construct(LINE *result, Point *pt, float8 m)
 		result->A = m;
 		result->B = -1.0;
 		result->C = pt->y - m * pt->x;
+		/* on some platforms, the preceding expression tends to produce -0 */
+		if (line->C == 0.0)
+			line->C = 0.0;
 	}
 }
 
#81Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Tomas Vondra (#80)
1 attachment(s)
Re: [PATCH] Improve geometric types

On 07/29/2018 05:14 PM, Tomas Vondra wrote:

On 07/29/2018 02:03 PM, Tomas Vondra wrote:

...

Hmm, I see. I think adding it to the else branch should do the trick,
then, I guess. But I'd be much happier if I could test it somewhere
before the commit.

FWIW I think this should fix it. Can someone with access to an affected
machine confirm?

Gah, shouldn't have posted before trying to compile it. Here is a fixed
version of the fix.

regards

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

Attachments:

zero-handling-v2.patchtext/x-patch; name=zero-handling-v2.patchDownload
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 1fb2ff2603..621b5c33ef 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -1024,6 +1024,9 @@ line_construct(LINE *result, Point *pt, float8 m)
 		result->A = m;
 		result->B = -1.0;
 		result->C = pt->y - m * pt->x;
+		/* on some platforms, the preceding expression tends to produce -0 */
+		if (result->C == 0.0)
+			result->C = 0.0;
 	}
 }
 
#82Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tomas Vondra (#81)
Re: [PATCH] Improve geometric types

Tomas Vondra <tomas.vondra@2ndquadrant.com> writes:

On 07/29/2018 05:14 PM, Tomas Vondra wrote:

FWIW I think this should fix it. Can someone with access to an affected
machine confirm?

Gah, shouldn't have posted before trying to compile it. Here is a fixed
version of the fix.

Sure, I'll try this on prairiedog. It's slow though ...

regards, tom lane

#83Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tom Lane (#82)
Re: [PATCH] Improve geometric types

I wrote:

Tomas Vondra <tomas.vondra@2ndquadrant.com> writes:

On 07/29/2018 05:14 PM, Tomas Vondra wrote:

FWIW I think this should fix it. Can someone with access to an affected
machine confirm?

Gah, shouldn't have posted before trying to compile it. Here is a fixed
version of the fix.

Sure, I'll try this on prairiedog. It's slow though ...

Yup, this fixes the core regression tests on that machine.
I was too lazy to try contrib.

regards, tom lane

#84Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Tom Lane (#83)
Re: [PATCH] Improve geometric types

On 07/29/2018 08:02 PM, Tom Lane wrote:

I wrote:

Tomas Vondra <tomas.vondra@2ndquadrant.com> writes:

On 07/29/2018 05:14 PM, Tomas Vondra wrote:

FWIW I think this should fix it. Can someone with access to an affected
machine confirm?

Gah, shouldn't have posted before trying to compile it. Here is a fixed
version of the fix.

Sure, I'll try this on prairiedog. It's slow though ...

Yup, this fixes the core regression tests on that machine.
I was too lazy to try contrib.

OK, thanks for confirming. I'll get it committed and we'll see what the
animals think soon.

regards

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

#85Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Tomas Vondra (#79)
1 attachment(s)
Re: [PATCH] Improve geometric types

On 07/29/2018 05:11 PM, Tomas Vondra wrote:

On 07/29/2018 04:31 PM, Jeff Janes wrote:

On Sat, Jul 28, 2018 at 9:54 PM, Tomas Vondra
<tomas.vondra@2ndquadrant.com <mailto:tomas.vondra@2ndquadrant.com>> wrote:

I've committed the first two parts, after a review and testing.

I'm getting a compiler warning now:

geo_ops.c: In function 'line_closept_point':
geo_ops.c:2528:7: warning: variable 'retval' set but not used
[-Wunused-but-set-variable]
  bool  retval;
 

Yeah, the variable is apparently only used in an assert. Will fix.

This should fix it I guess, and it's how we deal with unused return
values elsewhere. I've considered using USE_ASSERT_CHECKING here, but it
seems rather ugly with that. I'll wait for Emre's opinion ...

regards

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

Attachments:

geo-compiler-warning.patchtext/x-patch; name=geo-compiler-warning.patchDownload
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 621b5c33ef..7e53ab819c 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -2535,7 +2535,11 @@ line_closept_point(Point *result, LINE *line, Point *point)
 	/* We drop a perpendicular to find the intersection point. */
 	line_construct(&tmp, point, line_invsl(line));
 	retval = line_interpt_line(&closept, line, &tmp);
-	Assert(retval);		/* XXX: We need something better. */
+
+	/* For perpendicular lines, the intersection should exist. */
+	Assert(retval);
+
+	(void) retval;	/* silence compiler warning in non-assert builds */
 
 	if (result != NULL)
 		*result = closept;
#86Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tomas Vondra (#85)
Re: [PATCH] Improve geometric types

Tomas Vondra <tomas.vondra@2ndquadrant.com> writes:

This should fix it I guess, and it's how we deal with unused return
values elsewhere. I've considered using USE_ASSERT_CHECKING here, but it
seems rather ugly with that. I'll wait for Emre's opinion ...

I think what you want is to mark the variable with
PG_USED_FOR_ASSERTS_ONLY.

regards, tom lane

#87Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Tom Lane (#86)
Re: [PATCH] Improve geometric types

On 07/29/2018 10:57 PM, Tom Lane wrote:

Tomas Vondra <tomas.vondra@2ndquadrant.com> writes:

This should fix it I guess, and it's how we deal with unused return
values elsewhere. I've considered using USE_ASSERT_CHECKING here, but it
seems rather ugly with that. I'll wait for Emre's opinion ...

I think what you want is to mark the variable with
PG_USED_FOR_ASSERTS_ONLY.

Oh, good idea. I don't think I've ever used that macro and I've
completely forgotten about it. Committed that way.

regards

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

#88Emre Hasegeli
emre@hasegeli.com
In reply to: Tomas Vondra (#85)
Re: [PATCH] Improve geometric types

This should fix it I guess, and it's how we deal with unused return
values elsewhere. I've considered using USE_ASSERT_CHECKING here, but it
seems rather ugly with that. I'll wait for Emre's opinion ...

Assert() is the wrong thing to do in here. Drawn-perpendicular lines
may not intersect because of precision loss. We have to check it and
return NULL. There a few of those that we crash, or return garbage,
or get NULL and fail in DirectFunctionCall()s. The next patch
"line-fixes" fixes them.

#89Emre Hasegeli
emre@hasegeli.com
In reply to: Tomas Vondra (#84)
Re: [PATCH] Improve geometric types

OK, thanks for confirming. I'll get it committed and we'll see what the
animals think soon.

Thank you for fixing this. I wanted to preserve this code but wasn't
sure about the correct place or whether it is still necessary.

There are more places we produce -0. The regression tests have
alternative results to cover them. I have the "float-zero" patch for
this. Although I am not sure if it is a correct fix. I think we
should find the correct fix, and apply it globally to floating point
operations. This can be only enabled for platforms which produce -0,
so the others don't have to pay the price.

#90Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Emre Hasegeli (#89)
Re: [PATCH] Improve geometric types

On 07/30/2018 11:57 AM, Emre Hasegeli wrote:

OK, thanks for confirming. I'll get it committed and we'll see what the
animals think soon.

Thank you for fixing this. I wanted to preserve this code but wasn't
sure about the correct place or whether it is still necessary.

There are more places we produce -0. The regression tests have
alternative results to cover them. I have the "float-zero" patch for
this. Although I am not sure if it is a correct fix. I think we
should find the correct fix, and apply it globally to floating point
operations. This can be only enabled for platforms which produce -0,
so the others don't have to pay the price.

Hmmm. It'll be difficult to review such patch without access to a
platform exhibiting such behavior ... IIRC IBM offers free access to
open-source devs, I wonder if that would be a way.

regards

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

#91Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Emre Hasegeli (#89)
Re: [PATCH] Improve geometric types

Hi Emre,

Now that the buildfarm is no longer complaining about 0001 and 0002, I'm
working on reviewing and committing 0003. It seems quite straightforward
but I do have couple of comment/questions:

1) common_entry_cmp is still handling 'delta' as double, although the
CommonEntry was modified to use float8. IMHO it should also simply call
float8_cmp_internal instead of doing comparisons.

2) gist_box_picksplit does this

int m = ceil(LIMIT_RATIO * (float8) nentries);

instead of

int m = ceil(LIMIT_RATIO * (double) nentries);

which seems rather unnecessary, considering the only point of the cast
was probably to do more accurate multiplication. And it seems pointless
to cast it to float8 but then not use float8_mul().

3) computeDistance does this:

if (point->y > box->high.y)
result = float8_mi(point->y, box->high.y);
else if (point->y < box->low.y)
result = float8_mi(box->low.y, point->y);

which seems suspicious. Shouldn't the comparisons be done by float8_lt
and float8_gt too? That's what we do elsewhere.

4) I think we should just get rid of GEODEBUG entirely. The preceding
patches removes about 20 out of 27 occurrences anyway, so let's ditch
the remaining few.

regards

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

#92Emre Hasegeli
emre@hasegeli.com
In reply to: Tomas Vondra (#91)
Re: [PATCH] Improve geometric types

1) common_entry_cmp is still handling 'delta' as double, although the
CommonEntry was modified to use float8. IMHO it should also simply call
float8_cmp_internal instead of doing comparisons.

I am changing it to define delta as "float8" and to use float8_cmp_internal().

2) gist_box_picksplit does this

int m = ceil(LIMIT_RATIO * (float8) nentries);

instead of

int m = ceil(LIMIT_RATIO * (double) nentries);

which seems rather unnecessary, considering the only point of the cast was
probably to do more accurate multiplication. And it seems pointless to cast
it to float8 but then not use float8_mul().

I am removing the cast.

3) computeDistance does this:

if (point->y > box->high.y)
result = float8_mi(point->y, box->high.y);
else if (point->y < box->low.y)
result = float8_mi(box->low.y, point->y);

which seems suspicious. Shouldn't the comparisons be done by float8_lt and
float8_gt too? That's what we do elsewhere.

I assumed the GiST code already handles NaNs correctly and tried not
to change its behavior. It may be a good idea to revert existing NaN
handling in favour of using the inline functions every time. Should I
do that?

4) I think we should just get rid of GEODEBUG entirely. The preceding
patches removes about 20 out of 27 occurrences anyway, so let's ditch the
remaining few.

I agree. Shall I append it to this patch?

#93Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Emre Hasegeli (#92)
Re: [PATCH] Improve geometric types

On 07/31/2018 05:14 PM, Emre Hasegeli wrote:

1) common_entry_cmp is still handling 'delta' as double, although the
CommonEntry was modified to use float8. IMHO it should also simply call
float8_cmp_internal instead of doing comparisons.

I am changing it to define delta as "float8" and to use float8_cmp_internal().

2) gist_box_picksplit does this

int m = ceil(LIMIT_RATIO * (float8) nentries);

instead of

int m = ceil(LIMIT_RATIO * (double) nentries);

which seems rather unnecessary, considering the only point of the cast was
probably to do more accurate multiplication. And it seems pointless to cast
it to float8 but then not use float8_mul().

I am removing the cast.

3) computeDistance does this:

if (point->y > box->high.y)
result = float8_mi(point->y, box->high.y);
else if (point->y < box->low.y)
result = float8_mi(box->low.y, point->y);

which seems suspicious. Shouldn't the comparisons be done by float8_lt and
float8_gt too? That's what we do elsewhere.

I assumed the GiST code already handles NaNs correctly and tried not
to change its behavior. It may be a good idea to revert existing NaN
handling in favour of using the inline functions every time. Should I
do that?

Ah, so there's an assumption that NaNs are handled earlier and never
reach this place? That's probably a safe assumption. I haven't thought
about that, it simply seemed suspicious that the code mixes direct
comparisons and float8_mi() calls.

4) I think we should just get rid of GEODEBUG entirely. The preceding
patches removes about 20 out of 27 occurrences anyway, so let's ditch the
remaining few.

I agree. Shall I append it to this patch?

Not sure, I'll leave that up to you. I don't mind doing it in a separate
patch (I'd probably prefer that over mixing it into unrelated patch).

regards

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

#94Emre Hasegeli
emre@hasegeli.com
In reply to: Tomas Vondra (#93)
4 attachment(s)
Re: [PATCH] Improve geometric types

Ah, so there's an assumption that NaNs are handled earlier and never reach
this place? That's probably a safe assumption. I haven't thought about that,
it simply seemed suspicious that the code mixes direct comparisons and
float8_mi() calls.

The comparison functions handle NaNs. The arithmetic functions handle
returning error on underflow, overflow and division by zero. I
assumed we want to return error on those in any case, but we don't
want to handle NaNs at every place.

Not sure, I'll leave that up to you. I don't mind doing it in a separate
patch (I'd probably prefer that over mixing it into unrelated patch).

It is attached separately.

Attachments:

0001-geo-debug-v00.patchapplication/octet-stream; name=0001-geo-debug-v00.patchDownload
From b914483dcd7e71331842c9a83032b2ceea95522b Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Wed, 1 Aug 2018 12:53:52 +0200
Subject: [PATCH 1/4] geo-debug-v00

Remove GEODEBUG
---
 src/backend/utils/adt/geo_ops.c | 27 ---------------------------
 1 file changed, 27 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 4490f933ba..bd8e21775d 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -2416,48 +2416,37 @@ dist_polyp(PG_FUNCTION_ARGS)
 
 static double
 dist_ppoly_internal(Point *pt, POLYGON *poly)
 {
 	float8		result;
 	float8		d;
 	int			i;
 	LSEG		seg;
 
 	if (point_inside(pt, poly->npts, poly->p) != 0)
-	{
-#ifdef GEODEBUG
-		printf("dist_ppoly_internal- point inside of polygon\n");
-#endif
 		return 0.0;
-	}
 
 	/* initialize distance with segment between first and last points */
 	seg.p[0].x = poly->p[0].x;
 	seg.p[0].y = poly->p[0].y;
 	seg.p[1].x = poly->p[poly->npts - 1].x;
 	seg.p[1].y = poly->p[poly->npts - 1].y;
 	result = lseg_closept_point(NULL, &seg, pt);
-#ifdef GEODEBUG
-	printf("dist_ppoly_internal- segment 0/n distance is %f\n", result);
-#endif
 
 	/* check distances for other segments */
 	for (i = 0; i < poly->npts - 1; i++)
 	{
 		seg.p[0].x = poly->p[i].x;
 		seg.p[0].y = poly->p[i].y;
 		seg.p[1].x = poly->p[i + 1].x;
 		seg.p[1].y = poly->p[i + 1].y;
 		d = lseg_closept_point(NULL, &seg, pt);
-#ifdef GEODEBUG
-		printf("dist_ppoly_internal- segment %d distance is %f\n", (i + 1), d);
-#endif
 		if (d < result)
 			result = d;
 	}
 
 	return result;
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
@@ -5226,49 +5215,33 @@ plist_same(int npts, Point *p1, Point *p2)
 	{
 		if (point_eq_point(&p2[i], &p1[0]))
 		{
 
 			/* match found? then look forward through remaining points */
 			for (ii = 1, j = i + 1; ii < npts; ii++, j++)
 			{
 				if (j >= npts)
 					j = 0;
 				if (!point_eq_point(&p2[j], &p1[ii]))
-				{
-#ifdef GEODEBUG
-					printf("plist_same- %d failed forward match with %d\n", j, ii);
-#endif
 					break;
-				}
 			}
-#ifdef GEODEBUG
-			printf("plist_same- ii = %d/%d after forward match\n", ii, npts);
-#endif
 			if (ii == npts)
 				return true;
 
 			/* match not found forwards? then look backwards */
 			for (ii = 1, j = i - 1; ii < npts; ii++, j--)
 			{
 				if (j < 0)
 					j = (npts - 1);
 				if (!point_eq_point(&p2[j], &p1[ii]))
-				{
-#ifdef GEODEBUG
-					printf("plist_same- %d failed reverse match with %d\n", j, ii);
-#endif
 					break;
-				}
 			}
-#ifdef GEODEBUG
-			printf("plist_same- ii = %d/%d after reverse match\n", ii, npts);
-#endif
 			if (ii == npts)
 				return true;
 		}
 	}
 
 	return false;
 }
 
 
 /*-------------------------------------------------------------------------
-- 
2.14.3 (Apple Git-98)

0002-geo-float-v14.patchapplication/octet-stream; name=0002-geo-float-v14.patchDownload
From 70fe6c4164d21e86fb80f5902345a50597efbb44 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Tue, 31 Jul 2018 16:50:59 +0200
Subject: [PATCH 2/4] geo-float-v14

Use the built-in float datatype to implement geometric types

This patch makes the geometric operators and functions use the exported
function of the float datatype.  The main reason of doing so is to check
for underflow and overflow, and to handle NaNs consciously.

The float datatypes consider NaNs to be equal and greater than any
non-NaN.  This change considers NaNs equal only for the equality
operators.  The placement operators, contains, overlaps, left/right of
etc. continues to return false when NaNs are involved.  We don't need
to worry about them being considered greater than any-NaN because there
aren't any basic comparison operators like less/greater than for the
geometric datatypes.

All changes can be summarised as:

* Check for underflow and overflow
* Check for division by zero
* Let the objects with NaN values to be the same
* Return NULL when the distance is NaN for all closest point operators
* Favour not-NaN over NaN where it makes sense

The patch also replaces all occurrences of "double" as "float8".  They
are the same, but were randomly spread on the same file.

Discussion:
https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com
---
 src/backend/access/gist/gistproc.c | 100 ++++----
 src/backend/utils/adt/geo_ops.c    | 499 ++++++++++++++++++++-----------------
 src/backend/utils/adt/geo_spgist.c |  28 +--
 src/include/utils/geo_decls.h      |  19 +-
 4 files changed, 342 insertions(+), 304 deletions(-)

diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index d6ce5ccf6c..c3383bd6da 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -48,55 +48,56 @@ rt_box_union(BOX *n, const BOX *a, const BOX *b)
 	n->high.x = float8_max(a->high.x, b->high.x);
 	n->high.y = float8_max(a->high.y, b->high.y);
 	n->low.x = float8_min(a->low.x, b->low.x);
 	n->low.y = float8_min(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
 	if (float8_le(box->high.x, box->low.x) ||
 		float8_le(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
-	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
+	return float8_mul(float8_mi(box->high.x, box->low.x),
+					  float8_mi(box->high.y, box->low.y));
 }
 
 /*
  * Return amount by which the union of the two boxes is larger than
  * the original BOX's area.  The result can be +Infinity, but not NaN.
  */
-static double
+static float8
 box_penalty(const BOX *original, const BOX *new)
 {
 	BOX			unionbox;
 
 	rt_box_union(&unionbox, original, new);
-	return size_box(&unionbox) - size_box(original);
+	return float8_mi(size_box(&unionbox), size_box(original));
 }
 
 /*
  * The GiST Consistent method for boxes
  *
  * Should return false if for all data items x below entry,
  * the predicate x op query must be false, where op is the oper
  * corresponding to strategy in the pg_amop table.
  */
 Datum
@@ -256,74 +257,74 @@ fallbackSplit(GistEntryVector *entryvec, GIST_SPLITVEC *v)
 
 /*
  * Represents information about an entry that can be placed to either group
  * without affecting overlap over selected axis ("common entry").
  */
 typedef struct
 {
 	/* Index of entry in the initial array */
 	int			index;
 	/* Delta between penalties of entry insertion into different groups */
-	double		delta;
+	float8		delta;
 } CommonEntry;
 
 /*
  * Context for g_box_consider_split. Contains information about currently
  * selected split and some general information.
  */
 typedef struct
 {
 	int			entriesCount;	/* total number of entries being split */
 	BOX			boundingBox;	/* minimum bounding box across all entries */
 
 	/* Information about currently selected split follows */
 
 	bool		first;			/* true if no split was selected yet */
 
-	double		leftUpper;		/* upper bound of left interval */
-	double		rightLower;		/* lower bound of right interval */
+	float8		leftUpper;		/* upper bound of left interval */
+	float8		rightLower;		/* lower bound of right interval */
 
 	float4		ratio;
 	float4		overlap;
 	int			dim;			/* axis of this split */
-	double		range;			/* width of general MBR projection to the
+	float8		range;			/* width of general MBR projection to the
 								 * selected axis */
 } ConsiderSplitContext;
 
 /*
  * Interval represents projection of box to axis.
  */
 typedef struct
 {
-	double		lower,
+	float8		lower,
 				upper;
 } SplitInterval;
 
 /*
  * Interval comparison function by lower bound of the interval;
  */
 static int
 interval_cmp_lower(const void *i1, const void *i2)
 {
-	double		lower1 = ((const SplitInterval *) i1)->lower,
+	float8		lower1 = ((const SplitInterval *) i1)->lower,
 				lower2 = ((const SplitInterval *) i2)->lower;
 
 	return float8_cmp_internal(lower1, lower2);
 }
 
 /*
  * Interval comparison function by upper bound of the interval;
  */
 static int
 interval_cmp_upper(const void *i1, const void *i2)
 {
-	double		upper1 = ((const SplitInterval *) i1)->upper,
+	float8		upper1 = ((const SplitInterval *) i1)->upper,
 				upper2 = ((const SplitInterval *) i2)->upper;
 
 	return float8_cmp_internal(upper1, upper2);
 }
 
 /*
  * Replace negative (or NaN) value with zero.
  */
 static inline float
 non_negative(float val)
@@ -332,28 +333,28 @@ non_negative(float val)
 		return val;
 	else
 		return 0.0f;
 }
 
 /*
  * Consider replacement of currently selected split with the better one.
  */
 static inline void
 g_box_consider_split(ConsiderSplitContext *context, int dimNum,
-					 double rightLower, int minLeftCount,
-					 double leftUpper, int maxLeftCount)
+					 float8 rightLower, int minLeftCount,
+					 float8 leftUpper, int maxLeftCount)
 {
 	int			leftCount,
 				rightCount;
 	float4		ratio,
 				overlap;
-	double		range;
+	float8		range;
 
 	/*
 	 * Calculate entries distribution ratio assuming most uniform distribution
 	 * of common entries.
 	 */
 	if (minLeftCount >= (context->entriesCount + 1) / 2)
 	{
 		leftCount = minLeftCount;
 	}
 	else
@@ -362,40 +363,41 @@ g_box_consider_split(ConsiderSplitContext *context, int dimNum,
 			leftCount = maxLeftCount;
 		else
 			leftCount = context->entriesCount / 2;
 	}
 	rightCount = context->entriesCount - leftCount;
 
 	/*
 	 * Ratio of split - quotient between size of lesser group and total
 	 * entries count.
 	 */
-	ratio = ((float4) Min(leftCount, rightCount)) /
-		((float4) context->entriesCount);
+	ratio = float4_div(Min(leftCount, rightCount), context->entriesCount);
 
 	if (ratio > LIMIT_RATIO)
 	{
 		bool		selectthis = false;
 
 		/*
 		 * The ratio is acceptable, so compare current split with previously
 		 * selected one. Between splits of one dimension we search for minimal
 		 * overlap (allowing negative values) and minimal ration (between same
 		 * overlaps. We switch dimension if find less overlap (non-negative)
 		 * or less range with same overlap.
 		 */
 		if (dimNum == 0)
-			range = context->boundingBox.high.x - context->boundingBox.low.x;
+			range = float8_mi(context->boundingBox.high.x,
+							  context->boundingBox.low.x);
 		else
-			range = context->boundingBox.high.y - context->boundingBox.low.y;
+			range = float8_mi(context->boundingBox.high.y,
+							  context->boundingBox.low.y);
 
-		overlap = (leftUpper - rightLower) / range;
+		overlap = float8_div(float8_mi(leftUpper, rightLower), range);
 
 		/* If there is no previous selection, select this */
 		if (context->first)
 			selectthis = true;
 		else if (context->dim == dimNum)
 		{
 			/*
 			 * Within the same dimension, choose the new split if it has a
 			 * smaller overlap, or same overlap but better ratio.
 			 */
@@ -437,34 +439,28 @@ g_box_consider_split(ConsiderSplitContext *context, int dimNum,
 			context->overlap = overlap;
 			context->rightLower = rightLower;
 			context->leftUpper = leftUpper;
 			context->dim = dimNum;
 		}
 	}
 }
 
 /*
  * Compare common entries by their deltas.
- * (We assume the deltas can't be NaN.)
  */
 static int
 common_entry_cmp(const void *i1, const void *i2)
 {
-	double		delta1 = ((const CommonEntry *) i1)->delta,
+	float8		delta1 = ((const CommonEntry *) i1)->delta,
 				delta2 = ((const CommonEntry *) i2)->delta;
 
-	if (delta1 < delta2)
-		return -1;
-	else if (delta1 > delta2)
-		return 1;
-	else
-		return 0;
+	return float8_cmp_internal(delta1, delta2);
 }
 
 /*
  * --------------------------------------------------------------------------
  * Double sorting split algorithm. This is used for both boxes and points.
  *
  * The algorithm finds split of boxes by considering splits along each axis.
  * Each entry is first projected as an interval on the X-axis, and different
  * ways to split the intervals into two groups are considered, trying to
  * minimize the overlap of the groups. Then the same is repeated for the
@@ -524,21 +520,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		else
 			adjustBox(&context.boundingBox, box);
 	}
 
 	/*
 	 * Iterate over axes for optimal split searching.
 	 */
 	context.first = true;		/* nothing selected yet */
 	for (dim = 0; dim < 2; dim++)
 	{
-		double		leftUpper,
+		float8		leftUpper,
 					rightLower;
 		int			i1,
 					i2;
 
 		/* Project each entry as an interval on the selected axis. */
 		for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 		{
 			box = DatumGetBoxP(entryvec->vector[i].key);
 			if (dim == 0)
 			{
@@ -721,21 +717,21 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 			*rightBox = *(box);					\
 		v->spl_right[v->spl_nright++] = off;	\
 	} while(0)
 
 	/*
 	 * Distribute entries which can be distributed unambiguously, and collect
 	 * common entries.
 	 */
 	for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 	{
-		double		lower,
+		float8		lower,
 					upper;
 
 		/*
 		 * Get upper and lower bounds along selected axis.
 		 */
 		box = DatumGetBoxP(entryvec->vector[i].key);
 		if (context.dim == 0)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
@@ -776,31 +772,31 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
 	{
 		/*
 		 * Calculate minimum number of entries that must be placed in both
 		 * groups, to reach LIMIT_RATIO.
 		 */
-		int			m = ceil(LIMIT_RATIO * (double) nentries);
+		int			m = ceil(LIMIT_RATIO * nentries);
 
 		/*
 		 * Calculate delta between penalties of join "common entries" to
 		 * different groups.
 		 */
 		for (i = 0; i < commonEntriesCount; i++)
 		{
 			box = DatumGetBoxP(entryvec->vector[commonEntries[i].index].key);
-			commonEntries[i].delta = Abs(box_penalty(leftBox, box) -
-										 box_penalty(rightBox, box));
+			commonEntries[i].delta = Abs(float8_mi(box_penalty(leftBox, box),
+												   box_penalty(rightBox, box)));
 		}
 
 		/*
 		 * Sort "common entries" by calculated deltas in order to distribute
 		 * the most ambiguous entries first.
 		 */
 		qsort(commonEntries, commonEntriesCount, sizeof(CommonEntry), common_entry_cmp);
 
 		/*
 		 * Distribute "common entries" between groups.
@@ -1100,24 +1096,24 @@ gist_circle_compress(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	GISTENTRY  *retval;
 
 	if (entry->leafkey)
 	{
 		CIRCLE	   *in = DatumGetCircleP(entry->key);
 		BOX		   *r;
 
 		r = (BOX *) palloc(sizeof(BOX));
-		r->high.x = in->center.x + in->radius;
-		r->low.x = in->center.x - in->radius;
-		r->high.y = in->center.y + in->radius;
-		r->low.y = in->center.y - in->radius;
+		r->high.x = float8_pl(in->center.x, in->radius);
+		r->low.x = float8_mi(in->center.x, in->radius);
+		r->high.y = float8_pl(in->center.y, in->radius);
+		r->low.y = float8_mi(in->center.y, in->radius);
 
 		retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
 		gistentryinit(*retval, PointerGetDatum(r),
 					  entry->rel, entry->page,
 					  entry->offset, false);
 	}
 	else
 		retval = entry;
 	PG_RETURN_POINTER(retval);
 }
@@ -1141,24 +1137,24 @@ gist_circle_consistent(PG_FUNCTION_ARGS)
 	*recheck = true;
 
 	if (DatumGetBoxP(entry->key) == NULL || query == NULL)
 		PG_RETURN_BOOL(false);
 
 	/*
 	 * Since the operators require recheck anyway, we can just use
 	 * rtree_internal_consistent even at leaf nodes.  (This works in part
 	 * because the index entries are bounding boxes not circles.)
 	 */
-	bbox.high.x = query->center.x + query->radius;
-	bbox.low.x = query->center.x - query->radius;
-	bbox.high.y = query->center.y + query->radius;
-	bbox.low.y = query->center.y - query->radius;
+	bbox.high.x = float8_pl(query->center.x, query->radius);
+	bbox.low.x = float8_mi(query->center.x, query->radius);
+	bbox.high.y = float8_pl(query->center.y, query->radius);
+	bbox.low.y = float8_mi(query->center.y, query->radius);
 
 	result = rtree_internal_consistent(DatumGetBoxP(entry->key),
 									   &bbox, strategy);
 
 	PG_RETURN_BOOL(result);
 }
 
 /**************************************************
  * Point ops
  **************************************************/
@@ -1209,63 +1205,63 @@ gist_point_fetch(PG_FUNCTION_ARGS)
 				  entry->offset, false);
 
 	PG_RETURN_POINTER(retval);
 }
 
 
 #define point_point_distance(p1,p2) \
 	DatumGetFloat8(DirectFunctionCall2(point_distance, \
 									   PointPGetDatum(p1), PointPGetDatum(p2)))
 
-static double
+static float8
 computeDistance(bool isLeaf, BOX *box, Point *point)
 {
-	double		result = 0.0;
+	float8		result = 0.0;
 
 	if (isLeaf)
 	{
 		/* simple point to point distance */
 		result = point_point_distance(point, &box->low);
 	}
 	else if (point->x <= box->high.x && point->x >= box->low.x &&
 			 point->y <= box->high.y && point->y >= box->low.y)
 	{
 		/* point inside the box */
 		result = 0.0;
 	}
 	else if (point->x <= box->high.x && point->x >= box->low.x)
 	{
 		/* point is over or below box */
 		Assert(box->low.y <= box->high.y);
 		if (point->y > box->high.y)
-			result = point->y - box->high.y;
+			result = float8_mi(point->y, box->high.y);
 		else if (point->y < box->low.y)
-			result = box->low.y - point->y;
+			result = float8_mi(box->low.y, point->y);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
 	else if (point->y <= box->high.y && point->y >= box->low.y)
 	{
 		/* point is to left or right of box */
 		Assert(box->low.x <= box->high.x);
 		if (point->x > box->high.x)
-			result = point->x - box->high.x;
+			result = float8_mi(point->x, box->high.x);
 		else if (point->x < box->low.x)
-			result = box->low.x - point->x;
+			result = float8_mi(box->low.x, point->x);
 		else
 			elog(ERROR, "inconsistent point values");
 	}
 	else
 	{
 		/* closest point will be a vertex */
 		Point		p;
-		double		subresult;
+		float8		subresult;
 
 		result = point_point_distance(point, &box->low);
 
 		subresult = point_point_distance(point, &box->high);
 		if (result > subresult)
 			result = subresult;
 
 		p.x = box->low.x;
 		p.y = box->high.y;
 		subresult = point_point_distance(point, &p);
@@ -1442,21 +1438,21 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 	}
 
 	PG_RETURN_BOOL(result);
 }
 
 Datum
 gist_point_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(GIST_LEAF(entry),
 									   DatumGetBoxP(entry->key),
 									   PG_GETARG_POINT_P(1));
 			break;
 		default:
@@ -1471,25 +1467,25 @@ gist_point_distance(PG_FUNCTION_ARGS)
 /*
  * The inexact GiST distance method for geometric types that store bounding
  * boxes.
  *
  * Compute lossy distance from point to index entries.  The result is inexact
  * because index entries are bounding boxes, not the exact shapes of the
  * indexed geometric types.  We use distance from point to MBR of index entry.
  * This is a lower bound estimate of distance from point to indexed geometric
  * type.
  */
-static double
+static float8
 gist_bbox_distance(GISTENTRY *entry, Datum query,
 				   StrategyNumber strategy, bool *recheck)
 {
-	double		distance;
+	float8		distance;
 	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 
 	/* Bounding box distance is always inexact. */
 	*recheck = true;
 
 	switch (strategyGroup)
 	{
 		case PointStrategyNumberGroup:
 			distance = computeDistance(false,
 									   DatumGetBoxP(entry->key),
@@ -1505,32 +1501,32 @@ gist_bbox_distance(GISTENTRY *entry, Datum query,
 
 Datum
 gist_circle_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
 
 Datum
 gist_poly_distance(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	Datum		query = PG_GETARG_DATUM(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	double		distance;
+	float8		distance;
 
 	distance = gist_bbox_distance(entry, query, strategy, recheck);
 
 	PG_RETURN_FLOAT8(distance);
 }
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index bd8e21775d..13dc1ab6e6 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -52,56 +52,56 @@ static inline float8 line_invsl(LINE *line);
 static bool	line_interpt_line(Point *result, LINE *l1, LINE *l2);
 static bool line_contain_point(LINE *line, Point *point);
 static float8 line_closept_point(Point *result, LINE *line, Point *pt);
 
 /* Routines for line segments */
 static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
 static inline float8 lseg_sl(LSEG *lseg);
 static inline float8 lseg_invsl(LSEG *lseg);
 static bool	lseg_interpt_line(Point *result, LSEG *lseg, LINE *line);
 static bool	lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2);
-static int	lseg_crossing(double x, double y, double px, double py);
+static int	lseg_crossing(float8 x, float8 y, float8 px, float8 py);
 static bool	lseg_contain_point(LSEG *lseg, Point *point);
 static float8 lseg_closept_point(Point *result, LSEG *lseg, Point *pt);
 static float8 lseg_closept_line(Point *result, LSEG *lseg, LINE *line);
 static float8 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2);
 
 /* Routines for boxes */
 static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
 static void box_cn(Point *center, BOX *box);
 static bool box_ov(BOX *box1, BOX *box2);
-static double box_ar(BOX *box);
-static double box_ht(BOX *box);
-static double box_wd(BOX *box);
+static float8 box_ar(BOX *box);
+static float8 box_ht(BOX *box);
+static float8 box_wd(BOX *box);
 static bool box_contain_point(BOX *box, Point *point);
 static bool box_contain_box(BOX *box1, BOX *box2);
 static bool box_contain_lseg(BOX *box, LSEG *lseg);
 static bool box_interpt_lseg(Point *result, BOX *box, LSEG *lseg);
 static float8 box_closept_point(Point *result, BOX *box, Point *point);
 static float8 box_closept_lseg(Point *result, BOX *box, LSEG *lseg);
 
 /* Routines for circles */
-static double circle_ar(CIRCLE *circle);
+static float8 circle_ar(CIRCLE *circle);
 
 /* Routines for polygons */
 static void make_bound_box(POLYGON *poly);
 static void poly_to_circle(CIRCLE *result, POLYGON *poly);
 static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
 static bool poly_contain_poly(POLYGON *polya, POLYGON *polyb);
 static bool plist_same(int npts, Point *p1, Point *p2);
 static float8 dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 /* Routines for encoding and decoding */
-static double single_decode(char *num, char **endptr_p,
+static float8 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
-static void pair_decode(char *str, double *x, double *y, char **endptr_p,
+static void pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
 static void path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
 			const char *type_name, const char *orig_string);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
 
 
 /*
@@ -139,38 +139,38 @@ static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
  *
  * For boxes, the points are opposite corners with the first point at the top right.
  * For closed paths and polygons, the points should be reordered to allow
  *	fast and correct equality comparisons.
  *
  * XXX perhaps points in complex shapes should be reordered internally
  *	to allow faster internal operations, but should keep track of input order
  *	and restore that order for text output - tgl 97/01/16
  */
 
-static double
+static float8
 single_decode(char *num, char **endptr_p,
 			  const char *type_name, const char *orig_string)
 {
 	return float8in_internal(num, endptr_p, type_name, orig_string);
 }								/* single_decode() */
 
 static void
 single_encode(float8 x, StringInfo str)
 {
 	char	   *xstr = float8out_internal(x);
 
 	appendStringInfoString(str, xstr);
 	pfree(xstr);
 }								/* single_encode() */
 
 static void
-pair_decode(char *str, double *x, double *y, char **endptr_p,
+pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 			const char *type_name, const char *orig_string)
 {
 	bool		has_delim;
 
 	while (isspace((unsigned char) *str))
 		str++;
 	if ((has_delim = (*str == LDELIM)))
 		str++;
 
 	*x = float8in_internal(str, &str, type_name, orig_string);
@@ -369,33 +369,33 @@ pair_count(char *s, char delim)
  *		External format: (two corners of box)
  *				"(f8, f8), (f8, f8)"
  *				also supports the older style "(f8, f8, f8, f8)"
  */
 Datum
 box_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	BOX		   *box = (BOX *) palloc(sizeof(BOX));
 	bool		isopen;
-	double		x,
+	float8		x,
 				y;
 
 	path_decode(str, false, 2, &(box->high), &isopen, NULL, "box", str);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*		box_out -		convert a box to external form.
@@ -409,38 +409,38 @@ box_out(PG_FUNCTION_ARGS)
 }
 
 /*
  *		box_recv			- converts external binary format to box
  */
 Datum
 box_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	BOX		   *box;
-	double		x,
+	float8		x,
 				y;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
 	box->high.x = pq_getmsgfloat8(buf);
 	box->high.y = pq_getmsgfloat8(buf);
 	box->low.x = pq_getmsgfloat8(buf);
 	box->low.y = pq_getmsgfloat8(buf);
 
 	/* reorder corners if necessary... */
-	if (box->high.x < box->low.x)
+	if (float8_lt(box->high.x, box->low.x))
 	{
 		x = box->high.x;
 		box->high.x = box->low.x;
 		box->low.x = x;
 	}
-	if (box->high.y < box->low.y)
+	if (float8_lt(box->high.y, box->low.y))
 	{
 		y = box->high.y;
 		box->high.y = box->low.y;
 		box->low.y = y;
 	}
 
 	PG_RETURN_BOX_P(box);
 }
 
 /*
@@ -459,31 +459,31 @@ box_send(PG_FUNCTION_ARGS)
 	pq_sendfloat8(&buf, box->low.y);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*		box_construct	-		fill in a new box.
  */
 static inline void
 box_construct(BOX *result, Point *pt1, Point *pt2)
 {
-	if (pt1->x > pt2->x)
+	if (float8_gt(pt1->x, pt2->x))
 	{
 		result->high.x = pt1->x;
 		result->low.x = pt2->x;
 	}
 	else
 	{
 		result->high.x = pt2->x;
 		result->low.x = pt1->x;
 	}
-	if (pt1->y > pt2->y)
+	if (float8_gt(pt1->y, pt2->y))
 	{
 		result->high.y = pt1->y;
 		result->low.y = pt2->y;
 	}
 	else
 	{
 		result->high.y = pt2->y;
 		result->low.y = pt1->y;
 	}
 }
@@ -801,54 +801,54 @@ box_center(PG_FUNCTION_ARGS)
 	Point	   *result = (Point *) palloc(sizeof(Point));
 
 	box_cn(result, box);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		box_ar	-		returns the area of the box.
  */
-static double
+static float8
 box_ar(BOX *box)
 {
-	return box_wd(box) * box_ht(box);
+	return float8_mul(box_wd(box), box_ht(box));
 }
 
 
 /*		box_cn	-		stores the centerpoint of the box into *center.
  */
 static void
 box_cn(Point *center, BOX *box)
 {
-	center->x = (box->high.x + box->low.x) / 2.0;
-	center->y = (box->high.y + box->low.y) / 2.0;
+	center->x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	center->y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 }
 
 
 /*		box_wd	-		returns the width (length) of the box
  *								  (horizontal magnitude).
  */
-static double
+static float8
 box_wd(BOX *box)
 {
-	return box->high.x - box->low.x;
+	return float8_mi(box->high.x, box->low.x);
 }
 
 
 /*		box_ht	-		returns the height of the box
  *								  (vertical magnitude).
  */
-static double
+static float8
 box_ht(BOX *box)
 {
-	return box->high.y - box->low.y;
+	return float8_mi(box->high.y, box->low.y);
 }
 
 
 /*----------------------------------------------------------
  *	Funky operations.
  *---------------------------------------------------------*/
 
 /*		box_intersect	-
  *				returns the overlapping portion of two boxes,
  *				  or NULL if they do not intersect.
@@ -858,24 +858,24 @@ box_intersect(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 	BOX		   *result;
 
 	if (!box_ov(box1, box2))
 		PG_RETURN_NULL();
 
 	result = (BOX *) palloc(sizeof(BOX));
 
-	result->high.x = Min(box1->high.x, box2->high.x);
-	result->low.x = Max(box1->low.x, box2->low.x);
-	result->high.y = Min(box1->high.y, box2->high.y);
-	result->low.y = Max(box1->low.y, box2->low.y);
+	result->high.x = float8_min(box1->high.x, box2->high.x);
+	result->low.x = float8_max(box1->low.x, box2->low.x);
+	result->high.y = float8_min(box1->high.y, box2->high.y);
+	result->low.y = float8_max(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(result);
 }
 
 
 /*		box_diagonal	-
  *				returns a line segment which happens to be the
  *				  positive-slope diagonal of "box".
  */
 Datum
@@ -1007,30 +1007,30 @@ line_send(PG_FUNCTION_ARGS)
 
 /*
  * Fill already-allocated LINE struct from the point and the slope
  */
 static inline void
 line_construct(LINE *result, Point *pt, float8 m)
 {
 	if (m == DBL_MAX)
 	{
 		/* vertical - use "x = C" */
-		result->A = -1;
-		result->B = 0;
+		result->A = -1.0;
+		result->B = 0.0;
 		result->C = pt->x;
 	}
 	else
 	{
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
-		result->C = pt->y - m * pt->x;
+		result->C = float8_mi(pt->y, float8_mul(m, pt->x));
 		/* on some platforms, the preceding expression tends to produce -0 */
 		if (result->C == 0.0)
 			result->C = 0.0;
 	}
 }
 
 /* line_construct_pp()
  * two points
  */
 Datum
@@ -1072,94 +1072,105 @@ Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
 	else if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
 
-	PG_RETURN_BOOL(FPeq(((l1->A * l2->B) / (l1->B * l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
+								   float8_mul(l1->B, l2->A)), -1.0));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
 Datum
 line_horizontal(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->A));
 }
 
+
+/*
+ * Check whether the two lines are the same
+ *
+ * We consider NaNs values to be equal to each other to let those lines
+ * to be found.
+ */
 Datum
 line_eq(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	double		k;
+	float8		ratio;
 
-	if (!FPzero(l2->A))
-		k = l1->A / l2->A;
-	else if (!FPzero(l2->B))
-		k = l1->B / l2->B;
-	else if (!FPzero(l2->C))
-		k = l1->C / l2->C;
+	if (!FPzero(l2->A) && !isnan(l2->A))
+		ratio = float8_div(l1->A, l2->A);
+	else if (!FPzero(l2->B) && !isnan(l2->B))
+		ratio = float8_div(l1->B, l2->B);
+	else if (!FPzero(l2->C) && !isnan(l2->C))
+		ratio = float8_div(l1->C, l2->C);
 	else
-		k = 1.0;
+		ratio = 1.0;
 
-	PG_RETURN_BOOL(FPeq(l1->A, k * l2->A) &&
-				   FPeq(l1->B, k * l2->B) &&
-				   FPeq(l1->C, k * l2->C));
+	PG_RETURN_BOOL((FPeq(l1->A, float8_mul(ratio, l2->A)) &&
+					FPeq(l1->B, float8_mul(ratio, l2->B)) &&
+					FPeq(l1->C, float8_mul(ratio, l2->C))) ||
+				   (float8_eq(l1->A, l2->A) &&
+					float8_eq(l1->B, l2->B) &&
+					float8_eq(l1->C, l2->C)));
 }
 
 
 /*----------------------------------------------------------
  *	Line arithmetic routines.
  *---------------------------------------------------------*/
 
 /*
  * Return inverse slope of the line
  */
 static inline float8
 line_invsl(LINE *line)
 {
 	if (FPzero(line->A))
 		return DBL_MAX;
 	if (FPzero(line->B))
 		return 0.0;
-	return line->B / line->A;
+	return float8_div(line->B, line->A);
 }
 
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 	float8		result;
 	Point		tmp;
 
 	if (line_interpt_line(NULL, l1, l2))	/* intersecting? */
 		PG_RETURN_FLOAT8(0.0);
 	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
+		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
 	point_construct(&tmp, 0.0, l1->C);
 	result = line_closept_point(NULL, l2, &tmp);
 	PG_RETURN_FLOAT8(result);
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
@@ -1178,47 +1189,51 @@ line_interpt(PG_FUNCTION_ARGS)
 /*
  * Internal version of line_interpt
  *
  * This returns true if two lines intersect (they do, if they are not
  * parallel), false if they do not.  This also sets the intersection point
  * to *result, if it is not NULL.
  *
  * NOTE: If the lines are identical then we will find they are parallel
  * and report "no intersection".  This is a little weird, but since
  * there's no *unique* intersection, maybe it's appropriate behavior.
+ *
+ * If the lines have NaN constants, we will return true, and the intersection
+ * point would have NaN coordinates.  We shouldn't return false in this case
+ * because that would mean the lines are parallel.
  */
 static bool
 line_interpt_line(Point *result, LINE *l1, LINE *l2)
 {
-	double		x,
+	float8		x,
 				y;
 
 	if (FPzero(l1->B))			/* l1 vertical? */
 	{
 		if (FPzero(l2->B))		/* l2 vertical? */
 			return false;
 
 		x = l1->C;
-		y = (l2->A * x + l2->C);
+		y = float8_pl(float8_mul(l2->A, x), l2->C);
 	}
 	else if (FPzero(l2->B))		/* l2 vertical? */
 	{
 		x = l2->C;
-		y = (l1->A * x + l1->C);
+		y = float8_pl(float8_mul(l1->A, x), l1->C);
 	}
 	else
 	{
-		if (FPeq(l2->A, l1->A * (l2->B / l1->B)))
+		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
 			return false;
 
-		x = (l1->C - l2->C) / (l2->A - l1->A);
-		y = (l1->A * x + l1->C);
+		x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
+		y = float8_pl(float8_mul(l1->A, x), l1->C);
 	}
 
 	if (result != NULL)
 		point_construct(result, x, y);
 
 	return true;
 }
 
 
 /***********************************************************************
@@ -1240,36 +1255,35 @@ line_interpt_line(Point *result, LINE *l1, LINE *l2)
  *				"(xcoord, ycoord),... "
  *				"[xcoord, ycoord,... ]"
  *		Also support older format:
  *				"(closed, npts, xcoord, ycoord,... )"
  *---------------------------------------------------------*/
 
 Datum
 path_area(PG_FUNCTION_ARGS)
 {
 	PATH	   *path = PG_GETARG_PATH_P(0);
-	double		area = 0.0;
+	float8		area = 0.0;
 	int			i,
 				j;
 
 	if (!path->closed)
 		PG_RETURN_NULL();
 
 	for (i = 0; i < path->npts; i++)
 	{
 		j = (i + 1) % path->npts;
-		area += path->p[i].x * path->p[j].y;
-		area -= path->p[i].y * path->p[j].x;
+		area = float8_pl(area, float8_mul(path->p[i].x, path->p[j].y));
+		area = float8_mi(area, float8_mul(path->p[i].y, path->p[j].x));
 	}
 
-	area *= 0.5;
-	PG_RETURN_FLOAT8(area < 0.0 ? -area : area);
+	PG_RETURN_FLOAT8(float8_div(fabs(area), 2.0));
 }
 
 
 Datum
 path_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	PATH	   *path;
 	bool		isopen;
 	char	   *s;
@@ -1525,33 +1539,33 @@ path_inter(PG_FUNCTION_ARGS)
 				j;
 	LSEG		seg1,
 				seg2;
 
 	Assert(p1->npts > 0 && p2->npts > 0);
 
 	b1.high.x = b1.low.x = p1->p[0].x;
 	b1.high.y = b1.low.y = p1->p[0].y;
 	for (i = 1; i < p1->npts; i++)
 	{
-		b1.high.x = Max(p1->p[i].x, b1.high.x);
-		b1.high.y = Max(p1->p[i].y, b1.high.y);
-		b1.low.x = Min(p1->p[i].x, b1.low.x);
-		b1.low.y = Min(p1->p[i].y, b1.low.y);
+		b1.high.x = float8_max(p1->p[i].x, b1.high.x);
+		b1.high.y = float8_max(p1->p[i].y, b1.high.y);
+		b1.low.x = float8_min(p1->p[i].x, b1.low.x);
+		b1.low.y = float8_min(p1->p[i].y, b1.low.y);
 	}
 	b2.high.x = b2.low.x = p2->p[0].x;
 	b2.high.y = b2.low.y = p2->p[0].y;
 	for (i = 1; i < p2->npts; i++)
 	{
-		b2.high.x = Max(p2->p[i].x, b2.high.x);
-		b2.high.y = Max(p2->p[i].y, b2.high.y);
-		b2.low.x = Min(p2->p[i].x, b2.low.x);
-		b2.low.y = Min(p2->p[i].y, b2.low.y);
+		b2.high.x = float8_max(p2->p[i].x, b2.high.x);
+		b2.high.y = float8_max(p2->p[i].y, b2.high.y);
+		b2.low.x = float8_min(p2->p[i].x, b2.low.x);
+		b2.low.y = float8_min(p2->p[i].y, b2.low.y);
 	}
 	if (!box_ov(&b1, &b2))
 		PG_RETURN_BOOL(false);
 
 	/* pairwise check lseg intersections */
 	for (i = 0; i < p1->npts; i++)
 	{
 		int			iprev;
 
 		if (i > 0)
@@ -1627,21 +1641,21 @@ path_distance(PG_FUNCTION_ARGS)
 			{
 				if (!p2->closed)
 					continue;
 				jprev = p2->npts - 1;	/* include the closure segment */
 			}
 
 			statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
 			statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
 			tmp = lseg_closept_lseg(NULL, &seg1, &seg2);
-			if (!have_min || tmp < min)
+			if (!have_min || float8_lt(tmp, min))
 			{
 				min = tmp;
 				have_min = true;
 			}
 		}
 	}
 
 	if (!have_min)
 		PG_RETURN_NULL();
 
@@ -1666,21 +1680,21 @@ path_length(PG_FUNCTION_ARGS)
 
 		if (i > 0)
 			iprev = i - 1;
 		else
 		{
 			if (!path->closed)
 				continue;
 			iprev = path->npts - 1; /* include the closure segment */
 		}
 
-		result += point_dt(&path->p[iprev], &path->p[i]);
+		result = float8_pl(result, point_dt(&path->p[iprev], &path->p[i]));
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /***********************************************************************
  **
  **		Routines for 2D points.
  **
  ***********************************************************************/
@@ -1826,44 +1840,52 @@ point_eq(PG_FUNCTION_ARGS)
 
 Datum
 point_ne(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_BOOL(!point_eq_point(pt1, pt2));
 }
 
+
+/*
+ * Check whether the two points are the same
+ *
+ * We consider NaNs coordinates to be equal to each other to let those points
+ * to be found.
+ */
 static inline bool
 point_eq_point(Point *pt1, Point *pt2)
 {
-	return FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y);
+	return ((FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y)) ||
+			(float8_eq(pt1->x, pt2->x) && float8_eq(pt1->y, pt2->y)));
 }
 
 
 /*----------------------------------------------------------
  *	"Arithmetic" operators on points.
  *---------------------------------------------------------*/
 
 Datum
 point_distance(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
 }
 
 static inline float8
 point_dt(Point *pt1, Point *pt2)
 {
-	return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
+	return HYPOT(float8_mi(pt1->x, pt2->x), float8_mi(pt1->y, pt2->y));
 }
 
 Datum
 point_slope(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(point_sl(pt1, pt2));
 }
@@ -1874,37 +1896,37 @@ point_slope(PG_FUNCTION_ARGS)
  *
  * Note that this function returns DBL_MAX when the points are the same.
  */
 static inline float8
 point_sl(Point *pt1, Point *pt2)
 {
 	if (FPeq(pt1->x, pt2->x))
 		return DBL_MAX;
 	if (FPeq(pt1->y, pt2->y))
 		return 0.0;
-	return (pt1->y - pt2->y) / (pt1->x - pt2->x);
+	return float8_div(float8_mi(pt1->y, pt2->y), float8_mi(pt1->x, pt2->x));
 }
 
 
 /*
  * Return inverse slope of two points
  *
  * Note that this function returns 0.0 when the points are the same.
  */
 static inline float8
 point_invsl(Point *pt1, Point *pt2)
 {
 	if (FPeq(pt1->x, pt2->x))
 		return 0.0;
 	if (FPeq(pt1->y, pt2->y))
 		return DBL_MAX;
-	return (pt1->x - pt2->x) / (pt2->y - pt1->y);
+	return float8_div(float8_mi(pt1->x, pt2->x), float8_mi(pt2->y, pt1->y));
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D line segments.
  **
  ***********************************************************************/
 
 /*----------------------------------------------------------
@@ -2164,22 +2186,22 @@ lseg_distance(PG_FUNCTION_ARGS)
 
 
 Datum
 lseg_center(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
-	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
+	result->x = float8_div(float8_pl(lseg->p[0].x, lseg->p[1].x), 2.0);
+	result->y = float8_div(float8_pl(lseg->p[0].y, lseg->p[1].y), 2.0);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  *		Find the intersection point of two segments (if any).
  *
  * This returns true if two line segments intersect, false if they do not.
  * This also sets the intersection point to *result, if it is not NULL.
@@ -2288,21 +2310,21 @@ dist_ppath(PG_FUNCTION_ARGS)
 			iprev = i - 1;
 		else
 		{
 			if (!path->closed)
 				continue;
 			iprev = path->npts - 1; /* Include the closure segment */
 		}
 
 		statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
 		tmp = lseg_closept_point(NULL, &lseg, pt);
-		if (!have_min || tmp < result)
+		if (!have_min || float8_lt(tmp, result))
 		{
 			result = tmp;
 			have_min = true;
 		}
 	}
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
@@ -2318,33 +2340,28 @@ dist_pb(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
-	float8		result,
-				d2;
+	float8		result;
 
 	if (lseg_interpt_line(NULL, lseg, line))
 		result = 0.0;
 	else
-	{
-		result = line_closept_point(NULL, line, &lseg->p[0]);
-		d2 = line_closept_point(NULL, line, &lseg->p[1]);
 		/* XXX shouldn't we take the min not max? */
-		if (d2 > result)
-			result = d2;
-	}
+		result = float8_max(line_closept_point(NULL, line, &lseg->p[0]),
+							line_closept_point(NULL, line, &lseg->p[1]));
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
@@ -2377,25 +2394,24 @@ dist_lb(PG_FUNCTION_ARGS)
  * Distance from a circle to a polygon
  */
 Datum
 dist_cpoly(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	POLYGON    *poly = PG_GETARG_POLYGON_P(1);
 	float8		result;
 
 	/* calculate distance to center, and subtract radius */
-	result = dist_ppoly_internal(&circle->center, poly);
-
-	result -= circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(dist_ppoly_internal(&circle->center, poly),
+					   circle->radius);
+	if (result < 0.0)
+		result = 0.0;
 
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a point to a polygon
  */
 Datum
 dist_ppoly(PG_FUNCTION_ARGS)
 {
@@ -2407,21 +2423,21 @@ dist_ppoly(PG_FUNCTION_ARGS)
 
 Datum
 dist_polyp(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 
 	PG_RETURN_FLOAT8(dist_ppoly_internal(point, poly));
 }
 
-static double
+static float8
 dist_ppoly_internal(Point *pt, POLYGON *poly)
 {
 	float8		result;
 	float8		d;
 	int			i;
 	LSEG		seg;
 
 	if (point_inside(pt, poly->npts, poly->p) != 0)
 		return 0.0;
 
@@ -2433,21 +2449,21 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
 	result = lseg_closept_point(NULL, &seg, pt);
 
 	/* check distances for other segments */
 	for (i = 0; i < poly->npts - 1; i++)
 	{
 		seg.p[0].x = poly->p[i].x;
 		seg.p[0].y = poly->p[i].y;
 		seg.p[1].x = poly->p[i + 1].x;
 		seg.p[1].y = poly->p[i + 1].y;
 		d = lseg_closept_point(NULL, &seg, pt);
-		if (d < result)
+		if (float8_lt(d, result))
 			result = d;
 	}
 
 	return result;
 }
 
 
 /*---------------------------------------------------------------------
  *		interpt_
  *				Intersection point of objects.
@@ -2536,21 +2552,22 @@ line_closept_point(Point *result, LINE *line, Point *point)
 
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	line_closept_point(result, line, pt);
+	if (isnan(line_closept_point(result, line, pt)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point on line segment to specified point.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
@@ -2593,134 +2610,136 @@ close_ps(PG_FUNCTION_ARGS)
 /*
  * Closest point on line segment to line segment
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
 {
 	Point		point;
-	double		dist;
-	double		d;
+	float8		dist,
+				d;
 
 	d = lseg_closept_point(NULL, l1, &l2->p[0]);
 	dist = d;
 	if (result != NULL)
 		*result = l2->p[0];
 
 	d = lseg_closept_point(NULL, l1, &l2->p[1]);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = l2->p[1];
 	}
 
-	if (lseg_closept_point(&point, l2, &l1->p[0]) < dist)
+	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[0]), dist))
 		d = lseg_closept_point(result, l1, &point);
 
-	if (lseg_closept_point(&point, l2, &l1->p[1]) < dist)
+	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[1]), dist))
 		d = lseg_closept_point(result, l1, &point);
 
-	if (d < dist)
+	if (float8_lt(d, dist))
 		dist = d;
 
 	return dist;
 }
 
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	lseg_closept_lseg(result, l2, l1);
+	if (isnan(lseg_closept_lseg(result, l2, l1)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point on or in box to specified point.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 box_closept_point(Point *result, BOX *box, Point *pt)
 {
-	LSEG		lseg;
+	float8		dist,
+				d;
 	Point		point,
 				closept;
-	double		dist,
-				d;
+	LSEG		lseg;
 
 	if (box_contain_point(box, pt))
 	{
 		if (result != NULL)
 			*result = *pt;
 
 		return 0.0;
 	}
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&lseg, &box->low, &point);
 	dist = lseg_closept_point(result, &lseg, pt);
 
 	statlseg_construct(&lseg, &box->high, &point);
 	d = lseg_closept_point(&closept, &lseg, pt);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&lseg, &box->low, &point);
 	d = lseg_closept_point(&closept, &lseg, pt);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	statlseg_construct(&lseg, &box->high, &point);
 	d = lseg_closept_point(&closept, &lseg, pt);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	return dist;
 }
 
 Datum
 close_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	box_closept_point(result, box, pt);
+	if (isnan(box_closept_point(result, box, pt)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /* close_sl()
  * Closest point on line to line segment.
  *
  * XXX THIS CODE IS WRONG
  * The code is actually calculating the point on the line segment
@@ -2738,21 +2757,21 @@ close_sl(PG_FUNCTION_ARGS)
 	float8		d1,
 				d2;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	if (lseg_interpt_line(result, lseg, line))
 		PG_RETURN_POINT_P(result);
 
 	d1 = line_closept_point(NULL, line, &lseg->p[0]);
 	d2 = line_closept_point(NULL, line, &lseg->p[1]);
-	if (d1 < d2)
+	if (float8_lt(d1, d2))
 		*result = lseg->p[0];
 	else
 		*result = lseg->p[1];
 
 	PG_RETURN_POINT_P(result);
 #endif
 
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("function \"close_sl\" not implemented")));
@@ -2802,92 +2821,94 @@ lseg_closept_line(Point *result, LSEG *lseg, LINE *line)
 
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	lseg_closept_line(result, lseg, line);
+	if (isnan(lseg_closept_line(result, lseg, line)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
  * Closest point on or in box to line segment.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 box_closept_lseg(Point *result, BOX *box, LSEG *lseg)
 {
+	float8		dist,
+				d;
 	Point		point,
 				closept;
 	LSEG		bseg;
-	double		dist,
-				d;
 
 	if (box_interpt_lseg(result, box, lseg))
 		return 0.0;
 
 	/* pairwise check lseg distances */
 	point.x = box->low.x;
 	point.y = box->high.y;
 	statlseg_construct(&bseg, &box->low, &point);
 	dist = lseg_closept_lseg(result, &bseg, lseg);
 
 	statlseg_construct(&bseg, &box->high, &point);
 	d = lseg_closept_lseg(&closept, &bseg, lseg);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	point.x = box->high.x;
 	point.y = box->low.y;
 	statlseg_construct(&bseg, &box->low, &point);
 	d = lseg_closept_lseg(&closept, &bseg, lseg);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	statlseg_construct(&bseg, &box->high, &point);
 	d = lseg_closept_lseg(&closept, &bseg, lseg);
-	if (d < dist)
+	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
 			*result = closept;
 	}
 
 	return dist;
 }
 
 Datum
 close_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	box_closept_lseg(result, box, lseg);
+	if (isnan(box_closept_lseg(result, box, lseg)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 Datum
 close_lb(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -2906,21 +2927,23 @@ close_lb(PG_FUNCTION_ARGS)
  *		on_
  *				Whether one object lies completely within another.
  *-------------------------------------------------------------------*/
 
 /*
  *		Does the point satisfy the equation?
  */
 static bool
 line_contain_point(LINE *line, Point *point)
 {
-	return FPzero(line->A * point->x + line->B * point->y + line->C);
+	return FPzero(float8_pl(float8_pl(float8_mul(line->A, point->x),
+									  float8_mul(line->B, point->y)),
+							line->C));
 }
 
 Datum
 on_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 
 	PG_RETURN_BOOL(line_contain_point(line, pt));
 }
@@ -2987,33 +3010,32 @@ box_contain_pt(PG_FUNCTION_ARGS)
  *				but not cross.
  *				(we can do p-in-p in lg(n), but it takes preprocessing)
  */
 Datum
 on_ppath(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	PATH	   *path = PG_GETARG_PATH_P(1);
 	int			i,
 				n;
-	double		a,
+	float8		a,
 				b;
 
 	/*-- OPEN --*/
 	if (!path->closed)
 	{
 		n = path->npts - 1;
 		a = point_dt(pt, &path->p[0]);
 		for (i = 0; i < n; i++)
 		{
 			b = point_dt(pt, &path->p[i + 1]);
-			if (FPeq(a + b,
-					 point_dt(&path->p[i], &path->p[i + 1])))
+			if (FPeq(float8_pl(a, b), point_dt(&path->p[i], &path->p[i + 1])))
 				PG_RETURN_BOOL(true);
 			a = b;
 		}
 		PG_RETURN_BOOL(false);
 	}
 
 	/*-- CLOSED --*/
 	PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
 }
 
@@ -3085,24 +3107,24 @@ inter_sl(PG_FUNCTION_ARGS)
  * Optimize for non-intersection by checking for box intersection first.
  * - thomas 1998-01-30
  */
 static bool
 box_interpt_lseg(Point *result, BOX *box, LSEG *lseg)
 {
 	BOX			lbox;
 	LSEG		bseg;
 	Point		point;
 
-	lbox.low.x = Min(lseg->p[0].x, lseg->p[1].x);
-	lbox.low.y = Min(lseg->p[0].y, lseg->p[1].y);
-	lbox.high.x = Max(lseg->p[0].x, lseg->p[1].x);
-	lbox.high.y = Max(lseg->p[0].y, lseg->p[1].y);
+	lbox.low.x = float8_min(lseg->p[0].x, lseg->p[1].x);
+	lbox.low.y = float8_min(lseg->p[0].y, lseg->p[1].y);
+	lbox.high.x = float8_max(lseg->p[0].x, lseg->p[1].x);
+	lbox.high.y = float8_max(lseg->p[0].y, lseg->p[1].y);
 
 	/* nothing close to overlap? then not going to intersect */
 	if (!box_ov(&lbox, box))
 		return false;
 
 	if (result != NULL)
 	{
 		box_cn(&point, box);
 		lseg_closept_point(result, lseg, &point);
 	}
@@ -3195,38 +3217,38 @@ inter_lb(PG_FUNCTION_ARGS)
  * make_bound_box - create the bounding box for the input polygon
  *------------------------------------------------------------------*/
 
 /*---------------------------------------------------------------------
  * Make the smallest bounding box for the given polygon.
  *---------------------------------------------------------------------*/
 static void
 make_bound_box(POLYGON *poly)
 {
 	int			i;
-	double		x1,
+	float8		x1,
 				y1,
 				x2,
 				y2;
 
 	Assert(poly->npts > 0);
 
 	x1 = x2 = poly->p[0].x;
 	y2 = y1 = poly->p[0].y;
 	for (i = 1; i < poly->npts; i++)
 	{
-		if (poly->p[i].x < x1)
+		if (float8_lt(poly->p[i].x, x1))
 			x1 = poly->p[i].x;
-		if (poly->p[i].x > x2)
+		if (float8_gt(poly->p[i].x, x2))
 			x2 = poly->p[i].x;
-		if (poly->p[i].y < y1)
+		if (float8_lt(poly->p[i].y, y1))
 			y1 = poly->p[i].y;
-		if (poly->p[i].y > y2)
+		if (float8_gt(poly->p[i].y, y2))
 			y2 = poly->p[i].y;
 	}
 
 	poly->boundbox.low.x = x1;
 	poly->boundbox.high.x = x2;
 	poly->boundbox.low.y = y1;
 	poly->boundbox.high.y = y2;
 }
 
 /*------------------------------------------------------------------
@@ -3725,22 +3747,22 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
 	}
 
 	if (res && !intersection)
 	{
 		Point		p;
 
 		/*
 		 * if X-intersection wasn't found  then check central point of tested
 		 * segment. In opposite case we already check all subsegments
 		 */
-		p.x = (t.p[0].x + t.p[1].x) / 2.0;
-		p.y = (t.p[0].y + t.p[1].y) / 2.0;
+		p.x = float8_div(float8_pl(t.p[0].x, t.p[1].x), 2.0);
+		p.y = float8_div(float8_pl(t.p[0].y, t.p[1].y), 2.0);
 
 		res = point_inside(&p, poly->npts, poly->p);
 	}
 
 	return res;
 }
 
 /*-----------------------------------------------------------------
  * Determine if polygon A contains polygon B.
  *-----------------------------------------------------------------*/
@@ -3866,22 +3888,22 @@ construct_point(PG_FUNCTION_ARGS)
 	point_construct(result, x, y);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_add_point(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x + pt2->x,
-					pt1->y + pt2->y);
+					float8_pl(pt1->x, pt2->x),
+					float8_pl(pt1->y, pt2->y));
 }
 
 Datum
 point_add(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -3889,22 +3911,22 @@ point_add(PG_FUNCTION_ARGS)
 	point_add_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_sub_point(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					pt1->x - pt2->x,
-					pt1->y - pt2->y);
+					float8_mi(pt1->x, pt2->x),
+					float8_mi(pt1->y, pt2->y));
 }
 
 Datum
 point_sub(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -3912,54 +3934,53 @@ point_sub(PG_FUNCTION_ARGS)
 	point_sub_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_mul_point(Point *result, Point *pt1, Point *pt2)
 {
 	point_construct(result,
-					(pt1->x * pt2->x) - (pt1->y * pt2->y),
-					(pt1->x * pt2->y) + (pt1->y * pt2->x));
+					float8_mi(float8_mul(pt1->x, pt2->x),
+							  float8_mul(pt1->y, pt2->y)),
+					float8_pl(float8_mul(pt1->x, pt2->y),
+							  float8_mul(pt1->y, pt2->x)));
 }
 
 Datum
 point_mul(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
 
 	point_mul_point(result, p1, p2);
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 static inline void
 point_div_point(Point *result, Point *pt1, Point *pt2)
 {
-	double		div;
+	float8		div;
 
-	div = (pt2->x * pt2->x) + (pt2->y * pt2->y);
-
-	if (div == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
+	div = float8_pl(float8_mul(pt2->x, pt2->x), float8_mul(pt2->y, pt2->y));
 
 	point_construct(result,
-					((pt1->x * pt2->x) + (pt1->y * pt2->y)) / div,
-					((pt2->x * pt1->y) - (pt2->y * pt1->x)) / div);
+					float8_div(float8_pl(float8_mul(pt1->x, pt2->x),
+										 float8_mul(pt1->y, pt2->y)), div),
+					float8_div(float8_mi(float8_mul(pt1->y, pt2->x),
+										 float8_mul(pt1->x, pt2->y)), div));
 }
 
 Datum
 point_div(PG_FUNCTION_ARGS)
 {
 	Point	   *p1 = PG_GETARG_POINT_P(0);
 	Point	   *p2 = PG_GETARG_POINT_P(1);
 	Point	   *result;
 
 	result = (Point *) palloc(sizeof(Point));
@@ -4082,24 +4103,24 @@ point_box(PG_FUNCTION_ARGS)
  */
 Datum
 boxes_bound_box(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0),
 			   *box2 = PG_GETARG_BOX_P(1),
 			   *container;
 
 	container = (BOX *) palloc(sizeof(BOX));
 
-	container->high.x = Max(box1->high.x, box2->high.x);
-	container->low.x = Min(box1->low.x, box2->low.x);
-	container->high.y = Max(box1->high.y, box2->high.y);
-	container->low.y = Min(box1->low.y, box2->low.y);
+	container->high.x = float8_max(box1->high.x, box2->high.x);
+	container->low.x = float8_min(box1->low.x, box2->low.x);
+	container->high.y = float8_max(box1->high.y, box2->high.y);
+	container->low.y = float8_min(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(container);
 }
 
 
 /***********************************************************************
  **
  **		Routines for 2D paths.
  **
  ***********************************************************************/
@@ -4405,21 +4426,22 @@ circle_in(PG_FUNCTION_ARGS)
 		if (*cp == LDELIM)
 			s = cp;
 	}
 
 	pair_decode(s, &circle->center.x, &circle->center.y, &s, "circle", str);
 
 	if (*s == DELIM)
 		s++;
 
 	circle->radius = single_decode(s, &s, "circle", str);
-	if (circle->radius < 0)
+	/* We have to accept NaN. */
+	if (circle->radius < 0.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
 
 	while (depth > 0)
 	{
 		if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
 		{
 			depth--;
@@ -4472,21 +4494,22 @@ circle_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	circle->center.x = pq_getmsgfloat8(buf);
 	circle->center.y = pq_getmsgfloat8(buf);
 	circle->radius = pq_getmsgfloat8(buf);
 
-	if (circle->radius < 0)
+	/* We have to accept NaN. */
+	if (circle->radius < 0.0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
 				 errmsg("invalid radius in external \"circle\" value")));
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 /*
  *		circle_send			- converts circle to binary format
  */
@@ -4503,166 +4526,170 @@ circle_send(PG_FUNCTION_ARGS)
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for CIRCLEs.
  *		<, >, <=, >=, and == are based on circle area.
  *---------------------------------------------------------*/
 
 /*		circles identical?
+ *
+ * We consider NaNs values to be equal to each other to let those circles
+ * to be found.
  */
 Datum
 circle_same(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPeq(circle1->radius, circle2->radius) &&
+	PG_RETURN_BOOL(((isnan(circle1->radius) && isnan(circle1->radius)) ||
+					FPeq(circle1->radius, circle2->radius)) &&
 				   point_eq_point(&circle1->center, &circle2->center));
 }
 
 /*		circle_overlap	-		does circle1 overlap circle2?
  */
 Datum
 circle_overlap(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle1->radius + circle2->radius));
+						float8_pl(circle1->radius, circle2->radius)));
 }
 
 /*		circle_overleft -		is the right edge of circle1 at or left of
  *								the right edge of circle2?
  */
 Datum
 circle_overleft(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.x + circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_left		-		is circle1 strictly left of circle2?
  */
 Datum
 circle_left(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.x + circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_right	-		is circle1 strictly right of circle2?
  */
 Datum
 circle_right(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.x - circle1->radius),
-						(circle2->center.x + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.x, circle1->radius),
+						float8_pl(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_overright	-	is the left edge of circle1 at or right of
  *								the left edge of circle2?
  */
 Datum
 circle_overright(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.x - circle1->radius),
-						(circle2->center.x - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.x, circle1->radius),
+						float8_mi(circle2->center.x, circle2->radius)));
 }
 
 /*		circle_contained		-		is circle1 contained by circle2?
  */
 Datum
 circle_contained(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle2->radius - circle1->radius));
+						float8_mi(circle2->radius, circle1->radius)));
 }
 
 /*		circle_contain	-		does circle1 contain circle2?
  */
 Datum
 circle_contain(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
 	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
-						circle1->radius - circle2->radius));
+						float8_mi(circle1->radius, circle2->radius)));
 }
 
 
 /*		circle_below		-		is circle1 strictly below circle2?
  */
 Datum
 circle_below(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPlt((circle1->center.y + circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_above	-		is circle1 strictly above circle2?
  */
 Datum
 circle_above(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPgt((circle1->center.y - circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overbelow -		is the upper edge of circle1 at or below
  *								the upper edge of circle2?
  */
 Datum
 circle_overbelow(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle((circle1->center.y + circle1->radius),
-						(circle2->center.y + circle2->radius)));
+	PG_RETURN_BOOL(FPle(float8_pl(circle1->center.y, circle1->radius),
+						float8_pl(circle2->center.y, circle2->radius)));
 }
 
 /*		circle_overabove	-	is the lower edge of circle1 at or above
  *								the lower edge of circle2?
  */
 Datum
 circle_overabove(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPge((circle1->center.y - circle1->radius),
-						(circle2->center.y - circle2->radius)));
+	PG_RETURN_BOOL(FPge(float8_mi(circle1->center.y, circle1->radius),
+						float8_mi(circle2->center.y, circle2->radius)));
 }
 
 
 /*		circle_relop	-		is area(circle1) relop area(circle2), within
  *								our accuracy constraint?
  */
 Datum
 circle_eq(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
@@ -4761,36 +4788,36 @@ circle_sub_pt(PG_FUNCTION_ARGS)
 Datum
 circle_mul_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_mul_point(&result->center, &circle->center, point);
-	result->radius = circle->radius * HYPOT(point->x, point->y);
+	result->radius = float8_mul(circle->radius, HYPOT(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_div_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	point_div_point(&result->center, &circle->center, point);
-	result->radius = circle->radius / HYPOT(point->x, point->y);
+	result->radius = float8_div(circle->radius, HYPOT(point->x, point->y));
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 
 /*		circle_area		-		returns the area of the circle.
  */
 Datum
 circle_area(PG_FUNCTION_ARGS)
 {
@@ -4800,21 +4827,21 @@ circle_area(PG_FUNCTION_ARGS)
 }
 
 
 /*		circle_diameter -		returns the diameter of the circle.
  */
 Datum
 circle_diameter(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
-	PG_RETURN_FLOAT8(2 * circle->radius);
+	PG_RETURN_FLOAT8(float8_mul(circle->radius, 2.0));
 }
 
 
 /*		circle_radius	-		returns the radius of the circle.
  */
 Datum
 circle_radius(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 
@@ -4825,81 +4852,85 @@ circle_radius(PG_FUNCTION_ARGS)
 /*		circle_distance -		returns the distance between
  *								  two circles.
  */
 Datum
 circle_distance(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(&circle1->center, &circle2->center) -
-		(circle1->radius + circle2->radius);
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(&circle1->center, &circle2->center),
+					   float8_pl(circle1->radius, circle2->radius));
+	if (result < 0.0)
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 
 Datum
 circle_contain_pt(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
 	PG_RETURN_BOOL(d <= circle->radius);
 }
 
 
 Datum
 pt_contained_circle(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
-	double		d;
+	float8		d;
 
 	d = point_dt(&circle->center, point);
 	PG_RETURN_BOOL(d <= circle->radius);
 }
 
 
 /*		dist_pc -		returns the distance between
  *						  a point and a circle.
  */
 Datum
 dist_pc(PG_FUNCTION_ARGS)
 {
 	Point	   *point = PG_GETARG_POINT_P(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center),
+					   circle->radius);
+	if (result < 0.0)
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a circle to a point
  */
 Datum
 dist_cpoint(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *point = PG_GETARG_POINT_P(1);
 	float8		result;
 
-	result = point_dt(point, &circle->center) - circle->radius;
-	if (result < 0)
-		result = 0;
+	result = float8_mi(point_dt(point, &circle->center), circle->radius);
+	if (result < 0.0)
+		result = 0.0;
+
 	PG_RETURN_FLOAT8(result);
 }
 
 /*		circle_center	-		returns the center point of the circle.
  */
 Datum
 circle_center(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	Point	   *result;
@@ -4907,24 +4938,24 @@ circle_center(PG_FUNCTION_ARGS)
 	result = (Point *) palloc(sizeof(Point));
 	result->x = circle->center.x;
 	result->y = circle->center.y;
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*		circle_ar		-		returns the area of the circle.
  */
-static double
+static float8
 circle_ar(CIRCLE *circle)
 {
-	return M_PI * (circle->radius * circle->radius);
+	return float8_mul(float8_mul(circle->radius, circle->radius), M_PI);
 }
 
 
 /*----------------------------------------------------------
  *	Conversion operators.
  *---------------------------------------------------------*/
 
 Datum
 cr_circle(PG_FUNCTION_ARGS)
 {
@@ -4939,65 +4970,65 @@ cr_circle(PG_FUNCTION_ARGS)
 	result->radius = radius;
 
 	PG_RETURN_CIRCLE_P(result);
 }
 
 Datum
 circle_box(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	BOX		   *box;
-	double		delta;
+	float8		delta;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
-	delta = circle->radius / sqrt(2.0);
+	delta = float8_div(circle->radius, sqrt(2.0));
 
-	box->high.x = circle->center.x + delta;
-	box->low.x = circle->center.x - delta;
-	box->high.y = circle->center.y + delta;
-	box->low.y = circle->center.y - delta;
+	box->high.x = float8_pl(circle->center.x, delta);
+	box->low.x = float8_mi(circle->center.x, delta);
+	box->high.y = float8_pl(circle->center.y, delta);
+	box->low.y = float8_mi(circle->center.y, delta);
 
 	PG_RETURN_BOX_P(box);
 }
 
 /* box_circle()
  * Convert a box to a circle.
  */
 Datum
 box_circle(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	circle->center.x = (box->high.x + box->low.x) / 2;
-	circle->center.y = (box->high.y + box->low.y) / 2;
+	circle->center.x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
+	circle->center.y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
 
 	circle->radius = point_dt(&circle->center, &box->high);
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
 
 Datum
 circle_poly(PG_FUNCTION_ARGS)
 {
 	int32		npts = PG_GETARG_INT32(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	POLYGON    *poly;
 	int			base_size,
 				size;
 	int			i;
-	double		angle;
-	double		anglestep;
+	float8		angle;
+	float8		anglestep;
 
 	if (FPzero(circle->radius))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("cannot convert circle with radius zero to polygon")));
 
 	if (npts < 2)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("must request at least 2 points")));
@@ -5008,27 +5039,30 @@ circle_poly(PG_FUNCTION_ARGS)
 	/* Check for integer overflow */
 	if (base_size / npts != sizeof(poly->p[0]) || size <= base_size)
 		ereport(ERROR,
 				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 				 errmsg("too many points requested")));
 
 	poly = (POLYGON *) palloc0(size);	/* zero any holes */
 	SET_VARSIZE(poly, size);
 	poly->npts = npts;
 
-	anglestep = (2.0 * M_PI) / npts;
+	anglestep = float8_div(2.0 * M_PI, npts);
 
 	for (i = 0; i < npts; i++)
 	{
-		angle = i * anglestep;
-		poly->p[i].x = circle->center.x - (circle->radius * cos(angle));
-		poly->p[i].y = circle->center.y + (circle->radius * sin(angle));
+		angle = float8_mul(anglestep, i);
+
+		poly->p[i].x = float8_mi(circle->center.x,
+								 float8_mul(circle->radius, cos(angle)));
+		poly->p[i].y = float8_pl(circle->center.y,
+								 float8_mul(circle->radius, sin(angle)));
 	}
 
 	make_bound_box(poly);
 
 	PG_RETURN_POLYGON_P(poly);
 }
 
 /*
  * Convert polygon to circle
  *
@@ -5043,26 +5077,27 @@ poly_to_circle(CIRCLE *result, POLYGON *poly)
 	int			i;
 
 	Assert(poly->npts > 0);
 
 	result->center.x = 0;
 	result->center.y = 0;
 	result->radius = 0;
 
 	for (i = 0; i < poly->npts; i++)
 		point_add_point(&result->center, &result->center, &poly->p[i]);
-	result->center.x /= poly->npts;
-	result->center.y /= poly->npts;
+	result->center.x = float8_div(result->center.x, poly->npts);
+	result->center.y = float8_div(result->center.y, poly->npts);
 
 	for (i = 0; i < poly->npts; i++)
-		result->radius += point_dt(&poly->p[i], &result->center);
-	result->radius /= poly->npts;
+		result->radius = float8_pl(result->radius,
+								   point_dt(&poly->p[i], &result->center));
+	result->radius = float8_div(result->radius, poly->npts);
 }
 
 Datum
 poly_circle(PG_FUNCTION_ARGS)
 {
 	POLYGON    *poly = PG_GETARG_POLYGON_P(0);
 	CIRCLE	   *result;
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
@@ -5087,44 +5122,44 @@ poly_circle(PG_FUNCTION_ARGS)
  *	http://hopf.math.northwestern.edu/index.html
  *	Description of algorithm:  http://www.linuxjournal.com/article/2197
  *							   http://www.linuxjournal.com/article/2029
  */
 
 #define POINT_ON_POLYGON INT_MAX
 
 static int
 point_inside(Point *p, int npts, Point *plist)
 {
-	double		x0,
+	float8		x0,
 				y0;
-	double		prev_x,
+	float8		prev_x,
 				prev_y;
 	int			i = 0;
-	double		x,
+	float8		x,
 				y;
 	int			cross,
 				total_cross = 0;
 
 	Assert(npts > 0);
 
 	/* compute first polygon point relative to single point */
-	x0 = plist[0].x - p->x;
-	y0 = plist[0].y - p->y;
+	x0 = float8_mi(plist[0].x, p->x);
+	y0 = float8_mi(plist[0].y, p->y);
 
 	prev_x = x0;
 	prev_y = y0;
 	/* loop over polygon points and aggregate total_cross */
 	for (i = 1; i < npts; i++)
 	{
 		/* compute next polygon point relative to single point */
-		x = plist[i].x - p->x;
-		y = plist[i].y - p->y;
+		x = float8_mi(plist[i].x, p->x);
+		y = float8_mi(plist[i].y, p->y);
 
 		/* compute previous to current point crossing */
 		if ((cross = lseg_crossing(x, y, prev_x, prev_y)) == POINT_ON_POLYGON)
 			return 2;
 		total_cross += cross;
 
 		prev_x = x;
 		prev_y = y;
 	}
 
@@ -5142,69 +5177,74 @@ point_inside(Point *p, int npts, Point *plist)
 /* lseg_crossing()
  * Returns +/-2 if line segment crosses the positive X-axis in a +/- direction.
  * Returns +/-1 if one point is on the positive X-axis.
  * Returns 0 if both points are on the positive X-axis, or there is no crossing.
  * Returns POINT_ON_POLYGON if the segment contains (0,0).
  * Wow, that is one confusing API, but it is used above, and when summed,
  * can tell is if a point is in a polygon.
  */
 
 static int
-lseg_crossing(double x, double y, double prev_x, double prev_y)
+lseg_crossing(float8 x, float8 y, float8 prev_x, float8 prev_y)
 {
-	double		z;
+	float8		z;
 	int			y_sign;
 
 	if (FPzero(y))
 	{							/* y == 0, on X axis */
 		if (FPzero(x))			/* (x,y) is (0,0)? */
 			return POINT_ON_POLYGON;
 		else if (FPgt(x, 0))
 		{						/* x > 0 */
 			if (FPzero(prev_y)) /* y and prev_y are zero */
 				/* prev_x > 0? */
-				return FPgt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
-			return FPlt(prev_y, 0) ? 1 : -1;
+				return FPgt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
+			return FPlt(prev_y, 0.0) ? 1 : -1;
 		}
 		else
 		{						/* x < 0, x not on positive X axis */
 			if (FPzero(prev_y))
 				/* prev_x < 0? */
-				return FPlt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
+				return FPlt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
 			return 0;
 		}
 	}
 	else
 	{							/* y != 0 */
 		/* compute y crossing direction from previous point */
-		y_sign = FPgt(y, 0) ? 1 : -1;
+		y_sign = FPgt(y, 0.0) ? 1 : -1;
 
 		if (FPzero(prev_y))
 			/* previous point was on X axis, so new point is either off or on */
-			return FPlt(prev_x, 0) ? 0 : y_sign;
-		else if (FPgt(y_sign * prev_y, 0))
+			return FPlt(prev_x, 0.0) ? 0 : y_sign;
+		else if ((y_sign < 0 && FPlt(prev_y, 0.0)) ||
+				 (y_sign > 0 && FPgt(prev_y, 0.0)))
 			/* both above or below X axis */
 			return 0;			/* same sign */
 		else
 		{						/* y and prev_y cross X-axis */
-			if (FPge(x, 0) && FPgt(prev_x, 0))
+			if (FPge(x, 0.0) && FPgt(prev_x, 0.0))
 				/* both non-negative so cross positive X-axis */
 				return 2 * y_sign;
-			if (FPlt(x, 0) && FPle(prev_x, 0))
+			if (FPlt(x, 0.0) && FPle(prev_x, 0.0))
 				/* both non-positive so do not cross positive X-axis */
 				return 0;
 
 			/* x and y cross axises, see URL above point_inside() */
-			z = (x - prev_x) * y - (y - prev_y) * x;
+			z = float8_mi(float8_mul(float8_mi(x, prev_x), y),
+						  float8_mul(float8_mi(y, prev_y), x));
 			if (FPzero(z))
 				return POINT_ON_POLYGON;
-			return FPgt((y_sign * z), 0) ? 0 : 2 * y_sign;
+			if ((y_sign < 0 && FPlt(z, 0.0)) ||
+				(y_sign > 0 && FPgt(z, 0.0)))
+				return 0;
+			return 2 * y_sign;
 		}
 	}
 }
 
 
 static bool
 plist_same(int npts, Point *p1, Point *p2)
 {
 	int			i,
 				ii,
@@ -5258,47 +5298,52 @@ plist_same(int npts, Point *p1, Point *p2)
  *					 = x * sqrt( 1 + y^2/x^2 )
  *					 = x * sqrt( 1 + y/x * y/x )
  *
  * It is expected that this routine will eventually be replaced with the
  * C99 hypot() function.
  *
  * This implementation conforms to IEEE Std 1003.1 and GLIBC, in that the
  * case of hypot(inf,nan) results in INF, and not NAN.
  *-----------------------------------------------------------------------
  */
-double
-pg_hypot(double x, double y)
+float8
+pg_hypot(float8 x, float8 y)
 {
-	double		yx;
+	float8		yx,
+				result;
 
 	/* Handle INF and NaN properly */
 	if (isinf(x) || isinf(y))
 		return get_float8_infinity();
 
 	if (isnan(x) || isnan(y))
 		return get_float8_nan();
 
 	/* Else, drop any minus signs */
 	x = fabs(x);
 	y = fabs(y);
 
 	/* Swap x and y if needed to make x the larger one */
 	if (x < y)
 	{
-		double		temp = x;
+		float8		temp = x;
 
 		x = y;
 		y = temp;
 	}
 
 	/*
 	 * If y is zero, the hypotenuse is x.  This test saves a few cycles in
 	 * such cases, but more importantly it also protects against
 	 * divide-by-zero errors, since now x >= y.
 	 */
 	if (y == 0.0)
 		return x;
 
 	/* Determine the hypotenuse */
 	yx = y / x;
-	return x * sqrt(1.0 + (yx * yx));
+	result = x * sqrt(1.0 + (yx * yx));
+
+	check_float8_val(result, false, false);
+
+	return result;
 }
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index fea36f361a..4aff973ef3 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -77,38 +77,38 @@
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
 #include "utils/float.h"
 #include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
- * is going only going to be used in a place to effect the performance
+ * is only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
 compareDoubles(const void *a, const void *b)
 {
-	double		x = *(double *) a;
-	double		y = *(double *) b;
+	float8		x = *(float8 *) a;
+	float8		y = *(float8 *) b;
 
 	if (x == y)
 		return 0;
 	return (x > y) ? 1 : -1;
 }
 
 typedef struct
 {
-	double		low;
-	double		high;
+	float8		low;
+	float8		high;
 } Range;
 
 typedef struct
 {
 	Range		left;
 	Range		right;
 } RangeBox;
 
 typedef struct
 {
@@ -168,21 +168,21 @@ getRangeBox(BOX *box)
 /*
  * Initialize the traversal value
  *
  * In the beginning, we don't have any restrictions.  We have to
  * initialize the struct to cover the whole 4D space.
  */
 static RectBox *
 initRectBox(void)
 {
 	RectBox    *rect_box = (RectBox *) palloc(sizeof(RectBox));
-	double		infinity = get_float8_infinity();
+	float8		infinity = get_float8_infinity();
 
 	rect_box->range_box_x.left.low = -infinity;
 	rect_box->range_box_x.left.high = infinity;
 
 	rect_box->range_box_x.right.low = -infinity;
 	rect_box->range_box_x.right.high = infinity;
 
 	rect_box->range_box_y.left.low = -infinity;
 	rect_box->range_box_y.left.high = infinity;
 
@@ -411,40 +411,40 @@ spg_box_quad_choose(PG_FUNCTION_ARGS)
  * point as the median of the coordinates of the boxes.
  */
 Datum
 spg_box_quad_picksplit(PG_FUNCTION_ARGS)
 {
 	spgPickSplitIn *in = (spgPickSplitIn *) PG_GETARG_POINTER(0);
 	spgPickSplitOut *out = (spgPickSplitOut *) PG_GETARG_POINTER(1);
 	BOX		   *centroid;
 	int			median,
 				i;
-	double	   *lowXs = palloc(sizeof(double) * in->nTuples);
-	double	   *highXs = palloc(sizeof(double) * in->nTuples);
-	double	   *lowYs = palloc(sizeof(double) * in->nTuples);
-	double	   *highYs = palloc(sizeof(double) * in->nTuples);
+	float8	   *lowXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highXs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *lowYs = palloc(sizeof(float8) * in->nTuples);
+	float8	   *highYs = palloc(sizeof(float8) * in->nTuples);
 
 	/* Calculate median of all 4D coordinates */
 	for (i = 0; i < in->nTuples; i++)
 	{
 		BOX		   *box = DatumGetBoxP(in->datums[i]);
 
 		lowXs[i] = box->low.x;
 		highXs[i] = box->high.x;
 		lowYs[i] = box->low.y;
 		highYs[i] = box->high.y;
 	}
 
-	qsort(lowXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highXs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(lowYs, in->nTuples, sizeof(double), compareDoubles);
-	qsort(highYs, in->nTuples, sizeof(double), compareDoubles);
+	qsort(lowXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highXs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(lowYs, in->nTuples, sizeof(float8), compareDoubles);
+	qsort(highYs, in->nTuples, sizeof(float8), compareDoubles);
 
 	median = in->nTuples / 2;
 
 	centroid = palloc(sizeof(BOX));
 
 	centroid->low.x = lowXs[median];
 	centroid->high.x = highXs[median];
 	centroid->low.y = lowYs[median];
 	centroid->high.y = highYs[median];
 
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 0e066894cd..9f8505804e 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -1,41 +1,38 @@
 /*-------------------------------------------------------------------------
  *
  * geo_decls.h - Declarations for various 2D constructs.
  *
  *
  * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * src/include/utils/geo_decls.h
  *
- * NOTE
- *	  These routines do *not* use the float types from adt/.
- *
  *	  XXX These routines were not written by a numerical analyst.
  *
  *	  XXX I have made some attempt to flesh out the operators
  *		and data types. There are still some more to do. - tgl 97/04/19
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEO_DECLS_H
 #define GEO_DECLS_H
 
-#include <math.h>
-
 #include "fmgr.h"
 
 /*--------------------------------------------------------------------
  * Useful floating point utilities and constants.
- *-------------------------------------------------------------------*/
-
+ *-------------------------------------------------------------------
+ *
+ * XXX: They are not NaN-aware.
+ */
 
 #define EPSILON					1.0E-06
 
 #ifdef EPSILON
 #define FPzero(A)				(fabs(A) <= EPSILON)
 #define FPeq(A,B)				(fabs((A) - (B)) <= EPSILON)
 #define FPne(A,B)				(fabs((A) - (B)) > EPSILON)
 #define FPlt(A,B)				((B) - (A) > EPSILON)
 #define FPle(A,B)				((A) - (B) <= EPSILON)
 #define FPgt(A,B)				((A) - (B) > EPSILON)
@@ -50,21 +47,21 @@
 #define FPge(A,B)				((A) >= (B))
 #endif
 
 #define HYPOT(A, B)				pg_hypot(A, B)
 
 /*---------------------------------------------------------------------
  * Point - (x,y)
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		x,
+	float8		x,
 				y;
 } Point;
 
 
 /*---------------------------------------------------------------------
  * LSEG - A straight line, specified by endpoints.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		p[2];
@@ -82,21 +79,21 @@ typedef struct
 	int32		dummy;			/* padding to make it double align */
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } PATH;
 
 
 /*---------------------------------------------------------------------
  * LINE - Specified by its general equation (Ax+By+C=0).
  *-------------------------------------------------------------------*/
 typedef struct
 {
-	double		A,
+	float8		A,
 				B,
 				C;
 } LINE;
 
 
 /*---------------------------------------------------------------------
  * BOX	- Specified by two corner points, which are
  *		 sorted to save calculation time later.
  *-------------------------------------------------------------------*/
 typedef struct
@@ -117,21 +114,21 @@ typedef struct
 	BOX			boundbox;
 	Point		p[FLEXIBLE_ARRAY_MEMBER];
 } POLYGON;
 
 /*---------------------------------------------------------------------
  * CIRCLE - Specified by a center point and radius.
  *-------------------------------------------------------------------*/
 typedef struct
 {
 	Point		center;
-	double		radius;
+	float8		radius;
 } CIRCLE;
 
 /*
  * fmgr interface macros
  *
  * Path and Polygon are toastable varlena types, the others are just
  * fixed-size pass-by-reference types.
  */
 
 #define DatumGetPointP(X)	 ((Point *) DatumGetPointer(X))
@@ -171,13 +168,13 @@ typedef struct
 #define DatumGetCircleP(X)	  ((CIRCLE *) DatumGetPointer(X))
 #define CirclePGetDatum(X)	  PointerGetDatum(X)
 #define PG_GETARG_CIRCLE_P(n) DatumGetCircleP(PG_GETARG_DATUM(n))
 #define PG_RETURN_CIRCLE_P(x) return CirclePGetDatum(x)
 
 
 /*
  * in geo_ops.c
  */
 
-extern double pg_hypot(double x, double y);
+extern float8 pg_hypot(float8 x, float8 y);
 
 #endif							/* GEO_DECLS_H */
-- 
2.14.3 (Apple Git-98)

0003-line-fixes-v13.patchapplication/octet-stream; name=0003-line-fixes-v13.patchDownload
From 078e52fbef0eae792d422b35829dde5aa7a59a02 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sun, 28 May 2017 11:35:17 +0200
Subject: [PATCH 3/4] line-fixes-v13

Fix obvious problems around the line datatype

I have noticed some line operators retuning wrong results, and Tom Lane
spotted similar problems on more places.  Source history reveals that
during 1990s, the internal format of the line datatype is changed, but
most functions haven't got the hint.  The fixes include:

* Reject invalid specification A=B=0 on receive
* Reject same points on line_construct_pp()
* Fix perpendicular operator when negative values are involved
* Avoid division by zero on perpendicular operator
* Fix intersection and distance operators when neither A nor B are 1
* Return NULL for closest point when objects are parallel
* Check whether closest point of line segments is the intersection point
* Fix closest point of line segments being on the wrong segment

The changes are also aiming make line operators more symmetric and less
sensitive to floating point precision loss.  The EPSILON interferes with
every minor change in different ways.  It is hard to guess which
behaviour is more expected, but we can assume threating both sides of
the operators more equally is more expected.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com

Parallel discussions:

* https://www.postgresql.org/message-id/CAE2gYzw_-z%3DV2kh8QqFjenu%3D8MJXzOP44wRW%3DAzzeamrmTT1%3DQ%40mail.gmail.com
* https://www.postgresql.org/message-id/20180201.205138.34583581.horiguchi.kyotaro@lab.ntt.co.jp
---
 src/backend/utils/adt/geo_ops.c | 158 ++++++++++++++++++++++++++--------------
 1 file changed, 105 insertions(+), 53 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 13dc1ab6e6..e0a9a0fa4f 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -41,20 +41,21 @@ static inline void point_add_point(Point *result, Point *pt1, Point *pt2);
 static inline void point_sub_point(Point *result, Point *pt1, Point *pt2);
 static inline void point_mul_point(Point *result, Point *pt1, Point *pt2);
 static inline void point_div_point(Point *result, Point *pt1, Point *pt2);
 static inline bool point_eq_point(Point *pt1, Point *pt2);
 static inline float8 point_dt(Point *pt1, Point *pt2);
 static inline float8 point_sl(Point *pt1, Point *pt2);
 static int	point_inside(Point *p, int npts, Point *plist);
 
 /* Routines for lines */
 static inline void line_construct(LINE *result, Point *pt, float8 m);
+static inline float8 line_sl(LINE *line);
 static inline float8 line_invsl(LINE *line);
 static bool	line_interpt_line(Point *result, LINE *l1, LINE *l2);
 static bool line_contain_point(LINE *line, Point *point);
 static float8 line_closept_point(Point *result, LINE *line, Point *pt);
 
 /* Routines for line segments */
 static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
 static inline float8 lseg_sl(LSEG *lseg);
 static inline float8 lseg_invsl(LSEG *lseg);
 static bool	lseg_interpt_line(Point *result, LSEG *lseg, LINE *line);
@@ -973,20 +974,25 @@ line_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LINE	   *line;
 
 	line = (LINE *) palloc(sizeof(LINE));
 
 	line->A = pq_getmsgfloat8(buf);
 	line->B = pq_getmsgfloat8(buf);
 	line->C = pq_getmsgfloat8(buf);
 
+	if (FPzero(line->A) && FPzero(line->B))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("invalid line specification: A and B cannot both be zero")));
+
 	PG_RETURN_LINE_P(line);
 }
 
 /*
  *		line_send			- converts line to binary format
  */
 Datum
 line_send(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -1033,20 +1039,25 @@ line_construct(LINE *result, Point *pt, float8 m)
 /* line_construct_pp()
  * two points
  */
 Datum
 line_construct_pp(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 	LINE	   *result = (LINE *) palloc(sizeof(LINE));
 
+	if (point_eq_point(pt1, pt2))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("invalid line specification: must be two distinct points")));
+
 	line_construct(result, pt1, point_sl(pt1, pt2));
 
 	PG_RETURN_LINE_P(result);
 }
 
 
 /*----------------------------------------------------------
  *	Relative position routines.
  *---------------------------------------------------------*/
 
@@ -1069,25 +1080,29 @@ line_parallel(PG_FUNCTION_ARGS)
 }
 
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
-	else if (FPzero(l1->B))
+	if (FPzero(l2->A))
+		PG_RETURN_BOOL(FPzero(l1->B));
+	if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
+	if (FPzero(l2->B))
+		PG_RETURN_BOOL(FPzero(l1->A));
 
-	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
-								   float8_mul(l1->B, l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->A),
+								   float8_mul(l1->B, l2->B)), -1.0));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
@@ -1128,20 +1143,34 @@ line_eq(PG_FUNCTION_ARGS)
 				   (float8_eq(l1->A, l2->A) &&
 					float8_eq(l1->B, l2->B) &&
 					float8_eq(l1->C, l2->C)));
 }
 
 
 /*----------------------------------------------------------
  *	Line arithmetic routines.
  *---------------------------------------------------------*/
 
+/*
+ * Return slope of the line
+ */
+static inline float8
+line_sl(LINE *line)
+{
+	if (FPzero(line->A))
+		return 0.0;
+	if (FPzero(line->B))
+		return DBL_MAX;
+	return float8_div(line->A, -line->B);
+}
+
+
 /*
  * Return inverse slope of the line
  */
 static inline float8
 line_invsl(LINE *line)
 {
 	if (FPzero(line->A))
 		return DBL_MAX;
 	if (FPzero(line->B))
 		return 0.0;
@@ -1150,30 +1179,35 @@ line_invsl(LINE *line)
 
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	float8		result;
-	Point		tmp;
+	float8		ratio;
 
 	if (line_interpt_line(NULL, l1, l2))	/* intersecting? */
 		PG_RETURN_FLOAT8(0.0);
-	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
-	point_construct(&tmp, 0.0, l1->C);
-	result = line_closept_point(NULL, l2, &tmp);
-	PG_RETURN_FLOAT8(result);
+
+	if (!FPzero(l1->A) && !isnan(l1->A) && !FPzero(l2->A) && !isnan(l2->A))
+		ratio = float8_div(l1->A, l2->A);
+	else if (!FPzero(l1->B) && !isnan(l1->B) && !FPzero(l2->B) && !isnan(l2->B))
+		ratio = float8_div(l1->B, l2->B);
+	else
+		ratio = 1.0;
+
+	PG_RETURN_FLOAT8(float8_div(fabs(float8_mi(l1->C,
+											   float8_mul(ratio, l2->C))),
+								HYPOT(l1->A, l1->B)));
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
@@ -1200,41 +1234,44 @@ line_interpt(PG_FUNCTION_ARGS)
  * If the lines have NaN constants, we will return true, and the intersection
  * point would have NaN coordinates.  We shouldn't return false in this case
  * because that would mean the lines are parallel.
  */
 static bool
 line_interpt_line(Point *result, LINE *l1, LINE *l2)
 {
 	float8		x,
 				y;
 
-	if (FPzero(l1->B))			/* l1 vertical? */
-	{
-		if (FPzero(l2->B))		/* l2 vertical? */
-			return false;
-
-		x = l1->C;
-		y = float8_pl(float8_mul(l2->A, x), l2->C);
-	}
-	else if (FPzero(l2->B))		/* l2 vertical? */
-	{
-		x = l2->C;
-		y = float8_pl(float8_mul(l1->A, x), l1->C);
-	}
-	else
+	if (!FPzero(l1->B))
 	{
 		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
 			return false;
 
-		x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
-		y = float8_pl(float8_mul(l1->A, x), l1->C);
+		x = float8_div(float8_mi(float8_mul(l1->B, l2->C),
+								 float8_mul(l2->B, l1->C)),
+					   float8_mi(float8_mul(l1->A, l2->B),
+								 float8_mul(l2->A, l1->B)));
+		y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
 	}
+	else if (!FPzero(l2->B))
+	{
+		if (FPeq(l1->A, float8_mul(l2->A, float8_div(l1->B, l2->B))))
+			return false;
+
+		x = float8_div(float8_mi(float8_mul(l2->B, l1->C),
+								 float8_mul(l1->B, l2->C)),
+					   float8_mi(float8_mul(l2->A, l1->B),
+								 float8_mul(l1->A, l2->B)));
+		y = float8_div(-float8_pl(float8_mul(l2->A, x), l2->C), l2->B);
+	}
+	else
+		return false;
 
 	if (result != NULL)
 		point_construct(result, x, y);
 
 	return true;
 }
 
 
 /***********************************************************************
  **
@@ -2340,30 +2377,22 @@ dist_pb(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
-	float8		result;
 
-	if (lseg_interpt_line(NULL, lseg, line))
-		result = 0.0;
-	else
-		/* XXX shouldn't we take the min not max? */
-		result = float8_max(line_closept_point(NULL, line, &lseg->p[0]),
-							line_closept_point(NULL, line, &lseg->p[1]));
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(lseg_closept_line(NULL, lseg, line));
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
@@ -2526,34 +2555,40 @@ lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
 /*
  *		The intersection point of a perpendicular of the line
  *		through the point.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 line_closept_point(Point *result, LINE *line, Point *point)
 {
-	bool		retval PG_USED_FOR_ASSERTS_ONLY;
-	Point       closept;
+	Point		closept;
 	LINE		tmp;
 
-	/* We drop a perpendicular to find the intersection point. */
+	/*
+	 * We drop a perpendicular to find the intersection point.  Ordinarily
+	 * we should always find it, but that can fail in the presence of NaN
+	 * coordinates, and perhaps even from simple roundoff issues.
+	 */
 	line_construct(&tmp, point, line_invsl(line));
-	retval = line_interpt_line(&closept, line, &tmp);
+	if (!line_interpt_line(&closept, &tmp, line))
+	{
+		if (result != NULL)
+			*result = *point;
 
-	Assert(retval);	/* perpendicular lines always intersect */
+		return get_float8_nan();
+	}
 
 	if (result != NULL)
 		*result = closept;
 
-	/* Then we calculate the distance between the points. */
 	return point_dt(&closept, point);
 }
 
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
@@ -2613,52 +2648,66 @@ close_ps(PG_FUNCTION_ARGS)
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
 {
 	Point		point;
 	float8		dist,
 				d;
 
-	d = lseg_closept_point(NULL, l1, &l2->p[0]);
-	dist = d;
-	if (result != NULL)
-		*result = l2->p[0];
+	/* First, we handle the case when the line segments are intersecting. */
+	if (lseg_interpt_lseg(result, l1, l2))
+		return 0.0;
 
-	d = lseg_closept_point(NULL, l1, &l2->p[1]);
+	/*
+	 * Then, we find the closest points from the endpoints of the second
+	 * line segment, and keep the closest one.
+	 */
+	dist = lseg_closept_point(result, l1, &l2->p[0]);
+	d = lseg_closept_point(&point, l1, &l2->p[1]);
 	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
-			*result = l2->p[1];
+			*result = point;
 	}
 
-	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[0]), dist))
-		d = lseg_closept_point(result, l1, &point);
-
-	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[1]), dist))
-		d = lseg_closept_point(result, l1, &point);
-
+	/* The closest point can still be one of the endpoints, so we test them. */
+	d = lseg_closept_point(NULL, l2, &l1->p[0]);
 	if (float8_lt(d, dist))
+	{
 		dist = d;
+		if (result != NULL)
+			*result = l1->p[0];
+	}
+	d = lseg_closept_point(NULL, l2, &l1->p[1]);
+	if (float8_lt(d, dist))
+	{
+		dist = d;
+		if (result != NULL)
+			*result = l1->p[1];
+	}
 
 	return dist;
 }
 
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
+	if (lseg_sl(l1) == lseg_sl(l2))
+		PG_RETURN_NULL();
+
 	result = (Point *) palloc(sizeof(Point));
 
 	if (isnan(lseg_closept_lseg(result, l2, l1)))
 		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
@@ -2819,20 +2868,23 @@ lseg_closept_line(Point *result, LSEG *lseg, LINE *line)
 	}
 }
 
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
+	if (lseg_sl(lseg) == line_sl(line))
+		PG_RETURN_NULL();
+
 	result = (Point *) palloc(sizeof(Point));
 
 	if (isnan(lseg_closept_line(result, lseg, line)))
 		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
-- 
2.14.3 (Apple Git-98)

0004-geo-tests-v09.patchapplication/octet-stream; name=0004-geo-tests-v09.patchDownload
From 460665bc617e6ee94df0253484baed4fafb3b85a Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Tue, 24 Oct 2017 11:28:21 +0200
Subject: [PATCH 4/4] geo-tests-v09

Improve test coverage of geometric types

The tests for the geometric functions and operators were in sad state.
This commit increases test coverage of geo_ops.c significantly.  It
removes the alternative results to expect -0 on some platforms.  We
better try to return the same results on different platforms, but if we
can't we can add them back using the results from build farm.

The tests are added to geometric.sql file.  It is not clear where to
put them as there are many cross datatype operators.  Organising them
on a single file sorted by the left hand side of the operators appear
to be a simple solution.  We may take this further and remove the other
tests later.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com
---
 src/test/regress/expected/box.out          |   44 +-
 src/test/regress/expected/circle.out       |   39 +-
 src/test/regress/expected/create_index.out |   73 +-
 src/test/regress/expected/geometry.out     | 4879 ++++++++++++++++++++++++++--
 src/test/regress/expected/geometry_1.out   | 4879 ++++++++++++++++++++++++++--
 src/test/regress/expected/geometry_2.out   |  563 ----
 src/test/regress/expected/line.out         |  272 +-
 src/test/regress/expected/lseg.out         |   24 +-
 src/test/regress/expected/path.out         |   49 +-
 src/test/regress/expected/point.out        |  358 +-
 src/test/regress/expected/polygon.out      |  200 +-
 src/test/regress/sql/box.sql               |    9 +
 src/test/regress/sql/circle.sql            |   10 +-
 src/test/regress/sql/geometry.sql          |  400 ++-
 src/test/regress/sql/line.sql              |   79 +-
 src/test/regress/sql/lseg.sql              |    9 +-
 src/test/regress/sql/path.sql              |   22 +-
 src/test/regress/sql/point.sql             |   10 +
 src/test/regress/sql/polygon.sql           |   91 +-
 19 files changed, 10086 insertions(+), 1924 deletions(-)
 delete mode 100644 src/test/regress/expected/geometry_2.out

diff --git a/src/test/regress/expected/box.out b/src/test/regress/expected/box.out
index 49af242c8c..998b52223c 100644
--- a/src/test/regress/expected/box.out
+++ b/src/test/regress/expected/box.out
@@ -11,92 +11,109 @@
 -- 1	| o-+-o
 --	|   |
 -- 0	+---+
 --
 --	0 1 2 3
 --
 -- boxes are specified by two points, given by four floats x1,y1,x2,y2
 CREATE TABLE BOX_TBL (f1 box);
 INSERT INTO BOX_TBL (f1) VALUES ('(2.0,2.0,0.0,0.0)');
 INSERT INTO BOX_TBL (f1) VALUES ('(1.0,1.0,3.0,3.0)');
+INSERT INTO BOX_TBL (f1) VALUES ('((-8, 2), (-2, -10))');
 -- degenerate cases where the box is a line or a point
 -- note that lines and points boxes all have zero area
 INSERT INTO BOX_TBL (f1) VALUES ('(2.5, 2.5, 2.5,3.5)');
 INSERT INTO BOX_TBL (f1) VALUES ('(3.0, 3.0,3.0,3.0)');
 -- badly formatted box inputs
 INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
 ERROR:  invalid input syntax for type box: "(2.3, 4.5)"
 LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
                                          ^
+INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+ERROR:  invalid input syntax for type box: "[1, 2, 3, 4)"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+                                         ^
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+ERROR:  invalid input syntax for type box: "(1, 2, 3, 4]"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+                                         ^
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+ERROR:  invalid input syntax for type box: "(1, 2, 3, 4) x"
+LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+                                         ^
 INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
 ERROR:  invalid input syntax for type box: "asdfasdf(ad"
 LINE 1: INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
                                          ^
 SELECT '' AS four, * FROM BOX_TBL;
  four |         f1          
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
+      | (-2,2),(-8,-10)
       | (2.5,3.5),(2.5,2.5)
       | (3,3),(3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, b.*, area(b.f1) as barea
    FROM BOX_TBL b;
  four |         f1          | barea 
 ------+---------------------+-------
       | (2,2),(0,0)         |     4
       | (3,3),(1,1)         |     4
+      | (-2,2),(-8,-10)     |    72
       | (2.5,3.5),(2.5,2.5) |     0
       | (3,3),(3,3)         |     0
-(4 rows)
+(5 rows)
 
 -- overlap
 SELECT '' AS three, b.f1
    FROM BOX_TBL b
    WHERE b.f1 && box '(2.5,2.5,1.0,1.0)';
  three |         f1          
 -------+---------------------
        | (2,2),(0,0)
        | (3,3),(1,1)
        | (2.5,3.5),(2.5,2.5)
 (3 rows)
 
 -- left-or-overlap (x only)
 SELECT '' AS two, b1.*
    FROM BOX_TBL b1
    WHERE b1.f1 &< box '(2.0,2.0,2.5,2.5)';
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- right-or-overlap (x only)
 SELECT '' AS two, b1.*
    FROM BOX_TBL b1
    WHERE b1.f1 &> box '(2.0,2.0,2.5,2.5)';
  two |         f1          
 -----+---------------------
      | (2.5,3.5),(2.5,2.5)
      | (3,3),(3,3)
 (2 rows)
 
 -- left of
 SELECT '' AS two, b.f1
    FROM BOX_TBL b
    WHERE b.f1 << box '(3.0,3.0,5.0,5.0)';
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- area <=
 SELECT '' AS four, b.f1
    FROM BOX_TBL b
    WHERE b.f1 <= box '(3.0,3.0,5.0,5.0)';
  four |         f1          
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
       | (2.5,3.5),(2.5,2.5)
@@ -120,47 +137,50 @@ SELECT '' AS two, b.f1
  two |     f1      
 -----+-------------
      | (2,2),(0,0)
      | (3,3),(1,1)
 (2 rows)
 
 -- area >
 SELECT '' AS two, b.f1
    FROM BOX_TBL b				-- zero area
    WHERE b.f1 > box '(3.5,3.0,4.5,3.0)';
- two |     f1      
------+-------------
+ two |       f1        
+-----+-----------------
      | (2,2),(0,0)
      | (3,3),(1,1)
-(2 rows)
+     | (-2,2),(-8,-10)
+(3 rows)
 
 -- area >=
 SELECT '' AS four, b.f1
    FROM BOX_TBL b				-- zero area
    WHERE b.f1 >= box '(3.5,3.0,4.5,3.0)';
  four |         f1          
 ------+---------------------
       | (2,2),(0,0)
       | (3,3),(1,1)
+      | (-2,2),(-8,-10)
       | (2.5,3.5),(2.5,2.5)
       | (3,3),(3,3)
-(4 rows)
+(5 rows)
 
 -- right of
 SELECT '' AS two, b.f1
    FROM BOX_TBL b
    WHERE box '(3.0,3.0,5.0,5.0)' >> b.f1;
  two |         f1          
 -----+---------------------
      | (2,2),(0,0)
+     | (-2,2),(-8,-10)
      | (2.5,3.5),(2.5,2.5)
-(2 rows)
+(3 rows)
 
 -- contained in
 SELECT '' AS three, b.f1
    FROM BOX_TBL b
    WHERE b.f1 <@ box '(0,0,3,3)';
  three |     f1      
 -------+-------------
        | (2,2),(0,0)
        | (3,3),(1,1)
        | (3,3),(3,3)
@@ -186,41 +206,43 @@ SELECT '' AS one, b.f1
      | (3,3),(1,1)
 (1 row)
 
 -- center of box, left unary operator
 SELECT '' AS four, @@(b1.f1) AS p
    FROM BOX_TBL b1;
  four |    p    
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 -- wholly-contained
 SELECT '' AS one, b1.*, b2.*
    FROM BOX_TBL b1, BOX_TBL b2
    WHERE b1.f1 @> b2.f1 and not b1.f1 ~= b2.f1;
  one |     f1      |     f1      
 -----+-------------+-------------
      | (3,3),(1,1) | (3,3),(3,3)
 (1 row)
 
 SELECT '' AS four, height(f1), width(f1) FROM BOX_TBL;
  four | height | width 
 ------+--------+-------
       |      2 |     2
       |      2 |     2
+      |     12 |     6
       |      1 |     0
       |      0 |     0
-(4 rows)
+(5 rows)
 
 --
 -- Test the SP-GiST index
 --
 CREATE TEMPORARY TABLE box_temp (f1 box);
 INSERT INTO box_temp
 	SELECT box(point(i, i), point(i * 2, i * 2))
 	FROM generate_series(1, 50) AS i;
 CREATE INDEX box_spgist ON box_temp USING spgist (f1);
 INSERT INTO box_temp
diff --git a/src/test/regress/expected/circle.out b/src/test/regress/expected/circle.out
index 9ba4a0495d..2ed74cc6aa 100644
--- a/src/test/regress/expected/circle.out
+++ b/src/test/regress/expected/circle.out
@@ -1,99 +1,122 @@
 --
 -- CIRCLE
 --
 CREATE TABLE CIRCLE_TBL (f1 circle);
 INSERT INTO CIRCLE_TBL VALUES ('<(5,1),3>');
 INSERT INTO CIRCLE_TBL VALUES ('<(1,2),100>');
 INSERT INTO CIRCLE_TBL VALUES ('1,3,5');
 INSERT INTO CIRCLE_TBL VALUES ('((1,2),3)');
 INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10>');
-INSERT INTO CIRCLE_TBL VALUES ('<(100,1),115>');
+INSERT INTO CIRCLE_TBL VALUES (' < ( 100 , 1 ) , 115 > ');
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),0>');	-- Zero radius
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),NaN>');	-- NaN radius
 -- bad values
 INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
 ERROR:  invalid input syntax for type circle: "<(-100,0),-100>"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
                                        ^
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+ERROR:  invalid input syntax for type circle: "<(100,200),10"
+LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+                                       ^
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+ERROR:  invalid input syntax for type circle: "<(100,200),10> x"
+LINE 1: INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+                                       ^
 INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
 ERROR:  invalid input syntax for type circle: "1abc,3,5"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
                                        ^
 INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
 ERROR:  invalid input syntax for type circle: "(3,(1,2),3)"
 LINE 1: INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
                                        ^
 SELECT * FROM CIRCLE_TBL;
        f1       
 ----------------
  <(5,1),3>
  <(1,2),100>
  <(1,3),5>
  <(1,2),3>
  <(100,200),10>
  <(100,1),115>
-(6 rows)
+ <(3,5),0>
+ <(3,5),NaN>
+(8 rows)
 
 SELECT '' AS six, center(f1) AS center
   FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS six, radius(f1) AS radius
   FROM CIRCLE_TBL;
  six | radius 
 -----+--------
      |      3
      |    100
      |      5
      |      3
      |     10
      |    115
-(6 rows)
+     |      0
+     |    NaN
+(8 rows)
 
 SELECT '' AS six, diameter(f1) AS diameter
   FROM CIRCLE_TBL;
  six | diameter 
 -----+----------
      |        6
      |      200
      |       10
      |        6
      |       20
      |      230
-(6 rows)
+     |        0
+     |      NaN
+(8 rows)
 
 SELECT '' AS two, f1 FROM CIRCLE_TBL WHERE radius(f1) < 5;
  two |    f1     
 -----+-----------
      | <(5,1),3>
      | <(1,2),3>
-(2 rows)
+     | <(3,5),0>
+(3 rows)
 
 SELECT '' AS four, f1 FROM CIRCLE_TBL WHERE diameter(f1) >= 10;
  four |       f1       
 ------+----------------
       | <(1,2),100>
       | <(1,3),5>
       | <(100,200),10>
       | <(100,1),115>
-(4 rows)
+      | <(3,5),NaN>
+(5 rows)
 
 SELECT '' as five, c1.f1 AS one, c2.f1 AS two, (c1.f1 <-> c2.f1) AS distance
   FROM CIRCLE_TBL c1, CIRCLE_TBL c2
   WHERE (c1.f1 < c2.f1) AND ((c1.f1 <-> c2.f1) > 0)
   ORDER BY distance, area(c1.f1), area(c2.f1);
  five |      one       |      two       |     distance     
 ------+----------------+----------------+------------------
+      | <(3,5),0>      | <(1,2),3>      | 0.60555127546399
+      | <(3,5),0>      | <(5,1),3>      | 1.47213595499958
       | <(100,200),10> | <(100,1),115>  |               74
       | <(100,200),10> | <(1,2),100>    | 111.370729772479
       | <(1,3),5>      | <(100,200),10> | 205.476756144497
       | <(5,1),3>      | <(100,200),10> |  207.51303816328
+      | <(3,5),0>      | <(100,200),10> | 207.793480159531
       | <(1,2),3>      | <(100,200),10> | 208.370729772479
-(5 rows)
+(8 rows)
 
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index be25101db2..c33910c392 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -150,96 +150,103 @@ SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)';
 
 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
+     5
 (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
+     3
 (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
+     4
 (1 row)
 
 SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
  count 
 -------
      1
 (1 row)
 
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
  (-5,-12)
  (5.1,34.5)
+ (1e+300,Infinity)
+ (NaN,NaN)
  
-(7 rows)
+(10 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NULL;
  f1 
 ----
  
 (1 row)
 
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (1e-300,-1e-300)
  (0,0)
  (-3,4)
  (-10,0)
  (10,10)
  (-5,-12)
  (5.1,34.5)
-(6 rows)
+ (1e+300,Infinity)
+ (NaN,NaN)
+(9 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
  count 
 -------
      3
 (1 row)
 
 SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
  count 
 -------
@@ -567,21 +574,21 @@ SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,
                                        QUERY PLAN                                       
 ----------------------------------------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     4
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>';
                      QUERY PLAN                     
 ----------------------------------------------------
  Aggregate
    ->  Index Only Scan using gpointind on point_tbl
          Index Cond: (f1 <@ '<(50,50),50>'::circle)
 (3 rows)
@@ -612,21 +619,21 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     3
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl p WHERE p.f1 <^ '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only Scan using gpointind on point_tbl p
          Index Cond: (f1 <^ '(0,0)'::point)
 (3 rows)
@@ -642,21 +649,21 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 >^ '(0.0, 0.0)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only 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
+     4
 (1 row)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
                       QUERY PLAN                      
 ------------------------------------------------------
  Aggregate
    ->  Index Only Scan using gpointind on point_tbl p
          Index Cond: (f1 ~= '(-5,-12)'::point)
 (3 rows)
@@ -669,30 +676,33 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
                   QUERY PLAN                  
 ----------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Order By: (f1 <-> '(0,1)'::point)
 (2 rows)
 
 SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (10,10)
+ (NaN,NaN)
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
- (10,10)
  (-5,-12)
  (5.1,34.5)
  
-(7 rows)
+ (1e+300,Infinity)
+(10 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 IS NULL;
                   QUERY PLAN                  
 ----------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Index Cond: (f1 IS NULL)
 (2 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NULL;
@@ -704,47 +714,51 @@ SELECT * FROM point_tbl WHERE f1 IS NULL;
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
                   QUERY PLAN                  
 ----------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Index Cond: (f1 IS NOT NULL)
    Order By: (f1 <-> '(0,1)'::point)
 (3 rows)
 
 SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
-     f1     
-------------
+        f1         
+-------------------
+ (10,10)
+ (NaN,NaN)
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
- (10,10)
  (-5,-12)
  (5.1,34.5)
-(6 rows)
+ (1e+300,Infinity)
+(9 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
                    QUERY PLAN                   
 ------------------------------------------------
  Index Only Scan using gpointind on point_tbl
    Index Cond: (f1 <@ '(10,10),(-10,-10)'::box)
    Order By: (f1 <-> '(0,1)'::point)
 (3 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
                         QUERY PLAN                         
 -----------------------------------------------------------
  Aggregate
    ->  Index Only Scan using sp_quad_ind on quad_point_tbl
          Index Cond: (p IS NULL)
 (3 rows)
 
@@ -1261,27 +1275,28 @@ SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0
 ------------------------------------------------------------
  Sort
    Sort Key: ((f1 <-> '(0,1)'::point))
    ->  Bitmap Heap Scan on point_tbl
          Recheck Cond: (f1 <@ '(10,10),(-10,-10)'::box)
          ->  Bitmap Index Scan on gpointind
                Index Cond: (f1 <@ '(10,10),(-10,-10)'::box)
 (6 rows)
 
 SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-   f1    
----------
+        f1        
+------------------
  (0,0)
+ (1e-300,-1e-300)
  (-3,4)
  (-10,0)
  (10,10)
-(4 rows)
+(5 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
                   QUERY PLAN                  
 ----------------------------------------------
  Aggregate
    ->  Bitmap Heap Scan on quad_point_tbl
          Recheck Cond: (p IS NULL)
          ->  Bitmap Index Scan on sp_quad_ind
                Index Cond: (p IS NULL)
diff --git a/src/test/regress/expected/geometry.out b/src/test/regress/expected/geometry.out
index e4c0039040..b4da3baa37 100644
--- a/src/test/regress/expected/geometry.out
+++ b/src/test/regress/expected/geometry.out
@@ -6,558 +6,4885 @@
 SET extra_float_digits TO -3;
 --
 -- Points
 --
 SELECT '' AS four, center(f1) AS center
    FROM BOX_TBL;
  four | center  
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, (@@ f1) AS center
    FROM BOX_TBL;
  four | center  
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS six, point(f1) AS center
    FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS six, (@@ f1) AS center
    FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS two, (@@ f1) AS center
    FROM POLYGON_TBL
    WHERE (# f1) > 2;
  two |            center             
 -----+-------------------------------
      | (1.33333333333,1.33333333333)
      | (2.33333333333,1.33333333333)
-(2 rows)
+     | (4,5)
+     | (4,5)
+     | (4,3)
+(5 rows)
 
 -- "is horizontal" function
 SELECT '' AS two, p1.f1
    FROM POINT_TBL p1
    WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 -- "is horizontal" operator
 SELECT '' AS two, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 -- "is vertical" function
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE isvertical(p1.f1, point '(5.1,34.5)');
  one |     f1     
 -----+------------
      | (5.1,34.5)
 (1 row)
 
 -- "is vertical" operator
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?| point '(5.1,34.5)';
  one |     f1     
 -----+------------
      | (5.1,34.5)
 (1 row)
 
+-- Slope
+SELECT p1.f1, p2.f1, slope(p1.f1, p2.f1) FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |       slope        
+-------------------+-------------------+--------------------
+ (0,0)             | (0,0)             | 1.79769313486e+308
+ (0,0)             | (-10,0)           |                  0
+ (0,0)             | (-3,4)            |     -1.33333333333
+ (0,0)             | (5.1,34.5)        |      6.76470588235
+ (0,0)             | (-5,-12)          |                2.4
+ (0,0)             | (1e-300,-1e-300)  | 1.79769313486e+308
+ (0,0)             | (1e+300,Infinity) |           Infinity
+ (0,0)             | (NaN,NaN)         |                NaN
+ (0,0)             | (10,10)           |                  1
+ (-10,0)           | (0,0)             |                  0
+ (-10,0)           | (-10,0)           | 1.79769313486e+308
+ (-10,0)           | (-3,4)            |     0.571428571429
+ (-10,0)           | (5.1,34.5)        |      2.28476821192
+ (-10,0)           | (-5,-12)          |               -2.4
+ (-10,0)           | (1e-300,-1e-300)  |                  0
+ (-10,0)           | (1e+300,Infinity) |           Infinity
+ (-10,0)           | (NaN,NaN)         |                NaN
+ (-10,0)           | (10,10)           |                0.5
+ (-3,4)            | (0,0)             |     -1.33333333333
+ (-3,4)            | (-10,0)           |     0.571428571429
+ (-3,4)            | (-3,4)            | 1.79769313486e+308
+ (-3,4)            | (5.1,34.5)        |      3.76543209877
+ (-3,4)            | (-5,-12)          |                  8
+ (-3,4)            | (1e-300,-1e-300)  |     -1.33333333333
+ (-3,4)            | (1e+300,Infinity) |           Infinity
+ (-3,4)            | (NaN,NaN)         |                NaN
+ (-3,4)            | (10,10)           |     0.461538461538
+ (5.1,34.5)        | (0,0)             |      6.76470588235
+ (5.1,34.5)        | (-10,0)           |      2.28476821192
+ (5.1,34.5)        | (-3,4)            |      3.76543209877
+ (5.1,34.5)        | (5.1,34.5)        | 1.79769313486e+308
+ (5.1,34.5)        | (-5,-12)          |      4.60396039604
+ (5.1,34.5)        | (1e-300,-1e-300)  |      6.76470588235
+ (5.1,34.5)        | (1e+300,Infinity) |           Infinity
+ (5.1,34.5)        | (NaN,NaN)         |                NaN
+ (5.1,34.5)        | (10,10)           |                 -5
+ (-5,-12)          | (0,0)             |                2.4
+ (-5,-12)          | (-10,0)           |               -2.4
+ (-5,-12)          | (-3,4)            |                  8
+ (-5,-12)          | (5.1,34.5)        |      4.60396039604
+ (-5,-12)          | (-5,-12)          | 1.79769313486e+308
+ (-5,-12)          | (1e-300,-1e-300)  |                2.4
+ (-5,-12)          | (1e+300,Infinity) |           Infinity
+ (-5,-12)          | (NaN,NaN)         |                NaN
+ (-5,-12)          | (10,10)           |      1.46666666667
+ (1e-300,-1e-300)  | (0,0)             | 1.79769313486e+308
+ (1e-300,-1e-300)  | (-10,0)           |                  0
+ (1e-300,-1e-300)  | (-3,4)            |     -1.33333333333
+ (1e-300,-1e-300)  | (5.1,34.5)        |      6.76470588235
+ (1e-300,-1e-300)  | (-5,-12)          |                2.4
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | 1.79769313486e+308
+ (1e-300,-1e-300)  | (1e+300,Infinity) |           Infinity
+ (1e-300,-1e-300)  | (NaN,NaN)         |                NaN
+ (1e-300,-1e-300)  | (10,10)           |                  1
+ (1e+300,Infinity) | (0,0)             |           Infinity
+ (1e+300,Infinity) | (-10,0)           |           Infinity
+ (1e+300,Infinity) | (-3,4)            |           Infinity
+ (1e+300,Infinity) | (5.1,34.5)        |           Infinity
+ (1e+300,Infinity) | (-5,-12)          |           Infinity
+ (1e+300,Infinity) | (1e-300,-1e-300)  |           Infinity
+ (1e+300,Infinity) | (1e+300,Infinity) | 1.79769313486e+308
+ (1e+300,Infinity) | (NaN,NaN)         |                NaN
+ (1e+300,Infinity) | (10,10)           |           Infinity
+ (NaN,NaN)         | (0,0)             |                NaN
+ (NaN,NaN)         | (-10,0)           |                NaN
+ (NaN,NaN)         | (-3,4)            |                NaN
+ (NaN,NaN)         | (5.1,34.5)        |                NaN
+ (NaN,NaN)         | (-5,-12)          |                NaN
+ (NaN,NaN)         | (1e-300,-1e-300)  |                NaN
+ (NaN,NaN)         | (1e+300,Infinity) |                NaN
+ (NaN,NaN)         | (NaN,NaN)         |                NaN
+ (NaN,NaN)         | (10,10)           |                NaN
+ (10,10)           | (0,0)             |                  1
+ (10,10)           | (-10,0)           |                0.5
+ (10,10)           | (-3,4)            |     0.461538461538
+ (10,10)           | (5.1,34.5)        |                 -5
+ (10,10)           | (-5,-12)          |      1.46666666667
+ (10,10)           | (1e-300,-1e-300)  |                  1
+ (10,10)           | (1e+300,Infinity) |           Infinity
+ (10,10)           | (NaN,NaN)         |                NaN
+ (10,10)           | (10,10)           | 1.79769313486e+308
+(81 rows)
+
+-- Add point
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |     ?column?      
+-------------------+-------------------+-------------------
+ (0,0)             | (0,0)             | (0,0)
+ (0,0)             | (-10,0)           | (-10,0)
+ (0,0)             | (-3,4)            | (-3,4)
+ (0,0)             | (5.1,34.5)        | (5.1,34.5)
+ (0,0)             | (-5,-12)          | (-5,-12)
+ (0,0)             | (1e-300,-1e-300)  | (1e-300,-1e-300)
+ (0,0)             | (1e+300,Infinity) | (1e+300,Infinity)
+ (0,0)             | (NaN,NaN)         | (NaN,NaN)
+ (0,0)             | (10,10)           | (10,10)
+ (-10,0)           | (0,0)             | (-10,0)
+ (-10,0)           | (-10,0)           | (-20,0)
+ (-10,0)           | (-3,4)            | (-13,4)
+ (-10,0)           | (5.1,34.5)        | (-4.9,34.5)
+ (-10,0)           | (-5,-12)          | (-15,-12)
+ (-10,0)           | (1e-300,-1e-300)  | (-10,-1e-300)
+ (-10,0)           | (1e+300,Infinity) | (1e+300,Infinity)
+ (-10,0)           | (NaN,NaN)         | (NaN,NaN)
+ (-10,0)           | (10,10)           | (0,10)
+ (-3,4)            | (0,0)             | (-3,4)
+ (-3,4)            | (-10,0)           | (-13,4)
+ (-3,4)            | (-3,4)            | (-6,8)
+ (-3,4)            | (5.1,34.5)        | (2.1,38.5)
+ (-3,4)            | (-5,-12)          | (-8,-8)
+ (-3,4)            | (1e-300,-1e-300)  | (-3,4)
+ (-3,4)            | (1e+300,Infinity) | (1e+300,Infinity)
+ (-3,4)            | (NaN,NaN)         | (NaN,NaN)
+ (-3,4)            | (10,10)           | (7,14)
+ (5.1,34.5)        | (0,0)             | (5.1,34.5)
+ (5.1,34.5)        | (-10,0)           | (-4.9,34.5)
+ (5.1,34.5)        | (-3,4)            | (2.1,38.5)
+ (5.1,34.5)        | (5.1,34.5)        | (10.2,69)
+ (5.1,34.5)        | (-5,-12)          | (0.1,22.5)
+ (5.1,34.5)        | (1e-300,-1e-300)  | (5.1,34.5)
+ (5.1,34.5)        | (1e+300,Infinity) | (1e+300,Infinity)
+ (5.1,34.5)        | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5)        | (10,10)           | (15.1,44.5)
+ (-5,-12)          | (0,0)             | (-5,-12)
+ (-5,-12)          | (-10,0)           | (-15,-12)
+ (-5,-12)          | (-3,4)            | (-8,-8)
+ (-5,-12)          | (5.1,34.5)        | (0.1,22.5)
+ (-5,-12)          | (-5,-12)          | (-10,-24)
+ (-5,-12)          | (1e-300,-1e-300)  | (-5,-12)
+ (-5,-12)          | (1e+300,Infinity) | (1e+300,Infinity)
+ (-5,-12)          | (NaN,NaN)         | (NaN,NaN)
+ (-5,-12)          | (10,10)           | (5,-2)
+ (1e-300,-1e-300)  | (0,0)             | (1e-300,-1e-300)
+ (1e-300,-1e-300)  | (-10,0)           | (-10,-1e-300)
+ (1e-300,-1e-300)  | (-3,4)            | (-3,4)
+ (1e-300,-1e-300)  | (5.1,34.5)        | (5.1,34.5)
+ (1e-300,-1e-300)  | (-5,-12)          | (-5,-12)
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | (2e-300,-2e-300)
+ (1e-300,-1e-300)  | (1e+300,Infinity) | (1e+300,Infinity)
+ (1e-300,-1e-300)  | (NaN,NaN)         | (NaN,NaN)
+ (1e-300,-1e-300)  | (10,10)           | (10,10)
+ (1e+300,Infinity) | (0,0)             | (1e+300,Infinity)
+ (1e+300,Infinity) | (-10,0)           | (1e+300,Infinity)
+ (1e+300,Infinity) | (-3,4)            | (1e+300,Infinity)
+ (1e+300,Infinity) | (5.1,34.5)        | (1e+300,Infinity)
+ (1e+300,Infinity) | (-5,-12)          | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e-300,-1e-300)  | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e+300,Infinity) | (2e+300,Infinity)
+ (1e+300,Infinity) | (NaN,NaN)         | (NaN,NaN)
+ (1e+300,Infinity) | (10,10)           | (1e+300,Infinity)
+ (NaN,NaN)         | (0,0)             | (NaN,NaN)
+ (NaN,NaN)         | (-10,0)           | (NaN,NaN)
+ (NaN,NaN)         | (-3,4)            | (NaN,NaN)
+ (NaN,NaN)         | (5.1,34.5)        | (NaN,NaN)
+ (NaN,NaN)         | (-5,-12)          | (NaN,NaN)
+ (NaN,NaN)         | (1e-300,-1e-300)  | (NaN,NaN)
+ (NaN,NaN)         | (1e+300,Infinity) | (NaN,NaN)
+ (NaN,NaN)         | (NaN,NaN)         | (NaN,NaN)
+ (NaN,NaN)         | (10,10)           | (NaN,NaN)
+ (10,10)           | (0,0)             | (10,10)
+ (10,10)           | (-10,0)           | (0,10)
+ (10,10)           | (-3,4)            | (7,14)
+ (10,10)           | (5.1,34.5)        | (15.1,44.5)
+ (10,10)           | (-5,-12)          | (5,-2)
+ (10,10)           | (1e-300,-1e-300)  | (10,10)
+ (10,10)           | (1e+300,Infinity) | (1e+300,Infinity)
+ (10,10)           | (NaN,NaN)         | (NaN,NaN)
+ (10,10)           | (10,10)           | (20,20)
+(81 rows)
+
+-- Subtract point
+SELECT p1.f1, p2.f1, p1.f1 - p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |      ?column?       
+-------------------+-------------------+---------------------
+ (0,0)             | (0,0)             | (0,0)
+ (0,0)             | (-10,0)           | (10,0)
+ (0,0)             | (-3,4)            | (3,-4)
+ (0,0)             | (5.1,34.5)        | (-5.1,-34.5)
+ (0,0)             | (-5,-12)          | (5,12)
+ (0,0)             | (1e-300,-1e-300)  | (-1e-300,1e-300)
+ (0,0)             | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (0,0)             | (NaN,NaN)         | (NaN,NaN)
+ (0,0)             | (10,10)           | (-10,-10)
+ (-10,0)           | (0,0)             | (-10,0)
+ (-10,0)           | (-10,0)           | (0,0)
+ (-10,0)           | (-3,4)            | (-7,-4)
+ (-10,0)           | (5.1,34.5)        | (-15.1,-34.5)
+ (-10,0)           | (-5,-12)          | (-5,12)
+ (-10,0)           | (1e-300,-1e-300)  | (-10,1e-300)
+ (-10,0)           | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-10,0)           | (NaN,NaN)         | (NaN,NaN)
+ (-10,0)           | (10,10)           | (-20,-10)
+ (-3,4)            | (0,0)             | (-3,4)
+ (-3,4)            | (-10,0)           | (7,4)
+ (-3,4)            | (-3,4)            | (0,0)
+ (-3,4)            | (5.1,34.5)        | (-8.1,-30.5)
+ (-3,4)            | (-5,-12)          | (2,16)
+ (-3,4)            | (1e-300,-1e-300)  | (-3,4)
+ (-3,4)            | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-3,4)            | (NaN,NaN)         | (NaN,NaN)
+ (-3,4)            | (10,10)           | (-13,-6)
+ (5.1,34.5)        | (0,0)             | (5.1,34.5)
+ (5.1,34.5)        | (-10,0)           | (15.1,34.5)
+ (5.1,34.5)        | (-3,4)            | (8.1,30.5)
+ (5.1,34.5)        | (5.1,34.5)        | (0,0)
+ (5.1,34.5)        | (-5,-12)          | (10.1,46.5)
+ (5.1,34.5)        | (1e-300,-1e-300)  | (5.1,34.5)
+ (5.1,34.5)        | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (5.1,34.5)        | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5)        | (10,10)           | (-4.9,24.5)
+ (-5,-12)          | (0,0)             | (-5,-12)
+ (-5,-12)          | (-10,0)           | (5,-12)
+ (-5,-12)          | (-3,4)            | (-2,-16)
+ (-5,-12)          | (5.1,34.5)        | (-10.1,-46.5)
+ (-5,-12)          | (-5,-12)          | (0,0)
+ (-5,-12)          | (1e-300,-1e-300)  | (-5,-12)
+ (-5,-12)          | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-5,-12)          | (NaN,NaN)         | (NaN,NaN)
+ (-5,-12)          | (10,10)           | (-15,-22)
+ (1e-300,-1e-300)  | (0,0)             | (1e-300,-1e-300)
+ (1e-300,-1e-300)  | (-10,0)           | (10,-1e-300)
+ (1e-300,-1e-300)  | (-3,4)            | (3,-4)
+ (1e-300,-1e-300)  | (5.1,34.5)        | (-5.1,-34.5)
+ (1e-300,-1e-300)  | (-5,-12)          | (5,12)
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | (0,0)
+ (1e-300,-1e-300)  | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (1e-300,-1e-300)  | (NaN,NaN)         | (NaN,NaN)
+ (1e-300,-1e-300)  | (10,10)           | (-10,-10)
+ (1e+300,Infinity) | (0,0)             | (1e+300,Infinity)
+ (1e+300,Infinity) | (-10,0)           | (1e+300,Infinity)
+ (1e+300,Infinity) | (-3,4)            | (1e+300,Infinity)
+ (1e+300,Infinity) | (5.1,34.5)        | (1e+300,Infinity)
+ (1e+300,Infinity) | (-5,-12)          | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e-300,-1e-300)  | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e+300,Infinity) | (0,NaN)
+ (1e+300,Infinity) | (NaN,NaN)         | (NaN,NaN)
+ (1e+300,Infinity) | (10,10)           | (1e+300,Infinity)
+ (NaN,NaN)         | (0,0)             | (NaN,NaN)
+ (NaN,NaN)         | (-10,0)           | (NaN,NaN)
+ (NaN,NaN)         | (-3,4)            | (NaN,NaN)
+ (NaN,NaN)         | (5.1,34.5)        | (NaN,NaN)
+ (NaN,NaN)         | (-5,-12)          | (NaN,NaN)
+ (NaN,NaN)         | (1e-300,-1e-300)  | (NaN,NaN)
+ (NaN,NaN)         | (1e+300,Infinity) | (NaN,NaN)
+ (NaN,NaN)         | (NaN,NaN)         | (NaN,NaN)
+ (NaN,NaN)         | (10,10)           | (NaN,NaN)
+ (10,10)           | (0,0)             | (10,10)
+ (10,10)           | (-10,0)           | (20,10)
+ (10,10)           | (-3,4)            | (13,6)
+ (10,10)           | (5.1,34.5)        | (4.9,-24.5)
+ (10,10)           | (-5,-12)          | (15,22)
+ (10,10)           | (1e-300,-1e-300)  | (10,10)
+ (10,10)           | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (10,10)           | (NaN,NaN)         | (NaN,NaN)
+ (10,10)           | (10,10)           | (0,0)
+(81 rows)
+
+-- Multiply with point
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+     f1     |        f1         |       ?column?        
+------------+-------------------+-----------------------
+ (5.1,34.5) | (0,0)             | (0,0)
+ (10,10)    | (0,0)             | (0,0)
+ (5.1,34.5) | (-10,0)           | (-51,-345)
+ (10,10)    | (-10,0)           | (-100,-100)
+ (5.1,34.5) | (-3,4)            | (-153.3,-83.1)
+ (10,10)    | (-3,4)            | (-70,10)
+ (5.1,34.5) | (5.1,34.5)        | (-1164.24,351.9)
+ (10,10)    | (5.1,34.5)        | (-294,396)
+ (5.1,34.5) | (-5,-12)          | (388.5,-233.7)
+ (10,10)    | (-5,-12)          | (70,-170)
+ (5.1,34.5) | (1e-300,-1e-300)  | (3.96e-299,2.94e-299)
+ (10,10)    | (1e-300,-1e-300)  | (2e-299,0)
+ (5.1,34.5) | (1e+300,Infinity) | (-Infinity,Infinity)
+ (10,10)    | (1e+300,Infinity) | (-Infinity,Infinity)
+ (5.1,34.5) | (NaN,NaN)         | (NaN,NaN)
+ (10,10)    | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5) | (10,10)           | (-294,396)
+ (10,10)    | (10,10)           | (0,200)
+(18 rows)
+
+-- Underflow error
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] < 1;
+ERROR:  value out of range: underflow
+-- Divide by point
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] BETWEEN 1 AND 1000;
+        f1         |     f1     |                 ?column?                  
+-------------------+------------+-------------------------------------------
+ (0,0)             | (5.1,34.5) | (0,0)
+ (0,0)             | (10,10)    | (0,0)
+ (-10,0)           | (5.1,34.5) | (-0.0419318237877,0.283656455034)
+ (-10,0)           | (10,10)    | (-0.5,0.5)
+ (-3,4)            | (5.1,34.5) | (0.100883034877,0.101869666025)
+ (-3,4)            | (10,10)    | (0.05,0.35)
+ (5.1,34.5)        | (5.1,34.5) | (1,0)
+ (5.1,34.5)        | (10,10)    | (1.98,1.47)
+ (-5,-12)          | (5.1,34.5) | (-0.361353657935,0.0915100389719)
+ (-5,-12)          | (10,10)    | (-0.85,-0.35)
+ (1e-300,-1e-300)  | (5.1,34.5) | (-2.41724631247e-302,-3.25588278822e-302)
+ (1e-300,-1e-300)  | (10,10)    | (0,-1e-301)
+ (1e+300,Infinity) | (5.1,34.5) | (Infinity,Infinity)
+ (1e+300,Infinity) | (10,10)    | (Infinity,Infinity)
+ (NaN,NaN)         | (5.1,34.5) | (NaN,NaN)
+ (NaN,NaN)         | (10,10)    | (NaN,NaN)
+ (10,10)           | (5.1,34.5) | (0.325588278822,-0.241724631247)
+ (10,10)           | (10,10)    | (1,0)
+(18 rows)
+
+-- Overflow error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] > 1000;
+ERROR:  value out of range: overflow
+-- Division by 0 error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to line
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LINE_TBL l;
+        f1         |                   s                   |      ?column?      
+-------------------+---------------------------------------+--------------------
+ (0,0)             | {0,-1,5}                              |                  5
+ (0,0)             | {1,0,5}                               |                  5
+ (0,0)             | {0,3,0}                               |                  0
+ (0,0)             | {1,-1,0}                              |                  0
+ (0,0)             | {-0.4,-1,-6}                          |      5.57086014531
+ (0,0)             | {-0.000184615384615,-1,15.3846153846} |      15.3846151224
+ (0,0)             | {3,NaN,5}                             |                NaN
+ (0,0)             | {NaN,NaN,NaN}                         |                NaN
+ (0,0)             | {0,-1,3}                              |                  3
+ (0,0)             | {-1,0,3}                              |                  3
+ (-10,0)           | {0,-1,5}                              |                  5
+ (-10,0)           | {1,0,5}                               |                  5
+ (-10,0)           | {0,3,0}                               |                  0
+ (-10,0)           | {1,-1,0}                              |      7.07106781187
+ (-10,0)           | {-0.4,-1,-6}                          |      1.85695338177
+ (-10,0)           | {-0.000184615384615,-1,15.3846153846} |      15.3864612763
+ (-10,0)           | {3,NaN,5}                             |                NaN
+ (-10,0)           | {NaN,NaN,NaN}                         |                NaN
+ (-10,0)           | {0,-1,3}                              |                  3
+ (-10,0)           | {-1,0,3}                              |                 13
+ (-3,4)            | {0,-1,5}                              |                  1
+ (-3,4)            | {1,0,5}                               |                  2
+ (-3,4)            | {0,3,0}                               |                  4
+ (-3,4)            | {1,-1,0}                              |      4.94974746831
+ (-3,4)            | {-0.4,-1,-6}                          |      8.17059487979
+ (-3,4)            | {-0.000184615384615,-1,15.3846153846} |      11.3851690368
+ (-3,4)            | {3,NaN,5}                             |                NaN
+ (-3,4)            | {NaN,NaN,NaN}                         |                NaN
+ (-3,4)            | {0,-1,3}                              |                  1
+ (-3,4)            | {-1,0,3}                              |                  6
+ (5.1,34.5)        | {0,-1,5}                              |               29.5
+ (5.1,34.5)        | {1,0,5}                               |               10.1
+ (5.1,34.5)        | {0,3,0}                               |               34.5
+ (5.1,34.5)        | {1,-1,0}                              |      20.7889393669
+ (5.1,34.5)        | {-0.4,-1,-6}                          |      39.4973984303
+ (5.1,34.5)        | {-0.000184615384615,-1,15.3846153846} |      19.1163258281
+ (5.1,34.5)        | {3,NaN,5}                             |                NaN
+ (5.1,34.5)        | {NaN,NaN,NaN}                         |                NaN
+ (5.1,34.5)        | {0,-1,3}                              |               31.5
+ (5.1,34.5)        | {-1,0,3}                              |                2.1
+ (-5,-12)          | {0,-1,5}                              |                 17
+ (-5,-12)          | {1,0,5}                               |                  0
+ (-5,-12)          | {0,3,0}                               |                 12
+ (-5,-12)          | {1,-1,0}                              |      4.94974746831
+ (-5,-12)          | {-0.4,-1,-6}                          |      7.42781352708
+ (-5,-12)          | {-0.000184615384615,-1,15.3846153846} |      27.3855379948
+ (-5,-12)          | {3,NaN,5}                             |                NaN
+ (-5,-12)          | {NaN,NaN,NaN}                         |                NaN
+ (-5,-12)          | {0,-1,3}                              |                 15
+ (-5,-12)          | {-1,0,3}                              |                  8
+ (1e-300,-1e-300)  | {0,-1,5}                              |                  5
+ (1e-300,-1e-300)  | {1,0,5}                               |                  5
+ (1e-300,-1e-300)  | {0,3,0}                               |             1e-300
+ (1e-300,-1e-300)  | {1,-1,0}                              | 1.41421356237e-300
+ (1e-300,-1e-300)  | {-0.4,-1,-6}                          |      5.57086014531
+ (1e-300,-1e-300)  | {-0.000184615384615,-1,15.3846153846} |      15.3846151224
+ (1e-300,-1e-300)  | {3,NaN,5}                             |                NaN
+ (1e-300,-1e-300)  | {NaN,NaN,NaN}                         |                NaN
+ (1e-300,-1e-300)  | {0,-1,3}                              |                  3
+ (1e-300,-1e-300)  | {-1,0,3}                              |                  3
+ (1e+300,Infinity) | {0,-1,5}                              |           Infinity
+ (1e+300,Infinity) | {1,0,5}                               |                NaN
+ (1e+300,Infinity) | {0,3,0}                               |           Infinity
+ (1e+300,Infinity) | {1,-1,0}                              |           Infinity
+ (1e+300,Infinity) | {-0.4,-1,-6}                          |           Infinity
+ (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} |           Infinity
+ (1e+300,Infinity) | {3,NaN,5}                             |                NaN
+ (1e+300,Infinity) | {NaN,NaN,NaN}                         |                NaN
+ (1e+300,Infinity) | {0,-1,3}                              |           Infinity
+ (1e+300,Infinity) | {-1,0,3}                              |                NaN
+ (NaN,NaN)         | {0,-1,5}                              |                NaN
+ (NaN,NaN)         | {1,0,5}                               |                NaN
+ (NaN,NaN)         | {0,3,0}                               |                NaN
+ (NaN,NaN)         | {1,-1,0}                              |                NaN
+ (NaN,NaN)         | {-0.4,-1,-6}                          |                NaN
+ (NaN,NaN)         | {-0.000184615384615,-1,15.3846153846} |                NaN
+ (NaN,NaN)         | {3,NaN,5}                             |                NaN
+ (NaN,NaN)         | {NaN,NaN,NaN}                         |                NaN
+ (NaN,NaN)         | {0,-1,3}                              |                NaN
+ (NaN,NaN)         | {-1,0,3}                              |                NaN
+ (10,10)           | {0,-1,5}                              |                  5
+ (10,10)           | {1,0,5}                               |                 15
+ (10,10)           | {0,3,0}                               |                 10
+ (10,10)           | {1,-1,0}                              |                  0
+ (10,10)           | {-0.4,-1,-6}                          |      18.5695338177
+ (10,10)           | {-0.000184615384615,-1,15.3846153846} |      5.38276913903
+ (10,10)           | {3,NaN,5}                             |                NaN
+ (10,10)           | {NaN,NaN,NaN}                         |                NaN
+ (10,10)           | {0,-1,3}                              |                  7
+ (10,10)           | {-1,0,3}                              |                  7
+(90 rows)
+
+-- Distance to line segment
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LSEG_TBL l;
+        f1         |               s               |      ?column?      
+-------------------+-------------------------------+--------------------
+ (0,0)             | [(1,2),(3,4)]                 |       2.2360679775
+ (0,0)             | [(0,0),(6,6)]                 |                  0
+ (0,0)             | [(10,-10),(-3,-4)]            |      4.88901207039
+ (0,0)             | [(-1000000,200),(300000,-40)] |      15.3846151224
+ (0,0)             | [(11,22),(33,44)]             |      24.5967477525
+ (0,0)             | [(-10,2),(-10,3)]             |      10.1980390272
+ (0,0)             | [(0,-20),(30,-20)]            |                 20
+ (0,0)             | [(NaN,1),(NaN,90)]            |                NaN
+ (-10,0)           | [(1,2),(3,4)]                 |      11.1803398875
+ (-10,0)           | [(0,0),(6,6)]                 |                 10
+ (-10,0)           | [(10,-10),(-3,-4)]            |       8.0622577483
+ (-10,0)           | [(-1000000,200),(300000,-40)] |      15.3864612763
+ (-10,0)           | [(11,22),(33,44)]             |      30.4138126515
+ (-10,0)           | [(-10,2),(-10,3)]             |                  2
+ (-10,0)           | [(0,-20),(30,-20)]            |       22.360679775
+ (-10,0)           | [(NaN,1),(NaN,90)]            |                NaN
+ (-3,4)            | [(1,2),(3,4)]                 |        4.472135955
+ (-3,4)            | [(0,0),(6,6)]                 |      4.94974746831
+ (-3,4)            | [(10,-10),(-3,-4)]            |                  8
+ (-3,4)            | [(-1000000,200),(300000,-40)] |      11.3851690367
+ (-3,4)            | [(11,22),(33,44)]             |       22.803508502
+ (-3,4)            | [(-10,2),(-10,3)]             |      7.07106781187
+ (-3,4)            | [(0,-20),(30,-20)]            |      24.1867732449
+ (-3,4)            | [(NaN,1),(NaN,90)]            |                NaN
+ (5.1,34.5)        | [(1,2),(3,4)]                 |      30.5722096028
+ (5.1,34.5)        | [(0,0),(6,6)]                 |      28.5142069853
+ (5.1,34.5)        | [(10,-10),(-3,-4)]            |      39.3428519556
+ (5.1,34.5)        | [(-1000000,200),(300000,-40)] |      19.1163258281
+ (5.1,34.5)        | [(11,22),(33,44)]             |      13.0107647738
+ (5.1,34.5)        | [(-10,2),(-10,3)]             |       34.932220084
+ (5.1,34.5)        | [(0,-20),(30,-20)]            |               54.5
+ (5.1,34.5)        | [(NaN,1),(NaN,90)]            |                NaN
+ (-5,-12)          | [(1,2),(3,4)]                 |      15.2315462117
+ (-5,-12)          | [(0,0),(6,6)]                 |                 13
+ (-5,-12)          | [(10,-10),(-3,-4)]            |      8.10179143093
+ (-5,-12)          | [(-1000000,200),(300000,-40)] |      27.3855379949
+ (-5,-12)          | [(11,22),(33,44)]             |      37.5765884561
+ (-5,-12)          | [(-10,2),(-10,3)]             |      14.8660687473
+ (-5,-12)          | [(0,-20),(30,-20)]            |      9.43398113206
+ (-5,-12)          | [(NaN,1),(NaN,90)]            |                NaN
+ (1e-300,-1e-300)  | [(1,2),(3,4)]                 |       2.2360679775
+ (1e-300,-1e-300)  | [(0,0),(6,6)]                 | 1.41421356237e-300
+ (1e-300,-1e-300)  | [(10,-10),(-3,-4)]            |      4.88901207039
+ (1e-300,-1e-300)  | [(-1000000,200),(300000,-40)] |      15.3846151224
+ (1e-300,-1e-300)  | [(11,22),(33,44)]             |      24.5967477525
+ (1e-300,-1e-300)  | [(-10,2),(-10,3)]             |      10.1980390272
+ (1e-300,-1e-300)  | [(0,-20),(30,-20)]            |                 20
+ (1e-300,-1e-300)  | [(NaN,1),(NaN,90)]            |                NaN
+ (1e+300,Infinity) | [(1,2),(3,4)]                 |           Infinity
+ (1e+300,Infinity) | [(0,0),(6,6)]                 |           Infinity
+ (1e+300,Infinity) | [(10,-10),(-3,-4)]            |           Infinity
+ (1e+300,Infinity) | [(-1000000,200),(300000,-40)] |           Infinity
+ (1e+300,Infinity) | [(11,22),(33,44)]             |           Infinity
+ (1e+300,Infinity) | [(-10,2),(-10,3)]             |           Infinity
+ (1e+300,Infinity) | [(0,-20),(30,-20)]            |           Infinity
+ (1e+300,Infinity) | [(NaN,1),(NaN,90)]            |           Infinity
+ (NaN,NaN)         | [(1,2),(3,4)]                 |                NaN
+ (NaN,NaN)         | [(0,0),(6,6)]                 |                NaN
+ (NaN,NaN)         | [(10,-10),(-3,-4)]            |                NaN
+ (NaN,NaN)         | [(-1000000,200),(300000,-40)] |                NaN
+ (NaN,NaN)         | [(11,22),(33,44)]             |                NaN
+ (NaN,NaN)         | [(-10,2),(-10,3)]             |                NaN
+ (NaN,NaN)         | [(0,-20),(30,-20)]            |                NaN
+ (NaN,NaN)         | [(NaN,1),(NaN,90)]            |                NaN
+ (10,10)           | [(1,2),(3,4)]                 |      9.21954445729
+ (10,10)           | [(0,0),(6,6)]                 |      5.65685424949
+ (10,10)           | [(10,-10),(-3,-4)]            |        18.15918769
+ (10,10)           | [(-1000000,200),(300000,-40)] |      5.38276913904
+ (10,10)           | [(11,22),(33,44)]             |      12.0415945788
+ (10,10)           | [(-10,2),(-10,3)]             |      21.1896201004
+ (10,10)           | [(0,-20),(30,-20)]            |                 30
+ (10,10)           | [(NaN,1),(NaN,90)]            |                NaN
+(72 rows)
+
+-- Distance to box
+SELECT p.f1, b.f1, p.f1 <-> b.f1 FROM POINT_TBL p, BOX_TBL b;
+        f1         |         f1          |      ?column?      
+-------------------+---------------------+--------------------
+ (0,0)             | (2,2),(0,0)         |                  0
+ (0,0)             | (3,3),(1,1)         |      1.41421356237
+ (0,0)             | (-2,2),(-8,-10)     |                  2
+ (0,0)             | (2.5,3.5),(2.5,2.5) |      3.53553390593
+ (0,0)             | (3,3),(3,3)         |      4.24264068712
+ (-10,0)           | (2,2),(0,0)         |                 10
+ (-10,0)           | (3,3),(1,1)         |      11.0453610172
+ (-10,0)           | (-2,2),(-8,-10)     |                  2
+ (-10,0)           | (2.5,3.5),(2.5,2.5) |       12.747548784
+ (-10,0)           | (3,3),(3,3)         |      13.3416640641
+ (-3,4)            | (2,2),(0,0)         |      3.60555127546
+ (-3,4)            | (3,3),(1,1)         |      4.12310562562
+ (-3,4)            | (-2,2),(-8,-10)     |                  2
+ (-3,4)            | (2.5,3.5),(2.5,2.5) |      5.52268050859
+ (-3,4)            | (3,3),(3,3)         |       6.0827625303
+ (5.1,34.5)        | (2,2),(0,0)         |      32.6475113906
+ (5.1,34.5)        | (3,3),(1,1)         |      31.5699223946
+ (5.1,34.5)        | (-2,2),(-8,-10)     |      33.2664996656
+ (5.1,34.5)        | (2.5,3.5),(2.5,2.5) |       31.108841187
+ (5.1,34.5)        | (3,3),(3,3)         |      31.5699223946
+ (-5,-12)          | (2,2),(0,0)         |                 13
+ (-5,-12)          | (3,3),(1,1)         |      14.3178210633
+ (-5,-12)          | (-2,2),(-8,-10)     |                  2
+ (-5,-12)          | (2.5,3.5),(2.5,2.5) |      16.3248277173
+ (-5,-12)          | (3,3),(3,3)         |                 17
+ (1e-300,-1e-300)  | (2,2),(0,0)         | 1.41421356237e-300
+ (1e-300,-1e-300)  | (3,3),(1,1)         |      1.41421356237
+ (1e-300,-1e-300)  | (-2,2),(-8,-10)     |                  2
+ (1e-300,-1e-300)  | (2.5,3.5),(2.5,2.5) |      3.53553390593
+ (1e-300,-1e-300)  | (3,3),(3,3)         |      4.24264068712
+ (1e+300,Infinity) | (2,2),(0,0)         |           Infinity
+ (1e+300,Infinity) | (3,3),(1,1)         |           Infinity
+ (1e+300,Infinity) | (-2,2),(-8,-10)     |           Infinity
+ (1e+300,Infinity) | (2.5,3.5),(2.5,2.5) |           Infinity
+ (1e+300,Infinity) | (3,3),(3,3)         |           Infinity
+ (NaN,NaN)         | (2,2),(0,0)         |                NaN
+ (NaN,NaN)         | (3,3),(1,1)         |                NaN
+ (NaN,NaN)         | (-2,2),(-8,-10)     |                NaN
+ (NaN,NaN)         | (2.5,3.5),(2.5,2.5) |                NaN
+ (NaN,NaN)         | (3,3),(3,3)         |                NaN
+ (10,10)           | (2,2),(0,0)         |       11.313708499
+ (10,10)           | (3,3),(1,1)         |      9.89949493661
+ (10,10)           | (-2,2),(-8,-10)     |      14.4222051019
+ (10,10)           | (2.5,3.5),(2.5,2.5) |      9.92471662064
+ (10,10)           | (3,3),(3,3)         |      9.89949493661
+(45 rows)
+
+-- Distance to path
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, PATH_TBL p1;
+        f1         |            f1             |      ?column?      
+-------------------+---------------------------+--------------------
+ (0,0)             | [(1,2),(3,4)]             |       2.2360679775
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | [(0,0),(3,0),(4,5),(1,6)] |                  0
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | [(1,2),(3,4)]             |       2.2360679775
+ (0,0)             | ((10,20))                 |       22.360679775
+ (0,0)             | [(11,12),(13,14)]         |      16.2788205961
+ (0,0)             | ((11,12),(13,14))         |      16.2788205961
+ (-10,0)           | [(1,2),(3,4)]             |      11.1803398875
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | [(0,0),(3,0),(4,5),(1,6)] |                 10
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | [(1,2),(3,4)]             |      11.1803398875
+ (-10,0)           | ((10,20))                 |      28.2842712475
+ (-10,0)           | [(11,12),(13,14)]         |      24.1867732449
+ (-10,0)           | ((11,12),(13,14))         |      24.1867732449
+ (-3,4)            | [(1,2),(3,4)]             |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | [(0,0),(3,0),(4,5),(1,6)] |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | [(1,2),(3,4)]             |        4.472135955
+ (-3,4)            | ((10,20))                 |      20.6155281281
+ (-3,4)            | [(11,12),(13,14)]         |      16.1245154966
+ (-3,4)            | ((11,12),(13,14))         |      16.1245154966
+ (5.1,34.5)        | [(1,2),(3,4)]             |      30.5722096028
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | [(0,0),(3,0),(4,5),(1,6)] |       28.793402022
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | [(1,2),(3,4)]             |      30.5722096028
+ (5.1,34.5)        | ((10,20))                 |      15.3055545473
+ (5.1,34.5)        | [(11,12),(13,14)]         |      21.9695243462
+ (5.1,34.5)        | ((11,12),(13,14))         |      21.9695243462
+ (-5,-12)          | [(1,2),(3,4)]             |      15.2315462117
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | [(0,0),(3,0),(4,5),(1,6)] |                 13
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | [(1,2),(3,4)]             |      15.2315462117
+ (-5,-12)          | ((10,20))                 |      35.3411940941
+ (-5,-12)          | [(11,12),(13,14)]         |      28.8444102037
+ (-5,-12)          | ((11,12),(13,14))         |      28.8444102037
+ (1e-300,-1e-300)  | [(1,2),(3,4)]             |       2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | [(0,0),(3,0),(4,5),(1,6)] | 1.41421356237e-300
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | [(1,2),(3,4)]             |       2.2360679775
+ (1e-300,-1e-300)  | ((10,20))                 |       22.360679775
+ (1e-300,-1e-300)  | [(11,12),(13,14)]         |      16.2788205961
+ (1e-300,-1e-300)  | ((11,12),(13,14))         |      16.2788205961
+ (1e+300,Infinity) | [(1,2),(3,4)]             |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | [(0,0),(3,0),(4,5),(1,6)] |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | [(1,2),(3,4)]             |           Infinity
+ (1e+300,Infinity) | ((10,20))                 |           Infinity
+ (1e+300,Infinity) | [(11,12),(13,14)]         |           Infinity
+ (1e+300,Infinity) | ((11,12),(13,14))         |           Infinity
+ (NaN,NaN)         | [(1,2),(3,4)]             |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | [(0,0),(3,0),(4,5),(1,6)] |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | [(1,2),(3,4)]             |                NaN
+ (NaN,NaN)         | ((10,20))                 |                NaN
+ (NaN,NaN)         | [(11,12),(13,14)]         |                NaN
+ (NaN,NaN)         | ((11,12),(13,14))         |                NaN
+ (10,10)           | [(1,2),(3,4)]             |      9.21954445729
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | [(0,0),(3,0),(4,5),(1,6)] |      7.81024967591
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | [(1,2),(3,4)]             |      9.21954445729
+ (10,10)           | ((10,20))                 |                 10
+ (10,10)           | [(11,12),(13,14)]         |       2.2360679775
+ (10,10)           | ((11,12),(13,14))         |       2.2360679775
+(81 rows)
+
+-- Distance to polygon
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, POLYGON_TBL p1;
+        f1         |             f1             |   ?column?    
+-------------------+----------------------------+---------------
+ (0,0)             | ((2,0),(2,4),(0,0))        |             0
+ (0,0)             | ((3,1),(3,3),(1,0))        |             1
+ (0,0)             | ((1,2),(3,4),(5,6),(7,8))  |  2.2360679775
+ (0,0)             | ((7,8),(5,6),(3,4),(1,2))  |  2.2360679775
+ (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | 1.58113883008
+ (0,0)             | ((0,0))                    |             0
+ (0,0)             | ((0,1),(0,1))              |             1
+ (-10,0)           | ((2,0),(2,4),(0,0))        |            10
+ (-10,0)           | ((3,1),(3,3),(1,0))        |            11
+ (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | 11.1803398875
+ (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | 11.1803398875
+ (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | 11.1803398875
+ (-10,0)           | ((0,0))                    |            10
+ (-10,0)           | ((0,1),(0,1))              | 10.0498756211
+ (-3,4)            | ((2,0),(2,4),(0,0))        |   4.472135955
+ (-3,4)            | ((3,1),(3,3),(1,0))        | 5.54700196225
+ (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  |   4.472135955
+ (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  |   4.472135955
+ (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) |   4.472135955
+ (-3,4)            | ((0,0))                    |             5
+ (-3,4)            | ((0,1),(0,1))              | 4.24264068712
+ (5.1,34.5)        | ((2,0),(2,4),(0,0))        | 30.6571362002
+ (5.1,34.5)        | ((3,1),(3,3),(1,0))        | 31.5699223946
+ (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | 26.5680258958
+ (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | 26.5680258958
+ (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | 26.5680258958
+ (5.1,34.5)        | ((0,0))                    | 34.8749193547
+ (5.1,34.5)        | ((0,1),(0,1))              | 33.8859853037
+ (-5,-12)          | ((2,0),(2,4),(0,0))        |            13
+ (-5,-12)          | ((3,1),(3,3),(1,0))        |  13.416407865
+ (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | 15.2315462117
+ (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | 15.2315462117
+ (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) |  11.313708499
+ (-5,-12)          | ((0,0))                    |            13
+ (-5,-12)          | ((0,1),(0,1))              | 13.9283882772
+ (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        |             0
+ (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        |             1
+ (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  |  2.2360679775
+ (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  |  2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | 1.58113883008
+ (1e-300,-1e-300)  | ((0,0))                    |             0
+ (1e-300,-1e-300)  | ((0,1),(0,1))              |             1
+ (1e+300,Infinity) | ((2,0),(2,4),(0,0))        |      Infinity
+ (1e+300,Infinity) | ((3,1),(3,3),(1,0))        |      Infinity
+ (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  |      Infinity
+ (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  |      Infinity
+ (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) |      Infinity
+ (1e+300,Infinity) | ((0,0))                    |      Infinity
+ (1e+300,Infinity) | ((0,1),(0,1))              |      Infinity
+ (NaN,NaN)         | ((2,0),(2,4),(0,0))        |             0
+ (NaN,NaN)         | ((3,1),(3,3),(1,0))        |             0
+ (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  |             0
+ (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  |             0
+ (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) |             0
+ (NaN,NaN)         | ((0,0))                    |             0
+ (NaN,NaN)         | ((0,1),(0,1))              |             0
+ (10,10)           | ((2,0),(2,4),(0,0))        |            10
+ (10,10)           | ((3,1),(3,3),(1,0))        | 9.89949493661
+ (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | 3.60555127546
+ (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | 3.60555127546
+ (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | 3.60555127546
+ (10,10)           | ((0,0))                    | 14.1421356237
+ (10,10)           | ((0,1),(0,1))              | 13.4536240471
+(63 rows)
+
+-- Closest point to line
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LINE_TBL l;
+        f1         |                   s                   |             ?column?             
+-------------------+---------------------------------------+----------------------------------
+ (0,0)             | {0,-1,5}                              | (0,5)
+ (0,0)             | {1,0,5}                               | (-5,0)
+ (0,0)             | {0,3,0}                               | (0,0)
+ (0,0)             | {1,-1,0}                              | (0,0)
+ (0,0)             | {-0.4,-1,-6}                          | (-2.06896551724,-5.1724137931)
+ (0,0)             | {-0.000184615384615,-1,15.3846153846} | (0.00284023658959,15.3846148603)
+ (0,0)             | {3,NaN,5}                             | 
+ (0,0)             | {NaN,NaN,NaN}                         | 
+ (0,0)             | {0,-1,3}                              | (0,3)
+ (0,0)             | {-1,0,3}                              | (3,0)
+ (-10,0)           | {0,-1,5}                              | (-10,5)
+ (-10,0)           | {1,0,5}                               | (-5,0)
+ (-10,0)           | {0,3,0}                               | (-10,0)
+ (-10,0)           | {1,-1,0}                              | (-5,-5)
+ (-10,0)           | {-0.4,-1,-6}                          | (-10.6896551724,-1.72413793103)
+ (-10,0)           | {-0.000184615384615,-1,15.3846153846} | (-9.99715942258,15.386461014)
+ (-10,0)           | {3,NaN,5}                             | 
+ (-10,0)           | {NaN,NaN,NaN}                         | 
+ (-10,0)           | {0,-1,3}                              | (-10,3)
+ (-10,0)           | {-1,0,3}                              | (3,0)
+ (-3,4)            | {0,-1,5}                              | (-3,5)
+ (-3,4)            | {1,0,5}                               | (-5,4)
+ (-3,4)            | {0,3,0}                               | (-3,0)
+ (-3,4)            | {1,-1,0}                              | (0.5,0.5)
+ (-3,4)            | {-0.4,-1,-6}                          | (-6.03448275862,-3.58620689655)
+ (-3,4)            | {-0.000184615384615,-1,15.3846153846} | (-2.99789812268,15.3851688427)
+ (-3,4)            | {3,NaN,5}                             | 
+ (-3,4)            | {NaN,NaN,NaN}                         | 
+ (-3,4)            | {0,-1,3}                              | (-3,3)
+ (-3,4)            | {-1,0,3}                              | (3,4)
+ (5.1,34.5)        | {0,-1,5}                              | (5.1,5)
+ (5.1,34.5)        | {1,0,5}                               | (-5,34.5)
+ (5.1,34.5)        | {0,3,0}                               | (5.1,0)
+ (5.1,34.5)        | {1,-1,0}                              | (19.8,19.8)
+ (5.1,34.5)        | {-0.4,-1,-6}                          | (-9.56896551724,-2.1724137931)
+ (5.1,34.5)        | {-0.000184615384615,-1,15.3846153846} | (5.09647083221,15.3836744977)
+ (5.1,34.5)        | {3,NaN,5}                             | 
+ (5.1,34.5)        | {NaN,NaN,NaN}                         | 
+ (5.1,34.5)        | {0,-1,3}                              | (5.1,3)
+ (5.1,34.5)        | {-1,0,3}                              | (3,34.5)
+ (-5,-12)          | {0,-1,5}                              | (-5,5)
+ (-5,-12)          | {1,0,5}                               | (-5,-12)
+ (-5,-12)          | {0,3,0}                               | (-5,0)
+ (-5,-12)          | {1,-1,0}                              | (-8.5,-8.5)
+ (-5,-12)          | {-0.4,-1,-6}                          | (-2.24137931034,-5.10344827586)
+ (-5,-12)          | {-0.000184615384615,-1,15.3846153846} | (-4.99494420846,15.3855375282)
+ (-5,-12)          | {3,NaN,5}                             | 
+ (-5,-12)          | {NaN,NaN,NaN}                         | 
+ (-5,-12)          | {0,-1,3}                              | (-5,3)
+ (-5,-12)          | {-1,0,3}                              | (3,-12)
+ (1e-300,-1e-300)  | {0,-1,5}                              | (1e-300,5)
+ (1e-300,-1e-300)  | {1,0,5}                               | (-5,-1e-300)
+ (1e-300,-1e-300)  | {0,3,0}                               | (1e-300,0)
+ (1e-300,-1e-300)  | {1,-1,0}                              | (0,0)
+ (1e-300,-1e-300)  | {-0.4,-1,-6}                          | (-2.06896551724,-5.1724137931)
+ (1e-300,-1e-300)  | {-0.000184615384615,-1,15.3846153846} | (0.00284023658959,15.3846148603)
+ (1e-300,-1e-300)  | {3,NaN,5}                             | 
+ (1e-300,-1e-300)  | {NaN,NaN,NaN}                         | 
+ (1e-300,-1e-300)  | {0,-1,3}                              | (1e-300,3)
+ (1e-300,-1e-300)  | {-1,0,3}                              | (3,-1e-300)
+ (1e+300,Infinity) | {0,-1,5}                              | (1e+300,5)
+ (1e+300,Infinity) | {1,0,5}                               | 
+ (1e+300,Infinity) | {0,3,0}                               | (1e+300,0)
+ (1e+300,Infinity) | {1,-1,0}                              | (Infinity,NaN)
+ (1e+300,Infinity) | {-0.4,-1,-6}                          | (-Infinity,NaN)
+ (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} | (-Infinity,NaN)
+ (1e+300,Infinity) | {3,NaN,5}                             | 
+ (1e+300,Infinity) | {NaN,NaN,NaN}                         | 
+ (1e+300,Infinity) | {0,-1,3}                              | (1e+300,3)
+ (1e+300,Infinity) | {-1,0,3}                              | 
+ (NaN,NaN)         | {0,-1,5}                              | 
+ (NaN,NaN)         | {1,0,5}                               | 
+ (NaN,NaN)         | {0,3,0}                               | 
+ (NaN,NaN)         | {1,-1,0}                              | 
+ (NaN,NaN)         | {-0.4,-1,-6}                          | 
+ (NaN,NaN)         | {-0.000184615384615,-1,15.3846153846} | 
+ (NaN,NaN)         | {3,NaN,5}                             | 
+ (NaN,NaN)         | {NaN,NaN,NaN}                         | 
+ (NaN,NaN)         | {0,-1,3}                              | 
+ (NaN,NaN)         | {-1,0,3}                              | 
+ (10,10)           | {0,-1,5}                              | (10,5)
+ (10,10)           | {1,0,5}                               | (-5,10)
+ (10,10)           | {0,3,0}                               | (10,0)
+ (10,10)           | {1,-1,0}                              | (10,10)
+ (10,10)           | {-0.4,-1,-6}                          | (3.10344827586,-7.24137931034)
+ (10,10)           | {-0.000184615384615,-1,15.3846153846} | (10.000993742,15.3827690473)
+ (10,10)           | {3,NaN,5}                             | 
+ (10,10)           | {NaN,NaN,NaN}                         | 
+ (10,10)           | {0,-1,3}                              | (10,3)
+ (10,10)           | {-1,0,3}                              | (3,10)
+(90 rows)
+
+-- Closest point to line segment
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LSEG_TBL l;
+        f1         |               s               |             ?column?             
+-------------------+-------------------------------+----------------------------------
+ (0,0)             | [(1,2),(3,4)]                 | (1,2)
+ (0,0)             | [(0,0),(6,6)]                 | (0,0)
+ (0,0)             | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ (0,0)             | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
+ (0,0)             | [(11,22),(33,44)]             | (11,22)
+ (0,0)             | [(-10,2),(-10,3)]             | (-10,2)
+ (0,0)             | [(0,-20),(30,-20)]            | (0,-20)
+ (0,0)             | [(NaN,1),(NaN,90)]            | 
+ (-10,0)           | [(1,2),(3,4)]                 | (1,2)
+ (-10,0)           | [(0,0),(6,6)]                 | (0,0)
+ (-10,0)           | [(10,-10),(-3,-4)]            | (-3,-4)
+ (-10,0)           | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
+ (-10,0)           | [(11,22),(33,44)]             | (11,22)
+ (-10,0)           | [(-10,2),(-10,3)]             | (-10,2)
+ (-10,0)           | [(0,-20),(30,-20)]            | (0,-20)
+ (-10,0)           | [(NaN,1),(NaN,90)]            | 
+ (-3,4)            | [(1,2),(3,4)]                 | (1,2)
+ (-3,4)            | [(0,0),(6,6)]                 | (0.5,0.5)
+ (-3,4)            | [(10,-10),(-3,-4)]            | (-3,-4)
+ (-3,4)            | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
+ (-3,4)            | [(11,22),(33,44)]             | (11,22)
+ (-3,4)            | [(-10,2),(-10,3)]             | (-10,3)
+ (-3,4)            | [(0,-20),(30,-20)]            | (0,-20)
+ (-3,4)            | [(NaN,1),(NaN,90)]            | 
+ (5.1,34.5)        | [(1,2),(3,4)]                 | (3,4)
+ (5.1,34.5)        | [(0,0),(6,6)]                 | (6,6)
+ (5.1,34.5)        | [(10,-10),(-3,-4)]            | (-3,-4)
+ (5.1,34.5)        | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
+ (5.1,34.5)        | [(11,22),(33,44)]             | (14.3,25.3)
+ (5.1,34.5)        | [(-10,2),(-10,3)]             | (-10,3)
+ (5.1,34.5)        | [(0,-20),(30,-20)]            | (5.1,-20)
+ (5.1,34.5)        | [(NaN,1),(NaN,90)]            | 
+ (-5,-12)          | [(1,2),(3,4)]                 | (1,2)
+ (-5,-12)          | [(0,0),(6,6)]                 | (0,0)
+ (-5,-12)          | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
+ (-5,-12)          | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
+ (-5,-12)          | [(11,22),(33,44)]             | (11,22)
+ (-5,-12)          | [(-10,2),(-10,3)]             | (-10,2)
+ (-5,-12)          | [(0,-20),(30,-20)]            | (0,-20)
+ (-5,-12)          | [(NaN,1),(NaN,90)]            | 
+ (1e-300,-1e-300)  | [(1,2),(3,4)]                 | (1,2)
+ (1e-300,-1e-300)  | [(0,0),(6,6)]                 | (0,0)
+ (1e-300,-1e-300)  | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ (1e-300,-1e-300)  | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
+ (1e-300,-1e-300)  | [(11,22),(33,44)]             | (11,22)
+ (1e-300,-1e-300)  | [(-10,2),(-10,3)]             | (-10,2)
+ (1e-300,-1e-300)  | [(0,-20),(30,-20)]            | (0,-20)
+ (1e-300,-1e-300)  | [(NaN,1),(NaN,90)]            | 
+ (1e+300,Infinity) | [(1,2),(3,4)]                 | (3,4)
+ (1e+300,Infinity) | [(0,0),(6,6)]                 | (6,6)
+ (1e+300,Infinity) | [(10,-10),(-3,-4)]            | (-3,-4)
+ (1e+300,Infinity) | [(-1000000,200),(300000,-40)] | (300000,-40)
+ (1e+300,Infinity) | [(11,22),(33,44)]             | (33,44)
+ (1e+300,Infinity) | [(-10,2),(-10,3)]             | (-10,3)
+ (1e+300,Infinity) | [(0,-20),(30,-20)]            | (30,-20)
+ (1e+300,Infinity) | [(NaN,1),(NaN,90)]            | (NaN,90)
+ (NaN,NaN)         | [(1,2),(3,4)]                 | 
+ (NaN,NaN)         | [(0,0),(6,6)]                 | 
+ (NaN,NaN)         | [(10,-10),(-3,-4)]            | 
+ (NaN,NaN)         | [(-1000000,200),(300000,-40)] | 
+ (NaN,NaN)         | [(11,22),(33,44)]             | 
+ (NaN,NaN)         | [(-10,2),(-10,3)]             | 
+ (NaN,NaN)         | [(0,-20),(30,-20)]            | 
+ (NaN,NaN)         | [(NaN,1),(NaN,90)]            | 
+ (10,10)           | [(1,2),(3,4)]                 | (3,4)
+ (10,10)           | [(0,0),(6,6)]                 | (6,6)
+ (10,10)           | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
+ (10,10)           | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
+ (10,10)           | [(11,22),(33,44)]             | (11,22)
+ (10,10)           | [(-10,2),(-10,3)]             | (-10,3)
+ (10,10)           | [(0,-20),(30,-20)]            | (10,-20)
+ (10,10)           | [(NaN,1),(NaN,90)]            | 
+(72 rows)
+
+-- Closest point to box
+SELECT p.f1, b.f1, p.f1 ## b.f1 FROM POINT_TBL p, BOX_TBL b;
+        f1         |         f1          |   ?column?   
+-------------------+---------------------+--------------
+ (0,0)             | (2,2),(0,0)         | (0,0)
+ (0,0)             | (3,3),(1,1)         | (1,1)
+ (0,0)             | (-2,2),(-8,-10)     | (-2,0)
+ (0,0)             | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (0,0)             | (3,3),(3,3)         | (3,3)
+ (-10,0)           | (2,2),(0,0)         | (0,0)
+ (-10,0)           | (3,3),(1,1)         | (1,1)
+ (-10,0)           | (-2,2),(-8,-10)     | (-8,0)
+ (-10,0)           | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (-10,0)           | (3,3),(3,3)         | (3,3)
+ (-3,4)            | (2,2),(0,0)         | (0,2)
+ (-3,4)            | (3,3),(1,1)         | (1,3)
+ (-3,4)            | (-2,2),(-8,-10)     | (-3,2)
+ (-3,4)            | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (-3,4)            | (3,3),(3,3)         | (3,3)
+ (5.1,34.5)        | (2,2),(0,0)         | (2,2)
+ (5.1,34.5)        | (3,3),(1,1)         | (3,3)
+ (5.1,34.5)        | (-2,2),(-8,-10)     | (-2,2)
+ (5.1,34.5)        | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (5.1,34.5)        | (3,3),(3,3)         | (3,3)
+ (-5,-12)          | (2,2),(0,0)         | (0,0)
+ (-5,-12)          | (3,3),(1,1)         | (1,1)
+ (-5,-12)          | (-2,2),(-8,-10)     | (-5,-10)
+ (-5,-12)          | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (-5,-12)          | (3,3),(3,3)         | (3,3)
+ (1e-300,-1e-300)  | (2,2),(0,0)         | (0,0)
+ (1e-300,-1e-300)  | (3,3),(1,1)         | (1,1)
+ (1e-300,-1e-300)  | (-2,2),(-8,-10)     | (-2,-1e-300)
+ (1e-300,-1e-300)  | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (1e-300,-1e-300)  | (3,3),(3,3)         | (3,3)
+ (1e+300,Infinity) | (2,2),(0,0)         | (0,2)
+ (1e+300,Infinity) | (3,3),(1,1)         | (1,3)
+ (1e+300,Infinity) | (-2,2),(-8,-10)     | (-8,2)
+ (1e+300,Infinity) | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (1e+300,Infinity) | (3,3),(3,3)         | (3,3)
+ (NaN,NaN)         | (2,2),(0,0)         | 
+ (NaN,NaN)         | (3,3),(1,1)         | 
+ (NaN,NaN)         | (-2,2),(-8,-10)     | 
+ (NaN,NaN)         | (2.5,3.5),(2.5,2.5) | 
+ (NaN,NaN)         | (3,3),(3,3)         | 
+ (10,10)           | (2,2),(0,0)         | (2,2)
+ (10,10)           | (3,3),(1,1)         | (3,3)
+ (10,10)           | (-2,2),(-8,-10)     | (-2,2)
+ (10,10)           | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (10,10)           | (3,3),(3,3)         | (3,3)
+(45 rows)
+
+-- On line
+SELECT p.f1, l.s FROM POINT_TBL p, LINE_TBL l WHERE p.f1 <@ l.s;
+        f1        |    s     
+------------------+----------
+ (0,0)            | {0,3,0}
+ (0,0)            | {1,-1,0}
+ (-10,0)          | {0,3,0}
+ (-5,-12)         | {1,0,5}
+ (1e-300,-1e-300) | {0,3,0}
+ (1e-300,-1e-300) | {1,-1,0}
+ (10,10)          | {1,-1,0}
+(7 rows)
+
+-- On line segment
+SELECT p.f1, l.s FROM POINT_TBL p, LSEG_TBL l WHERE p.f1 <@ l.s;
+        f1        |       s       
+------------------+---------------
+ (0,0)            | [(0,0),(6,6)]
+ (1e-300,-1e-300) | [(0,0),(6,6)]
+(2 rows)
+
+-- On path
+SELECT p.f1, p1.f1 FROM POINT_TBL p, PATH_TBL p1 WHERE p.f1 <@ p1.f1;
+        f1        |            f1             
+------------------+---------------------------
+ (0,0)            | [(0,0),(3,0),(4,5),(1,6)]
+ (1e-300,-1e-300) | [(0,0),(3,0),(4,5),(1,6)]
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((10,20))
+ (NaN,NaN)        | ((11,12),(13,14))
+(7 rows)
+
+--
+-- Lines
+--
+-- Vertical
+SELECT s FROM LINE_TBL WHERE ?| s;
+    s     
+----------
+ {1,0,5}
+ {-1,0,3}
+(2 rows)
+
+-- Horizontal
+SELECT s FROM LINE_TBL WHERE ?- s;
+    s     
+----------
+ {0,-1,5}
+ {0,3,0}
+ {0,-1,3}
+(3 rows)
+
+-- Same as line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s = l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {0,-1,5}
+ {1,0,5}                               | {1,0,5}
+ {0,3,0}                               | {0,3,0}
+ {1,-1,0}                              | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846}
+ {3,NaN,5}                             | {3,NaN,5}
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}
+ {0,-1,3}                              | {0,-1,3}
+ {-1,0,3}                              | {-1,0,3}
+(10 rows)
+
+-- Parallel to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?|| l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {0,-1,5}
+ {0,-1,5}                              | {0,3,0}
+ {0,-1,5}                              | {0,-1,3}
+ {1,0,5}                               | {1,0,5}
+ {1,0,5}                               | {-1,0,3}
+ {0,3,0}                               | {0,-1,5}
+ {0,3,0}                               | {0,3,0}
+ {0,3,0}                               | {0,-1,3}
+ {1,-1,0}                              | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,3}                              | {0,-1,5}
+ {0,-1,3}                              | {0,3,0}
+ {0,-1,3}                              | {0,-1,3}
+ {-1,0,3}                              | {1,0,5}
+ {-1,0,3}                              | {-1,0,3}
+(16 rows)
+
+-- Perpendicular to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?-| l2.s;
+    s     |    s     
+----------+----------
+ {0,-1,5} | {1,0,5}
+ {0,-1,5} | {-1,0,3}
+ {1,0,5}  | {0,-1,5}
+ {1,0,5}  | {0,3,0}
+ {1,0,5}  | {0,-1,3}
+ {0,3,0}  | {1,0,5}
+ {0,3,0}  | {-1,0,3}
+ {0,-1,3} | {1,0,5}
+ {0,-1,3} | {-1,0,3}
+ {-1,0,3} | {0,-1,5}
+ {-1,0,3} | {0,3,0}
+ {-1,0,3} | {0,-1,3}
+(12 rows)
+
+-- Distance to line
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2;
+                   s                   |                   s                   | ?column? 
+---------------------------------------+---------------------------------------+----------
+ {0,-1,5}                              | {0,-1,5}                              |        0
+ {0,-1,5}                              | {1,0,5}                               |        0
+ {0,-1,5}                              | {0,3,0}                               |        5
+ {0,-1,5}                              | {1,-1,0}                              |        0
+ {0,-1,5}                              | {-0.4,-1,-6}                          |        0
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,-1,5}                              | {3,NaN,5}                             |        0
+ {0,-1,5}                              | {NaN,NaN,NaN}                         |        0
+ {0,-1,5}                              | {0,-1,3}                              |        2
+ {0,-1,5}                              | {-1,0,3}                              |        0
+ {1,0,5}                               | {0,-1,5}                              |        0
+ {1,0,5}                               | {1,0,5}                               |        0
+ {1,0,5}                               | {0,3,0}                               |        0
+ {1,0,5}                               | {1,-1,0}                              |        0
+ {1,0,5}                               | {-0.4,-1,-6}                          |        0
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846} |        0
+ {1,0,5}                               | {3,NaN,5}                             |        0
+ {1,0,5}                               | {NaN,NaN,NaN}                         |        0
+ {1,0,5}                               | {0,-1,3}                              |        0
+ {1,0,5}                               | {-1,0,3}                              |        8
+ {0,3,0}                               | {0,-1,5}                              |        5
+ {0,3,0}                               | {1,0,5}                               |        0
+ {0,3,0}                               | {0,3,0}                               |        0
+ {0,3,0}                               | {1,-1,0}                              |        0
+ {0,3,0}                               | {-0.4,-1,-6}                          |        0
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,3,0}                               | {3,NaN,5}                             |        0
+ {0,3,0}                               | {NaN,NaN,NaN}                         |        0
+ {0,3,0}                               | {0,-1,3}                              |        3
+ {0,3,0}                               | {-1,0,3}                              |        0
+ {1,-1,0}                              | {0,-1,5}                              |        0
+ {1,-1,0}                              | {1,0,5}                               |        0
+ {1,-1,0}                              | {0,3,0}                               |        0
+ {1,-1,0}                              | {1,-1,0}                              |        0
+ {1,-1,0}                              | {-0.4,-1,-6}                          |        0
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {1,-1,0}                              | {3,NaN,5}                             |        0
+ {1,-1,0}                              | {NaN,NaN,NaN}                         |        0
+ {1,-1,0}                              | {0,-1,3}                              |        0
+ {1,-1,0}                              | {-1,0,3}                              |        0
+ {-0.4,-1,-6}                          | {0,-1,5}                              |        0
+ {-0.4,-1,-6}                          | {1,0,5}                               |        0
+ {-0.4,-1,-6}                          | {0,3,0}                               |        0
+ {-0.4,-1,-6}                          | {1,-1,0}                              |        0
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}                          |        0
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846} |        0
+ {-0.4,-1,-6}                          | {3,NaN,5}                             |        0
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}                         |        0
+ {-0.4,-1,-6}                          | {0,-1,3}                              |        0
+ {-0.4,-1,-6}                          | {-1,0,3}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}                               |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}                               |        0
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}                          |        0
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} |        0
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}                             |        0
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}                         |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}                              |        0
+ {3,NaN,5}                             | {0,-1,5}                              |        0
+ {3,NaN,5}                             | {1,0,5}                               |        0
+ {3,NaN,5}                             | {0,3,0}                               |        0
+ {3,NaN,5}                             | {1,-1,0}                              |        0
+ {3,NaN,5}                             | {-0.4,-1,-6}                          |        0
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846} |        0
+ {3,NaN,5}                             | {3,NaN,5}                             |        0
+ {3,NaN,5}                             | {NaN,NaN,NaN}                         |        0
+ {3,NaN,5}                             | {0,-1,3}                              |        0
+ {3,NaN,5}                             | {-1,0,3}                              |        0
+ {NaN,NaN,NaN}                         | {0,-1,5}                              |        0
+ {NaN,NaN,NaN}                         | {1,0,5}                               |        0
+ {NaN,NaN,NaN}                         | {0,3,0}                               |        0
+ {NaN,NaN,NaN}                         | {1,-1,0}                              |        0
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}                          |        0
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846} |        0
+ {NaN,NaN,NaN}                         | {3,NaN,5}                             |        0
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}                         |        0
+ {NaN,NaN,NaN}                         | {0,-1,3}                              |        0
+ {NaN,NaN,NaN}                         | {-1,0,3}                              |        0
+ {0,-1,3}                              | {0,-1,5}                              |        2
+ {0,-1,3}                              | {1,0,5}                               |        0
+ {0,-1,3}                              | {0,3,0}                               |        3
+ {0,-1,3}                              | {1,-1,0}                              |        0
+ {0,-1,3}                              | {-0.4,-1,-6}                          |        0
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,-1,3}                              | {3,NaN,5}                             |        0
+ {0,-1,3}                              | {NaN,NaN,NaN}                         |        0
+ {0,-1,3}                              | {0,-1,3}                              |        0
+ {0,-1,3}                              | {-1,0,3}                              |        0
+ {-1,0,3}                              | {0,-1,5}                              |        0
+ {-1,0,3}                              | {1,0,5}                               |        8
+ {-1,0,3}                              | {0,3,0}                               |        0
+ {-1,0,3}                              | {1,-1,0}                              |        0
+ {-1,0,3}                              | {-0.4,-1,-6}                          |        0
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {-1,0,3}                              | {3,NaN,5}                             |        0
+ {-1,0,3}                              | {NaN,NaN,NaN}                         |        0
+ {-1,0,3}                              | {0,-1,3}                              |        0
+ {-1,0,3}                              | {-1,0,3}                              |        0
+(100 rows)
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LINE_TBL l, BOX_TBL b;
+ERROR:  function "dist_lb" not implemented
+-- Intersect with line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?# l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {1,0,5}
+ {0,-1,5}                              | {1,-1,0}
+ {0,-1,5}                              | {-0.4,-1,-6}
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,5}                              | {3,NaN,5}
+ {0,-1,5}                              | {NaN,NaN,NaN}
+ {0,-1,5}                              | {-1,0,3}
+ {1,0,5}                               | {0,-1,5}
+ {1,0,5}                               | {0,3,0}
+ {1,0,5}                               | {1,-1,0}
+ {1,0,5}                               | {-0.4,-1,-6}
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846}
+ {1,0,5}                               | {3,NaN,5}
+ {1,0,5}                               | {NaN,NaN,NaN}
+ {1,0,5}                               | {0,-1,3}
+ {0,3,0}                               | {1,0,5}
+ {0,3,0}                               | {1,-1,0}
+ {0,3,0}                               | {-0.4,-1,-6}
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846}
+ {0,3,0}                               | {3,NaN,5}
+ {0,3,0}                               | {NaN,NaN,NaN}
+ {0,3,0}                               | {-1,0,3}
+ {1,-1,0}                              | {0,-1,5}
+ {1,-1,0}                              | {1,0,5}
+ {1,-1,0}                              | {0,3,0}
+ {1,-1,0}                              | {-0.4,-1,-6}
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846}
+ {1,-1,0}                              | {3,NaN,5}
+ {1,-1,0}                              | {NaN,NaN,NaN}
+ {1,-1,0}                              | {0,-1,3}
+ {1,-1,0}                              | {-1,0,3}
+ {-0.4,-1,-6}                          | {0,-1,5}
+ {-0.4,-1,-6}                          | {1,0,5}
+ {-0.4,-1,-6}                          | {0,3,0}
+ {-0.4,-1,-6}                          | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846}
+ {-0.4,-1,-6}                          | {3,NaN,5}
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}
+ {-0.4,-1,-6}                          | {0,-1,3}
+ {-0.4,-1,-6}                          | {-1,0,3}
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}
+ {3,NaN,5}                             | {0,-1,5}
+ {3,NaN,5}                             | {1,0,5}
+ {3,NaN,5}                             | {0,3,0}
+ {3,NaN,5}                             | {1,-1,0}
+ {3,NaN,5}                             | {-0.4,-1,-6}
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846}
+ {3,NaN,5}                             | {3,NaN,5}
+ {3,NaN,5}                             | {NaN,NaN,NaN}
+ {3,NaN,5}                             | {0,-1,3}
+ {3,NaN,5}                             | {-1,0,3}
+ {NaN,NaN,NaN}                         | {0,-1,5}
+ {NaN,NaN,NaN}                         | {1,0,5}
+ {NaN,NaN,NaN}                         | {0,3,0}
+ {NaN,NaN,NaN}                         | {1,-1,0}
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846}
+ {NaN,NaN,NaN}                         | {3,NaN,5}
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}
+ {NaN,NaN,NaN}                         | {0,-1,3}
+ {NaN,NaN,NaN}                         | {-1,0,3}
+ {0,-1,3}                              | {1,0,5}
+ {0,-1,3}                              | {1,-1,0}
+ {0,-1,3}                              | {-0.4,-1,-6}
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,3}                              | {3,NaN,5}
+ {0,-1,3}                              | {NaN,NaN,NaN}
+ {0,-1,3}                              | {-1,0,3}
+ {-1,0,3}                              | {0,-1,5}
+ {-1,0,3}                              | {0,3,0}
+ {-1,0,3}                              | {1,-1,0}
+ {-1,0,3}                              | {-0.4,-1,-6}
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846}
+ {-1,0,3}                              | {3,NaN,5}
+ {-1,0,3}                              | {NaN,NaN,NaN}
+ {-1,0,3}                              | {0,-1,3}
+(84 rows)
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LINE_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+      s       |         f1          
+--------------+---------------------
+ {1,0,5}      | (-2,2),(-8,-10)
+ {0,3,0}      | (2,2),(0,0)
+ {0,3,0}      | (-2,2),(-8,-10)
+ {1,-1,0}     | (2,2),(0,0)
+ {1,-1,0}     | (3,3),(1,1)
+ {1,-1,0}     | (-2,2),(-8,-10)
+ {1,-1,0}     | (2.5,3.5),(2.5,2.5)
+ {1,-1,0}     | (3,3),(3,3)
+ {-0.4,-1,-6} | (-2,2),(-8,-10)
+ {0,-1,3}     | (3,3),(1,1)
+ {0,-1,3}     | (2.5,3.5),(2.5,2.5)
+ {0,-1,3}     | (3,3),(3,3)
+ {-1,0,3}     | (3,3),(1,1)
+(13 rows)
+
+-- Intersection point with line
+SELECT l1.s, l2.s, l1.s # l2.s FROM LINE_TBL l1, LINE_TBL l2;
+                   s                   |                   s                   |             ?column?              
+---------------------------------------+---------------------------------------+-----------------------------------
+ {0,-1,5}                              | {0,-1,5}                              | 
+ {0,-1,5}                              | {1,0,5}                               | (-5,5)
+ {0,-1,5}                              | {0,3,0}                               | 
+ {0,-1,5}                              | {1,-1,0}                              | (5,5)
+ {0,-1,5}                              | {-0.4,-1,-6}                          | (-27.5,5)
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846} | (56250,5)
+ {0,-1,5}                              | {3,NaN,5}                             | (NaN,NaN)
+ {0,-1,5}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,-1,5}                              | {0,-1,3}                              | 
+ {0,-1,5}                              | {-1,0,3}                              | (3,5)
+ {1,0,5}                               | {0,-1,5}                              | (-5,5)
+ {1,0,5}                               | {1,0,5}                               | 
+ {1,0,5}                               | {0,3,0}                               | (-5,0)
+ {1,0,5}                               | {1,-1,0}                              | (-5,-5)
+ {1,0,5}                               | {-0.4,-1,-6}                          | (-5,-4)
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846} | (-5,15.3855384615)
+ {1,0,5}                               | {3,NaN,5}                             | (NaN,NaN)
+ {1,0,5}                               | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {1,0,5}                               | {0,-1,3}                              | (-5,3)
+ {1,0,5}                               | {-1,0,3}                              | 
+ {0,3,0}                               | {0,-1,5}                              | 
+ {0,3,0}                               | {1,0,5}                               | (-5,0)
+ {0,3,0}                               | {0,3,0}                               | 
+ {0,3,0}                               | {1,-1,0}                              | (0,0)
+ {0,3,0}                               | {-0.4,-1,-6}                          | (-15,0)
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846} | (83333.3333333,0)
+ {0,3,0}                               | {3,NaN,5}                             | (NaN,NaN)
+ {0,3,0}                               | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,3,0}                               | {0,-1,3}                              | 
+ {0,3,0}                               | {-1,0,3}                              | (3,0)
+ {1,-1,0}                              | {0,-1,5}                              | (5,5)
+ {1,-1,0}                              | {1,0,5}                               | (-5,-5)
+ {1,-1,0}                              | {0,3,0}                               | (0,0)
+ {1,-1,0}                              | {1,-1,0}                              | 
+ {1,-1,0}                              | {-0.4,-1,-6}                          | (-4.28571428571,-4.28571428571)
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846} | (15.3817756722,15.3817756722)
+ {1,-1,0}                              | {3,NaN,5}                             | (NaN,NaN)
+ {1,-1,0}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {1,-1,0}                              | {0,-1,3}                              | (3,3)
+ {1,-1,0}                              | {-1,0,3}                              | (3,3)
+ {-0.4,-1,-6}                          | {0,-1,5}                              | (-27.5,5)
+ {-0.4,-1,-6}                          | {1,0,5}                               | (-5,-4)
+ {-0.4,-1,-6}                          | {0,3,0}                               | (-15,0)
+ {-0.4,-1,-6}                          | {1,-1,0}                              | (-4.28571428571,-4.28571428571)
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}                          | 
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846} | (-53.4862244113,15.3944897645)
+ {-0.4,-1,-6}                          | {3,NaN,5}                             | (NaN,NaN)
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-0.4,-1,-6}                          | {0,-1,3}                              | (-22.5,3)
+ {-0.4,-1,-6}                          | {-1,0,3}                              | (3,-7.2)
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}                              | (56250,5)
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}                               | (-5,15.3855384615)
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}                               | (83333.3333333,-1.7763568394e-15)
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}                              | (15.3817756722,15.3817756722)
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}                          | (-53.4862244113,15.3944897645)
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} | 
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}                             | (NaN,NaN)
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}                              | (67083.3333333,3)
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}                              | (3,15.3840615385)
+ {3,NaN,5}                             | {0,-1,5}                              | (NaN,NaN)
+ {3,NaN,5}                             | {1,0,5}                               | (NaN,NaN)
+ {3,NaN,5}                             | {0,3,0}                               | (NaN,NaN)
+ {3,NaN,5}                             | {1,-1,0}                              | (NaN,NaN)
+ {3,NaN,5}                             | {-0.4,-1,-6}                          | (NaN,NaN)
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ {3,NaN,5}                             | {3,NaN,5}                             | (NaN,NaN)
+ {3,NaN,5}                             | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {3,NaN,5}                             | {0,-1,3}                              | (NaN,NaN)
+ {3,NaN,5}                             | {-1,0,3}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,-1,5}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {1,0,5}                               | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,3,0}                               | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {1,-1,0}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}                          | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {3,NaN,5}                             | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,-1,3}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-1,0,3}                              | (NaN,NaN)
+ {0,-1,3}                              | {0,-1,5}                              | 
+ {0,-1,3}                              | {1,0,5}                               | (-5,3)
+ {0,-1,3}                              | {0,3,0}                               | 
+ {0,-1,3}                              | {1,-1,0}                              | (3,3)
+ {0,-1,3}                              | {-0.4,-1,-6}                          | (-22.5,3)
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846} | (67083.3333333,3)
+ {0,-1,3}                              | {3,NaN,5}                             | (NaN,NaN)
+ {0,-1,3}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,-1,3}                              | {0,-1,3}                              | 
+ {0,-1,3}                              | {-1,0,3}                              | (3,3)
+ {-1,0,3}                              | {0,-1,5}                              | (3,5)
+ {-1,0,3}                              | {1,0,5}                               | 
+ {-1,0,3}                              | {0,3,0}                               | (3,0)
+ {-1,0,3}                              | {1,-1,0}                              | (3,3)
+ {-1,0,3}                              | {-0.4,-1,-6}                          | (3,-7.2)
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846} | (3,15.3840615385)
+ {-1,0,3}                              | {3,NaN,5}                             | (NaN,NaN)
+ {-1,0,3}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-1,0,3}                              | {0,-1,3}                              | (3,3)
+ {-1,0,3}                              | {-1,0,3}                              | 
+(100 rows)
+
+-- Closest point to line segment
+SELECT l.s, l1.s, l.s ## l1.s FROM LINE_TBL l, LSEG_TBL l1;
+                   s                   |               s               |             ?column?              
+---------------------------------------+-------------------------------+-----------------------------------
+ {0,-1,5}                              | [(1,2),(3,4)]                 | (3,4)
+ {0,-1,5}                              | [(0,0),(6,6)]                 | (5,5)
+ {0,-1,5}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,-1,5}                              | [(-1000000,200),(300000,-40)] | (56250,5)
+ {0,-1,5}                              | [(11,22),(33,44)]             | (11,22)
+ {0,-1,5}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {0,-1,5}                              | [(0,-20),(30,-20)]            | 
+ {0,-1,5}                              | [(NaN,1),(NaN,90)]            | 
+ {1,0,5}                               | [(1,2),(3,4)]                 | (1,2)
+ {1,0,5}                               | [(0,0),(6,6)]                 | (0,0)
+ {1,0,5}                               | [(10,-10),(-3,-4)]            | (-3,-4)
+ {1,0,5}                               | [(-1000000,200),(300000,-40)] | (-5,15.3855384615)
+ {1,0,5}                               | [(11,22),(33,44)]             | (11,22)
+ {1,0,5}                               | [(-10,2),(-10,3)]             | 
+ {1,0,5}                               | [(0,-20),(30,-20)]            | (0,-20)
+ {1,0,5}                               | [(NaN,1),(NaN,90)]            | 
+ {0,3,0}                               | [(1,2),(3,4)]                 | (1,2)
+ {0,3,0}                               | [(0,0),(6,6)]                 | (0,0)
+ {0,3,0}                               | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,3,0}                               | [(-1000000,200),(300000,-40)] | (83333.3333333,-1.7763568394e-15)
+ {0,3,0}                               | [(11,22),(33,44)]             | (11,22)
+ {0,3,0}                               | [(-10,2),(-10,3)]             | (-10,2)
+ {0,3,0}                               | [(0,-20),(30,-20)]            | 
+ {0,3,0}                               | [(NaN,1),(NaN,90)]            | 
+ {1,-1,0}                              | [(1,2),(3,4)]                 | 
+ {1,-1,0}                              | [(0,0),(6,6)]                 | 
+ {1,-1,0}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {1,-1,0}                              | [(-1000000,200),(300000,-40)] | (15.3817756722,15.3817756722)
+ {1,-1,0}                              | [(11,22),(33,44)]             | 
+ {1,-1,0}                              | [(-10,2),(-10,3)]             | (-10,2)
+ {1,-1,0}                              | [(0,-20),(30,-20)]            | (0,-20)
+ {1,-1,0}                              | [(NaN,1),(NaN,90)]            | 
+ {-0.4,-1,-6}                          | [(1,2),(3,4)]                 | (1,2)
+ {-0.4,-1,-6}                          | [(0,0),(6,6)]                 | (0,0)
+ {-0.4,-1,-6}                          | [(10,-10),(-3,-4)]            | (10,-10)
+ {-0.4,-1,-6}                          | [(-1000000,200),(300000,-40)] | (-53.4862244113,15.3944897645)
+ {-0.4,-1,-6}                          | [(11,22),(33,44)]             | (11,22)
+ {-0.4,-1,-6}                          | [(-10,2),(-10,3)]             | (-10,2)
+ {-0.4,-1,-6}                          | [(0,-20),(30,-20)]            | (30,-20)
+ {-0.4,-1,-6}                          | [(NaN,1),(NaN,90)]            | 
+ {-0.000184615384615,-1,15.3846153846} | [(1,2),(3,4)]                 | (3,4)
+ {-0.000184615384615,-1,15.3846153846} | [(0,0),(6,6)]                 | (6,6)
+ {-0.000184615384615,-1,15.3846153846} | [(10,-10),(-3,-4)]            | (-3,-4)
+ {-0.000184615384615,-1,15.3846153846} | [(-1000000,200),(300000,-40)] | 
+ {-0.000184615384615,-1,15.3846153846} | [(11,22),(33,44)]             | (11,22)
+ {-0.000184615384615,-1,15.3846153846} | [(-10,2),(-10,3)]             | (-10,3)
+ {-0.000184615384615,-1,15.3846153846} | [(0,-20),(30,-20)]            | (30,-20)
+ {-0.000184615384615,-1,15.3846153846} | [(NaN,1),(NaN,90)]            | 
+ {3,NaN,5}                             | [(1,2),(3,4)]                 | 
+ {3,NaN,5}                             | [(0,0),(6,6)]                 | 
+ {3,NaN,5}                             | [(10,-10),(-3,-4)]            | 
+ {3,NaN,5}                             | [(-1000000,200),(300000,-40)] | 
+ {3,NaN,5}                             | [(11,22),(33,44)]             | 
+ {3,NaN,5}                             | [(-10,2),(-10,3)]             | 
+ {3,NaN,5}                             | [(0,-20),(30,-20)]            | 
+ {3,NaN,5}                             | [(NaN,1),(NaN,90)]            | 
+ {NaN,NaN,NaN}                         | [(1,2),(3,4)]                 | 
+ {NaN,NaN,NaN}                         | [(0,0),(6,6)]                 | 
+ {NaN,NaN,NaN}                         | [(10,-10),(-3,-4)]            | 
+ {NaN,NaN,NaN}                         | [(-1000000,200),(300000,-40)] | 
+ {NaN,NaN,NaN}                         | [(11,22),(33,44)]             | 
+ {NaN,NaN,NaN}                         | [(-10,2),(-10,3)]             | 
+ {NaN,NaN,NaN}                         | [(0,-20),(30,-20)]            | 
+ {NaN,NaN,NaN}                         | [(NaN,1),(NaN,90)]            | 
+ {0,-1,3}                              | [(1,2),(3,4)]                 | (2,3)
+ {0,-1,3}                              | [(0,0),(6,6)]                 | (3,3)
+ {0,-1,3}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,-1,3}                              | [(-1000000,200),(300000,-40)] | (67083.3333333,3)
+ {0,-1,3}                              | [(11,22),(33,44)]             | (11,22)
+ {0,-1,3}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {0,-1,3}                              | [(0,-20),(30,-20)]            | 
+ {0,-1,3}                              | [(NaN,1),(NaN,90)]            | 
+ {-1,0,3}                              | [(1,2),(3,4)]                 | (3,4)
+ {-1,0,3}                              | [(0,0),(6,6)]                 | (3,3)
+ {-1,0,3}                              | [(10,-10),(-3,-4)]            | (3,-6.76923076923)
+ {-1,0,3}                              | [(-1000000,200),(300000,-40)] | (3,15.3840615385)
+ {-1,0,3}                              | [(11,22),(33,44)]             | (11,22)
+ {-1,0,3}                              | [(-10,2),(-10,3)]             | 
+ {-1,0,3}                              | [(0,-20),(30,-20)]            | (3,-20)
+ {-1,0,3}                              | [(NaN,1),(NaN,90)]            | 
+(80 rows)
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LINE_TBL l, BOX_TBL b;
+ERROR:  function "close_lb" not implemented
 --
 -- Line segments
 --
 -- intersection
 SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
    FROM LSEG_TBL l, POINT_TBL p;
 ERROR:  operator does not exist: lseg # point
 LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
                                            ^
 HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (-0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
+-- Length
+SELECT s, @-@ s FROM LSEG_TBL;
+               s               |   ?column?    
+-------------------------------+---------------
+ [(1,2),(3,4)]                 | 2.82842712475
+ [(0,0),(6,6)]                 | 8.48528137424
+ [(10,-10),(-3,-4)]            | 14.3178210633
+ [(-1000000,200),(300000,-40)] | 1300000.02215
+ [(11,22),(33,44)]             | 31.1126983722
+ [(-10,2),(-10,3)]             |             1
+ [(0,-20),(30,-20)]            |            30
+ [(NaN,1),(NaN,90)]            |           NaN
+(8 rows)
+
+-- Vertical
+SELECT s FROM LSEG_TBL WHERE ?| s;
+         s         
+-------------------
+ [(-10,2),(-10,3)]
+(1 row)
+
+-- Horizontal
+SELECT s FROM LSEG_TBL WHERE ?- s;
+         s          
+--------------------
+ [(0,-20),(30,-20)]
+(1 row)
+
+-- Center
+SELECT s, @@ s FROM LSEG_TBL;
+               s               |   ?column?   
+-------------------------------+--------------
+ [(1,2),(3,4)]                 | (2,3)
+ [(0,0),(6,6)]                 | (3,3)
+ [(10,-10),(-3,-4)]            | (3.5,-7)
+ [(-1000000,200),(300000,-40)] | (-350000,80)
+ [(11,22),(33,44)]             | (22,33)
+ [(-10,2),(-10,3)]             | (-10,2.5)
+ [(0,-20),(30,-20)]            | (15,-20)
+ [(NaN,1),(NaN,90)]            | (NaN,45.5)
+(8 rows)
+
+-- To point
+SELECT s, s::point FROM LSEG_TBL;
+               s               |      s       
+-------------------------------+--------------
+ [(1,2),(3,4)]                 | (2,3)
+ [(0,0),(6,6)]                 | (3,3)
+ [(10,-10),(-3,-4)]            | (3.5,-7)
+ [(-1000000,200),(300000,-40)] | (-350000,80)
+ [(11,22),(33,44)]             | (22,33)
+ [(-10,2),(-10,3)]             | (-10,2.5)
+ [(0,-20),(30,-20)]            | (15,-20)
+ [(NaN,1),(NaN,90)]            | (NaN,45.5)
+(8 rows)
+
+-- Has points less than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s < l2.s;
+         s          |               s               
+--------------------+-------------------------------
+ [(1,2),(3,4)]      | [(0,0),(6,6)]
+ [(1,2),(3,4)]      | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]      | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]      | [(11,22),(33,44)]
+ [(1,2),(3,4)]      | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]      | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]      | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]      | [(11,22),(33,44)]
+ [(0,0),(6,6)]      | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)] | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)] | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]  | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]  | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]  | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]  | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]  | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]  | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]  | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)] | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)] | [(11,22),(33,44)]
+(21 rows)
+
+-- Has points less than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s <= l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(28 rows)
+
+-- Has points equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s = l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]
+(8 rows)
+
+-- Has points greater than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s >= l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(28 rows)
+
+-- Has points greater than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s > l2.s;
+               s               |         s          
+-------------------------------+--------------------
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+(21 rows)
+
+-- Has points not equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s != l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)]
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]
+(56 rows)
+
+-- Parallel with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?|| l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(13 rows)
+
+-- Perpendicular with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?-| l2.s;
+         s          |         s          
+--------------------+--------------------
+ [(-10,2),(-10,3)]  | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)] | [(-10,2),(-10,3)]
+(2 rows)
+
+-- Distance to line
+SELECT l.s, l1.s, l.s <-> l1.s FROM LSEG_TBL l, LINE_TBL l1;
+               s               |                   s                   |    ?column?    
+-------------------------------+---------------------------------------+----------------
+ [(1,2),(3,4)]                 | {0,-1,5}                              |              1
+ [(0,0),(6,6)]                 | {0,-1,5}                              |              0
+ [(10,-10),(-3,-4)]            | {0,-1,5}                              |              9
+ [(-1000000,200),(300000,-40)] | {0,-1,5}                              |              0
+ [(11,22),(33,44)]             | {0,-1,5}                              |             17
+ [(-10,2),(-10,3)]             | {0,-1,5}                              |              2
+ [(0,-20),(30,-20)]            | {0,-1,5}                              |             25
+ [(NaN,1),(NaN,90)]            | {0,-1,5}                              |            NaN
+ [(1,2),(3,4)]                 | {1,0,5}                               |              6
+ [(0,0),(6,6)]                 | {1,0,5}                               |              5
+ [(10,-10),(-3,-4)]            | {1,0,5}                               |              2
+ [(-1000000,200),(300000,-40)] | {1,0,5}                               |              0
+ [(11,22),(33,44)]             | {1,0,5}                               |             16
+ [(-10,2),(-10,3)]             | {1,0,5}                               |              5
+ [(0,-20),(30,-20)]            | {1,0,5}                               |              5
+ [(NaN,1),(NaN,90)]            | {1,0,5}                               |            NaN
+ [(1,2),(3,4)]                 | {0,3,0}                               |              2
+ [(0,0),(6,6)]                 | {0,3,0}                               |              0
+ [(10,-10),(-3,-4)]            | {0,3,0}                               |              4
+ [(-1000000,200),(300000,-40)] | {0,3,0}                               |              0
+ [(11,22),(33,44)]             | {0,3,0}                               |             22
+ [(-10,2),(-10,3)]             | {0,3,0}                               |              2
+ [(0,-20),(30,-20)]            | {0,3,0}                               |             20
+ [(NaN,1),(NaN,90)]            | {0,3,0}                               |            NaN
+ [(1,2),(3,4)]                 | {1,-1,0}                              | 0.707106781187
+ [(0,0),(6,6)]                 | {1,-1,0}                              |              0
+ [(10,-10),(-3,-4)]            | {1,-1,0}                              | 0.707106781187
+ [(-1000000,200),(300000,-40)] | {1,-1,0}                              |              0
+ [(11,22),(33,44)]             | {1,-1,0}                              |  7.77817459305
+ [(-10,2),(-10,3)]             | {1,-1,0}                              |  8.48528137424
+ [(0,-20),(30,-20)]            | {1,-1,0}                              |  14.1421356237
+ [(NaN,1),(NaN,90)]            | {1,-1,0}                              |            NaN
+ [(1,2),(3,4)]                 | {-0.4,-1,-6}                          |  7.79920420344
+ [(0,0),(6,6)]                 | {-0.4,-1,-6}                          |  5.57086014531
+ [(10,-10),(-3,-4)]            | {-0.4,-1,-6}                          |              0
+ [(-1000000,200),(300000,-40)] | {-0.4,-1,-6}                          |              0
+ [(11,22),(33,44)]             | {-0.4,-1,-6}                          |  30.0826447847
+ [(-10,2),(-10,3)]             | {-0.4,-1,-6}                          |  3.71390676354
+ [(0,-20),(30,-20)]            | {-0.4,-1,-6}                          |  1.85695338177
+ [(NaN,1),(NaN,90)]            | {-0.4,-1,-6}                          |            NaN
+ [(1,2),(3,4)]                 | {-0.000184615384615,-1,15.3846153846} |  11.3840613445
+ [(0,0),(6,6)]                 | {-0.000184615384615,-1,15.3846153846} |   9.3835075324
+ [(10,-10),(-3,-4)]            | {-0.000184615384615,-1,15.3846153846} |  19.3851689004
+ [(-1000000,200),(300000,-40)] | {-0.000184615384615,-1,15.3846153846} |              0
+ [(11,22),(33,44)]             | {-0.000184615384615,-1,15.3846153846} |  6.61741527185
+ [(-10,2),(-10,3)]             | {-0.000184615384615,-1,15.3846153846} |  12.3864613274
+ [(0,-20),(30,-20)]            | {-0.000184615384615,-1,15.3846153846} |  35.3790763202
+ [(NaN,1),(NaN,90)]            | {-0.000184615384615,-1,15.3846153846} |            NaN
+ [(1,2),(3,4)]                 | {3,NaN,5}                             |            NaN
+ [(0,0),(6,6)]                 | {3,NaN,5}                             |            NaN
+ [(10,-10),(-3,-4)]            | {3,NaN,5}                             |            NaN
+ [(-1000000,200),(300000,-40)] | {3,NaN,5}                             |            NaN
+ [(11,22),(33,44)]             | {3,NaN,5}                             |            NaN
+ [(-10,2),(-10,3)]             | {3,NaN,5}                             |            NaN
+ [(0,-20),(30,-20)]            | {3,NaN,5}                             |            NaN
+ [(NaN,1),(NaN,90)]            | {3,NaN,5}                             |            NaN
+ [(1,2),(3,4)]                 | {NaN,NaN,NaN}                         |            NaN
+ [(0,0),(6,6)]                 | {NaN,NaN,NaN}                         |            NaN
+ [(10,-10),(-3,-4)]            | {NaN,NaN,NaN}                         |            NaN
+ [(-1000000,200),(300000,-40)] | {NaN,NaN,NaN}                         |            NaN
+ [(11,22),(33,44)]             | {NaN,NaN,NaN}                         |            NaN
+ [(-10,2),(-10,3)]             | {NaN,NaN,NaN}                         |            NaN
+ [(0,-20),(30,-20)]            | {NaN,NaN,NaN}                         |            NaN
+ [(NaN,1),(NaN,90)]            | {NaN,NaN,NaN}                         |            NaN
+ [(1,2),(3,4)]                 | {0,-1,3}                              |              0
+ [(0,0),(6,6)]                 | {0,-1,3}                              |              0
+ [(10,-10),(-3,-4)]            | {0,-1,3}                              |              7
+ [(-1000000,200),(300000,-40)] | {0,-1,3}                              |              0
+ [(11,22),(33,44)]             | {0,-1,3}                              |             19
+ [(-10,2),(-10,3)]             | {0,-1,3}                              |              0
+ [(0,-20),(30,-20)]            | {0,-1,3}                              |             23
+ [(NaN,1),(NaN,90)]            | {0,-1,3}                              |            NaN
+ [(1,2),(3,4)]                 | {-1,0,3}                              |              0
+ [(0,0),(6,6)]                 | {-1,0,3}                              |              0
+ [(10,-10),(-3,-4)]            | {-1,0,3}                              |              0
+ [(-1000000,200),(300000,-40)] | {-1,0,3}                              |              0
+ [(11,22),(33,44)]             | {-1,0,3}                              |              8
+ [(-10,2),(-10,3)]             | {-1,0,3}                              |             13
+ [(0,-20),(30,-20)]            | {-1,0,3}                              |              0
+ [(NaN,1),(NaN,90)]            | {-1,0,3}                              |            NaN
+(80 rows)
+
+-- Distance to line segment
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               |    ?column?    
+-------------------------------+-------------------------------+----------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 |              0
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 0.707106781187
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            |  7.12398901685
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] |  11.3840613445
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             |  19.6977156036
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             |             11
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            |             22
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            |            NaN
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 0.707106781187
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 |              0
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            |  4.88901207039
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] |   9.3835075324
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             |  16.7630546142
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             |  10.1980390272
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            |             20
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            |            NaN
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 |  7.12398901685
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 |  4.88901207039
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            |              0
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] |  19.3851689004
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             |  29.4737584815
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             |  9.21954445729
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            |             10
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            |            NaN
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 |  11.3840613445
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 |   9.3835075324
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            |  19.3851689004
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] |              0
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             |  6.61741527185
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             |  12.3864613274
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            |  35.3790763202
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            |            NaN
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 |  19.6977156036
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 |  16.7630546142
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            |  29.4737584815
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] |  6.61741527185
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             |              0
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             |   28.319604517
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            |             42
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            |            NaN
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 |             11
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 |  10.1980390272
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            |  9.21954445729
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] |  12.3864613274
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             |   28.319604517
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             |              0
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            |  24.1660919472
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            |            NaN
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 |             22
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 |             20
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            |             10
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] |  35.3790763202
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             |             42
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             |  24.1660919472
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            |              0
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 |            NaN
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 |            NaN
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] |            NaN
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             |            NaN
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             |            NaN
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            |            NaN
+(64 rows)
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LSEG_TBL l, BOX_TBL b;
+               s               |         f1          |    ?column?    
+-------------------------------+---------------------+----------------
+ [(1,2),(3,4)]                 | (2,2),(0,0)         |              0
+ [(1,2),(3,4)]                 | (3,3),(1,1)         |              0
+ [(1,2),(3,4)]                 | (-2,2),(-8,-10)     |              3
+ [(1,2),(3,4)]                 | (2.5,3.5),(2.5,2.5) |              0
+ [(1,2),(3,4)]                 | (3,3),(3,3)         | 0.707106781187
+ [(0,0),(6,6)]                 | (2,2),(0,0)         |              0
+ [(0,0),(6,6)]                 | (3,3),(1,1)         |              0
+ [(0,0),(6,6)]                 | (-2,2),(-8,-10)     |              2
+ [(0,0),(6,6)]                 | (2.5,3.5),(2.5,2.5) |              0
+ [(0,0),(6,6)]                 | (3,3),(3,3)         |              0
+ [(10,-10),(-3,-4)]            | (2,2),(0,0)         |  4.88901207039
+ [(10,-10),(-3,-4)]            | (3,3),(1,1)         |  6.21602963235
+ [(10,-10),(-3,-4)]            | (-2,2),(-8,-10)     |              0
+ [(10,-10),(-3,-4)]            | (2.5,3.5),(2.5,2.5) |  8.20655597529
+ [(10,-10),(-3,-4)]            | (3,3),(3,3)         |  8.87006475627
+ [(-1000000,200),(300000,-40)] | (2,2),(0,0)         |  13.3842459258
+ [(-1000000,200),(300000,-40)] | (3,3),(1,1)         |  12.3840613274
+ [(-1000000,200),(300000,-40)] | (-2,2),(-8,-10)     |  13.3849843873
+ [(-1000000,200),(300000,-40)] | (2.5,3.5),(2.5,2.5) |  11.8841536436
+ [(-1000000,200),(300000,-40)] | (3,3),(3,3)         |  12.3840613274
+ [(11,22),(33,44)]             | (2,2),(0,0)         |  21.9317121995
+ [(11,22),(33,44)]             | (3,3),(1,1)         |  20.6155281281
+ [(11,22),(33,44)]             | (-2,2),(-8,-10)     |  23.8537208838
+ [(11,22),(33,44)]             | (2.5,3.5),(2.5,2.5) |  20.3592730715
+ [(11,22),(33,44)]             | (3,3),(3,3)         |  20.6155281281
+ [(-10,2),(-10,3)]             | (2,2),(0,0)         |             10
+ [(-10,2),(-10,3)]             | (3,3),(1,1)         |             11
+ [(-10,2),(-10,3)]             | (-2,2),(-8,-10)     |              2
+ [(-10,2),(-10,3)]             | (2.5,3.5),(2.5,2.5) |           12.5
+ [(-10,2),(-10,3)]             | (3,3),(3,3)         |             13
+ [(0,-20),(30,-20)]            | (2,2),(0,0)         |             20
+ [(0,-20),(30,-20)]            | (3,3),(1,1)         |             21
+ [(0,-20),(30,-20)]            | (-2,2),(-8,-10)     |  10.1980390272
+ [(0,-20),(30,-20)]            | (2.5,3.5),(2.5,2.5) |           22.5
+ [(0,-20),(30,-20)]            | (3,3),(3,3)         |             23
+ [(NaN,1),(NaN,90)]            | (2,2),(0,0)         |            NaN
+ [(NaN,1),(NaN,90)]            | (3,3),(1,1)         |            NaN
+ [(NaN,1),(NaN,90)]            | (-2,2),(-8,-10)     |            NaN
+ [(NaN,1),(NaN,90)]            | (2.5,3.5),(2.5,2.5) |            NaN
+ [(NaN,1),(NaN,90)]            | (3,3),(3,3)         |            NaN
+(40 rows)
+
+-- Intersect with line segment
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s ?# l1.s;
+               s               |      s       
+-------------------------------+--------------
+ [(0,0),(6,6)]                 | {0,-1,5}
+ [(-1000000,200),(300000,-40)] | {0,-1,5}
+ [(-1000000,200),(300000,-40)] | {1,0,5}
+ [(0,0),(6,6)]                 | {0,3,0}
+ [(-1000000,200),(300000,-40)] | {0,3,0}
+ [(-1000000,200),(300000,-40)] | {1,-1,0}
+ [(10,-10),(-3,-4)]            | {-0.4,-1,-6}
+ [(-1000000,200),(300000,-40)] | {-0.4,-1,-6}
+ [(1,2),(3,4)]                 | {0,-1,3}
+ [(0,0),(6,6)]                 | {0,-1,3}
+ [(-1000000,200),(300000,-40)] | {0,-1,3}
+ [(-10,2),(-10,3)]             | {0,-1,3}
+ [(1,2),(3,4)]                 | {-1,0,3}
+ [(0,0),(6,6)]                 | {-1,0,3}
+ [(10,-10),(-3,-4)]            | {-1,0,3}
+ [(-1000000,200),(300000,-40)] | {-1,0,3}
+ [(0,-20),(30,-20)]            | {-1,0,3}
+(17 rows)
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+         s          |         f1          
+--------------------+---------------------
+ [(1,2),(3,4)]      | (2,2),(0,0)
+ [(1,2),(3,4)]      | (3,3),(1,1)
+ [(1,2),(3,4)]      | (2.5,3.5),(2.5,2.5)
+ [(0,0),(6,6)]      | (2,2),(0,0)
+ [(0,0),(6,6)]      | (3,3),(1,1)
+ [(0,0),(6,6)]      | (2.5,3.5),(2.5,2.5)
+ [(0,0),(6,6)]      | (3,3),(3,3)
+ [(10,-10),(-3,-4)] | (-2,2),(-8,-10)
+(8 rows)
+
+-- Intersection point with line segment
+SELECT l1.s, l2.s, l1.s # l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               | ?column? 
+-------------------------------+-------------------------------+----------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 | 
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            | 
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] | 
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             | 
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             | 
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            | 
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            | 
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 | 
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            | 
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] | 
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             | 
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             | 
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            | 
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            | 
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 | 
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 | 
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            | 
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] | 
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             | 
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             | 
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            | 
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            | 
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 | 
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 | 
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            | 
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] | 
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             | 
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             | 
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            | 
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            | 
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 | 
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 | 
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            | 
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] | 
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             | 
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             | 
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            | 
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            | 
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 | 
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 | 
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            | 
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] | 
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             | 
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             | 
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            | 
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            | 
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 | 
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 | 
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            | 
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] | 
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             | 
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             | 
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            | 
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            | 
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 | 
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 | 
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            | 
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] | 
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             | 
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             | 
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            | 
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            | 
+(64 rows)
+
+-- Closest point to line
+SELECT l.s, l1.s, l.s ## l1.s FROM LSEG_TBL l, LINE_TBL l1;
+ERROR:  function "close_sl" not implemented
+-- Closest point to line segment
+SELECT l1.s, l2.s, l1.s ## l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               |            ?column?             
+-------------------------------+-------------------------------+---------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 | 
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            | (-1.98536585366,-4.46829268293)
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] | (3.00210167283,15.3840611505)
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             | 
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             | (-10,2)
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            | (1,-20)
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            | 
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 | 
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] | (6.00173233982,15.3835073725)
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             | 
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             | (-10,2)
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            | (0,-20)
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            | 
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 | (1,2)
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 | (0,0)
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            | 
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] | (-2.99642119965,15.3851685701)
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             | (11,22)
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             | (-10,2)
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            | (10,-20)
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            | 
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 | (3,4)
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 | (6,6)
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            | (-3,-4)
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] | 
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             | (11,22)
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             | (-10,3)
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            | (30,-20)
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            | 
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 | 
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 | 
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            | (-1.3512195122,-4.76097560976)
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] | (10.9987783234,15.3825848409)
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             | 
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             | (-10,3)
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            | (11,-20)
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            | 
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 | (1,2)
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 | (0,0)
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            | (-3,-4)
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] | (-9.99771326872,15.3864611163)
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             | (11,22)
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             | 
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            | (0,-20)
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            | 
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 | (1,2)
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 | (0,0)
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            | (10,-10)
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] | (30.0065315217,15.3790757173)
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             | (11,22)
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             | (-10,2)
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            | 
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            | 
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 | 
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 | 
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            | 
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] | 
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             | 
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             | 
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            | 
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            | 
+(64 rows)
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LSEG_TBL l, BOX_TBL b;
+               s               |         f1          |  ?column?   
+-------------------------------+---------------------+-------------
+ [(1,2),(3,4)]                 | (2,2),(0,0)         | (1,2)
+ [(1,2),(3,4)]                 | (3,3),(1,1)         | (1.5,2.5)
+ [(1,2),(3,4)]                 | (-2,2),(-8,-10)     | (-2,2)
+ [(1,2),(3,4)]                 | (2.5,3.5),(2.5,2.5) | (2.25,3.25)
+ [(1,2),(3,4)]                 | (3,3),(3,3)         | (3,3)
+ [(0,0),(6,6)]                 | (2,2),(0,0)         | (1,1)
+ [(0,0),(6,6)]                 | (3,3),(1,1)         | (2,2)
+ [(0,0),(6,6)]                 | (-2,2),(-8,-10)     | (-2,0)
+ [(0,0),(6,6)]                 | (2.5,3.5),(2.5,2.5) | (2.75,2.75)
+ [(0,0),(6,6)]                 | (3,3),(3,3)         | (3,3)
+ [(10,-10),(-3,-4)]            | (2,2),(0,0)         | (0,0)
+ [(10,-10),(-3,-4)]            | (3,3),(1,1)         | (1,1)
+ [(10,-10),(-3,-4)]            | (-2,2),(-8,-10)     | (-3,-4)
+ [(10,-10),(-3,-4)]            | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ [(10,-10),(-3,-4)]            | (3,3),(3,3)         | (3,3)
+ [(-1000000,200),(300000,-40)] | (2,2),(0,0)         | (2,2)
+ [(-1000000,200),(300000,-40)] | (3,3),(1,1)         | (3,3)
+ [(-1000000,200),(300000,-40)] | (-2,2),(-8,-10)     | (-2,2)
+ [(-1000000,200),(300000,-40)] | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ [(-1000000,200),(300000,-40)] | (3,3),(3,3)         | (3,3)
+ [(11,22),(33,44)]             | (2,2),(0,0)         | (2,2)
+ [(11,22),(33,44)]             | (3,3),(1,1)         | (3,3)
+ [(11,22),(33,44)]             | (-2,2),(-8,-10)     | (-2,2)
+ [(11,22),(33,44)]             | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ [(11,22),(33,44)]             | (3,3),(3,3)         | (3,3)
+ [(-10,2),(-10,3)]             | (2,2),(0,0)         | (0,2)
+ [(-10,2),(-10,3)]             | (3,3),(1,1)         | (1,2)
+ [(-10,2),(-10,3)]             | (-2,2),(-8,-10)     | (-8,2)
+ [(-10,2),(-10,3)]             | (2.5,3.5),(2.5,2.5) | (2.5,3)
+ [(-10,2),(-10,3)]             | (3,3),(3,3)         | (3,3)
+ [(0,-20),(30,-20)]            | (2,2),(0,0)         | (0,0)
+ [(0,-20),(30,-20)]            | (3,3),(1,1)         | (1,1)
+ [(0,-20),(30,-20)]            | (-2,2),(-8,-10)     | (-2,-10)
+ [(0,-20),(30,-20)]            | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ [(0,-20),(30,-20)]            | (3,3),(3,3)         | (3,3)
+ [(NaN,1),(NaN,90)]            | (2,2),(0,0)         | 
+ [(NaN,1),(NaN,90)]            | (3,3),(1,1)         | 
+ [(NaN,1),(NaN,90)]            | (-2,2),(-8,-10)     | 
+ [(NaN,1),(NaN,90)]            | (2.5,3.5),(2.5,2.5) | 
+ [(NaN,1),(NaN,90)]            | (3,3),(3,3)         | 
+(40 rows)
+
+-- On line
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s <@ l1.s;
+               s               |                   s                   
+-------------------------------+---------------------------------------
+ [(0,0),(6,6)]                 | {1,-1,0}
+ [(-1000000,200),(300000,-40)] | {-0.000184615384615,-1,15.3846153846}
+(2 rows)
+
+-- On box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s <@ b.f1;
+ s | f1 
+---+----
+(0 rows)
 
 --
 -- Boxes
 --
 SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
  six |                              box                               
 -----+----------------------------------------------------------------
      | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
      | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
      | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
      | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
      | (107.071067812,207.071067812),(92.9289321881,192.928932188)
      | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
+     | (3,5),(3,5)
+     | (NaN,NaN),(NaN,NaN)
+(8 rows)
 
 -- translation
 SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
+ twentyfour |             translation             
+------------+-------------------------------------
             | (2,2),(0,0)
             | (3,3),(1,1)
+            | (-2,2),(-8,-10)
             | (2.5,3.5),(2.5,2.5)
             | (3,3),(3,3)
             | (-8,2),(-10,0)
             | (-7,3),(-9,1)
+            | (-12,2),(-18,-10)
             | (-7.5,3.5),(-7.5,2.5)
             | (-7,3),(-7,3)
             | (-1,6),(-3,4)
             | (0,7),(-2,5)
+            | (-5,6),(-11,-6)
             | (-0.5,7.5),(-0.5,6.5)
             | (0,7),(0,7)
             | (7.1,36.5),(5.1,34.5)
             | (8.1,37.5),(6.1,35.5)
+            | (3.1,36.5),(-2.9,24.5)
             | (7.6,38),(7.6,37)
             | (8.1,37.5),(8.1,37.5)
             | (-3,-10),(-5,-12)
             | (-2,-9),(-4,-11)
+            | (-7,-10),(-13,-22)
             | (-2.5,-8.5),(-2.5,-9.5)
             | (-2,-9),(-2,-9)
+            | (2,2),(1e-300,-1e-300)
+            | (3,3),(1,1)
+            | (-2,2),(-8,-10)
+            | (2.5,3.5),(2.5,2.5)
+            | (3,3),(3,3)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
             | (12,12),(10,10)
             | (13,13),(11,11)
+            | (8,12),(2,0)
             | (12.5,13.5),(12.5,12.5)
             | (13,13),(13,13)
-(24 rows)
+(45 rows)
 
 SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
+ twentyfour |               translation               
+------------+-----------------------------------------
             | (2,2),(0,0)
             | (3,3),(1,1)
+            | (-2,2),(-8,-10)
             | (2.5,3.5),(2.5,2.5)
             | (3,3),(3,3)
             | (12,2),(10,0)
             | (13,3),(11,1)
+            | (8,2),(2,-10)
             | (12.5,3.5),(12.5,2.5)
             | (13,3),(13,3)
             | (5,-2),(3,-4)
             | (6,-1),(4,-3)
+            | (1,-2),(-5,-14)
             | (5.5,-0.5),(5.5,-1.5)
             | (6,-1),(6,-1)
             | (-3.1,-32.5),(-5.1,-34.5)
             | (-2.1,-31.5),(-4.1,-33.5)
+            | (-7.1,-32.5),(-13.1,-44.5)
             | (-2.6,-31),(-2.6,-32)
             | (-2.1,-31.5),(-2.1,-31.5)
             | (7,14),(5,12)
             | (8,15),(6,13)
+            | (3,14),(-3,2)
             | (7.5,15.5),(7.5,14.5)
             | (8,15),(8,15)
+            | (2,2),(-1e-300,1e-300)
+            | (3,3),(1,1)
+            | (-2,2),(-8,-10)
+            | (2.5,3.5),(2.5,2.5)
+            | (3,3),(3,3)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
             | (-8,-8),(-10,-10)
             | (-7,-7),(-9,-9)
+            | (-12,-8),(-18,-20)
             | (-7.5,-6.5),(-7.5,-7.5)
             | (-7,-7),(-7,-7)
-(24 rows)
+(45 rows)
 
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (-0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (-0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,-0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
+-- Multiply with point
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+         f1          |     f1     |          ?column?           
+---------------------+------------+-----------------------------
+ (2,2),(0,0)         | (5.1,34.5) | (0,79.2),(-58.8,0)
+ (2,2),(0,0)         | (10,10)    | (0,40),(0,0)
+ (3,3),(1,1)         | (5.1,34.5) | (-29.4,118.8),(-88.2,39.6)
+ (3,3),(1,1)         | (10,10)    | (0,60),(0,20)
+ (-2,2),(-8,-10)     | (5.1,34.5) | (304.2,-58.8),(-79.2,-327)
+ (-2,2),(-8,-10)     | (10,10)    | (20,0),(-40,-180)
+ (2.5,3.5),(2.5,2.5) | (5.1,34.5) | (-73.5,104.1),(-108,99)
+ (2.5,3.5),(2.5,2.5) | (10,10)    | (0,60),(-10,50)
+ (3,3),(3,3)         | (5.1,34.5) | (-88.2,118.8),(-88.2,118.8)
+ (3,3),(3,3)         | (10,10)    | (0,60),(0,60)
+(10 rows)
 
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,-0),(-0.2,-0.2)
-        | (0.08,-0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (-0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
+-- Overflow error
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] > 1000;
+         f1          |        f1         |                  ?column?                  
+---------------------+-------------------+--------------------------------------------
+ (2,2),(0,0)         | (1e+300,Infinity) | (NaN,NaN),(-Infinity,Infinity)
+ (2,2),(0,0)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (3,3),(1,1)         | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (3,3),(1,1)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (-2,2),(-8,-10)     | (1e+300,Infinity) | (Infinity,-Infinity),(-Infinity,-Infinity)
+ (-2,2),(-8,-10)     | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (2.5,3.5),(2.5,2.5) | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (2.5,3.5),(2.5,2.5) | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (3,3),(3,3)         | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (3,3),(3,3)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+(10 rows)
 
+-- Divide by point
+SELECT b.f1, p.f1, b.f1 / p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+         f1          |     f1     |                               ?column?                               
+---------------------+------------+----------------------------------------------------------------------
+ (2,2),(0,0)         | (5.1,34.5) | (0.0651176557644,0),(0,-0.0483449262493)
+ (2,2),(0,0)         | (10,10)    | (0.2,0),(0,0)
+ (3,3),(1,1)         | (5.1,34.5) | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
+ (3,3),(1,1)         | (10,10)    | (0.3,0),(0.1,0)
+ (-2,2),(-8,-10)     | (5.1,34.5) | (0.0483449262493,0.18499334024),(-0.317201914064,0.0651176557644)
+ (-2,2),(-8,-10)     | (10,10)    | (0,0.2),(-0.9,-0.1)
+ (2.5,3.5),(2.5,2.5) | (5.1,34.5) | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
+ (2.5,3.5),(2.5,2.5) | (10,10)    | (0.3,0.05),(0.25,0)
+ (3,3),(3,3)         | (5.1,34.5) | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
+ (3,3),(3,3)         | (10,10)    | (0.3,0),(0.3,0)
+(10 rows)
+
+-- To box
 SELECT f1::box
 	FROM POINT_TBL;
-          f1           
------------------------
+                 f1                  
+-------------------------------------
  (0,0),(0,0)
  (-10,0),(-10,0)
  (-3,4),(-3,4)
  (5.1,34.5),(5.1,34.5)
  (-5,-12),(-5,-12)
+ (1e-300,-1e-300),(1e-300,-1e-300)
+ (1e+300,Infinity),(1e+300,Infinity)
+ (NaN,NaN),(NaN,NaN)
  (10,10),(10,10)
-(6 rows)
+(9 rows)
 
 SELECT bound_box(a.f1, b.f1)
 	FROM BOX_TBL a, BOX_TBL b;
       bound_box      
 ---------------------
  (2,2),(0,0)
  (3,3),(0,0)
+ (2,2),(-8,-10)
  (2.5,3.5),(0,0)
  (3,3),(0,0)
  (3,3),(0,0)
  (3,3),(1,1)
+ (3,3),(-8,-10)
  (3,3.5),(1,1)
  (3,3),(1,1)
+ (2,2),(-8,-10)
+ (3,3),(-8,-10)
+ (-2,2),(-8,-10)
+ (2.5,3.5),(-8,-10)
+ (3,3),(-8,-10)
  (2.5,3.5),(0,0)
  (3,3.5),(1,1)
+ (2.5,3.5),(-8,-10)
  (2.5,3.5),(2.5,2.5)
  (3,3.5),(2.5,2.5)
  (3,3),(0,0)
  (3,3),(1,1)
+ (3,3),(-8,-10)
  (3,3.5),(2.5,2.5)
  (3,3),(3,3)
-(16 rows)
+(25 rows)
+
+-- Below box
+SELECT b1.f1, b2.f1, b1.f1 <^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          | ?column? 
+---------------------+---------------------+----------
+ (2,2),(0,0)         | (2,2),(0,0)         | f
+ (2,2),(0,0)         | (3,3),(1,1)         | f
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | f
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | t
+ (2,2),(0,0)         | (3,3),(3,3)         | t
+ (3,3),(1,1)         | (2,2),(0,0)         | f
+ (3,3),(1,1)         | (3,3),(1,1)         | f
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | f
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(1,1)         | (3,3),(3,3)         | t
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | f
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | f
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | f
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | t
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | t
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | f
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | f
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | f
+ (3,3),(3,3)         | (2,2),(0,0)         | f
+ (3,3),(3,3)         | (3,3),(1,1)         | f
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | f
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(3,3)         | (3,3),(3,3)         | t
+(25 rows)
+
+-- Above box
+SELECT b1.f1, b2.f1, b1.f1 >^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          | ?column? 
+---------------------+---------------------+----------
+ (2,2),(0,0)         | (2,2),(0,0)         | f
+ (2,2),(0,0)         | (3,3),(1,1)         | f
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | f
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | f
+ (2,2),(0,0)         | (3,3),(3,3)         | f
+ (3,3),(1,1)         | (2,2),(0,0)         | f
+ (3,3),(1,1)         | (3,3),(1,1)         | f
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | f
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(1,1)         | (3,3),(3,3)         | f
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | f
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | f
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | f
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | f
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | f
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | t
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | f
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | t
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | f
+ (3,3),(3,3)         | (2,2),(0,0)         | t
+ (3,3),(3,3)         | (3,3),(1,1)         | t
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | t
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(3,3)         | (3,3),(3,3)         | t
+(25 rows)
+
+-- Intersection point with box
+SELECT b1.f1, b2.f1, b1.f1 # b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          |      ?column?       
+---------------------+---------------------+---------------------
+ (2,2),(0,0)         | (2,2),(0,0)         | (2,2),(0,0)
+ (2,2),(0,0)         | (3,3),(1,1)         | (2,2),(1,1)
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | 
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | 
+ (2,2),(0,0)         | (3,3),(3,3)         | 
+ (3,3),(1,1)         | (2,2),(0,0)         | (2,2),(1,1)
+ (3,3),(1,1)         | (3,3),(1,1)         | (3,3),(1,1)
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | 
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | (2.5,3),(2.5,2.5)
+ (3,3),(1,1)         | (3,3),(3,3)         | (3,3),(3,3)
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | 
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | 
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | (-2,2),(-8,-10)
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | 
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | 
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | 
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | (2.5,3),(2.5,2.5)
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | 
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5)
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | 
+ (3,3),(3,3)         | (2,2),(0,0)         | 
+ (3,3),(3,3)         | (3,3),(1,1)         | (3,3),(3,3)
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | 
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | 
+ (3,3),(3,3)         | (3,3),(3,3)         | (3,3),(3,3)
+(25 rows)
+
+-- Diagonal
+SELECT f1, diagonal(f1) FROM BOX_TBL;
+         f1          |       diagonal        
+---------------------+-----------------------
+ (2,2),(0,0)         | [(2,2),(0,0)]
+ (3,3),(1,1)         | [(3,3),(1,1)]
+ (-2,2),(-8,-10)     | [(-2,2),(-8,-10)]
+ (2.5,3.5),(2.5,2.5) | [(2.5,3.5),(2.5,2.5)]
+ (3,3),(3,3)         | [(3,3),(3,3)]
+(5 rows)
+
+-- Distance to box
+SELECT b1.f1, b2.f1, b1.f1 <-> b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          |   ?column?    
+---------------------+---------------------+---------------
+ (2,2),(0,0)         | (2,2),(0,0)         |             0
+ (2,2),(0,0)         | (3,3),(1,1)         | 1.41421356237
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | 7.81024967591
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) |           2.5
+ (2,2),(0,0)         | (3,3),(3,3)         | 2.82842712475
+ (3,3),(1,1)         | (2,2),(0,0)         | 1.41421356237
+ (3,3),(1,1)         | (3,3),(1,1)         |             0
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | 9.21954445729
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | 1.11803398875
+ (3,3),(1,1)         | (3,3),(3,3)         | 1.41421356237
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | 7.81024967591
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | 9.21954445729
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     |             0
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | 10.2591422643
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | 10.6301458127
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         |           2.5
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | 1.11803398875
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | 10.2591422643
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) |             0
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         |           0.5
+ (3,3),(3,3)         | (2,2),(0,0)         | 2.82842712475
+ (3,3),(3,3)         | (3,3),(1,1)         | 1.41421356237
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | 10.6301458127
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) |           0.5
+ (3,3),(3,3)         | (3,3),(3,3)         |             0
+(25 rows)
 
 --
 -- Paths
 --
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
+-- Points
+SELECT f1, npoints(f1) FROM PATH_TBL;
+            f1             | npoints 
+---------------------------+---------
+ [(1,2),(3,4)]             |       2
+ ((1,2),(3,4))             |       2
+ [(0,0),(3,0),(4,5),(1,6)] |       4
+ ((1,2),(3,4))             |       2
+ ((1,2),(3,4))             |       2
+ [(1,2),(3,4)]             |       2
+ ((10,20))                 |       1
+ [(11,12),(13,14)]         |       2
+ ((11,12),(13,14))         |       2
+(9 rows)
 
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
+-- Area
+SELECT f1, area(f1) FROM PATH_TBL;
+            f1             | area 
+---------------------------+------
+ [(1,2),(3,4)]             |     
+ ((1,2),(3,4))             |    0
+ [(0,0),(3,0),(4,5),(1,6)] |     
+ ((1,2),(3,4))             |    0
+ ((1,2),(3,4))             |    0
+ [(1,2),(3,4)]             |     
+ ((10,20))                 |    0
+ [(11,12),(13,14)]         |     
+ ((11,12),(13,14))         |    0
+(9 rows)
 
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
+-- Length
+SELECT f1, @-@ f1 FROM PATH_TBL;
+            f1             |   ?column?    
+---------------------------+---------------
+ [(1,2),(3,4)]             | 2.82842712475
+ ((1,2),(3,4))             | 5.65685424949
+ [(0,0),(3,0),(4,5),(1,6)] | 11.2612971738
+ ((1,2),(3,4))             | 5.65685424949
+ ((1,2),(3,4))             | 5.65685424949
+ [(1,2),(3,4)]             | 2.82842712475
+ ((10,20))                 |             0
+ [(11,12),(13,14)]         | 2.82842712475
+ ((11,12),(13,14))         | 5.65685424949
+(9 rows)
 
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
+-- Center
+SELECT f1, @@ f1 FROM PATH_TBL;
+ERROR:  function "path_center" not implemented
+-- To polygon
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isclosed(f1);
+        f1         |        f1         
+-------------------+-------------------
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((10,20))         | ((10,20))
+ ((11,12),(13,14)) | ((11,12),(13,14))
+(5 rows)
+
+-- Open path cannot be converted to polygon error
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isopen(f1);
+ERROR:  open path cannot be converted to polygon
+-- Has points less than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 < p2.f1;
+        f1         |            f1             
+-------------------+---------------------------
+ [(1,2),(3,4)]     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]     | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))         | [(1,2),(3,4)]
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | [(1,2),(3,4)]
+ ((10,20))         | [(11,12),(13,14)]
+ ((10,20))         | ((11,12),(13,14))
+ [(11,12),(13,14)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((11,12),(13,14)) | [(0,0),(3,0),(4,5),(1,6)]
+(15 rows)
+
+-- Has points less than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 <= p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | [(1,2),(3,4)]
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | [(1,2),(3,4)]
+ ((10,20))                 | ((10,20))
+ ((10,20))                 | [(11,12),(13,14)]
+ ((10,20))                 | ((11,12),(13,14))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(66 rows)
+
+-- Has points equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 = p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | ((10,20))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(51 rows)
+
+-- Has points greater than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 >= p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | ((10,20))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((10,20))
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((10,20))
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(66 rows)
+
+-- Has points greater than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 > p2.f1;
+            f1             |        f1         
+---------------------------+-------------------
+ [(1,2),(3,4)]             | ((10,20))
+ ((1,2),(3,4))             | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | ((10,20))
+ [(1,2),(3,4)]             | ((10,20))
+ [(11,12),(13,14)]         | ((10,20))
+ ((11,12),(13,14))         | ((10,20))
+(15 rows)
+
+-- Add path
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+            f1             |            f1             |                     ?column?                      
+---------------------------+---------------------------+---------------------------------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4),(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))                 | 
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         | [(1,2),(3,4),(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6),(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6),(0,0),(3,0),(4,5),(1,6)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6),(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))                 | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6),(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4),(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))                 | 
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         | [(1,2),(3,4),(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))         | 
+ ((10,20))                 | [(1,2),(3,4)]             | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | [(1,2),(3,4)]             | 
+ ((10,20))                 | ((10,20))                 | 
+ ((10,20))                 | [(11,12),(13,14)]         | 
+ ((10,20))                 | ((11,12),(13,14))         | 
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             | [(11,12),(13,14),(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14),(0,0),(3,0),(4,5),(1,6)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             | [(11,12),(13,14),(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((10,20))                 | 
+ [(11,12),(13,14)]         | [(11,12),(13,14)]         | [(11,12),(13,14),(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))         | 
+ ((11,12),(13,14))         | [(1,2),(3,4)]             | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | [(1,2),(3,4)]             | 
+ ((11,12),(13,14))         | ((10,20))                 | 
+ ((11,12),(13,14))         | [(11,12),(13,14)]         | 
+ ((11,12),(13,14))         | ((11,12),(13,14))         | 
+(81 rows)
+
+-- Add point
+SELECT p.f1, p1.f1, p.f1 + p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                                 ?column?                                  
+---------------------------+-------------------+---------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((10,20))                 | (0,0)             | ((10,20))
+ [(11,12),(13,14)]         | (0,0)             | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (0,0)             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (-10,0)           | [(-9,2),(-7,4)]
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(-10,0),(-7,0),(-6,5),(-9,6)]
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ [(1,2),(3,4)]             | (-10,0)           | [(-9,2),(-7,4)]
+ ((10,20))                 | (-10,0)           | ((0,20))
+ [(11,12),(13,14)]         | (-10,0)           | [(1,12),(3,14)]
+ ((11,12),(13,14))         | (-10,0)           | ((1,12),(3,14))
+ [(1,2),(3,4)]             | (-3,4)            | [(-2,6),(0,8)]
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(-3,4),(0,4),(1,9),(-2,10)]
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ [(1,2),(3,4)]             | (-3,4)            | [(-2,6),(0,8)]
+ ((10,20))                 | (-3,4)            | ((7,24))
+ [(11,12),(13,14)]         | (-3,4)            | [(8,16),(10,18)]
+ ((11,12),(13,14))         | (-3,4)            | ((8,16),(10,18))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(6.1,36.5),(8.1,38.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(5.1,34.5),(8.1,34.5),(9.1,39.5),(6.1,40.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(6.1,36.5),(8.1,38.5)]
+ ((10,20))                 | (5.1,34.5)        | ((15.1,54.5))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(16.1,46.5),(18.1,48.5)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((16.1,46.5),(18.1,48.5))
+ [(1,2),(3,4)]             | (-5,-12)          | [(-4,-10),(-2,-8)]
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(-5,-12),(-2,-12),(-1,-7),(-4,-6)]
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ [(1,2),(3,4)]             | (-5,-12)          | [(-4,-10),(-2,-8)]
+ ((10,20))                 | (-5,-12)          | ((5,8))
+ [(11,12),(13,14)]         | (-5,-12)          | [(6,0),(8,2)]
+ ((11,12),(13,14))         | (-5,-12)          | ((6,0),(8,2))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(1e-300,-1e-300),(3,-1e-300),(4,5),(1,6)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((10,20))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity),(1e+300,Infinity),(1e+300,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((1e+300,Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(11,12),(13,14)]
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(10,10),(13,10),(14,15),(11,16)]
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (10,10)           | [(11,12),(13,14)]
+ ((10,20))                 | (10,10)           | ((20,30))
+ [(11,12),(13,14)]         | (10,10)           | [(21,22),(23,24)]
+ ((11,12),(13,14))         | (10,10)           | ((21,22),(23,24))
+(81 rows)
+
+-- Subtract point
+SELECT p.f1, p1.f1, p.f1 - p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                                     ?column?                                      
+---------------------------+-------------------+-----------------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((10,20))                 | (0,0)             | ((10,20))
+ [(11,12),(13,14)]         | (0,0)             | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (0,0)             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (-10,0)           | [(11,2),(13,4)]
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(10,0),(13,0),(14,5),(11,6)]
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ [(1,2),(3,4)]             | (-10,0)           | [(11,2),(13,4)]
+ ((10,20))                 | (-10,0)           | ((20,20))
+ [(11,12),(13,14)]         | (-10,0)           | [(21,12),(23,14)]
+ ((11,12),(13,14))         | (-10,0)           | ((21,12),(23,14))
+ [(1,2),(3,4)]             | (-3,4)            | [(4,-2),(6,0)]
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(3,-4),(6,-4),(7,1),(4,2)]
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ [(1,2),(3,4)]             | (-3,4)            | [(4,-2),(6,0)]
+ ((10,20))                 | (-3,4)            | ((13,16))
+ [(11,12),(13,14)]         | (-3,4)            | [(14,8),(16,10)]
+ ((11,12),(13,14))         | (-3,4)            | ((14,8),(16,10))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-4.1,-32.5),(-2.1,-30.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(-5.1,-34.5),(-2.1,-34.5),(-1.1,-29.5),(-4.1,-28.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-4.1,-32.5),(-2.1,-30.5)]
+ ((10,20))                 | (5.1,34.5)        | ((4.9,-14.5))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(5.9,-22.5),(7.9,-20.5)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((5.9,-22.5),(7.9,-20.5))
+ [(1,2),(3,4)]             | (-5,-12)          | [(6,14),(8,16)]
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(5,12),(8,12),(9,17),(6,18)]
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ [(1,2),(3,4)]             | (-5,-12)          | [(6,14),(8,16)]
+ ((10,20))                 | (-5,-12)          | ((15,32))
+ [(11,12),(13,14)]         | (-5,-12)          | [(16,24),(18,26)]
+ ((11,12),(13,14))         | (-5,-12)          | ((16,24),(18,26))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(-1e-300,1e-300),(3,1e-300),(4,5),(1,6)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((10,20))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity),(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((-1e+300,-Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(-9,-8),(-7,-6)]
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(-10,-10),(-7,-10),(-6,-5),(-9,-4)]
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ [(1,2),(3,4)]             | (10,10)           | [(-9,-8),(-7,-6)]
+ ((10,20))                 | (10,10)           | ((0,10))
+ [(11,12),(13,14)]         | (10,10)           | [(1,2),(3,4)]
+ ((11,12),(13,14))         | (10,10)           | ((1,2),(3,4))
+(81 rows)
+
+-- Multiply with point
+SELECT p.f1, p1.f1, p.f1 * p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                               ?column?                               
+---------------------------+-------------------+----------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(0,0),(0,0)]
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(0,0),(0,0),(0,0)]
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ [(1,2),(3,4)]             | (0,0)             | [(0,0),(0,0)]
+ ((10,20))                 | (0,0)             | ((0,0))
+ [(11,12),(13,14)]         | (0,0)             | [(0,0),(0,0)]
+ ((11,12),(13,14))         | (0,0)             | ((0,0),(0,0))
+ [(1,2),(3,4)]             | (-10,0)           | [(-10,-20),(-30,-40)]
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(0,0),(-30,0),(-40,-50),(-10,-60)]
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ [(1,2),(3,4)]             | (-10,0)           | [(-10,-20),(-30,-40)]
+ ((10,20))                 | (-10,0)           | ((-100,-200))
+ [(11,12),(13,14)]         | (-10,0)           | [(-110,-120),(-130,-140)]
+ ((11,12),(13,14))         | (-10,0)           | ((-110,-120),(-130,-140))
+ [(1,2),(3,4)]             | (-3,4)            | [(-11,-2),(-25,0)]
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(0,0),(-9,12),(-32,1),(-27,-14)]
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ [(1,2),(3,4)]             | (-3,4)            | [(-11,-2),(-25,0)]
+ ((10,20))                 | (-3,4)            | ((-110,-20))
+ [(11,12),(13,14)]         | (-3,4)            | [(-81,8),(-95,10)]
+ ((11,12),(13,14))         | (-3,4)            | ((-81,8),(-95,10))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-63.9,44.7),(-122.7,123.9)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(0,0),(15.3,103.5),(-152.1,163.5),(-201.9,65.1)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-63.9,44.7),(-122.7,123.9)]
+ ((10,20))                 | (5.1,34.5)        | ((-639,447))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(-357.9,440.7),(-416.7,519.9)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((-357.9,440.7),(-416.7,519.9))
+ [(1,2),(3,4)]             | (-5,-12)          | [(19,-22),(33,-56)]
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(0,0),(-15,-36),(40,-73),(67,-42)]
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ [(1,2),(3,4)]             | (-5,-12)          | [(19,-22),(33,-56)]
+ ((10,20))                 | (-5,-12)          | ((190,-220))
+ [(11,12),(13,14)]         | (-5,-12)          | [(89,-192),(103,-226)]
+ ((11,12),(13,14))         | (-5,-12)          | ((89,-192),(103,-226))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(3e-300,1e-300),(7e-300,1e-300)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(0,0),(3e-300,-3e-300),(9e-300,1e-300),(7e-300,5e-300)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(3e-300,1e-300),(7e-300,1e-300)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((3e-299,1e-299))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(2.3e-299,1e-300),(2.7e-299,1e-300)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((2.3e-299,1e-300),(2.7e-299,1e-300))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(NaN,NaN),(NaN,Infinity),(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((-Infinity,Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(-10,30),(-10,70)]
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(0,0),(30,30),(-10,90),(-50,70)]
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ [(1,2),(3,4)]             | (10,10)           | [(-10,30),(-10,70)]
+ ((10,20))                 | (10,10)           | ((-100,300))
+ [(11,12),(13,14)]         | (10,10)           | [(-10,230),(-10,270)]
+ ((11,12),(13,14))         | (10,10)           | ((-10,230),(-10,270))
+(81 rows)
+
+-- Divide by point
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+            f1             |     f1     |                                                    ?column?                                                     
+---------------------------+------------+-----------------------------------------------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (5.1,34.5) | [(0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952)]
+ [(1,2),(3,4)]             | (10,10)    | [(0.15,0.05),(0.35,0.05)]
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5) | [(0,0),(0.0125795471363,-0.0850969365103),(0.158600957032,-0.0924966701199),(0.174387055399,-0.00320655123082)]
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)    | [(0,0),(0.15,-0.15),(0.45,0.05),(0.35,0.25)]
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ [(1,2),(3,4)]             | (5.1,34.5) | [(0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952)]
+ [(1,2),(3,4)]             | (10,10)    | [(0.15,0.05),(0.35,0.05)]
+ ((10,20))                 | (5.1,34.5) | ((0.609244733856,-0.199792807459))
+ ((10,20))                 | (10,10)    | ((1.5,0.5))
+ [(11,12),(13,14)]         | (5.1,34.5) | [(0.386512752208,-0.261703911993),(0.451630407972,-0.310048838242)]
+ [(11,12),(13,14)]         | (10,10)    | [(1.15,0.05),(1.35,0.05)]
+ ((11,12),(13,14))         | (5.1,34.5) | ((0.386512752208,-0.261703911993),(0.451630407972,-0.310048838242))
+ ((11,12),(13,14))         | (10,10)    | ((1.15,0.05),(1.35,0.05))
+(18 rows)
+
+-- Division by 0 error
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to path
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+            f1             |            f1             |    ?column?    
+---------------------------+---------------------------+----------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((10,20))                 |  17.4642491966
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         |   11.313708499
+ [(1,2),(3,4)]             | ((11,12),(13,14))         |   11.313708499
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)] |              0
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))                 |  16.1554944214
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]         |  9.89949493661
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))         |  9.89949493661
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((10,20))                 |  17.4642491966
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         |   11.313708499
+ [(1,2),(3,4)]             | ((11,12),(13,14))         |   11.313708499
+ ((10,20))                 | [(1,2),(3,4)]             |  17.4642491966
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)] |  16.1554944214
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | [(1,2),(3,4)]             |  17.4642491966
+ ((10,20))                 | ((10,20))                 |              0
+ ((10,20))                 | [(11,12),(13,14)]         |   6.7082039325
+ ((10,20))                 | ((11,12),(13,14))         |   6.7082039325
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             |   11.313708499
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)] |  9.89949493661
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             |   11.313708499
+ [(11,12),(13,14)]         | ((10,20))                 |   6.7082039325
+ [(11,12),(13,14)]         | [(11,12),(13,14)]         |              0
+ [(11,12),(13,14)]         | ((11,12),(13,14))         |              0
+ ((11,12),(13,14))         | [(1,2),(3,4)]             |   11.313708499
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)] |  9.89949493661
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | [(1,2),(3,4)]             |   11.313708499
+ ((11,12),(13,14))         | ((10,20))                 |   6.7082039325
+ ((11,12),(13,14))         | [(11,12),(13,14)]         |              0
+ ((11,12),(13,14))         | ((11,12),(13,14))         |              0
+(81 rows)
 
 --
 -- Polygons
 --
 -- containment
 SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
    FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
+ twentyfour |        f1         |             f1             | contains 
+------------+-------------------+----------------------------+----------
+            | (0,0)             | ((2,0),(2,4),(0,0))        | t
+            | (0,0)             | ((3,1),(3,3),(1,0))        | f
+            | (0,0)             | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (0,0)             | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (0,0)             | ((0,0))                    | t
+            | (0,0)             | ((0,1),(0,1))              | f
+            | (-10,0)           | ((2,0),(2,4),(0,0))        | f
+            | (-10,0)           | ((3,1),(3,3),(1,0))        | f
+            | (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-10,0)           | ((0,0))                    | f
+            | (-10,0)           | ((0,1),(0,1))              | f
+            | (-3,4)            | ((2,0),(2,4),(0,0))        | f
+            | (-3,4)            | ((3,1),(3,3),(1,0))        | f
+            | (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-3,4)            | ((0,0))                    | f
+            | (-3,4)            | ((0,1),(0,1))              | f
+            | (5.1,34.5)        | ((2,0),(2,4),(0,0))        | f
+            | (5.1,34.5)        | ((3,1),(3,3),(1,0))        | f
+            | (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (5.1,34.5)        | ((0,0))                    | f
+            | (5.1,34.5)        | ((0,1),(0,1))              | f
+            | (-5,-12)          | ((2,0),(2,4),(0,0))        | f
+            | (-5,-12)          | ((3,1),(3,3),(1,0))        | f
+            | (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-5,-12)          | ((0,0))                    | f
+            | (-5,-12)          | ((0,1),(0,1))              | f
+            | (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        | t
+            | (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        | f
+            | (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e-300,-1e-300)  | ((0,0))                    | t
+            | (1e-300,-1e-300)  | ((0,1),(0,1))              | f
+            | (1e+300,Infinity) | ((2,0),(2,4),(0,0))        | f
+            | (1e+300,Infinity) | ((3,1),(3,3),(1,0))        | f
+            | (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e+300,Infinity) | ((0,0))                    | f
+            | (1e+300,Infinity) | ((0,1),(0,1))              | f
+            | (NaN,NaN)         | ((2,0),(2,4),(0,0))        | t
+            | (NaN,NaN)         | ((3,1),(3,3),(1,0))        | t
+            | (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  | t
+            | (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  | t
+            | (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) | t
+            | (NaN,NaN)         | ((0,0))                    | t
+            | (NaN,NaN)         | ((0,1),(0,1))              | t
+            | (10,10)           | ((2,0),(2,4),(0,0))        | f
+            | (10,10)           | ((3,1),(3,3),(1,0))        | f
+            | (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (10,10)           | ((0,0))                    | f
+            | (10,10)           | ((0,1),(0,1))              | f
+(63 rows)
 
 SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
    FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
+ twentyfour |        f1         |             f1             | contained 
+------------+-------------------+----------------------------+-----------
+            | (0,0)             | ((2,0),(2,4),(0,0))        | t
+            | (0,0)             | ((3,1),(3,3),(1,0))        | f
+            | (0,0)             | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (0,0)             | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (0,0)             | ((0,0))                    | t
+            | (0,0)             | ((0,1),(0,1))              | f
+            | (-10,0)           | ((2,0),(2,4),(0,0))        | f
+            | (-10,0)           | ((3,1),(3,3),(1,0))        | f
+            | (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-10,0)           | ((0,0))                    | f
+            | (-10,0)           | ((0,1),(0,1))              | f
+            | (-3,4)            | ((2,0),(2,4),(0,0))        | f
+            | (-3,4)            | ((3,1),(3,3),(1,0))        | f
+            | (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-3,4)            | ((0,0))                    | f
+            | (-3,4)            | ((0,1),(0,1))              | f
+            | (5.1,34.5)        | ((2,0),(2,4),(0,0))        | f
+            | (5.1,34.5)        | ((3,1),(3,3),(1,0))        | f
+            | (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (5.1,34.5)        | ((0,0))                    | f
+            | (5.1,34.5)        | ((0,1),(0,1))              | f
+            | (-5,-12)          | ((2,0),(2,4),(0,0))        | f
+            | (-5,-12)          | ((3,1),(3,3),(1,0))        | f
+            | (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-5,-12)          | ((0,0))                    | f
+            | (-5,-12)          | ((0,1),(0,1))              | f
+            | (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        | t
+            | (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        | f
+            | (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e-300,-1e-300)  | ((0,0))                    | t
+            | (1e-300,-1e-300)  | ((0,1),(0,1))              | f
+            | (1e+300,Infinity) | ((2,0),(2,4),(0,0))        | f
+            | (1e+300,Infinity) | ((3,1),(3,3),(1,0))        | f
+            | (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e+300,Infinity) | ((0,0))                    | f
+            | (1e+300,Infinity) | ((0,1),(0,1))              | f
+            | (NaN,NaN)         | ((2,0),(2,4),(0,0))        | t
+            | (NaN,NaN)         | ((3,1),(3,3),(1,0))        | t
+            | (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  | t
+            | (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  | t
+            | (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) | t
+            | (NaN,NaN)         | ((0,0))                    | t
+            | (NaN,NaN)         | ((0,1),(0,1))              | t
+            | (10,10)           | ((2,0),(2,4),(0,0))        | f
+            | (10,10)           | ((3,1),(3,3),(1,0))        | f
+            | (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (10,10)           | ((0,0))                    | f
+            | (10,10)           | ((0,1),(0,1))              | f
+(63 rows)
 
 SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
    FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
+ four | npoints |          polygon           
+------+---------+----------------------------
       |       3 | ((2,0),(2,4),(0,0))
       |       3 | ((3,1),(3,3),(1,0))
+      |       4 | ((1,2),(3,4),(5,6),(7,8))
+      |       4 | ((7,8),(5,6),(3,4),(1,2))
+      |       4 | ((1,2),(7,8),(5,6),(3,-4))
       |       1 | ((0,0))
       |       2 | ((0,1),(0,1))
-(4 rows)
+(7 rows)
 
 SELECT '' AS four, polygon(f1)
    FROM BOX_TBL;
  four |                  polygon                  
 ------+-------------------------------------------
       | ((0,0),(0,2),(2,2),(2,0))
       | ((1,1),(1,3),(3,3),(3,1))
+      | ((-8,-10),(-8,2),(-2,2),(-2,-10))
       | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
       | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, polygon(f1)
    FROM PATH_TBL WHERE isclosed(f1);
  four |      polygon      
 ------+-------------------
       | ((1,2),(3,4))
       | ((1,2),(3,4))
       | ((1,2),(3,4))
+      | ((10,20))
       | ((11,12),(13,14))
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
    FROM PATH_TBL
    WHERE isopen(f1);
  four |         open_path         |          polygon          
 ------+---------------------------+---------------------------
       | [(1,2),(3,4)]             | ((1,2),(3,4))
       | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
       | [(1,2),(3,4)]             | ((1,2),(3,4))
       | [(11,12),(13,14)]         | ((11,12),(13,14))
 (4 rows)
 
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
+-- To box
+SELECT f1, f1::box FROM POLYGON_TBL;
+             f1             |      f1      
+----------------------------+--------------
+ ((2,0),(2,4),(0,0))        | (2,4),(0,0)
+ ((3,1),(3,3),(1,0))        | (3,3),(1,0)
+ ((1,2),(3,4),(5,6),(7,8))  | (7,8),(1,2)
+ ((7,8),(5,6),(3,4),(1,2))  | (7,8),(1,2)
+ ((1,2),(7,8),(5,6),(3,-4)) | (7,8),(1,-4)
+ ((0,0))                    | (0,0),(0,0)
+ ((0,1),(0,1))              | (0,1),(0,1)
+(7 rows)
 
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
+-- To path
+SELECT f1, f1::path FROM POLYGON_TBL;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(7 rows)
 
+-- Same as polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 ~= p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(9 rows)
+
+-- Contained by polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <@ p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(12 rows)
+
+-- Contains polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 @> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(12 rows)
+
+-- Overlap with polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 && p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(25 rows)
+
+-- Left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 << p2.f1;
+      f1       |             f1             
+---------------+----------------------------
+ ((0,0))       | ((3,1),(3,3),(1,0))
+ ((0,0))       | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))       | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))       | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1)) | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1)) | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1)) | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1)) | ((1,2),(7,8),(5,6),(3,-4))
+(8 rows)
+
+-- Overlap of left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &< p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))                    | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1))              | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(32 rows)
+
+-- Right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 >> p2.f1;
+             f1             |      f1       
+----------------------------+---------------
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((0,1),(0,1))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1))
+(8 rows)
+
+-- Overlap of right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((2,0),(2,4),(0,0))        | ((0,1),(0,1))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((0,1),(0,1))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((3,1),(3,3),(1,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(37 rows)
+
+-- Below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <<| p2.f1;
+      f1       |            f1             
+---------------+---------------------------
+ ((0,0))       | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))       | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))       | ((0,1),(0,1))
+ ((0,1),(0,1)) | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1)) | ((7,8),(5,6),(3,4),(1,2))
+(5 rows)
+
+-- Overlap or below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &<| p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))                    | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1))              | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(31 rows)
+
+-- Above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |>> p2.f1;
+            f1             |      f1       
+---------------------------+---------------
+ ((1,2),(3,4),(5,6),(7,8)) | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8)) | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2)) | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2)) | ((0,1),(0,1))
+ ((0,1),(0,1))             | ((0,0))
+(5 rows)
+
+-- Overlap or above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |&> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((3,1),(3,3),(1,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(32 rows)
+
+-- Distance to polygon
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2;
+ERROR:  function "poly_distance" not implemented
 --
 -- Circles
 --
 SELECT '' AS six, circle(f1, 50.0)
    FROM POINT_TBL;
- six |     circle      
------+-----------------
+ six |         circle         
+-----+------------------------
      | <(0,0),50>
      | <(-10,0),50>
      | <(-3,4),50>
      | <(5.1,34.5),50>
      | <(-5,-12),50>
+     | <(1e-300,-1e-300),50>
+     | <(1e+300,Infinity),50>
+     | <(NaN,NaN),50>
      | <(10,10),50>
-(6 rows)
+(9 rows)
 
 SELECT '' AS four, circle(f1)
    FROM BOX_TBL;
- four |        circle         
-------+-----------------------
+ four |         circle         
+------+------------------------
       | <(1,1),1.41421356237>
       | <(2,2),1.41421356237>
+      | <(-5,-4),6.7082039325>
       | <(2.5,3),0.5>
       | <(3,3),0>
-(4 rows)
+(5 rows)
 
 SELECT '' AS two, circle(f1)
    FROM POLYGON_TBL
    WHERE (# f1) >= 3;
  two |                    circle                     
 -----+-----------------------------------------------
      | <(1.33333333333,1.33333333333),2.04168905064>
      | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
+     | <(4,5),2.82842712475>
+     | <(4,5),2.82842712475>
+     | <(4,3),4.80664375676>
+(5 rows)
 
 SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
    FROM CIRCLE_TBL c1, POINT_TBL p1
    WHERE (p1.f1 <-> c1.f1) > 0
    ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
+ twentyfour |     circle     |       point       |   distance    
+------------+----------------+-------------------+---------------
+            | <(1,2),3>      | (-3,4)            |   1.472135955
+            | <(5,1),3>      | (0,0)             | 2.09901951359
+            | <(5,1),3>      | (1e-300,-1e-300)  | 2.09901951359
+            | <(5,1),3>      | (-3,4)            | 5.54400374532
+            | <(3,5),0>      | (0,0)             | 5.83095189485
+            | <(3,5),0>      | (1e-300,-1e-300)  | 5.83095189485
+            | <(3,5),0>      | (-3,4)            |  6.0827625303
+            | <(1,3),5>      | (-10,0)           | 6.40175425099
+            | <(1,3),5>      | (10,10)           | 6.40175425099
+            | <(5,1),3>      | (10,10)           | 7.29563014099
+            | <(1,2),3>      | (-10,0)           |  8.1803398875
+            | <(3,5),0>      | (10,10)           | 8.60232526704
+            | <(1,2),3>      | (10,10)           | 9.04159457879
+            | <(1,3),5>      | (-5,-12)          | 11.1554944214
+            | <(5,1),3>      | (-10,0)           | 12.0332963784
+            | <(1,2),3>      | (-5,-12)          | 12.2315462117
+            | <(5,1),3>      | (-5,-12)          | 13.4012194669
+            | <(3,5),0>      | (-10,0)           | 13.9283882772
+            | <(3,5),0>      | (-5,-12)          | 18.7882942281
+            | <(1,3),5>      | (5.1,34.5)        | 26.7657047773
+            | <(3,5),0>      | (5.1,34.5)        | 29.5746513082
+            | <(1,2),3>      | (5.1,34.5)        | 29.7575945393
+            | <(5,1),3>      | (5.1,34.5)        | 30.5001492534
+            | <(100,200),10> | (5.1,34.5)        | 180.778038568
+            | <(100,200),10> | (10,10)           | 200.237960416
+            | <(100,200),10> | (-3,4)            | 211.415898255
+            | <(100,200),10> | (0,0)             |  213.60679775
+            | <(100,200),10> | (1e-300,-1e-300)  |  213.60679775
+            | <(100,200),10> | (-10,0)           |  218.25424421
+            | <(100,200),10> | (-5,-12)          | 226.577682802
+            | <(3,5),0>      | (1e+300,Infinity) |      Infinity
+            | <(1,2),3>      | (1e+300,Infinity) |      Infinity
+            | <(5,1),3>      | (1e+300,Infinity) |      Infinity
+            | <(1,3),5>      | (1e+300,Infinity) |      Infinity
+            | <(100,200),10> | (1e+300,Infinity) |      Infinity
+            | <(1,2),100>    | (1e+300,Infinity) |      Infinity
+            | <(100,1),115>  | (1e+300,Infinity) |      Infinity
+            | <(3,5),0>      | (NaN,NaN)         |           NaN
+            | <(1,2),3>      | (NaN,NaN)         |           NaN
+            | <(5,1),3>      | (NaN,NaN)         |           NaN
+            | <(1,3),5>      | (NaN,NaN)         |           NaN
+            | <(100,200),10> | (NaN,NaN)         |           NaN
+            | <(1,2),100>    | (NaN,NaN)         |           NaN
+            | <(100,1),115>  | (NaN,NaN)         |           NaN
+            | <(3,5),NaN>    | (-10,0)           |           NaN
+            | <(3,5),NaN>    | (-5,-12)          |           NaN
+            | <(3,5),NaN>    | (-3,4)            |           NaN
+            | <(3,5),NaN>    | (0,0)             |           NaN
+            | <(3,5),NaN>    | (1e-300,-1e-300)  |           NaN
+            | <(3,5),NaN>    | (5.1,34.5)        |           NaN
+            | <(3,5),NaN>    | (10,10)           |           NaN
+            | <(3,5),NaN>    | (1e+300,Infinity) |           NaN
+            | <(3,5),NaN>    | (NaN,NaN)         |           NaN
+(53 rows)
+
+-- To polygon
+SELECT f1, f1::polygon FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+       f1       |                                                                                                          f1                                                                                                          
+----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ <(5,1),3>      | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
+ <(1,2),100>    | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
+ <(1,3),5>      | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
+ <(1,2),3>      | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
+ <(100,200),10> | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
+ <(100,1),115>  | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
+(6 rows)
+
+-- To polygon with less points
+SELECT f1, polygon(8, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+       f1       |                                                                             polygon                                                                              
+----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ <(5,1),3>      | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
+ <(1,2),100>    | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
+ <(1,3),5>      | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
+ <(1,2),3>      | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
+ <(100,200),10> | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
+ <(100,1),115>  | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
+(6 rows)
+
+-- Too less points error
+SELECT f1, polygon(1, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+ERROR:  must request at least 2 points
+-- Zero radius error
+SELECT f1, polygon(10, f1) FROM CIRCLE_TBL WHERE f1 < '<(0,0),1>';
+ERROR:  cannot convert circle with radius zero to polygon
+-- Same as circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 ~= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+ <(3,5),NaN>    | <(3,5),0>
+ <(3,5),NaN>    | <(3,5),NaN>
+(9 rows)
+
+-- Overlap with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 && c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,1),115>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(100,1),115>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(33 rows)
+
+-- Overlap or left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &< c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(28 rows)
+
+-- Left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 << c2.f1;
+    f1     |       f1       
+-----------+----------------
+ <(5,1),3> | <(100,200),10>
+ <(1,3),5> | <(100,200),10>
+ <(1,2),3> | <(100,200),10>
+ <(3,5),0> | <(100,200),10>
+(4 rows)
+
+-- Right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >> c2.f1;
+       f1       |    f1     
+----------------+-----------
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(3,5),0>
+(4 rows)
+
+-- Overlap or right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(28 rows)
+
+-- Contained by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <@ c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(17 rows)
+
+-- Contain by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 @> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(3,5),0>
+(17 rows)
+
+-- Below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <<| c2.f1;
+      f1       |       f1       
+---------------+----------------
+ <(5,1),3>     | <(100,200),10>
+ <(5,1),3>     | <(3,5),0>
+ <(1,2),100>   | <(100,200),10>
+ <(1,3),5>     | <(100,200),10>
+ <(1,2),3>     | <(100,200),10>
+ <(100,1),115> | <(100,200),10>
+ <(3,5),0>     | <(100,200),10>
+(7 rows)
+
+-- Above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |>> c2.f1;
+       f1       |      f1       
+----------------+---------------
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(3,5),0>      | <(5,1),3>
+(7 rows)
+
+-- Overlap or below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &<| c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Overlap or above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |&> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 = c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(9 rows)
+
+-- Area not equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 != c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(40 rows)
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 > c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(3,5),0>
+(20 rows)
+
+-- Area less than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area greater than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Add point
+SELECT c.f1, p.f1, c.f1 + p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |        ?column?         
+----------------+-------------------+-------------------------
+ <(5,1),3>      | (0,0)             | <(5,1),3>
+ <(1,2),100>    | (0,0)             | <(1,2),100>
+ <(1,3),5>      | (0,0)             | <(1,3),5>
+ <(1,2),3>      | (0,0)             | <(1,2),3>
+ <(100,200),10> | (0,0)             | <(100,200),10>
+ <(100,1),115>  | (0,0)             | <(100,1),115>
+ <(3,5),0>      | (0,0)             | <(3,5),0>
+ <(3,5),NaN>    | (0,0)             | <(3,5),NaN>
+ <(5,1),3>      | (-10,0)           | <(-5,1),3>
+ <(1,2),100>    | (-10,0)           | <(-9,2),100>
+ <(1,3),5>      | (-10,0)           | <(-9,3),5>
+ <(1,2),3>      | (-10,0)           | <(-9,2),3>
+ <(100,200),10> | (-10,0)           | <(90,200),10>
+ <(100,1),115>  | (-10,0)           | <(90,1),115>
+ <(3,5),0>      | (-10,0)           | <(-7,5),0>
+ <(3,5),NaN>    | (-10,0)           | <(-7,5),NaN>
+ <(5,1),3>      | (-3,4)            | <(2,5),3>
+ <(1,2),100>    | (-3,4)            | <(-2,6),100>
+ <(1,3),5>      | (-3,4)            | <(-2,7),5>
+ <(1,2),3>      | (-3,4)            | <(-2,6),3>
+ <(100,200),10> | (-3,4)            | <(97,204),10>
+ <(100,1),115>  | (-3,4)            | <(97,5),115>
+ <(3,5),0>      | (-3,4)            | <(0,9),0>
+ <(3,5),NaN>    | (-3,4)            | <(0,9),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(10.1,35.5),3>
+ <(1,2),100>    | (5.1,34.5)        | <(6.1,36.5),100>
+ <(1,3),5>      | (5.1,34.5)        | <(6.1,37.5),5>
+ <(1,2),3>      | (5.1,34.5)        | <(6.1,36.5),3>
+ <(100,200),10> | (5.1,34.5)        | <(105.1,234.5),10>
+ <(100,1),115>  | (5.1,34.5)        | <(105.1,35.5),115>
+ <(3,5),0>      | (5.1,34.5)        | <(8.1,39.5),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(8.1,39.5),NaN>
+ <(5,1),3>      | (-5,-12)          | <(0,-11),3>
+ <(1,2),100>    | (-5,-12)          | <(-4,-10),100>
+ <(1,3),5>      | (-5,-12)          | <(-4,-9),5>
+ <(1,2),3>      | (-5,-12)          | <(-4,-10),3>
+ <(100,200),10> | (-5,-12)          | <(95,188),10>
+ <(100,1),115>  | (-5,-12)          | <(95,-11),115>
+ <(3,5),0>      | (-5,-12)          | <(-2,-7),0>
+ <(3,5),NaN>    | (-5,-12)          | <(-2,-7),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(5,1),3>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(1,2),100>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(1,3),5>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(1,2),3>
+ <(100,200),10> | (1e-300,-1e-300)  | <(100,200),10>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(100,1),115>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(3,5),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(3,5),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(1e+300,Infinity),3>
+ <(1,2),100>    | (1e+300,Infinity) | <(1e+300,Infinity),100>
+ <(1,3),5>      | (1e+300,Infinity) | <(1e+300,Infinity),5>
+ <(1,2),3>      | (1e+300,Infinity) | <(1e+300,Infinity),3>
+ <(100,200),10> | (1e+300,Infinity) | <(1e+300,Infinity),10>
+ <(100,1),115>  | (1e+300,Infinity) | <(1e+300,Infinity),115>
+ <(3,5),0>      | (1e+300,Infinity) | <(1e+300,Infinity),0>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(1e+300,Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),100>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),5>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),10>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),115>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),0>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(15,11),3>
+ <(1,2),100>    | (10,10)           | <(11,12),100>
+ <(1,3),5>      | (10,10)           | <(11,13),5>
+ <(1,2),3>      | (10,10)           | <(11,12),3>
+ <(100,200),10> | (10,10)           | <(110,210),10>
+ <(100,1),115>  | (10,10)           | <(110,11),115>
+ <(3,5),0>      | (10,10)           | <(13,15),0>
+ <(3,5),NaN>    | (10,10)           | <(13,15),NaN>
+(72 rows)
+
+-- Subtract point
+SELECT c.f1, p.f1, c.f1 - p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |         ?column?          
+----------------+-------------------+---------------------------
+ <(5,1),3>      | (0,0)             | <(5,1),3>
+ <(1,2),100>    | (0,0)             | <(1,2),100>
+ <(1,3),5>      | (0,0)             | <(1,3),5>
+ <(1,2),3>      | (0,0)             | <(1,2),3>
+ <(100,200),10> | (0,0)             | <(100,200),10>
+ <(100,1),115>  | (0,0)             | <(100,1),115>
+ <(3,5),0>      | (0,0)             | <(3,5),0>
+ <(3,5),NaN>    | (0,0)             | <(3,5),NaN>
+ <(5,1),3>      | (-10,0)           | <(15,1),3>
+ <(1,2),100>    | (-10,0)           | <(11,2),100>
+ <(1,3),5>      | (-10,0)           | <(11,3),5>
+ <(1,2),3>      | (-10,0)           | <(11,2),3>
+ <(100,200),10> | (-10,0)           | <(110,200),10>
+ <(100,1),115>  | (-10,0)           | <(110,1),115>
+ <(3,5),0>      | (-10,0)           | <(13,5),0>
+ <(3,5),NaN>    | (-10,0)           | <(13,5),NaN>
+ <(5,1),3>      | (-3,4)            | <(8,-3),3>
+ <(1,2),100>    | (-3,4)            | <(4,-2),100>
+ <(1,3),5>      | (-3,4)            | <(4,-1),5>
+ <(1,2),3>      | (-3,4)            | <(4,-2),3>
+ <(100,200),10> | (-3,4)            | <(103,196),10>
+ <(100,1),115>  | (-3,4)            | <(103,-3),115>
+ <(3,5),0>      | (-3,4)            | <(6,1),0>
+ <(3,5),NaN>    | (-3,4)            | <(6,1),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(-0.1,-33.5),3>
+ <(1,2),100>    | (5.1,34.5)        | <(-4.1,-32.5),100>
+ <(1,3),5>      | (5.1,34.5)        | <(-4.1,-31.5),5>
+ <(1,2),3>      | (5.1,34.5)        | <(-4.1,-32.5),3>
+ <(100,200),10> | (5.1,34.5)        | <(94.9,165.5),10>
+ <(100,1),115>  | (5.1,34.5)        | <(94.9,-33.5),115>
+ <(3,5),0>      | (5.1,34.5)        | <(-2.1,-29.5),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(-2.1,-29.5),NaN>
+ <(5,1),3>      | (-5,-12)          | <(10,13),3>
+ <(1,2),100>    | (-5,-12)          | <(6,14),100>
+ <(1,3),5>      | (-5,-12)          | <(6,15),5>
+ <(1,2),3>      | (-5,-12)          | <(6,14),3>
+ <(100,200),10> | (-5,-12)          | <(105,212),10>
+ <(100,1),115>  | (-5,-12)          | <(105,13),115>
+ <(3,5),0>      | (-5,-12)          | <(8,17),0>
+ <(3,5),NaN>    | (-5,-12)          | <(8,17),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(5,1),3>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(1,2),100>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(1,3),5>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(1,2),3>
+ <(100,200),10> | (1e-300,-1e-300)  | <(100,200),10>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(100,1),115>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(3,5),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(3,5),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(-1e+300,-Infinity),3>
+ <(1,2),100>    | (1e+300,Infinity) | <(-1e+300,-Infinity),100>
+ <(1,3),5>      | (1e+300,Infinity) | <(-1e+300,-Infinity),5>
+ <(1,2),3>      | (1e+300,Infinity) | <(-1e+300,-Infinity),3>
+ <(100,200),10> | (1e+300,Infinity) | <(-1e+300,-Infinity),10>
+ <(100,1),115>  | (1e+300,Infinity) | <(-1e+300,-Infinity),115>
+ <(3,5),0>      | (1e+300,Infinity) | <(-1e+300,-Infinity),0>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(-1e+300,-Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),100>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),5>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),10>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),115>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),0>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(-5,-9),3>
+ <(1,2),100>    | (10,10)           | <(-9,-8),100>
+ <(1,3),5>      | (10,10)           | <(-9,-7),5>
+ <(1,2),3>      | (10,10)           | <(-9,-8),3>
+ <(100,200),10> | (10,10)           | <(90,190),10>
+ <(100,1),115>  | (10,10)           | <(90,-9),115>
+ <(3,5),0>      | (10,10)           | <(-7,-5),0>
+ <(3,5),NaN>    | (10,10)           | <(-7,-5),NaN>
+(72 rows)
+
+-- Multiply with point
+SELECT c.f1, p.f1, c.f1 * p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |                  ?column?                  
+----------------+-------------------+--------------------------------------------
+ <(5,1),3>      | (0,0)             | <(0,0),0>
+ <(1,2),100>    | (0,0)             | <(0,0),0>
+ <(1,3),5>      | (0,0)             | <(0,0),0>
+ <(1,2),3>      | (0,0)             | <(0,0),0>
+ <(100,200),10> | (0,0)             | <(0,0),0>
+ <(100,1),115>  | (0,0)             | <(0,0),0>
+ <(3,5),0>      | (0,0)             | <(0,0),0>
+ <(3,5),NaN>    | (0,0)             | <(0,0),NaN>
+ <(5,1),3>      | (-10,0)           | <(-50,-10),30>
+ <(1,2),100>    | (-10,0)           | <(-10,-20),1000>
+ <(1,3),5>      | (-10,0)           | <(-10,-30),50>
+ <(1,2),3>      | (-10,0)           | <(-10,-20),30>
+ <(100,200),10> | (-10,0)           | <(-1000,-2000),100>
+ <(100,1),115>  | (-10,0)           | <(-1000,-10),1150>
+ <(3,5),0>      | (-10,0)           | <(-30,-50),0>
+ <(3,5),NaN>    | (-10,0)           | <(-30,-50),NaN>
+ <(5,1),3>      | (-3,4)            | <(-19,17),15>
+ <(1,2),100>    | (-3,4)            | <(-11,-2),500>
+ <(1,3),5>      | (-3,4)            | <(-15,-5),25>
+ <(1,2),3>      | (-3,4)            | <(-11,-2),15>
+ <(100,200),10> | (-3,4)            | <(-1100,-200),50>
+ <(100,1),115>  | (-3,4)            | <(-304,397),575>
+ <(3,5),0>      | (-3,4)            | <(-29,-3),0>
+ <(3,5),NaN>    | (-3,4)            | <(-29,-3),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(-9,177.6),104.624758064>
+ <(1,2),100>    | (5.1,34.5)        | <(-63.9,44.7),3487.49193547>
+ <(1,3),5>      | (5.1,34.5)        | <(-98.4,49.8),174.374596774>
+ <(1,2),3>      | (5.1,34.5)        | <(-63.9,44.7),104.624758064>
+ <(100,200),10> | (5.1,34.5)        | <(-6390,4470),348.749193547>
+ <(100,1),115>  | (5.1,34.5)        | <(475.5,3455.1),4010.6157258>
+ <(3,5),0>      | (5.1,34.5)        | <(-157.2,129),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(-157.2,129),NaN>
+ <(5,1),3>      | (-5,-12)          | <(-13,-65),39>
+ <(1,2),100>    | (-5,-12)          | <(19,-22),1300>
+ <(1,3),5>      | (-5,-12)          | <(31,-27),65>
+ <(1,2),3>      | (-5,-12)          | <(19,-22),39>
+ <(100,200),10> | (-5,-12)          | <(1900,-2200),130>
+ <(100,1),115>  | (-5,-12)          | <(-488,-1205),1495>
+ <(3,5),0>      | (-5,-12)          | <(45,-61),0>
+ <(3,5),NaN>    | (-5,-12)          | <(45,-61),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(6e-300,-4e-300),4.24264068712e-300>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(3e-300,1e-300),1.41421356237e-298>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(4e-300,2e-300),7.07106781187e-300>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(3e-300,1e-300),4.24264068712e-300>
+ <(100,200),10> | (1e-300,-1e-300)  | <(3e-298,1e-298),1.41421356237e-299>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(1.01e-298,-9.9e-299),1.62634559673e-298>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(8e-300,2e-300),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(8e-300,2e-300),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,2),100>    | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,3),5>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,2),3>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(100,200),10> | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(100,1),115>  | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(3,5),0>      | (1e+300,Infinity) | <(-Infinity,Infinity),NaN>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(-Infinity,Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(40,60),42.4264068712>
+ <(1,2),100>    | (10,10)           | <(-10,30),1414.21356237>
+ <(1,3),5>      | (10,10)           | <(-20,40),70.7106781187>
+ <(1,2),3>      | (10,10)           | <(-10,30),42.4264068712>
+ <(100,200),10> | (10,10)           | <(-1000,3000),141.421356237>
+ <(100,1),115>  | (10,10)           | <(990,1010),1626.34559673>
+ <(3,5),0>      | (10,10)           | <(-20,80),0>
+ <(3,5),NaN>    | (10,10)           | <(-20,80),NaN>
+(72 rows)
+
+-- Divide by point
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+       f1       |     f1     |                       ?column?                       
+----------------+------------+------------------------------------------------------
+ <(5,1),3>      | (5.1,34.5) | <(0.0493315573973,-0.137635045138),0.0860217042937>
+ <(5,1),3>      | (10,10)    | <(0.3,-0.2),0.212132034356>
+ <(1,2),100>    | (5.1,34.5) | <(0.0609244733856,-0.0199792807459),2.86739014312>
+ <(1,2),100>    | (10,10)    | <(0.15,0.05),7.07106781187>
+ <(1,3),5>      | (5.1,34.5) | <(0.0892901188891,-0.0157860983671),0.143369507156>
+ <(1,3),5>      | (10,10)    | <(0.2,0.1),0.353553390593>
+ <(1,2),3>      | (5.1,34.5) | <(0.0609244733856,-0.0199792807459),0.0860217042937>
+ <(1,2),3>      | (10,10)    | <(0.15,0.05),0.212132034356>
+ <(100,200),10> | (5.1,34.5) | <(6.09244733856,-1.99792807459),0.286739014312>
+ <(100,200),10> | (10,10)    | <(15,5),0.707106781187>
+ <(100,1),115>  | (5.1,34.5) | <(0.44768388338,-2.83237136796),3.29749866459>
+ <(100,1),115>  | (10,10)    | <(5.05,-4.95),8.13172798365>
+ <(3,5),0>      | (5.1,34.5) | <(0.154407774653,-0.0641310246164),0>
+ <(3,5),0>      | (10,10)    | <(0.4,0.1),0>
+ <(3,5),NaN>    | (5.1,34.5) | <(0.154407774653,-0.0641310246164),NaN>
+ <(3,5),NaN>    | (10,10)    | <(0.4,0.1),NaN>
+(16 rows)
+
+-- Overflow error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] > 1000;
+ERROR:  value out of range: overflow
+-- Division by 0 error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to polygon
+SELECT c.f1, p.f1, c.f1 <-> p.f1 FROM CIRCLE_TBL c, POLYGON_TBL p;
+       f1       |             f1             |    ?column?    
+----------------+----------------------------+----------------
+ <(5,1),3>      | ((2,0),(2,4),(0,0))        |              0
+ <(5,1),3>      | ((3,1),(3,3),(1,0))        |              0
+ <(5,1),3>      | ((1,2),(3,4),(5,6),(7,8))  | 0.535533905933
+ <(5,1),3>      | ((7,8),(5,6),(3,4),(1,2))  | 0.535533905933
+ <(5,1),3>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(5,1),3>      | ((0,0))                    |  2.09901951359
+ <(5,1),3>      | ((0,1),(0,1))              |              2
+ <(1,2),100>    | ((2,0),(2,4),(0,0))        |              0
+ <(1,2),100>    | ((3,1),(3,3),(1,0))        |              0
+ <(1,2),100>    | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,2),100>    | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,2),100>    | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,2),100>    | ((0,0))                    |              0
+ <(1,2),100>    | ((0,1),(0,1))              |              0
+ <(1,3),5>      | ((2,0),(2,4),(0,0))        |              0
+ <(1,3),5>      | ((3,1),(3,3),(1,0))        |              0
+ <(1,3),5>      | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,3),5>      | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,3),5>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,3),5>      | ((0,0))                    |              0
+ <(1,3),5>      | ((0,1),(0,1))              |              0
+ <(1,2),3>      | ((2,0),(2,4),(0,0))        |              0
+ <(1,2),3>      | ((3,1),(3,3),(1,0))        |              0
+ <(1,2),3>      | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,2),3>      | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,2),3>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,2),3>      | ((0,0))                    |              0
+ <(1,2),3>      | ((0,1),(0,1))              |              0
+ <(100,200),10> | ((2,0),(2,4),(0,0))        |  209.134661795
+ <(100,200),10> | ((3,1),(3,3),(1,0))        |  209.585974051
+ <(100,200),10> | ((1,2),(3,4),(5,6),(7,8))  |  203.337760371
+ <(100,200),10> | ((7,8),(5,6),(3,4),(1,2))  |  203.337760371
+ <(100,200),10> | ((1,2),(7,8),(5,6),(3,-4)) |  203.337760371
+ <(100,200),10> | ((0,0))                    |   213.60679775
+ <(100,200),10> | ((0,1),(0,1))              |  212.712819568
+ <(100,1),115>  | ((2,0),(2,4),(0,0))        |              0
+ <(100,1),115>  | ((3,1),(3,3),(1,0))        |              0
+ <(100,1),115>  | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(100,1),115>  | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(100,1),115>  | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(100,1),115>  | ((0,0))                    |              0
+ <(100,1),115>  | ((0,1),(0,1))              |              0
+ <(3,5),0>      | ((2,0),(2,4),(0,0))        |  1.41421356237
+ <(3,5),0>      | ((3,1),(3,3),(1,0))        |              2
+ <(3,5),0>      | ((1,2),(3,4),(5,6),(7,8))  | 0.707106781187
+ <(3,5),0>      | ((7,8),(5,6),(3,4),(1,2))  | 0.707106781187
+ <(3,5),0>      | ((1,2),(7,8),(5,6),(3,-4)) | 0.707106781187
+ <(3,5),0>      | ((0,0))                    |  5.83095189485
+ <(3,5),0>      | ((0,1),(0,1))              |              5
+ <(3,5),NaN>    | ((2,0),(2,4),(0,0))        |            NaN
+ <(3,5),NaN>    | ((3,1),(3,3),(1,0))        |            NaN
+ <(3,5),NaN>    | ((1,2),(3,4),(5,6),(7,8))  |            NaN
+ <(3,5),NaN>    | ((7,8),(5,6),(3,4),(1,2))  |            NaN
+ <(3,5),NaN>    | ((1,2),(7,8),(5,6),(3,-4)) |            NaN
+ <(3,5),NaN>    | ((0,0))                    |            NaN
+ <(3,5),NaN>    | ((0,1),(0,1))              |            NaN
+(56 rows)
 
diff --git a/src/test/regress/expected/geometry_1.out b/src/test/regress/expected/geometry_1.out
index 3b92e23059..48f4aa8638 100644
--- a/src/test/regress/expected/geometry_1.out
+++ b/src/test/regress/expected/geometry_1.out
@@ -6,558 +6,4885 @@
 SET extra_float_digits TO -3;
 --
 -- Points
 --
 SELECT '' AS four, center(f1) AS center
    FROM BOX_TBL;
  four | center  
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, (@@ f1) AS center
    FROM BOX_TBL;
  four | center  
 ------+---------
       | (1,1)
       | (2,2)
+      | (-5,-4)
       | (2.5,3)
       | (3,3)
-(4 rows)
+(5 rows)
 
 SELECT '' AS six, point(f1) AS center
    FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS six, (@@ f1) AS center
    FROM CIRCLE_TBL;
  six |  center   
 -----+-----------
      | (5,1)
      | (1,2)
      | (1,3)
      | (1,2)
      | (100,200)
      | (100,1)
-(6 rows)
+     | (3,5)
+     | (3,5)
+(8 rows)
 
 SELECT '' AS two, (@@ f1) AS center
    FROM POLYGON_TBL
    WHERE (# f1) > 2;
  two |            center             
 -----+-------------------------------
      | (1.33333333333,1.33333333333)
      | (2.33333333333,1.33333333333)
-(2 rows)
+     | (4,5)
+     | (4,5)
+     | (4,3)
+(5 rows)
 
 -- "is horizontal" function
 SELECT '' AS two, p1.f1
    FROM POINT_TBL p1
    WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 -- "is horizontal" operator
 SELECT '' AS two, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 -- "is vertical" function
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE isvertical(p1.f1, point '(5.1,34.5)');
  one |     f1     
 -----+------------
      | (5.1,34.5)
 (1 row)
 
 -- "is vertical" operator
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?| point '(5.1,34.5)';
  one |     f1     
 -----+------------
      | (5.1,34.5)
 (1 row)
 
+-- Slope
+SELECT p1.f1, p2.f1, slope(p1.f1, p2.f1) FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |       slope        
+-------------------+-------------------+--------------------
+ (0,0)             | (0,0)             | 1.79769313486e+308
+ (0,0)             | (-10,0)           |                  0
+ (0,0)             | (-3,4)            |     -1.33333333333
+ (0,0)             | (5.1,34.5)        |      6.76470588235
+ (0,0)             | (-5,-12)          |                2.4
+ (0,0)             | (1e-300,-1e-300)  | 1.79769313486e+308
+ (0,0)             | (1e+300,Infinity) |           Infinity
+ (0,0)             | (NaN,NaN)         |                NaN
+ (0,0)             | (10,10)           |                  1
+ (-10,0)           | (0,0)             |                  0
+ (-10,0)           | (-10,0)           | 1.79769313486e+308
+ (-10,0)           | (-3,4)            |     0.571428571429
+ (-10,0)           | (5.1,34.5)        |      2.28476821192
+ (-10,0)           | (-5,-12)          |               -2.4
+ (-10,0)           | (1e-300,-1e-300)  |                  0
+ (-10,0)           | (1e+300,Infinity) |           Infinity
+ (-10,0)           | (NaN,NaN)         |                NaN
+ (-10,0)           | (10,10)           |                0.5
+ (-3,4)            | (0,0)             |     -1.33333333333
+ (-3,4)            | (-10,0)           |     0.571428571429
+ (-3,4)            | (-3,4)            | 1.79769313486e+308
+ (-3,4)            | (5.1,34.5)        |      3.76543209877
+ (-3,4)            | (-5,-12)          |                  8
+ (-3,4)            | (1e-300,-1e-300)  |     -1.33333333333
+ (-3,4)            | (1e+300,Infinity) |           Infinity
+ (-3,4)            | (NaN,NaN)         |                NaN
+ (-3,4)            | (10,10)           |     0.461538461538
+ (5.1,34.5)        | (0,0)             |      6.76470588235
+ (5.1,34.5)        | (-10,0)           |      2.28476821192
+ (5.1,34.5)        | (-3,4)            |      3.76543209877
+ (5.1,34.5)        | (5.1,34.5)        | 1.79769313486e+308
+ (5.1,34.5)        | (-5,-12)          |      4.60396039604
+ (5.1,34.5)        | (1e-300,-1e-300)  |      6.76470588235
+ (5.1,34.5)        | (1e+300,Infinity) |           Infinity
+ (5.1,34.5)        | (NaN,NaN)         |                NaN
+ (5.1,34.5)        | (10,10)           |                 -5
+ (-5,-12)          | (0,0)             |                2.4
+ (-5,-12)          | (-10,0)           |               -2.4
+ (-5,-12)          | (-3,4)            |                  8
+ (-5,-12)          | (5.1,34.5)        |      4.60396039604
+ (-5,-12)          | (-5,-12)          | 1.79769313486e+308
+ (-5,-12)          | (1e-300,-1e-300)  |                2.4
+ (-5,-12)          | (1e+300,Infinity) |           Infinity
+ (-5,-12)          | (NaN,NaN)         |                NaN
+ (-5,-12)          | (10,10)           |      1.46666666667
+ (1e-300,-1e-300)  | (0,0)             | 1.79769313486e+308
+ (1e-300,-1e-300)  | (-10,0)           |                  0
+ (1e-300,-1e-300)  | (-3,4)            |     -1.33333333333
+ (1e-300,-1e-300)  | (5.1,34.5)        |      6.76470588235
+ (1e-300,-1e-300)  | (-5,-12)          |                2.4
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | 1.79769313486e+308
+ (1e-300,-1e-300)  | (1e+300,Infinity) |           Infinity
+ (1e-300,-1e-300)  | (NaN,NaN)         |                NaN
+ (1e-300,-1e-300)  | (10,10)           |                  1
+ (1e+300,Infinity) | (0,0)             |           Infinity
+ (1e+300,Infinity) | (-10,0)           |           Infinity
+ (1e+300,Infinity) | (-3,4)            |           Infinity
+ (1e+300,Infinity) | (5.1,34.5)        |           Infinity
+ (1e+300,Infinity) | (-5,-12)          |           Infinity
+ (1e+300,Infinity) | (1e-300,-1e-300)  |           Infinity
+ (1e+300,Infinity) | (1e+300,Infinity) | 1.79769313486e+308
+ (1e+300,Infinity) | (NaN,NaN)         |                NaN
+ (1e+300,Infinity) | (10,10)           |           Infinity
+ (NaN,NaN)         | (0,0)             |                NaN
+ (NaN,NaN)         | (-10,0)           |                NaN
+ (NaN,NaN)         | (-3,4)            |                NaN
+ (NaN,NaN)         | (5.1,34.5)        |                NaN
+ (NaN,NaN)         | (-5,-12)          |                NaN
+ (NaN,NaN)         | (1e-300,-1e-300)  |                NaN
+ (NaN,NaN)         | (1e+300,Infinity) |                NaN
+ (NaN,NaN)         | (NaN,NaN)         |                NaN
+ (NaN,NaN)         | (10,10)           |                NaN
+ (10,10)           | (0,0)             |                  1
+ (10,10)           | (-10,0)           |                0.5
+ (10,10)           | (-3,4)            |     0.461538461538
+ (10,10)           | (5.1,34.5)        |                 -5
+ (10,10)           | (-5,-12)          |      1.46666666667
+ (10,10)           | (1e-300,-1e-300)  |                  1
+ (10,10)           | (1e+300,Infinity) |           Infinity
+ (10,10)           | (NaN,NaN)         |                NaN
+ (10,10)           | (10,10)           | 1.79769313486e+308
+(81 rows)
+
+-- Add point
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |     ?column?      
+-------------------+-------------------+-------------------
+ (0,0)             | (0,0)             | (0,0)
+ (0,0)             | (-10,0)           | (-10,0)
+ (0,0)             | (-3,4)            | (-3,4)
+ (0,0)             | (5.1,34.5)        | (5.1,34.5)
+ (0,0)             | (-5,-12)          | (-5,-12)
+ (0,0)             | (1e-300,-1e-300)  | (1e-300,-1e-300)
+ (0,0)             | (1e+300,Infinity) | (1e+300,Infinity)
+ (0,0)             | (NaN,NaN)         | (NaN,NaN)
+ (0,0)             | (10,10)           | (10,10)
+ (-10,0)           | (0,0)             | (-10,0)
+ (-10,0)           | (-10,0)           | (-20,0)
+ (-10,0)           | (-3,4)            | (-13,4)
+ (-10,0)           | (5.1,34.5)        | (-4.9,34.5)
+ (-10,0)           | (-5,-12)          | (-15,-12)
+ (-10,0)           | (1e-300,-1e-300)  | (-10,-1e-300)
+ (-10,0)           | (1e+300,Infinity) | (1e+300,Infinity)
+ (-10,0)           | (NaN,NaN)         | (NaN,NaN)
+ (-10,0)           | (10,10)           | (0,10)
+ (-3,4)            | (0,0)             | (-3,4)
+ (-3,4)            | (-10,0)           | (-13,4)
+ (-3,4)            | (-3,4)            | (-6,8)
+ (-3,4)            | (5.1,34.5)        | (2.1,38.5)
+ (-3,4)            | (-5,-12)          | (-8,-8)
+ (-3,4)            | (1e-300,-1e-300)  | (-3,4)
+ (-3,4)            | (1e+300,Infinity) | (1e+300,Infinity)
+ (-3,4)            | (NaN,NaN)         | (NaN,NaN)
+ (-3,4)            | (10,10)           | (7,14)
+ (5.1,34.5)        | (0,0)             | (5.1,34.5)
+ (5.1,34.5)        | (-10,0)           | (-4.9,34.5)
+ (5.1,34.5)        | (-3,4)            | (2.1,38.5)
+ (5.1,34.5)        | (5.1,34.5)        | (10.2,69)
+ (5.1,34.5)        | (-5,-12)          | (0.1,22.5)
+ (5.1,34.5)        | (1e-300,-1e-300)  | (5.1,34.5)
+ (5.1,34.5)        | (1e+300,Infinity) | (1e+300,Infinity)
+ (5.1,34.5)        | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5)        | (10,10)           | (15.1,44.5)
+ (-5,-12)          | (0,0)             | (-5,-12)
+ (-5,-12)          | (-10,0)           | (-15,-12)
+ (-5,-12)          | (-3,4)            | (-8,-8)
+ (-5,-12)          | (5.1,34.5)        | (0.1,22.5)
+ (-5,-12)          | (-5,-12)          | (-10,-24)
+ (-5,-12)          | (1e-300,-1e-300)  | (-5,-12)
+ (-5,-12)          | (1e+300,Infinity) | (1e+300,Infinity)
+ (-5,-12)          | (NaN,NaN)         | (NaN,NaN)
+ (-5,-12)          | (10,10)           | (5,-2)
+ (1e-300,-1e-300)  | (0,0)             | (1e-300,-1e-300)
+ (1e-300,-1e-300)  | (-10,0)           | (-10,-1e-300)
+ (1e-300,-1e-300)  | (-3,4)            | (-3,4)
+ (1e-300,-1e-300)  | (5.1,34.5)        | (5.1,34.5)
+ (1e-300,-1e-300)  | (-5,-12)          | (-5,-12)
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | (2e-300,-2e-300)
+ (1e-300,-1e-300)  | (1e+300,Infinity) | (1e+300,Infinity)
+ (1e-300,-1e-300)  | (NaN,NaN)         | (NaN,NaN)
+ (1e-300,-1e-300)  | (10,10)           | (10,10)
+ (1e+300,Infinity) | (0,0)             | (1e+300,Infinity)
+ (1e+300,Infinity) | (-10,0)           | (1e+300,Infinity)
+ (1e+300,Infinity) | (-3,4)            | (1e+300,Infinity)
+ (1e+300,Infinity) | (5.1,34.5)        | (1e+300,Infinity)
+ (1e+300,Infinity) | (-5,-12)          | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e-300,-1e-300)  | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e+300,Infinity) | (2e+300,Infinity)
+ (1e+300,Infinity) | (NaN,NaN)         | (NaN,NaN)
+ (1e+300,Infinity) | (10,10)           | (1e+300,Infinity)
+ (NaN,NaN)         | (0,0)             | (NaN,NaN)
+ (NaN,NaN)         | (-10,0)           | (NaN,NaN)
+ (NaN,NaN)         | (-3,4)            | (NaN,NaN)
+ (NaN,NaN)         | (5.1,34.5)        | (NaN,NaN)
+ (NaN,NaN)         | (-5,-12)          | (NaN,NaN)
+ (NaN,NaN)         | (1e-300,-1e-300)  | (NaN,NaN)
+ (NaN,NaN)         | (1e+300,Infinity) | (NaN,NaN)
+ (NaN,NaN)         | (NaN,NaN)         | (NaN,NaN)
+ (NaN,NaN)         | (10,10)           | (NaN,NaN)
+ (10,10)           | (0,0)             | (10,10)
+ (10,10)           | (-10,0)           | (0,10)
+ (10,10)           | (-3,4)            | (7,14)
+ (10,10)           | (5.1,34.5)        | (15.1,44.5)
+ (10,10)           | (-5,-12)          | (5,-2)
+ (10,10)           | (1e-300,-1e-300)  | (10,10)
+ (10,10)           | (1e+300,Infinity) | (1e+300,Infinity)
+ (10,10)           | (NaN,NaN)         | (NaN,NaN)
+ (10,10)           | (10,10)           | (20,20)
+(81 rows)
+
+-- Subtract point
+SELECT p1.f1, p2.f1, p1.f1 - p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+        f1         |        f1         |      ?column?       
+-------------------+-------------------+---------------------
+ (0,0)             | (0,0)             | (0,0)
+ (0,0)             | (-10,0)           | (10,0)
+ (0,0)             | (-3,4)            | (3,-4)
+ (0,0)             | (5.1,34.5)        | (-5.1,-34.5)
+ (0,0)             | (-5,-12)          | (5,12)
+ (0,0)             | (1e-300,-1e-300)  | (-1e-300,1e-300)
+ (0,0)             | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (0,0)             | (NaN,NaN)         | (NaN,NaN)
+ (0,0)             | (10,10)           | (-10,-10)
+ (-10,0)           | (0,0)             | (-10,0)
+ (-10,0)           | (-10,0)           | (0,0)
+ (-10,0)           | (-3,4)            | (-7,-4)
+ (-10,0)           | (5.1,34.5)        | (-15.1,-34.5)
+ (-10,0)           | (-5,-12)          | (-5,12)
+ (-10,0)           | (1e-300,-1e-300)  | (-10,1e-300)
+ (-10,0)           | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-10,0)           | (NaN,NaN)         | (NaN,NaN)
+ (-10,0)           | (10,10)           | (-20,-10)
+ (-3,4)            | (0,0)             | (-3,4)
+ (-3,4)            | (-10,0)           | (7,4)
+ (-3,4)            | (-3,4)            | (0,0)
+ (-3,4)            | (5.1,34.5)        | (-8.1,-30.5)
+ (-3,4)            | (-5,-12)          | (2,16)
+ (-3,4)            | (1e-300,-1e-300)  | (-3,4)
+ (-3,4)            | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-3,4)            | (NaN,NaN)         | (NaN,NaN)
+ (-3,4)            | (10,10)           | (-13,-6)
+ (5.1,34.5)        | (0,0)             | (5.1,34.5)
+ (5.1,34.5)        | (-10,0)           | (15.1,34.5)
+ (5.1,34.5)        | (-3,4)            | (8.1,30.5)
+ (5.1,34.5)        | (5.1,34.5)        | (0,0)
+ (5.1,34.5)        | (-5,-12)          | (10.1,46.5)
+ (5.1,34.5)        | (1e-300,-1e-300)  | (5.1,34.5)
+ (5.1,34.5)        | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (5.1,34.5)        | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5)        | (10,10)           | (-4.9,24.5)
+ (-5,-12)          | (0,0)             | (-5,-12)
+ (-5,-12)          | (-10,0)           | (5,-12)
+ (-5,-12)          | (-3,4)            | (-2,-16)
+ (-5,-12)          | (5.1,34.5)        | (-10.1,-46.5)
+ (-5,-12)          | (-5,-12)          | (0,0)
+ (-5,-12)          | (1e-300,-1e-300)  | (-5,-12)
+ (-5,-12)          | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (-5,-12)          | (NaN,NaN)         | (NaN,NaN)
+ (-5,-12)          | (10,10)           | (-15,-22)
+ (1e-300,-1e-300)  | (0,0)             | (1e-300,-1e-300)
+ (1e-300,-1e-300)  | (-10,0)           | (10,-1e-300)
+ (1e-300,-1e-300)  | (-3,4)            | (3,-4)
+ (1e-300,-1e-300)  | (5.1,34.5)        | (-5.1,-34.5)
+ (1e-300,-1e-300)  | (-5,-12)          | (5,12)
+ (1e-300,-1e-300)  | (1e-300,-1e-300)  | (0,0)
+ (1e-300,-1e-300)  | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (1e-300,-1e-300)  | (NaN,NaN)         | (NaN,NaN)
+ (1e-300,-1e-300)  | (10,10)           | (-10,-10)
+ (1e+300,Infinity) | (0,0)             | (1e+300,Infinity)
+ (1e+300,Infinity) | (-10,0)           | (1e+300,Infinity)
+ (1e+300,Infinity) | (-3,4)            | (1e+300,Infinity)
+ (1e+300,Infinity) | (5.1,34.5)        | (1e+300,Infinity)
+ (1e+300,Infinity) | (-5,-12)          | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e-300,-1e-300)  | (1e+300,Infinity)
+ (1e+300,Infinity) | (1e+300,Infinity) | (0,NaN)
+ (1e+300,Infinity) | (NaN,NaN)         | (NaN,NaN)
+ (1e+300,Infinity) | (10,10)           | (1e+300,Infinity)
+ (NaN,NaN)         | (0,0)             | (NaN,NaN)
+ (NaN,NaN)         | (-10,0)           | (NaN,NaN)
+ (NaN,NaN)         | (-3,4)            | (NaN,NaN)
+ (NaN,NaN)         | (5.1,34.5)        | (NaN,NaN)
+ (NaN,NaN)         | (-5,-12)          | (NaN,NaN)
+ (NaN,NaN)         | (1e-300,-1e-300)  | (NaN,NaN)
+ (NaN,NaN)         | (1e+300,Infinity) | (NaN,NaN)
+ (NaN,NaN)         | (NaN,NaN)         | (NaN,NaN)
+ (NaN,NaN)         | (10,10)           | (NaN,NaN)
+ (10,10)           | (0,0)             | (10,10)
+ (10,10)           | (-10,0)           | (20,10)
+ (10,10)           | (-3,4)            | (13,6)
+ (10,10)           | (5.1,34.5)        | (4.9,-24.5)
+ (10,10)           | (-5,-12)          | (15,22)
+ (10,10)           | (1e-300,-1e-300)  | (10,10)
+ (10,10)           | (1e+300,Infinity) | (-1e+300,-Infinity)
+ (10,10)           | (NaN,NaN)         | (NaN,NaN)
+ (10,10)           | (10,10)           | (0,0)
+(81 rows)
+
+-- Multiply with point
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+     f1     |        f1         |       ?column?        
+------------+-------------------+-----------------------
+ (5.1,34.5) | (0,0)             | (0,0)
+ (10,10)    | (0,0)             | (0,0)
+ (5.1,34.5) | (-10,0)           | (-51,-345)
+ (10,10)    | (-10,0)           | (-100,-100)
+ (5.1,34.5) | (-3,4)            | (-153.3,-83.1)
+ (10,10)    | (-3,4)            | (-70,10)
+ (5.1,34.5) | (5.1,34.5)        | (-1164.24,351.9)
+ (10,10)    | (5.1,34.5)        | (-294,396)
+ (5.1,34.5) | (-5,-12)          | (388.5,-233.7)
+ (10,10)    | (-5,-12)          | (70,-170)
+ (5.1,34.5) | (1e-300,-1e-300)  | (3.96e-299,2.94e-299)
+ (10,10)    | (1e-300,-1e-300)  | (2e-299,0)
+ (5.1,34.5) | (1e+300,Infinity) | (-Infinity,Infinity)
+ (10,10)    | (1e+300,Infinity) | (-Infinity,Infinity)
+ (5.1,34.5) | (NaN,NaN)         | (NaN,NaN)
+ (10,10)    | (NaN,NaN)         | (NaN,NaN)
+ (5.1,34.5) | (10,10)           | (-294,396)
+ (10,10)    | (10,10)           | (0,200)
+(18 rows)
+
+-- Underflow error
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] < 1;
+ERROR:  value out of range: underflow
+-- Divide by point
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] BETWEEN 1 AND 1000;
+        f1         |     f1     |                 ?column?                  
+-------------------+------------+-------------------------------------------
+ (0,0)             | (5.1,34.5) | (0,0)
+ (0,0)             | (10,10)    | (0,0)
+ (-10,0)           | (5.1,34.5) | (-0.0419318237877,0.283656455034)
+ (-10,0)           | (10,10)    | (-0.5,0.5)
+ (-3,4)            | (5.1,34.5) | (0.100883034877,0.101869666025)
+ (-3,4)            | (10,10)    | (0.05,0.35)
+ (5.1,34.5)        | (5.1,34.5) | (1,0)
+ (5.1,34.5)        | (10,10)    | (1.98,1.47)
+ (-5,-12)          | (5.1,34.5) | (-0.361353657935,0.0915100389719)
+ (-5,-12)          | (10,10)    | (-0.85,-0.35)
+ (1e-300,-1e-300)  | (5.1,34.5) | (-2.41724631247e-302,-3.25588278822e-302)
+ (1e-300,-1e-300)  | (10,10)    | (0,-1e-301)
+ (1e+300,Infinity) | (5.1,34.5) | (Infinity,Infinity)
+ (1e+300,Infinity) | (10,10)    | (Infinity,Infinity)
+ (NaN,NaN)         | (5.1,34.5) | (NaN,NaN)
+ (NaN,NaN)         | (10,10)    | (NaN,NaN)
+ (10,10)           | (5.1,34.5) | (0.325588278822,-0.241724631247)
+ (10,10)           | (10,10)    | (1,0)
+(18 rows)
+
+-- Overflow error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] > 1000;
+ERROR:  value out of range: overflow
+-- Division by 0 error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to line
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LINE_TBL l;
+        f1         |                   s                   |      ?column?      
+-------------------+---------------------------------------+--------------------
+ (0,0)             | {0,-1,5}                              |                  5
+ (0,0)             | {1,0,5}                               |                  5
+ (0,0)             | {0,3,0}                               |                  0
+ (0,0)             | {1,-1,0}                              |                  0
+ (0,0)             | {-0.4,-1,-6}                          |      5.57086014531
+ (0,0)             | {-0.000184615384615,-1,15.3846153846} |      15.3846151224
+ (0,0)             | {3,NaN,5}                             |                NaN
+ (0,0)             | {NaN,NaN,NaN}                         |                NaN
+ (0,0)             | {0,-1,3}                              |                  3
+ (0,0)             | {-1,0,3}                              |                  3
+ (-10,0)           | {0,-1,5}                              |                  5
+ (-10,0)           | {1,0,5}                               |                  5
+ (-10,0)           | {0,3,0}                               |                  0
+ (-10,0)           | {1,-1,0}                              |      7.07106781187
+ (-10,0)           | {-0.4,-1,-6}                          |      1.85695338177
+ (-10,0)           | {-0.000184615384615,-1,15.3846153846} |      15.3864612763
+ (-10,0)           | {3,NaN,5}                             |                NaN
+ (-10,0)           | {NaN,NaN,NaN}                         |                NaN
+ (-10,0)           | {0,-1,3}                              |                  3
+ (-10,0)           | {-1,0,3}                              |                 13
+ (-3,4)            | {0,-1,5}                              |                  1
+ (-3,4)            | {1,0,5}                               |                  2
+ (-3,4)            | {0,3,0}                               |                  4
+ (-3,4)            | {1,-1,0}                              |      4.94974746831
+ (-3,4)            | {-0.4,-1,-6}                          |      8.17059487979
+ (-3,4)            | {-0.000184615384615,-1,15.3846153846} |      11.3851690368
+ (-3,4)            | {3,NaN,5}                             |                NaN
+ (-3,4)            | {NaN,NaN,NaN}                         |                NaN
+ (-3,4)            | {0,-1,3}                              |                  1
+ (-3,4)            | {-1,0,3}                              |                  6
+ (5.1,34.5)        | {0,-1,5}                              |               29.5
+ (5.1,34.5)        | {1,0,5}                               |               10.1
+ (5.1,34.5)        | {0,3,0}                               |               34.5
+ (5.1,34.5)        | {1,-1,0}                              |      20.7889393669
+ (5.1,34.5)        | {-0.4,-1,-6}                          |      39.4973984303
+ (5.1,34.5)        | {-0.000184615384615,-1,15.3846153846} |      19.1163258281
+ (5.1,34.5)        | {3,NaN,5}                             |                NaN
+ (5.1,34.5)        | {NaN,NaN,NaN}                         |                NaN
+ (5.1,34.5)        | {0,-1,3}                              |               31.5
+ (5.1,34.5)        | {-1,0,3}                              |                2.1
+ (-5,-12)          | {0,-1,5}                              |                 17
+ (-5,-12)          | {1,0,5}                               |                  0
+ (-5,-12)          | {0,3,0}                               |                 12
+ (-5,-12)          | {1,-1,0}                              |      4.94974746831
+ (-5,-12)          | {-0.4,-1,-6}                          |      7.42781352708
+ (-5,-12)          | {-0.000184615384615,-1,15.3846153846} |      27.3855379948
+ (-5,-12)          | {3,NaN,5}                             |                NaN
+ (-5,-12)          | {NaN,NaN,NaN}                         |                NaN
+ (-5,-12)          | {0,-1,3}                              |                 15
+ (-5,-12)          | {-1,0,3}                              |                  8
+ (1e-300,-1e-300)  | {0,-1,5}                              |                  5
+ (1e-300,-1e-300)  | {1,0,5}                               |                  5
+ (1e-300,-1e-300)  | {0,3,0}                               |             1e-300
+ (1e-300,-1e-300)  | {1,-1,0}                              | 1.41421356237e-300
+ (1e-300,-1e-300)  | {-0.4,-1,-6}                          |      5.57086014531
+ (1e-300,-1e-300)  | {-0.000184615384615,-1,15.3846153846} |      15.3846151224
+ (1e-300,-1e-300)  | {3,NaN,5}                             |                NaN
+ (1e-300,-1e-300)  | {NaN,NaN,NaN}                         |                NaN
+ (1e-300,-1e-300)  | {0,-1,3}                              |                  3
+ (1e-300,-1e-300)  | {-1,0,3}                              |                  3
+ (1e+300,Infinity) | {0,-1,5}                              |           Infinity
+ (1e+300,Infinity) | {1,0,5}                               |                NaN
+ (1e+300,Infinity) | {0,3,0}                               |           Infinity
+ (1e+300,Infinity) | {1,-1,0}                              |           Infinity
+ (1e+300,Infinity) | {-0.4,-1,-6}                          |           Infinity
+ (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} |           Infinity
+ (1e+300,Infinity) | {3,NaN,5}                             |                NaN
+ (1e+300,Infinity) | {NaN,NaN,NaN}                         |                NaN
+ (1e+300,Infinity) | {0,-1,3}                              |           Infinity
+ (1e+300,Infinity) | {-1,0,3}                              |                NaN
+ (NaN,NaN)         | {0,-1,5}                              |                NaN
+ (NaN,NaN)         | {1,0,5}                               |                NaN
+ (NaN,NaN)         | {0,3,0}                               |                NaN
+ (NaN,NaN)         | {1,-1,0}                              |                NaN
+ (NaN,NaN)         | {-0.4,-1,-6}                          |                NaN
+ (NaN,NaN)         | {-0.000184615384615,-1,15.3846153846} |                NaN
+ (NaN,NaN)         | {3,NaN,5}                             |                NaN
+ (NaN,NaN)         | {NaN,NaN,NaN}                         |                NaN
+ (NaN,NaN)         | {0,-1,3}                              |                NaN
+ (NaN,NaN)         | {-1,0,3}                              |                NaN
+ (10,10)           | {0,-1,5}                              |                  5
+ (10,10)           | {1,0,5}                               |                 15
+ (10,10)           | {0,3,0}                               |                 10
+ (10,10)           | {1,-1,0}                              |                  0
+ (10,10)           | {-0.4,-1,-6}                          |      18.5695338177
+ (10,10)           | {-0.000184615384615,-1,15.3846153846} |      5.38276913903
+ (10,10)           | {3,NaN,5}                             |                NaN
+ (10,10)           | {NaN,NaN,NaN}                         |                NaN
+ (10,10)           | {0,-1,3}                              |                  7
+ (10,10)           | {-1,0,3}                              |                  7
+(90 rows)
+
+-- Distance to line segment
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LSEG_TBL l;
+        f1         |               s               |      ?column?      
+-------------------+-------------------------------+--------------------
+ (0,0)             | [(1,2),(3,4)]                 |       2.2360679775
+ (0,0)             | [(0,0),(6,6)]                 |                  0
+ (0,0)             | [(10,-10),(-3,-4)]            |      4.88901207039
+ (0,0)             | [(-1000000,200),(300000,-40)] |      15.3846151224
+ (0,0)             | [(11,22),(33,44)]             |      24.5967477525
+ (0,0)             | [(-10,2),(-10,3)]             |      10.1980390272
+ (0,0)             | [(0,-20),(30,-20)]            |                 20
+ (0,0)             | [(NaN,1),(NaN,90)]            |                NaN
+ (-10,0)           | [(1,2),(3,4)]                 |      11.1803398875
+ (-10,0)           | [(0,0),(6,6)]                 |                 10
+ (-10,0)           | [(10,-10),(-3,-4)]            |       8.0622577483
+ (-10,0)           | [(-1000000,200),(300000,-40)] |      15.3864612763
+ (-10,0)           | [(11,22),(33,44)]             |      30.4138126515
+ (-10,0)           | [(-10,2),(-10,3)]             |                  2
+ (-10,0)           | [(0,-20),(30,-20)]            |       22.360679775
+ (-10,0)           | [(NaN,1),(NaN,90)]            |                NaN
+ (-3,4)            | [(1,2),(3,4)]                 |        4.472135955
+ (-3,4)            | [(0,0),(6,6)]                 |      4.94974746831
+ (-3,4)            | [(10,-10),(-3,-4)]            |                  8
+ (-3,4)            | [(-1000000,200),(300000,-40)] |      11.3851690367
+ (-3,4)            | [(11,22),(33,44)]             |       22.803508502
+ (-3,4)            | [(-10,2),(-10,3)]             |      7.07106781187
+ (-3,4)            | [(0,-20),(30,-20)]            |      24.1867732449
+ (-3,4)            | [(NaN,1),(NaN,90)]            |                NaN
+ (5.1,34.5)        | [(1,2),(3,4)]                 |      30.5722096028
+ (5.1,34.5)        | [(0,0),(6,6)]                 |      28.5142069853
+ (5.1,34.5)        | [(10,-10),(-3,-4)]            |      39.3428519556
+ (5.1,34.5)        | [(-1000000,200),(300000,-40)] |      19.1163258281
+ (5.1,34.5)        | [(11,22),(33,44)]             |      13.0107647738
+ (5.1,34.5)        | [(-10,2),(-10,3)]             |       34.932220084
+ (5.1,34.5)        | [(0,-20),(30,-20)]            |               54.5
+ (5.1,34.5)        | [(NaN,1),(NaN,90)]            |                NaN
+ (-5,-12)          | [(1,2),(3,4)]                 |      15.2315462117
+ (-5,-12)          | [(0,0),(6,6)]                 |                 13
+ (-5,-12)          | [(10,-10),(-3,-4)]            |      8.10179143093
+ (-5,-12)          | [(-1000000,200),(300000,-40)] |      27.3855379949
+ (-5,-12)          | [(11,22),(33,44)]             |      37.5765884561
+ (-5,-12)          | [(-10,2),(-10,3)]             |      14.8660687473
+ (-5,-12)          | [(0,-20),(30,-20)]            |      9.43398113206
+ (-5,-12)          | [(NaN,1),(NaN,90)]            |                NaN
+ (1e-300,-1e-300)  | [(1,2),(3,4)]                 |       2.2360679775
+ (1e-300,-1e-300)  | [(0,0),(6,6)]                 | 1.41421356237e-300
+ (1e-300,-1e-300)  | [(10,-10),(-3,-4)]            |      4.88901207039
+ (1e-300,-1e-300)  | [(-1000000,200),(300000,-40)] |      15.3846151224
+ (1e-300,-1e-300)  | [(11,22),(33,44)]             |      24.5967477525
+ (1e-300,-1e-300)  | [(-10,2),(-10,3)]             |      10.1980390272
+ (1e-300,-1e-300)  | [(0,-20),(30,-20)]            |                 20
+ (1e-300,-1e-300)  | [(NaN,1),(NaN,90)]            |                NaN
+ (1e+300,Infinity) | [(1,2),(3,4)]                 |           Infinity
+ (1e+300,Infinity) | [(0,0),(6,6)]                 |           Infinity
+ (1e+300,Infinity) | [(10,-10),(-3,-4)]            |           Infinity
+ (1e+300,Infinity) | [(-1000000,200),(300000,-40)] |           Infinity
+ (1e+300,Infinity) | [(11,22),(33,44)]             |           Infinity
+ (1e+300,Infinity) | [(-10,2),(-10,3)]             |           Infinity
+ (1e+300,Infinity) | [(0,-20),(30,-20)]            |           Infinity
+ (1e+300,Infinity) | [(NaN,1),(NaN,90)]            |           Infinity
+ (NaN,NaN)         | [(1,2),(3,4)]                 |                NaN
+ (NaN,NaN)         | [(0,0),(6,6)]                 |                NaN
+ (NaN,NaN)         | [(10,-10),(-3,-4)]            |                NaN
+ (NaN,NaN)         | [(-1000000,200),(300000,-40)] |                NaN
+ (NaN,NaN)         | [(11,22),(33,44)]             |                NaN
+ (NaN,NaN)         | [(-10,2),(-10,3)]             |                NaN
+ (NaN,NaN)         | [(0,-20),(30,-20)]            |                NaN
+ (NaN,NaN)         | [(NaN,1),(NaN,90)]            |                NaN
+ (10,10)           | [(1,2),(3,4)]                 |      9.21954445729
+ (10,10)           | [(0,0),(6,6)]                 |      5.65685424949
+ (10,10)           | [(10,-10),(-3,-4)]            |        18.15918769
+ (10,10)           | [(-1000000,200),(300000,-40)] |      5.38276913904
+ (10,10)           | [(11,22),(33,44)]             |      12.0415945788
+ (10,10)           | [(-10,2),(-10,3)]             |      21.1896201004
+ (10,10)           | [(0,-20),(30,-20)]            |                 30
+ (10,10)           | [(NaN,1),(NaN,90)]            |                NaN
+(72 rows)
+
+-- Distance to box
+SELECT p.f1, b.f1, p.f1 <-> b.f1 FROM POINT_TBL p, BOX_TBL b;
+        f1         |         f1          |      ?column?      
+-------------------+---------------------+--------------------
+ (0,0)             | (2,2),(0,0)         |                  0
+ (0,0)             | (3,3),(1,1)         |      1.41421356237
+ (0,0)             | (-2,2),(-8,-10)     |                  2
+ (0,0)             | (2.5,3.5),(2.5,2.5) |      3.53553390593
+ (0,0)             | (3,3),(3,3)         |      4.24264068712
+ (-10,0)           | (2,2),(0,0)         |                 10
+ (-10,0)           | (3,3),(1,1)         |      11.0453610172
+ (-10,0)           | (-2,2),(-8,-10)     |                  2
+ (-10,0)           | (2.5,3.5),(2.5,2.5) |       12.747548784
+ (-10,0)           | (3,3),(3,3)         |      13.3416640641
+ (-3,4)            | (2,2),(0,0)         |      3.60555127546
+ (-3,4)            | (3,3),(1,1)         |      4.12310562562
+ (-3,4)            | (-2,2),(-8,-10)     |                  2
+ (-3,4)            | (2.5,3.5),(2.5,2.5) |      5.52268050859
+ (-3,4)            | (3,3),(3,3)         |       6.0827625303
+ (5.1,34.5)        | (2,2),(0,0)         |      32.6475113906
+ (5.1,34.5)        | (3,3),(1,1)         |      31.5699223946
+ (5.1,34.5)        | (-2,2),(-8,-10)     |      33.2664996656
+ (5.1,34.5)        | (2.5,3.5),(2.5,2.5) |       31.108841187
+ (5.1,34.5)        | (3,3),(3,3)         |      31.5699223946
+ (-5,-12)          | (2,2),(0,0)         |                 13
+ (-5,-12)          | (3,3),(1,1)         |      14.3178210633
+ (-5,-12)          | (-2,2),(-8,-10)     |                  2
+ (-5,-12)          | (2.5,3.5),(2.5,2.5) |      16.3248277173
+ (-5,-12)          | (3,3),(3,3)         |                 17
+ (1e-300,-1e-300)  | (2,2),(0,0)         | 1.41421356237e-300
+ (1e-300,-1e-300)  | (3,3),(1,1)         |      1.41421356237
+ (1e-300,-1e-300)  | (-2,2),(-8,-10)     |                  2
+ (1e-300,-1e-300)  | (2.5,3.5),(2.5,2.5) |      3.53553390593
+ (1e-300,-1e-300)  | (3,3),(3,3)         |      4.24264068712
+ (1e+300,Infinity) | (2,2),(0,0)         |           Infinity
+ (1e+300,Infinity) | (3,3),(1,1)         |           Infinity
+ (1e+300,Infinity) | (-2,2),(-8,-10)     |           Infinity
+ (1e+300,Infinity) | (2.5,3.5),(2.5,2.5) |           Infinity
+ (1e+300,Infinity) | (3,3),(3,3)         |           Infinity
+ (NaN,NaN)         | (2,2),(0,0)         |                NaN
+ (NaN,NaN)         | (3,3),(1,1)         |                NaN
+ (NaN,NaN)         | (-2,2),(-8,-10)     |                NaN
+ (NaN,NaN)         | (2.5,3.5),(2.5,2.5) |                NaN
+ (NaN,NaN)         | (3,3),(3,3)         |                NaN
+ (10,10)           | (2,2),(0,0)         |       11.313708499
+ (10,10)           | (3,3),(1,1)         |      9.89949493661
+ (10,10)           | (-2,2),(-8,-10)     |      14.4222051019
+ (10,10)           | (2.5,3.5),(2.5,2.5) |      9.92471662064
+ (10,10)           | (3,3),(3,3)         |      9.89949493661
+(45 rows)
+
+-- Distance to path
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, PATH_TBL p1;
+        f1         |            f1             |      ?column?      
+-------------------+---------------------------+--------------------
+ (0,0)             | [(1,2),(3,4)]             |       2.2360679775
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | [(0,0),(3,0),(4,5),(1,6)] |                  0
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | ((1,2),(3,4))             |       2.2360679775
+ (0,0)             | [(1,2),(3,4)]             |       2.2360679775
+ (0,0)             | ((10,20))                 |       22.360679775
+ (0,0)             | [(11,12),(13,14)]         |      16.2788205961
+ (0,0)             | ((11,12),(13,14))         |      16.2788205961
+ (-10,0)           | [(1,2),(3,4)]             |      11.1803398875
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | [(0,0),(3,0),(4,5),(1,6)] |                 10
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | ((1,2),(3,4))             |      11.1803398875
+ (-10,0)           | [(1,2),(3,4)]             |      11.1803398875
+ (-10,0)           | ((10,20))                 |      28.2842712475
+ (-10,0)           | [(11,12),(13,14)]         |      24.1867732449
+ (-10,0)           | ((11,12),(13,14))         |      24.1867732449
+ (-3,4)            | [(1,2),(3,4)]             |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | [(0,0),(3,0),(4,5),(1,6)] |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | ((1,2),(3,4))             |        4.472135955
+ (-3,4)            | [(1,2),(3,4)]             |        4.472135955
+ (-3,4)            | ((10,20))                 |      20.6155281281
+ (-3,4)            | [(11,12),(13,14)]         |      16.1245154966
+ (-3,4)            | ((11,12),(13,14))         |      16.1245154966
+ (5.1,34.5)        | [(1,2),(3,4)]             |      30.5722096028
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | [(0,0),(3,0),(4,5),(1,6)] |       28.793402022
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | ((1,2),(3,4))             |      30.5722096028
+ (5.1,34.5)        | [(1,2),(3,4)]             |      30.5722096028
+ (5.1,34.5)        | ((10,20))                 |      15.3055545473
+ (5.1,34.5)        | [(11,12),(13,14)]         |      21.9695243462
+ (5.1,34.5)        | ((11,12),(13,14))         |      21.9695243462
+ (-5,-12)          | [(1,2),(3,4)]             |      15.2315462117
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | [(0,0),(3,0),(4,5),(1,6)] |                 13
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | ((1,2),(3,4))             |      15.2315462117
+ (-5,-12)          | [(1,2),(3,4)]             |      15.2315462117
+ (-5,-12)          | ((10,20))                 |      35.3411940941
+ (-5,-12)          | [(11,12),(13,14)]         |      28.8444102037
+ (-5,-12)          | ((11,12),(13,14))         |      28.8444102037
+ (1e-300,-1e-300)  | [(1,2),(3,4)]             |       2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | [(0,0),(3,0),(4,5),(1,6)] | 1.41421356237e-300
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(3,4))             |       2.2360679775
+ (1e-300,-1e-300)  | [(1,2),(3,4)]             |       2.2360679775
+ (1e-300,-1e-300)  | ((10,20))                 |       22.360679775
+ (1e-300,-1e-300)  | [(11,12),(13,14)]         |      16.2788205961
+ (1e-300,-1e-300)  | ((11,12),(13,14))         |      16.2788205961
+ (1e+300,Infinity) | [(1,2),(3,4)]             |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | [(0,0),(3,0),(4,5),(1,6)] |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | ((1,2),(3,4))             |           Infinity
+ (1e+300,Infinity) | [(1,2),(3,4)]             |           Infinity
+ (1e+300,Infinity) | ((10,20))                 |           Infinity
+ (1e+300,Infinity) | [(11,12),(13,14)]         |           Infinity
+ (1e+300,Infinity) | ((11,12),(13,14))         |           Infinity
+ (NaN,NaN)         | [(1,2),(3,4)]             |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | [(0,0),(3,0),(4,5),(1,6)] |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | ((1,2),(3,4))             |                NaN
+ (NaN,NaN)         | [(1,2),(3,4)]             |                NaN
+ (NaN,NaN)         | ((10,20))                 |                NaN
+ (NaN,NaN)         | [(11,12),(13,14)]         |                NaN
+ (NaN,NaN)         | ((11,12),(13,14))         |                NaN
+ (10,10)           | [(1,2),(3,4)]             |      9.21954445729
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | [(0,0),(3,0),(4,5),(1,6)] |      7.81024967591
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | ((1,2),(3,4))             |      9.21954445729
+ (10,10)           | [(1,2),(3,4)]             |      9.21954445729
+ (10,10)           | ((10,20))                 |                 10
+ (10,10)           | [(11,12),(13,14)]         |       2.2360679775
+ (10,10)           | ((11,12),(13,14))         |       2.2360679775
+(81 rows)
+
+-- Distance to polygon
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, POLYGON_TBL p1;
+        f1         |             f1             |   ?column?    
+-------------------+----------------------------+---------------
+ (0,0)             | ((2,0),(2,4),(0,0))        |             0
+ (0,0)             | ((3,1),(3,3),(1,0))        |             1
+ (0,0)             | ((1,2),(3,4),(5,6),(7,8))  |  2.2360679775
+ (0,0)             | ((7,8),(5,6),(3,4),(1,2))  |  2.2360679775
+ (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | 1.58113883008
+ (0,0)             | ((0,0))                    |             0
+ (0,0)             | ((0,1),(0,1))              |             1
+ (-10,0)           | ((2,0),(2,4),(0,0))        |            10
+ (-10,0)           | ((3,1),(3,3),(1,0))        |            11
+ (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | 11.1803398875
+ (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | 11.1803398875
+ (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | 11.1803398875
+ (-10,0)           | ((0,0))                    |            10
+ (-10,0)           | ((0,1),(0,1))              | 10.0498756211
+ (-3,4)            | ((2,0),(2,4),(0,0))        |   4.472135955
+ (-3,4)            | ((3,1),(3,3),(1,0))        | 5.54700196225
+ (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  |   4.472135955
+ (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  |   4.472135955
+ (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) |   4.472135955
+ (-3,4)            | ((0,0))                    |             5
+ (-3,4)            | ((0,1),(0,1))              | 4.24264068712
+ (5.1,34.5)        | ((2,0),(2,4),(0,0))        | 30.6571362002
+ (5.1,34.5)        | ((3,1),(3,3),(1,0))        | 31.5699223946
+ (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | 26.5680258958
+ (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | 26.5680258958
+ (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | 26.5680258958
+ (5.1,34.5)        | ((0,0))                    | 34.8749193547
+ (5.1,34.5)        | ((0,1),(0,1))              | 33.8859853037
+ (-5,-12)          | ((2,0),(2,4),(0,0))        |            13
+ (-5,-12)          | ((3,1),(3,3),(1,0))        |  13.416407865
+ (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | 15.2315462117
+ (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | 15.2315462117
+ (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) |  11.313708499
+ (-5,-12)          | ((0,0))                    |            13
+ (-5,-12)          | ((0,1),(0,1))              | 13.9283882772
+ (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        |             0
+ (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        |             1
+ (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  |  2.2360679775
+ (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  |  2.2360679775
+ (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | 1.58113883008
+ (1e-300,-1e-300)  | ((0,0))                    |             0
+ (1e-300,-1e-300)  | ((0,1),(0,1))              |             1
+ (1e+300,Infinity) | ((2,0),(2,4),(0,0))        |      Infinity
+ (1e+300,Infinity) | ((3,1),(3,3),(1,0))        |      Infinity
+ (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  |      Infinity
+ (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  |      Infinity
+ (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) |      Infinity
+ (1e+300,Infinity) | ((0,0))                    |      Infinity
+ (1e+300,Infinity) | ((0,1),(0,1))              |      Infinity
+ (NaN,NaN)         | ((2,0),(2,4),(0,0))        |             0
+ (NaN,NaN)         | ((3,1),(3,3),(1,0))        |             0
+ (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  |             0
+ (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  |             0
+ (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) |             0
+ (NaN,NaN)         | ((0,0))                    |             0
+ (NaN,NaN)         | ((0,1),(0,1))              |             0
+ (10,10)           | ((2,0),(2,4),(0,0))        |            10
+ (10,10)           | ((3,1),(3,3),(1,0))        | 9.89949493661
+ (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | 3.60555127546
+ (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | 3.60555127546
+ (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | 3.60555127546
+ (10,10)           | ((0,0))                    | 14.1421356237
+ (10,10)           | ((0,1),(0,1))              | 13.4536240471
+(63 rows)
+
+-- Closest point to line
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LINE_TBL l;
+        f1         |                   s                   |             ?column?             
+-------------------+---------------------------------------+----------------------------------
+ (0,0)             | {0,-1,5}                              | (0,5)
+ (0,0)             | {1,0,5}                               | (-5,0)
+ (0,0)             | {0,3,0}                               | (0,0)
+ (0,0)             | {1,-1,0}                              | (0,0)
+ (0,0)             | {-0.4,-1,-6}                          | (-2.06896551724,-5.1724137931)
+ (0,0)             | {-0.000184615384615,-1,15.3846153846} | (0.00284023658959,15.3846148603)
+ (0,0)             | {3,NaN,5}                             | 
+ (0,0)             | {NaN,NaN,NaN}                         | 
+ (0,0)             | {0,-1,3}                              | (0,3)
+ (0,0)             | {-1,0,3}                              | (3,0)
+ (-10,0)           | {0,-1,5}                              | (-10,5)
+ (-10,0)           | {1,0,5}                               | (-5,0)
+ (-10,0)           | {0,3,0}                               | (-10,0)
+ (-10,0)           | {1,-1,0}                              | (-5,-5)
+ (-10,0)           | {-0.4,-1,-6}                          | (-10.6896551724,-1.72413793103)
+ (-10,0)           | {-0.000184615384615,-1,15.3846153846} | (-9.99715942258,15.386461014)
+ (-10,0)           | {3,NaN,5}                             | 
+ (-10,0)           | {NaN,NaN,NaN}                         | 
+ (-10,0)           | {0,-1,3}                              | (-10,3)
+ (-10,0)           | {-1,0,3}                              | (3,0)
+ (-3,4)            | {0,-1,5}                              | (-3,5)
+ (-3,4)            | {1,0,5}                               | (-5,4)
+ (-3,4)            | {0,3,0}                               | (-3,0)
+ (-3,4)            | {1,-1,0}                              | (0.5,0.5)
+ (-3,4)            | {-0.4,-1,-6}                          | (-6.03448275862,-3.58620689655)
+ (-3,4)            | {-0.000184615384615,-1,15.3846153846} | (-2.99789812268,15.3851688427)
+ (-3,4)            | {3,NaN,5}                             | 
+ (-3,4)            | {NaN,NaN,NaN}                         | 
+ (-3,4)            | {0,-1,3}                              | (-3,3)
+ (-3,4)            | {-1,0,3}                              | (3,4)
+ (5.1,34.5)        | {0,-1,5}                              | (5.1,5)
+ (5.1,34.5)        | {1,0,5}                               | (-5,34.5)
+ (5.1,34.5)        | {0,3,0}                               | (5.1,0)
+ (5.1,34.5)        | {1,-1,0}                              | (19.8,19.8)
+ (5.1,34.5)        | {-0.4,-1,-6}                          | (-9.56896551724,-2.1724137931)
+ (5.1,34.5)        | {-0.000184615384615,-1,15.3846153846} | (5.09647083221,15.3836744977)
+ (5.1,34.5)        | {3,NaN,5}                             | 
+ (5.1,34.5)        | {NaN,NaN,NaN}                         | 
+ (5.1,34.5)        | {0,-1,3}                              | (5.1,3)
+ (5.1,34.5)        | {-1,0,3}                              | (3,34.5)
+ (-5,-12)          | {0,-1,5}                              | (-5,5)
+ (-5,-12)          | {1,0,5}                               | (-5,-12)
+ (-5,-12)          | {0,3,0}                               | (-5,0)
+ (-5,-12)          | {1,-1,0}                              | (-8.5,-8.5)
+ (-5,-12)          | {-0.4,-1,-6}                          | (-2.24137931034,-5.10344827586)
+ (-5,-12)          | {-0.000184615384615,-1,15.3846153846} | (-4.99494420846,15.3855375282)
+ (-5,-12)          | {3,NaN,5}                             | 
+ (-5,-12)          | {NaN,NaN,NaN}                         | 
+ (-5,-12)          | {0,-1,3}                              | (-5,3)
+ (-5,-12)          | {-1,0,3}                              | (3,-12)
+ (1e-300,-1e-300)  | {0,-1,5}                              | (1e-300,5)
+ (1e-300,-1e-300)  | {1,0,5}                               | (-5,-1e-300)
+ (1e-300,-1e-300)  | {0,3,0}                               | (1e-300,0)
+ (1e-300,-1e-300)  | {1,-1,0}                              | (0,0)
+ (1e-300,-1e-300)  | {-0.4,-1,-6}                          | (-2.06896551724,-5.1724137931)
+ (1e-300,-1e-300)  | {-0.000184615384615,-1,15.3846153846} | (0.00284023658959,15.3846148603)
+ (1e-300,-1e-300)  | {3,NaN,5}                             | 
+ (1e-300,-1e-300)  | {NaN,NaN,NaN}                         | 
+ (1e-300,-1e-300)  | {0,-1,3}                              | (1e-300,3)
+ (1e-300,-1e-300)  | {-1,0,3}                              | (3,-1e-300)
+ (1e+300,Infinity) | {0,-1,5}                              | (1e+300,5)
+ (1e+300,Infinity) | {1,0,5}                               | 
+ (1e+300,Infinity) | {0,3,0}                               | (1e+300,0)
+ (1e+300,Infinity) | {1,-1,0}                              | (Infinity,NaN)
+ (1e+300,Infinity) | {-0.4,-1,-6}                          | (-Infinity,NaN)
+ (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} | (-Infinity,NaN)
+ (1e+300,Infinity) | {3,NaN,5}                             | 
+ (1e+300,Infinity) | {NaN,NaN,NaN}                         | 
+ (1e+300,Infinity) | {0,-1,3}                              | (1e+300,3)
+ (1e+300,Infinity) | {-1,0,3}                              | 
+ (NaN,NaN)         | {0,-1,5}                              | 
+ (NaN,NaN)         | {1,0,5}                               | 
+ (NaN,NaN)         | {0,3,0}                               | 
+ (NaN,NaN)         | {1,-1,0}                              | 
+ (NaN,NaN)         | {-0.4,-1,-6}                          | 
+ (NaN,NaN)         | {-0.000184615384615,-1,15.3846153846} | 
+ (NaN,NaN)         | {3,NaN,5}                             | 
+ (NaN,NaN)         | {NaN,NaN,NaN}                         | 
+ (NaN,NaN)         | {0,-1,3}                              | 
+ (NaN,NaN)         | {-1,0,3}                              | 
+ (10,10)           | {0,-1,5}                              | (10,5)
+ (10,10)           | {1,0,5}                               | (-5,10)
+ (10,10)           | {0,3,0}                               | (10,0)
+ (10,10)           | {1,-1,0}                              | (10,10)
+ (10,10)           | {-0.4,-1,-6}                          | (3.10344827586,-7.24137931034)
+ (10,10)           | {-0.000184615384615,-1,15.3846153846} | (10.000993742,15.3827690473)
+ (10,10)           | {3,NaN,5}                             | 
+ (10,10)           | {NaN,NaN,NaN}                         | 
+ (10,10)           | {0,-1,3}                              | (10,3)
+ (10,10)           | {-1,0,3}                              | (3,10)
+(90 rows)
+
+-- Closest point to line segment
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LSEG_TBL l;
+        f1         |               s               |             ?column?             
+-------------------+-------------------------------+----------------------------------
+ (0,0)             | [(1,2),(3,4)]                 | (1,2)
+ (0,0)             | [(0,0),(6,6)]                 | (0,0)
+ (0,0)             | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ (0,0)             | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
+ (0,0)             | [(11,22),(33,44)]             | (11,22)
+ (0,0)             | [(-10,2),(-10,3)]             | (-10,2)
+ (0,0)             | [(0,-20),(30,-20)]            | (0,-20)
+ (0,0)             | [(NaN,1),(NaN,90)]            | 
+ (-10,0)           | [(1,2),(3,4)]                 | (1,2)
+ (-10,0)           | [(0,0),(6,6)]                 | (0,0)
+ (-10,0)           | [(10,-10),(-3,-4)]            | (-3,-4)
+ (-10,0)           | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
+ (-10,0)           | [(11,22),(33,44)]             | (11,22)
+ (-10,0)           | [(-10,2),(-10,3)]             | (-10,2)
+ (-10,0)           | [(0,-20),(30,-20)]            | (0,-20)
+ (-10,0)           | [(NaN,1),(NaN,90)]            | 
+ (-3,4)            | [(1,2),(3,4)]                 | (1,2)
+ (-3,4)            | [(0,0),(6,6)]                 | (0.5,0.5)
+ (-3,4)            | [(10,-10),(-3,-4)]            | (-3,-4)
+ (-3,4)            | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
+ (-3,4)            | [(11,22),(33,44)]             | (11,22)
+ (-3,4)            | [(-10,2),(-10,3)]             | (-10,3)
+ (-3,4)            | [(0,-20),(30,-20)]            | (0,-20)
+ (-3,4)            | [(NaN,1),(NaN,90)]            | 
+ (5.1,34.5)        | [(1,2),(3,4)]                 | (3,4)
+ (5.1,34.5)        | [(0,0),(6,6)]                 | (6,6)
+ (5.1,34.5)        | [(10,-10),(-3,-4)]            | (-3,-4)
+ (5.1,34.5)        | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
+ (5.1,34.5)        | [(11,22),(33,44)]             | (14.3,25.3)
+ (5.1,34.5)        | [(-10,2),(-10,3)]             | (-10,3)
+ (5.1,34.5)        | [(0,-20),(30,-20)]            | (5.1,-20)
+ (5.1,34.5)        | [(NaN,1),(NaN,90)]            | 
+ (-5,-12)          | [(1,2),(3,4)]                 | (1,2)
+ (-5,-12)          | [(0,0),(6,6)]                 | (0,0)
+ (-5,-12)          | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
+ (-5,-12)          | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
+ (-5,-12)          | [(11,22),(33,44)]             | (11,22)
+ (-5,-12)          | [(-10,2),(-10,3)]             | (-10,2)
+ (-5,-12)          | [(0,-20),(30,-20)]            | (0,-20)
+ (-5,-12)          | [(NaN,1),(NaN,90)]            | 
+ (1e-300,-1e-300)  | [(1,2),(3,4)]                 | (1,2)
+ (1e-300,-1e-300)  | [(0,0),(6,6)]                 | (0,0)
+ (1e-300,-1e-300)  | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ (1e-300,-1e-300)  | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
+ (1e-300,-1e-300)  | [(11,22),(33,44)]             | (11,22)
+ (1e-300,-1e-300)  | [(-10,2),(-10,3)]             | (-10,2)
+ (1e-300,-1e-300)  | [(0,-20),(30,-20)]            | (0,-20)
+ (1e-300,-1e-300)  | [(NaN,1),(NaN,90)]            | 
+ (1e+300,Infinity) | [(1,2),(3,4)]                 | (3,4)
+ (1e+300,Infinity) | [(0,0),(6,6)]                 | (6,6)
+ (1e+300,Infinity) | [(10,-10),(-3,-4)]            | (-3,-4)
+ (1e+300,Infinity) | [(-1000000,200),(300000,-40)] | (300000,-40)
+ (1e+300,Infinity) | [(11,22),(33,44)]             | (33,44)
+ (1e+300,Infinity) | [(-10,2),(-10,3)]             | (-10,3)
+ (1e+300,Infinity) | [(0,-20),(30,-20)]            | (30,-20)
+ (1e+300,Infinity) | [(NaN,1),(NaN,90)]            | (NaN,90)
+ (NaN,NaN)         | [(1,2),(3,4)]                 | 
+ (NaN,NaN)         | [(0,0),(6,6)]                 | 
+ (NaN,NaN)         | [(10,-10),(-3,-4)]            | 
+ (NaN,NaN)         | [(-1000000,200),(300000,-40)] | 
+ (NaN,NaN)         | [(11,22),(33,44)]             | 
+ (NaN,NaN)         | [(-10,2),(-10,3)]             | 
+ (NaN,NaN)         | [(0,-20),(30,-20)]            | 
+ (NaN,NaN)         | [(NaN,1),(NaN,90)]            | 
+ (10,10)           | [(1,2),(3,4)]                 | (3,4)
+ (10,10)           | [(0,0),(6,6)]                 | (6,6)
+ (10,10)           | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
+ (10,10)           | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
+ (10,10)           | [(11,22),(33,44)]             | (11,22)
+ (10,10)           | [(-10,2),(-10,3)]             | (-10,3)
+ (10,10)           | [(0,-20),(30,-20)]            | (10,-20)
+ (10,10)           | [(NaN,1),(NaN,90)]            | 
+(72 rows)
+
+-- Closest point to box
+SELECT p.f1, b.f1, p.f1 ## b.f1 FROM POINT_TBL p, BOX_TBL b;
+        f1         |         f1          |   ?column?   
+-------------------+---------------------+--------------
+ (0,0)             | (2,2),(0,0)         | (0,0)
+ (0,0)             | (3,3),(1,1)         | (1,1)
+ (0,0)             | (-2,2),(-8,-10)     | (-2,0)
+ (0,0)             | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (0,0)             | (3,3),(3,3)         | (3,3)
+ (-10,0)           | (2,2),(0,0)         | (0,0)
+ (-10,0)           | (3,3),(1,1)         | (1,1)
+ (-10,0)           | (-2,2),(-8,-10)     | (-8,0)
+ (-10,0)           | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (-10,0)           | (3,3),(3,3)         | (3,3)
+ (-3,4)            | (2,2),(0,0)         | (0,2)
+ (-3,4)            | (3,3),(1,1)         | (1,3)
+ (-3,4)            | (-2,2),(-8,-10)     | (-3,2)
+ (-3,4)            | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (-3,4)            | (3,3),(3,3)         | (3,3)
+ (5.1,34.5)        | (2,2),(0,0)         | (2,2)
+ (5.1,34.5)        | (3,3),(1,1)         | (3,3)
+ (5.1,34.5)        | (-2,2),(-8,-10)     | (-2,2)
+ (5.1,34.5)        | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (5.1,34.5)        | (3,3),(3,3)         | (3,3)
+ (-5,-12)          | (2,2),(0,0)         | (0,0)
+ (-5,-12)          | (3,3),(1,1)         | (1,1)
+ (-5,-12)          | (-2,2),(-8,-10)     | (-5,-10)
+ (-5,-12)          | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (-5,-12)          | (3,3),(3,3)         | (3,3)
+ (1e-300,-1e-300)  | (2,2),(0,0)         | (0,0)
+ (1e-300,-1e-300)  | (3,3),(1,1)         | (1,1)
+ (1e-300,-1e-300)  | (-2,2),(-8,-10)     | (-2,-1e-300)
+ (1e-300,-1e-300)  | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ (1e-300,-1e-300)  | (3,3),(3,3)         | (3,3)
+ (1e+300,Infinity) | (2,2),(0,0)         | (0,2)
+ (1e+300,Infinity) | (3,3),(1,1)         | (1,3)
+ (1e+300,Infinity) | (-2,2),(-8,-10)     | (-8,2)
+ (1e+300,Infinity) | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (1e+300,Infinity) | (3,3),(3,3)         | (3,3)
+ (NaN,NaN)         | (2,2),(0,0)         | 
+ (NaN,NaN)         | (3,3),(1,1)         | 
+ (NaN,NaN)         | (-2,2),(-8,-10)     | 
+ (NaN,NaN)         | (2.5,3.5),(2.5,2.5) | 
+ (NaN,NaN)         | (3,3),(3,3)         | 
+ (10,10)           | (2,2),(0,0)         | (2,2)
+ (10,10)           | (3,3),(1,1)         | (3,3)
+ (10,10)           | (-2,2),(-8,-10)     | (-2,2)
+ (10,10)           | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ (10,10)           | (3,3),(3,3)         | (3,3)
+(45 rows)
+
+-- On line
+SELECT p.f1, l.s FROM POINT_TBL p, LINE_TBL l WHERE p.f1 <@ l.s;
+        f1        |    s     
+------------------+----------
+ (0,0)            | {0,3,0}
+ (0,0)            | {1,-1,0}
+ (-10,0)          | {0,3,0}
+ (-5,-12)         | {1,0,5}
+ (1e-300,-1e-300) | {0,3,0}
+ (1e-300,-1e-300) | {1,-1,0}
+ (10,10)          | {1,-1,0}
+(7 rows)
+
+-- On line segment
+SELECT p.f1, l.s FROM POINT_TBL p, LSEG_TBL l WHERE p.f1 <@ l.s;
+        f1        |       s       
+------------------+---------------
+ (0,0)            | [(0,0),(6,6)]
+ (1e-300,-1e-300) | [(0,0),(6,6)]
+(2 rows)
+
+-- On path
+SELECT p.f1, p1.f1 FROM POINT_TBL p, PATH_TBL p1 WHERE p.f1 <@ p1.f1;
+        f1        |            f1             
+------------------+---------------------------
+ (0,0)            | [(0,0),(3,0),(4,5),(1,6)]
+ (1e-300,-1e-300) | [(0,0),(3,0),(4,5),(1,6)]
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((1,2),(3,4))
+ (NaN,NaN)        | ((10,20))
+ (NaN,NaN)        | ((11,12),(13,14))
+(7 rows)
+
+--
+-- Lines
+--
+-- Vertical
+SELECT s FROM LINE_TBL WHERE ?| s;
+    s     
+----------
+ {1,0,5}
+ {-1,0,3}
+(2 rows)
+
+-- Horizontal
+SELECT s FROM LINE_TBL WHERE ?- s;
+    s     
+----------
+ {0,-1,5}
+ {0,3,0}
+ {0,-1,3}
+(3 rows)
+
+-- Same as line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s = l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {0,-1,5}
+ {1,0,5}                               | {1,0,5}
+ {0,3,0}                               | {0,3,0}
+ {1,-1,0}                              | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846}
+ {3,NaN,5}                             | {3,NaN,5}
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}
+ {0,-1,3}                              | {0,-1,3}
+ {-1,0,3}                              | {-1,0,3}
+(10 rows)
+
+-- Parallel to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?|| l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {0,-1,5}
+ {0,-1,5}                              | {0,3,0}
+ {0,-1,5}                              | {0,-1,3}
+ {1,0,5}                               | {1,0,5}
+ {1,0,5}                               | {-1,0,3}
+ {0,3,0}                               | {0,-1,5}
+ {0,3,0}                               | {0,3,0}
+ {0,3,0}                               | {0,-1,3}
+ {1,-1,0}                              | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,3}                              | {0,-1,5}
+ {0,-1,3}                              | {0,3,0}
+ {0,-1,3}                              | {0,-1,3}
+ {-1,0,3}                              | {1,0,5}
+ {-1,0,3}                              | {-1,0,3}
+(16 rows)
+
+-- Perpendicular to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?-| l2.s;
+    s     |    s     
+----------+----------
+ {0,-1,5} | {1,0,5}
+ {0,-1,5} | {-1,0,3}
+ {1,0,5}  | {0,-1,5}
+ {1,0,5}  | {0,3,0}
+ {1,0,5}  | {0,-1,3}
+ {0,3,0}  | {1,0,5}
+ {0,3,0}  | {-1,0,3}
+ {0,-1,3} | {1,0,5}
+ {0,-1,3} | {-1,0,3}
+ {-1,0,3} | {0,-1,5}
+ {-1,0,3} | {0,3,0}
+ {-1,0,3} | {0,-1,3}
+(12 rows)
+
+-- Distance to line
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2;
+                   s                   |                   s                   | ?column? 
+---------------------------------------+---------------------------------------+----------
+ {0,-1,5}                              | {0,-1,5}                              |        0
+ {0,-1,5}                              | {1,0,5}                               |        0
+ {0,-1,5}                              | {0,3,0}                               |        5
+ {0,-1,5}                              | {1,-1,0}                              |        0
+ {0,-1,5}                              | {-0.4,-1,-6}                          |        0
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,-1,5}                              | {3,NaN,5}                             |        0
+ {0,-1,5}                              | {NaN,NaN,NaN}                         |        0
+ {0,-1,5}                              | {0,-1,3}                              |        2
+ {0,-1,5}                              | {-1,0,3}                              |        0
+ {1,0,5}                               | {0,-1,5}                              |        0
+ {1,0,5}                               | {1,0,5}                               |        0
+ {1,0,5}                               | {0,3,0}                               |        0
+ {1,0,5}                               | {1,-1,0}                              |        0
+ {1,0,5}                               | {-0.4,-1,-6}                          |        0
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846} |        0
+ {1,0,5}                               | {3,NaN,5}                             |        0
+ {1,0,5}                               | {NaN,NaN,NaN}                         |        0
+ {1,0,5}                               | {0,-1,3}                              |        0
+ {1,0,5}                               | {-1,0,3}                              |        8
+ {0,3,0}                               | {0,-1,5}                              |        5
+ {0,3,0}                               | {1,0,5}                               |        0
+ {0,3,0}                               | {0,3,0}                               |        0
+ {0,3,0}                               | {1,-1,0}                              |        0
+ {0,3,0}                               | {-0.4,-1,-6}                          |        0
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,3,0}                               | {3,NaN,5}                             |        0
+ {0,3,0}                               | {NaN,NaN,NaN}                         |        0
+ {0,3,0}                               | {0,-1,3}                              |        3
+ {0,3,0}                               | {-1,0,3}                              |        0
+ {1,-1,0}                              | {0,-1,5}                              |        0
+ {1,-1,0}                              | {1,0,5}                               |        0
+ {1,-1,0}                              | {0,3,0}                               |        0
+ {1,-1,0}                              | {1,-1,0}                              |        0
+ {1,-1,0}                              | {-0.4,-1,-6}                          |        0
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {1,-1,0}                              | {3,NaN,5}                             |        0
+ {1,-1,0}                              | {NaN,NaN,NaN}                         |        0
+ {1,-1,0}                              | {0,-1,3}                              |        0
+ {1,-1,0}                              | {-1,0,3}                              |        0
+ {-0.4,-1,-6}                          | {0,-1,5}                              |        0
+ {-0.4,-1,-6}                          | {1,0,5}                               |        0
+ {-0.4,-1,-6}                          | {0,3,0}                               |        0
+ {-0.4,-1,-6}                          | {1,-1,0}                              |        0
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}                          |        0
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846} |        0
+ {-0.4,-1,-6}                          | {3,NaN,5}                             |        0
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}                         |        0
+ {-0.4,-1,-6}                          | {0,-1,3}                              |        0
+ {-0.4,-1,-6}                          | {-1,0,3}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}                               |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}                               |        0
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}                          |        0
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} |        0
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}                             |        0
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}                         |        0
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}                              |        0
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}                              |        0
+ {3,NaN,5}                             | {0,-1,5}                              |        0
+ {3,NaN,5}                             | {1,0,5}                               |        0
+ {3,NaN,5}                             | {0,3,0}                               |        0
+ {3,NaN,5}                             | {1,-1,0}                              |        0
+ {3,NaN,5}                             | {-0.4,-1,-6}                          |        0
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846} |        0
+ {3,NaN,5}                             | {3,NaN,5}                             |        0
+ {3,NaN,5}                             | {NaN,NaN,NaN}                         |        0
+ {3,NaN,5}                             | {0,-1,3}                              |        0
+ {3,NaN,5}                             | {-1,0,3}                              |        0
+ {NaN,NaN,NaN}                         | {0,-1,5}                              |        0
+ {NaN,NaN,NaN}                         | {1,0,5}                               |        0
+ {NaN,NaN,NaN}                         | {0,3,0}                               |        0
+ {NaN,NaN,NaN}                         | {1,-1,0}                              |        0
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}                          |        0
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846} |        0
+ {NaN,NaN,NaN}                         | {3,NaN,5}                             |        0
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}                         |        0
+ {NaN,NaN,NaN}                         | {0,-1,3}                              |        0
+ {NaN,NaN,NaN}                         | {-1,0,3}                              |        0
+ {0,-1,3}                              | {0,-1,5}                              |        2
+ {0,-1,3}                              | {1,0,5}                               |        0
+ {0,-1,3}                              | {0,3,0}                               |        3
+ {0,-1,3}                              | {1,-1,0}                              |        0
+ {0,-1,3}                              | {-0.4,-1,-6}                          |        0
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {0,-1,3}                              | {3,NaN,5}                             |        0
+ {0,-1,3}                              | {NaN,NaN,NaN}                         |        0
+ {0,-1,3}                              | {0,-1,3}                              |        0
+ {0,-1,3}                              | {-1,0,3}                              |        0
+ {-1,0,3}                              | {0,-1,5}                              |        0
+ {-1,0,3}                              | {1,0,5}                               |        8
+ {-1,0,3}                              | {0,3,0}                               |        0
+ {-1,0,3}                              | {1,-1,0}                              |        0
+ {-1,0,3}                              | {-0.4,-1,-6}                          |        0
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846} |        0
+ {-1,0,3}                              | {3,NaN,5}                             |        0
+ {-1,0,3}                              | {NaN,NaN,NaN}                         |        0
+ {-1,0,3}                              | {0,-1,3}                              |        0
+ {-1,0,3}                              | {-1,0,3}                              |        0
+(100 rows)
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LINE_TBL l, BOX_TBL b;
+ERROR:  function "dist_lb" not implemented
+-- Intersect with line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?# l2.s;
+                   s                   |                   s                   
+---------------------------------------+---------------------------------------
+ {0,-1,5}                              | {1,0,5}
+ {0,-1,5}                              | {1,-1,0}
+ {0,-1,5}                              | {-0.4,-1,-6}
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,5}                              | {3,NaN,5}
+ {0,-1,5}                              | {NaN,NaN,NaN}
+ {0,-1,5}                              | {-1,0,3}
+ {1,0,5}                               | {0,-1,5}
+ {1,0,5}                               | {0,3,0}
+ {1,0,5}                               | {1,-1,0}
+ {1,0,5}                               | {-0.4,-1,-6}
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846}
+ {1,0,5}                               | {3,NaN,5}
+ {1,0,5}                               | {NaN,NaN,NaN}
+ {1,0,5}                               | {0,-1,3}
+ {0,3,0}                               | {1,0,5}
+ {0,3,0}                               | {1,-1,0}
+ {0,3,0}                               | {-0.4,-1,-6}
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846}
+ {0,3,0}                               | {3,NaN,5}
+ {0,3,0}                               | {NaN,NaN,NaN}
+ {0,3,0}                               | {-1,0,3}
+ {1,-1,0}                              | {0,-1,5}
+ {1,-1,0}                              | {1,0,5}
+ {1,-1,0}                              | {0,3,0}
+ {1,-1,0}                              | {-0.4,-1,-6}
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846}
+ {1,-1,0}                              | {3,NaN,5}
+ {1,-1,0}                              | {NaN,NaN,NaN}
+ {1,-1,0}                              | {0,-1,3}
+ {1,-1,0}                              | {-1,0,3}
+ {-0.4,-1,-6}                          | {0,-1,5}
+ {-0.4,-1,-6}                          | {1,0,5}
+ {-0.4,-1,-6}                          | {0,3,0}
+ {-0.4,-1,-6}                          | {1,-1,0}
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846}
+ {-0.4,-1,-6}                          | {3,NaN,5}
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}
+ {-0.4,-1,-6}                          | {0,-1,3}
+ {-0.4,-1,-6}                          | {-1,0,3}
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}
+ {3,NaN,5}                             | {0,-1,5}
+ {3,NaN,5}                             | {1,0,5}
+ {3,NaN,5}                             | {0,3,0}
+ {3,NaN,5}                             | {1,-1,0}
+ {3,NaN,5}                             | {-0.4,-1,-6}
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846}
+ {3,NaN,5}                             | {3,NaN,5}
+ {3,NaN,5}                             | {NaN,NaN,NaN}
+ {3,NaN,5}                             | {0,-1,3}
+ {3,NaN,5}                             | {-1,0,3}
+ {NaN,NaN,NaN}                         | {0,-1,5}
+ {NaN,NaN,NaN}                         | {1,0,5}
+ {NaN,NaN,NaN}                         | {0,3,0}
+ {NaN,NaN,NaN}                         | {1,-1,0}
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846}
+ {NaN,NaN,NaN}                         | {3,NaN,5}
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}
+ {NaN,NaN,NaN}                         | {0,-1,3}
+ {NaN,NaN,NaN}                         | {-1,0,3}
+ {0,-1,3}                              | {1,0,5}
+ {0,-1,3}                              | {1,-1,0}
+ {0,-1,3}                              | {-0.4,-1,-6}
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846}
+ {0,-1,3}                              | {3,NaN,5}
+ {0,-1,3}                              | {NaN,NaN,NaN}
+ {0,-1,3}                              | {-1,0,3}
+ {-1,0,3}                              | {0,-1,5}
+ {-1,0,3}                              | {0,3,0}
+ {-1,0,3}                              | {1,-1,0}
+ {-1,0,3}                              | {-0.4,-1,-6}
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846}
+ {-1,0,3}                              | {3,NaN,5}
+ {-1,0,3}                              | {NaN,NaN,NaN}
+ {-1,0,3}                              | {0,-1,3}
+(84 rows)
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LINE_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+      s       |         f1          
+--------------+---------------------
+ {1,0,5}      | (-2,2),(-8,-10)
+ {0,3,0}      | (2,2),(0,0)
+ {0,3,0}      | (-2,2),(-8,-10)
+ {1,-1,0}     | (2,2),(0,0)
+ {1,-1,0}     | (3,3),(1,1)
+ {1,-1,0}     | (-2,2),(-8,-10)
+ {1,-1,0}     | (2.5,3.5),(2.5,2.5)
+ {1,-1,0}     | (3,3),(3,3)
+ {-0.4,-1,-6} | (-2,2),(-8,-10)
+ {0,-1,3}     | (3,3),(1,1)
+ {0,-1,3}     | (2.5,3.5),(2.5,2.5)
+ {0,-1,3}     | (3,3),(3,3)
+ {-1,0,3}     | (3,3),(1,1)
+(13 rows)
+
+-- Intersection point with line
+SELECT l1.s, l2.s, l1.s # l2.s FROM LINE_TBL l1, LINE_TBL l2;
+                   s                   |                   s                   |             ?column?              
+---------------------------------------+---------------------------------------+------------------------------------
+ {0,-1,5}                              | {0,-1,5}                              | 
+ {0,-1,5}                              | {1,0,5}                               | (-5,5)
+ {0,-1,5}                              | {0,3,0}                               | 
+ {0,-1,5}                              | {1,-1,0}                              | (5,5)
+ {0,-1,5}                              | {-0.4,-1,-6}                          | (-27.5,5)
+ {0,-1,5}                              | {-0.000184615384615,-1,15.3846153846} | (56250,5)
+ {0,-1,5}                              | {3,NaN,5}                             | (NaN,NaN)
+ {0,-1,5}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,-1,5}                              | {0,-1,3}                              | 
+ {0,-1,5}                              | {-1,0,3}                              | (3,5)
+ {1,0,5}                               | {0,-1,5}                              | (-5,5)
+ {1,0,5}                               | {1,0,5}                               | 
+ {1,0,5}                               | {0,3,0}                               | (-5,0)
+ {1,0,5}                               | {1,-1,0}                              | (-5,-5)
+ {1,0,5}                               | {-0.4,-1,-6}                          | (-5,-4)
+ {1,0,5}                               | {-0.000184615384615,-1,15.3846153846} | (-5,15.3855384615)
+ {1,0,5}                               | {3,NaN,5}                             | (NaN,NaN)
+ {1,0,5}                               | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {1,0,5}                               | {0,-1,3}                              | (-5,3)
+ {1,0,5}                               | {-1,0,3}                              | 
+ {0,3,0}                               | {0,-1,5}                              | 
+ {0,3,0}                               | {1,0,5}                               | (-5,0)
+ {0,3,0}                               | {0,3,0}                               | 
+ {0,3,0}                               | {1,-1,0}                              | (0,0)
+ {0,3,0}                               | {-0.4,-1,-6}                          | (-15,0)
+ {0,3,0}                               | {-0.000184615384615,-1,15.3846153846} | (83333.3333333,0)
+ {0,3,0}                               | {3,NaN,5}                             | (NaN,NaN)
+ {0,3,0}                               | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,3,0}                               | {0,-1,3}                              | 
+ {0,3,0}                               | {-1,0,3}                              | (3,0)
+ {1,-1,0}                              | {0,-1,5}                              | (5,5)
+ {1,-1,0}                              | {1,0,5}                               | (-5,-5)
+ {1,-1,0}                              | {0,3,0}                               | (0,0)
+ {1,-1,0}                              | {1,-1,0}                              | 
+ {1,-1,0}                              | {-0.4,-1,-6}                          | (-4.28571428571,-4.28571428571)
+ {1,-1,0}                              | {-0.000184615384615,-1,15.3846153846} | (15.3817756722,15.3817756722)
+ {1,-1,0}                              | {3,NaN,5}                             | (NaN,NaN)
+ {1,-1,0}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {1,-1,0}                              | {0,-1,3}                              | (3,3)
+ {1,-1,0}                              | {-1,0,3}                              | (3,3)
+ {-0.4,-1,-6}                          | {0,-1,5}                              | (-27.5,5)
+ {-0.4,-1,-6}                          | {1,0,5}                               | (-5,-4)
+ {-0.4,-1,-6}                          | {0,3,0}                               | (-15,0)
+ {-0.4,-1,-6}                          | {1,-1,0}                              | (-4.28571428571,-4.28571428571)
+ {-0.4,-1,-6}                          | {-0.4,-1,-6}                          | 
+ {-0.4,-1,-6}                          | {-0.000184615384615,-1,15.3846153846} | (-53.4862244113,15.3944897645)
+ {-0.4,-1,-6}                          | {3,NaN,5}                             | (NaN,NaN)
+ {-0.4,-1,-6}                          | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-0.4,-1,-6}                          | {0,-1,3}                              | (-22.5,3)
+ {-0.4,-1,-6}                          | {-1,0,3}                              | (3,-7.2)
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,5}                              | (56250,5)
+ {-0.000184615384615,-1,15.3846153846} | {1,0,5}                               | (-5,15.3855384615)
+ {-0.000184615384615,-1,15.3846153846} | {0,3,0}                               | (83333.3333333,-1.7763568394e-015)
+ {-0.000184615384615,-1,15.3846153846} | {1,-1,0}                              | (15.3817756722,15.3817756722)
+ {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6}                          | (-53.4862244113,15.3944897645)
+ {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} | 
+ {-0.000184615384615,-1,15.3846153846} | {3,NaN,5}                             | (NaN,NaN)
+ {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-0.000184615384615,-1,15.3846153846} | {0,-1,3}                              | (67083.3333333,3)
+ {-0.000184615384615,-1,15.3846153846} | {-1,0,3}                              | (3,15.3840615385)
+ {3,NaN,5}                             | {0,-1,5}                              | (NaN,NaN)
+ {3,NaN,5}                             | {1,0,5}                               | (NaN,NaN)
+ {3,NaN,5}                             | {0,3,0}                               | (NaN,NaN)
+ {3,NaN,5}                             | {1,-1,0}                              | (NaN,NaN)
+ {3,NaN,5}                             | {-0.4,-1,-6}                          | (NaN,NaN)
+ {3,NaN,5}                             | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ {3,NaN,5}                             | {3,NaN,5}                             | (NaN,NaN)
+ {3,NaN,5}                             | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {3,NaN,5}                             | {0,-1,3}                              | (NaN,NaN)
+ {3,NaN,5}                             | {-1,0,3}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,-1,5}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {1,0,5}                               | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,3,0}                               | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {1,-1,0}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-0.4,-1,-6}                          | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {3,NaN,5}                             | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {0,-1,3}                              | (NaN,NaN)
+ {NaN,NaN,NaN}                         | {-1,0,3}                              | (NaN,NaN)
+ {0,-1,3}                              | {0,-1,5}                              | 
+ {0,-1,3}                              | {1,0,5}                               | (-5,3)
+ {0,-1,3}                              | {0,3,0}                               | 
+ {0,-1,3}                              | {1,-1,0}                              | (3,3)
+ {0,-1,3}                              | {-0.4,-1,-6}                          | (-22.5,3)
+ {0,-1,3}                              | {-0.000184615384615,-1,15.3846153846} | (67083.3333333,3)
+ {0,-1,3}                              | {3,NaN,5}                             | (NaN,NaN)
+ {0,-1,3}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {0,-1,3}                              | {0,-1,3}                              | 
+ {0,-1,3}                              | {-1,0,3}                              | (3,3)
+ {-1,0,3}                              | {0,-1,5}                              | (3,5)
+ {-1,0,3}                              | {1,0,5}                               | 
+ {-1,0,3}                              | {0,3,0}                               | (3,0)
+ {-1,0,3}                              | {1,-1,0}                              | (3,3)
+ {-1,0,3}                              | {-0.4,-1,-6}                          | (3,-7.2)
+ {-1,0,3}                              | {-0.000184615384615,-1,15.3846153846} | (3,15.3840615385)
+ {-1,0,3}                              | {3,NaN,5}                             | (NaN,NaN)
+ {-1,0,3}                              | {NaN,NaN,NaN}                         | (NaN,NaN)
+ {-1,0,3}                              | {0,-1,3}                              | (3,3)
+ {-1,0,3}                              | {-1,0,3}                              | 
+(100 rows)
+
+-- Closest point to line segment
+SELECT l.s, l1.s, l.s ## l1.s FROM LINE_TBL l, LSEG_TBL l1;
+                   s                   |               s               |             ?column?              
+---------------------------------------+-------------------------------+------------------------------------
+ {0,-1,5}                              | [(1,2),(3,4)]                 | (3,4)
+ {0,-1,5}                              | [(0,0),(6,6)]                 | (5,5)
+ {0,-1,5}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,-1,5}                              | [(-1000000,200),(300000,-40)] | (56250,5)
+ {0,-1,5}                              | [(11,22),(33,44)]             | (11,22)
+ {0,-1,5}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {0,-1,5}                              | [(0,-20),(30,-20)]            | 
+ {0,-1,5}                              | [(NaN,1),(NaN,90)]            | 
+ {1,0,5}                               | [(1,2),(3,4)]                 | (1,2)
+ {1,0,5}                               | [(0,0),(6,6)]                 | (0,0)
+ {1,0,5}                               | [(10,-10),(-3,-4)]            | (-3,-4)
+ {1,0,5}                               | [(-1000000,200),(300000,-40)] | (-5,15.3855384615)
+ {1,0,5}                               | [(11,22),(33,44)]             | (11,22)
+ {1,0,5}                               | [(-10,2),(-10,3)]             | 
+ {1,0,5}                               | [(0,-20),(30,-20)]            | (0,-20)
+ {1,0,5}                               | [(NaN,1),(NaN,90)]            | 
+ {0,3,0}                               | [(1,2),(3,4)]                 | (1,2)
+ {0,3,0}                               | [(0,0),(6,6)]                 | (0,0)
+ {0,3,0}                               | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,3,0}                               | [(-1000000,200),(300000,-40)] | (83333.3333333,-1.7763568394e-015)
+ {0,3,0}                               | [(11,22),(33,44)]             | (11,22)
+ {0,3,0}                               | [(-10,2),(-10,3)]             | (-10,2)
+ {0,3,0}                               | [(0,-20),(30,-20)]            | 
+ {0,3,0}                               | [(NaN,1),(NaN,90)]            | 
+ {1,-1,0}                              | [(1,2),(3,4)]                 | 
+ {1,-1,0}                              | [(0,0),(6,6)]                 | 
+ {1,-1,0}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {1,-1,0}                              | [(-1000000,200),(300000,-40)] | (15.3817756722,15.3817756722)
+ {1,-1,0}                              | [(11,22),(33,44)]             | 
+ {1,-1,0}                              | [(-10,2),(-10,3)]             | (-10,2)
+ {1,-1,0}                              | [(0,-20),(30,-20)]            | (0,-20)
+ {1,-1,0}                              | [(NaN,1),(NaN,90)]            | 
+ {-0.4,-1,-6}                          | [(1,2),(3,4)]                 | (1,2)
+ {-0.4,-1,-6}                          | [(0,0),(6,6)]                 | (0,0)
+ {-0.4,-1,-6}                          | [(10,-10),(-3,-4)]            | (10,-10)
+ {-0.4,-1,-6}                          | [(-1000000,200),(300000,-40)] | (-53.4862244113,15.3944897645)
+ {-0.4,-1,-6}                          | [(11,22),(33,44)]             | (11,22)
+ {-0.4,-1,-6}                          | [(-10,2),(-10,3)]             | (-10,2)
+ {-0.4,-1,-6}                          | [(0,-20),(30,-20)]            | (30,-20)
+ {-0.4,-1,-6}                          | [(NaN,1),(NaN,90)]            | 
+ {-0.000184615384615,-1,15.3846153846} | [(1,2),(3,4)]                 | (3,4)
+ {-0.000184615384615,-1,15.3846153846} | [(0,0),(6,6)]                 | (6,6)
+ {-0.000184615384615,-1,15.3846153846} | [(10,-10),(-3,-4)]            | (-3,-4)
+ {-0.000184615384615,-1,15.3846153846} | [(-1000000,200),(300000,-40)] | 
+ {-0.000184615384615,-1,15.3846153846} | [(11,22),(33,44)]             | (11,22)
+ {-0.000184615384615,-1,15.3846153846} | [(-10,2),(-10,3)]             | (-10,3)
+ {-0.000184615384615,-1,15.3846153846} | [(0,-20),(30,-20)]            | (30,-20)
+ {-0.000184615384615,-1,15.3846153846} | [(NaN,1),(NaN,90)]            | 
+ {3,NaN,5}                             | [(1,2),(3,4)]                 | 
+ {3,NaN,5}                             | [(0,0),(6,6)]                 | 
+ {3,NaN,5}                             | [(10,-10),(-3,-4)]            | 
+ {3,NaN,5}                             | [(-1000000,200),(300000,-40)] | 
+ {3,NaN,5}                             | [(11,22),(33,44)]             | 
+ {3,NaN,5}                             | [(-10,2),(-10,3)]             | 
+ {3,NaN,5}                             | [(0,-20),(30,-20)]            | 
+ {3,NaN,5}                             | [(NaN,1),(NaN,90)]            | 
+ {NaN,NaN,NaN}                         | [(1,2),(3,4)]                 | 
+ {NaN,NaN,NaN}                         | [(0,0),(6,6)]                 | 
+ {NaN,NaN,NaN}                         | [(10,-10),(-3,-4)]            | 
+ {NaN,NaN,NaN}                         | [(-1000000,200),(300000,-40)] | 
+ {NaN,NaN,NaN}                         | [(11,22),(33,44)]             | 
+ {NaN,NaN,NaN}                         | [(-10,2),(-10,3)]             | 
+ {NaN,NaN,NaN}                         | [(0,-20),(30,-20)]            | 
+ {NaN,NaN,NaN}                         | [(NaN,1),(NaN,90)]            | 
+ {0,-1,3}                              | [(1,2),(3,4)]                 | (2,3)
+ {0,-1,3}                              | [(0,0),(6,6)]                 | (3,3)
+ {0,-1,3}                              | [(10,-10),(-3,-4)]            | (-3,-4)
+ {0,-1,3}                              | [(-1000000,200),(300000,-40)] | (67083.3333333,3)
+ {0,-1,3}                              | [(11,22),(33,44)]             | (11,22)
+ {0,-1,3}                              | [(-10,2),(-10,3)]             | (-10,3)
+ {0,-1,3}                              | [(0,-20),(30,-20)]            | 
+ {0,-1,3}                              | [(NaN,1),(NaN,90)]            | 
+ {-1,0,3}                              | [(1,2),(3,4)]                 | (3,4)
+ {-1,0,3}                              | [(0,0),(6,6)]                 | (3,3)
+ {-1,0,3}                              | [(10,-10),(-3,-4)]            | (3,-6.76923076923)
+ {-1,0,3}                              | [(-1000000,200),(300000,-40)] | (3,15.3840615385)
+ {-1,0,3}                              | [(11,22),(33,44)]             | (11,22)
+ {-1,0,3}                              | [(-10,2),(-10,3)]             | 
+ {-1,0,3}                              | [(0,-20),(30,-20)]            | (3,-20)
+ {-1,0,3}                              | [(NaN,1),(NaN,90)]            | 
+(80 rows)
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LINE_TBL l, BOX_TBL b;
+ERROR:  function "close_lb" not implemented
 --
 -- Line segments
 --
 -- intersection
 SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
    FROM LSEG_TBL l, POINT_TBL p;
 ERROR:  operator does not exist: lseg # point
 LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
                                            ^
 HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
+-- Length
+SELECT s, @-@ s FROM LSEG_TBL;
+               s               |   ?column?    
+-------------------------------+---------------
+ [(1,2),(3,4)]                 | 2.82842712475
+ [(0,0),(6,6)]                 | 8.48528137424
+ [(10,-10),(-3,-4)]            | 14.3178210633
+ [(-1000000,200),(300000,-40)] | 1300000.02215
+ [(11,22),(33,44)]             | 31.1126983722
+ [(-10,2),(-10,3)]             |             1
+ [(0,-20),(30,-20)]            |            30
+ [(NaN,1),(NaN,90)]            |           NaN
+(8 rows)
+
+-- Vertical
+SELECT s FROM LSEG_TBL WHERE ?| s;
+         s         
+-------------------
+ [(-10,2),(-10,3)]
+(1 row)
+
+-- Horizontal
+SELECT s FROM LSEG_TBL WHERE ?- s;
+         s          
+--------------------
+ [(0,-20),(30,-20)]
+(1 row)
+
+-- Center
+SELECT s, @@ s FROM LSEG_TBL;
+               s               |   ?column?   
+-------------------------------+--------------
+ [(1,2),(3,4)]                 | (2,3)
+ [(0,0),(6,6)]                 | (3,3)
+ [(10,-10),(-3,-4)]            | (3.5,-7)
+ [(-1000000,200),(300000,-40)] | (-350000,80)
+ [(11,22),(33,44)]             | (22,33)
+ [(-10,2),(-10,3)]             | (-10,2.5)
+ [(0,-20),(30,-20)]            | (15,-20)
+ [(NaN,1),(NaN,90)]            | (NaN,45.5)
+(8 rows)
+
+-- To point
+SELECT s, s::point FROM LSEG_TBL;
+               s               |      s       
+-------------------------------+--------------
+ [(1,2),(3,4)]                 | (2,3)
+ [(0,0),(6,6)]                 | (3,3)
+ [(10,-10),(-3,-4)]            | (3.5,-7)
+ [(-1000000,200),(300000,-40)] | (-350000,80)
+ [(11,22),(33,44)]             | (22,33)
+ [(-10,2),(-10,3)]             | (-10,2.5)
+ [(0,-20),(30,-20)]            | (15,-20)
+ [(NaN,1),(NaN,90)]            | (NaN,45.5)
+(8 rows)
+
+-- Has points less than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s < l2.s;
+         s          |               s               
+--------------------+-------------------------------
+ [(1,2),(3,4)]      | [(0,0),(6,6)]
+ [(1,2),(3,4)]      | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]      | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]      | [(11,22),(33,44)]
+ [(1,2),(3,4)]      | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]      | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]      | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]      | [(11,22),(33,44)]
+ [(0,0),(6,6)]      | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)] | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)] | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]  | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]  | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]  | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]  | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]  | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]  | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]  | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)] | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)] | [(11,22),(33,44)]
+(21 rows)
+
+-- Has points less than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s <= l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(28 rows)
+
+-- Has points equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s = l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]
+(8 rows)
+
+-- Has points greater than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s >= l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(28 rows)
+
+-- Has points greater than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s > l2.s;
+               s               |         s          
+-------------------------------+--------------------
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+(21 rows)
+
+-- Has points not equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s != l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)]
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)]
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)]
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)]
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]
+(56 rows)
+
+-- Parallel with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?|| l2.s;
+               s               |               s               
+-------------------------------+-------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)]
+ [(11,22),(33,44)]             | [(1,2),(3,4)]
+ [(11,22),(33,44)]             | [(0,0),(6,6)]
+ [(11,22),(33,44)]             | [(11,22),(33,44)]
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]
+(13 rows)
+
+-- Perpendicular with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?-| l2.s;
+         s          |         s          
+--------------------+--------------------
+ [(-10,2),(-10,3)]  | [(0,-20),(30,-20)]
+ [(0,-20),(30,-20)] | [(-10,2),(-10,3)]
+(2 rows)
+
+-- Distance to line
+SELECT l.s, l1.s, l.s <-> l1.s FROM LSEG_TBL l, LINE_TBL l1;
+               s               |                   s                   |    ?column?    
+-------------------------------+---------------------------------------+----------------
+ [(1,2),(3,4)]                 | {0,-1,5}                              |              1
+ [(0,0),(6,6)]                 | {0,-1,5}                              |              0
+ [(10,-10),(-3,-4)]            | {0,-1,5}                              |              9
+ [(-1000000,200),(300000,-40)] | {0,-1,5}                              |              0
+ [(11,22),(33,44)]             | {0,-1,5}                              |             17
+ [(-10,2),(-10,3)]             | {0,-1,5}                              |              2
+ [(0,-20),(30,-20)]            | {0,-1,5}                              |             25
+ [(NaN,1),(NaN,90)]            | {0,-1,5}                              |            NaN
+ [(1,2),(3,4)]                 | {1,0,5}                               |              6
+ [(0,0),(6,6)]                 | {1,0,5}                               |              5
+ [(10,-10),(-3,-4)]            | {1,0,5}                               |              2
+ [(-1000000,200),(300000,-40)] | {1,0,5}                               |              0
+ [(11,22),(33,44)]             | {1,0,5}                               |             16
+ [(-10,2),(-10,3)]             | {1,0,5}                               |              5
+ [(0,-20),(30,-20)]            | {1,0,5}                               |              5
+ [(NaN,1),(NaN,90)]            | {1,0,5}                               |            NaN
+ [(1,2),(3,4)]                 | {0,3,0}                               |              2
+ [(0,0),(6,6)]                 | {0,3,0}                               |              0
+ [(10,-10),(-3,-4)]            | {0,3,0}                               |              4
+ [(-1000000,200),(300000,-40)] | {0,3,0}                               |              0
+ [(11,22),(33,44)]             | {0,3,0}                               |             22
+ [(-10,2),(-10,3)]             | {0,3,0}                               |              2
+ [(0,-20),(30,-20)]            | {0,3,0}                               |             20
+ [(NaN,1),(NaN,90)]            | {0,3,0}                               |            NaN
+ [(1,2),(3,4)]                 | {1,-1,0}                              | 0.707106781187
+ [(0,0),(6,6)]                 | {1,-1,0}                              |              0
+ [(10,-10),(-3,-4)]            | {1,-1,0}                              | 0.707106781187
+ [(-1000000,200),(300000,-40)] | {1,-1,0}                              |              0
+ [(11,22),(33,44)]             | {1,-1,0}                              |  7.77817459305
+ [(-10,2),(-10,3)]             | {1,-1,0}                              |  8.48528137424
+ [(0,-20),(30,-20)]            | {1,-1,0}                              |  14.1421356237
+ [(NaN,1),(NaN,90)]            | {1,-1,0}                              |            NaN
+ [(1,2),(3,4)]                 | {-0.4,-1,-6}                          |  7.79920420344
+ [(0,0),(6,6)]                 | {-0.4,-1,-6}                          |  5.57086014531
+ [(10,-10),(-3,-4)]            | {-0.4,-1,-6}                          |              0
+ [(-1000000,200),(300000,-40)] | {-0.4,-1,-6}                          |              0
+ [(11,22),(33,44)]             | {-0.4,-1,-6}                          |  30.0826447847
+ [(-10,2),(-10,3)]             | {-0.4,-1,-6}                          |  3.71390676354
+ [(0,-20),(30,-20)]            | {-0.4,-1,-6}                          |  1.85695338177
+ [(NaN,1),(NaN,90)]            | {-0.4,-1,-6}                          |            NaN
+ [(1,2),(3,4)]                 | {-0.000184615384615,-1,15.3846153846} |  11.3840613445
+ [(0,0),(6,6)]                 | {-0.000184615384615,-1,15.3846153846} |   9.3835075324
+ [(10,-10),(-3,-4)]            | {-0.000184615384615,-1,15.3846153846} |  19.3851689004
+ [(-1000000,200),(300000,-40)] | {-0.000184615384615,-1,15.3846153846} |              0
+ [(11,22),(33,44)]             | {-0.000184615384615,-1,15.3846153846} |  6.61741527185
+ [(-10,2),(-10,3)]             | {-0.000184615384615,-1,15.3846153846} |  12.3864613274
+ [(0,-20),(30,-20)]            | {-0.000184615384615,-1,15.3846153846} |  35.3790763202
+ [(NaN,1),(NaN,90)]            | {-0.000184615384615,-1,15.3846153846} |            NaN
+ [(1,2),(3,4)]                 | {3,NaN,5}                             |            NaN
+ [(0,0),(6,6)]                 | {3,NaN,5}                             |            NaN
+ [(10,-10),(-3,-4)]            | {3,NaN,5}                             |            NaN
+ [(-1000000,200),(300000,-40)] | {3,NaN,5}                             |            NaN
+ [(11,22),(33,44)]             | {3,NaN,5}                             |            NaN
+ [(-10,2),(-10,3)]             | {3,NaN,5}                             |            NaN
+ [(0,-20),(30,-20)]            | {3,NaN,5}                             |            NaN
+ [(NaN,1),(NaN,90)]            | {3,NaN,5}                             |            NaN
+ [(1,2),(3,4)]                 | {NaN,NaN,NaN}                         |            NaN
+ [(0,0),(6,6)]                 | {NaN,NaN,NaN}                         |            NaN
+ [(10,-10),(-3,-4)]            | {NaN,NaN,NaN}                         |            NaN
+ [(-1000000,200),(300000,-40)] | {NaN,NaN,NaN}                         |            NaN
+ [(11,22),(33,44)]             | {NaN,NaN,NaN}                         |            NaN
+ [(-10,2),(-10,3)]             | {NaN,NaN,NaN}                         |            NaN
+ [(0,-20),(30,-20)]            | {NaN,NaN,NaN}                         |            NaN
+ [(NaN,1),(NaN,90)]            | {NaN,NaN,NaN}                         |            NaN
+ [(1,2),(3,4)]                 | {0,-1,3}                              |              0
+ [(0,0),(6,6)]                 | {0,-1,3}                              |              0
+ [(10,-10),(-3,-4)]            | {0,-1,3}                              |              7
+ [(-1000000,200),(300000,-40)] | {0,-1,3}                              |              0
+ [(11,22),(33,44)]             | {0,-1,3}                              |             19
+ [(-10,2),(-10,3)]             | {0,-1,3}                              |              0
+ [(0,-20),(30,-20)]            | {0,-1,3}                              |             23
+ [(NaN,1),(NaN,90)]            | {0,-1,3}                              |            NaN
+ [(1,2),(3,4)]                 | {-1,0,3}                              |              0
+ [(0,0),(6,6)]                 | {-1,0,3}                              |              0
+ [(10,-10),(-3,-4)]            | {-1,0,3}                              |              0
+ [(-1000000,200),(300000,-40)] | {-1,0,3}                              |              0
+ [(11,22),(33,44)]             | {-1,0,3}                              |              8
+ [(-10,2),(-10,3)]             | {-1,0,3}                              |             13
+ [(0,-20),(30,-20)]            | {-1,0,3}                              |              0
+ [(NaN,1),(NaN,90)]            | {-1,0,3}                              |            NaN
+(80 rows)
+
+-- Distance to line segment
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               |    ?column?    
+-------------------------------+-------------------------------+----------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 |              0
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 0.707106781187
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            |  7.12398901685
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] |  11.3840613445
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             |  19.6977156036
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             |             11
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            |             22
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            |            NaN
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 0.707106781187
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 |              0
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            |  4.88901207039
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] |   9.3835075324
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             |  16.7630546142
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             |  10.1980390272
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            |             20
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            |            NaN
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 |  7.12398901685
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 |  4.88901207039
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            |              0
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] |  19.3851689004
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             |  29.4737584815
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             |  9.21954445729
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            |             10
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            |            NaN
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 |  11.3840613445
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 |   9.3835075324
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            |  19.3851689004
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] |              0
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             |  6.61741527185
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             |  12.3864613274
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            |  35.3790763202
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            |            NaN
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 |  19.6977156036
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 |  16.7630546142
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            |  29.4737584815
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] |  6.61741527185
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             |              0
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             |   28.319604517
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            |             42
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            |            NaN
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 |             11
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 |  10.1980390272
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            |  9.21954445729
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] |  12.3864613274
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             |   28.319604517
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             |              0
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            |  24.1660919472
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            |            NaN
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 |             22
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 |             20
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            |             10
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] |  35.3790763202
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             |             42
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             |  24.1660919472
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            |              0
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 |            NaN
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 |            NaN
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] |            NaN
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             |            NaN
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             |            NaN
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            |            NaN
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            |            NaN
+(64 rows)
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LSEG_TBL l, BOX_TBL b;
+               s               |         f1          |    ?column?    
+-------------------------------+---------------------+----------------
+ [(1,2),(3,4)]                 | (2,2),(0,0)         |              0
+ [(1,2),(3,4)]                 | (3,3),(1,1)         |              0
+ [(1,2),(3,4)]                 | (-2,2),(-8,-10)     |              3
+ [(1,2),(3,4)]                 | (2.5,3.5),(2.5,2.5) |              0
+ [(1,2),(3,4)]                 | (3,3),(3,3)         | 0.707106781187
+ [(0,0),(6,6)]                 | (2,2),(0,0)         |              0
+ [(0,0),(6,6)]                 | (3,3),(1,1)         |              0
+ [(0,0),(6,6)]                 | (-2,2),(-8,-10)     |              2
+ [(0,0),(6,6)]                 | (2.5,3.5),(2.5,2.5) |              0
+ [(0,0),(6,6)]                 | (3,3),(3,3)         |              0
+ [(10,-10),(-3,-4)]            | (2,2),(0,0)         |  4.88901207039
+ [(10,-10),(-3,-4)]            | (3,3),(1,1)         |  6.21602963235
+ [(10,-10),(-3,-4)]            | (-2,2),(-8,-10)     |              0
+ [(10,-10),(-3,-4)]            | (2.5,3.5),(2.5,2.5) |  8.20655597529
+ [(10,-10),(-3,-4)]            | (3,3),(3,3)         |  8.87006475627
+ [(-1000000,200),(300000,-40)] | (2,2),(0,0)         |  13.3842459258
+ [(-1000000,200),(300000,-40)] | (3,3),(1,1)         |  12.3840613274
+ [(-1000000,200),(300000,-40)] | (-2,2),(-8,-10)     |  13.3849843873
+ [(-1000000,200),(300000,-40)] | (2.5,3.5),(2.5,2.5) |  11.8841536436
+ [(-1000000,200),(300000,-40)] | (3,3),(3,3)         |  12.3840613274
+ [(11,22),(33,44)]             | (2,2),(0,0)         |  21.9317121995
+ [(11,22),(33,44)]             | (3,3),(1,1)         |  20.6155281281
+ [(11,22),(33,44)]             | (-2,2),(-8,-10)     |  23.8537208838
+ [(11,22),(33,44)]             | (2.5,3.5),(2.5,2.5) |  20.3592730715
+ [(11,22),(33,44)]             | (3,3),(3,3)         |  20.6155281281
+ [(-10,2),(-10,3)]             | (2,2),(0,0)         |             10
+ [(-10,2),(-10,3)]             | (3,3),(1,1)         |             11
+ [(-10,2),(-10,3)]             | (-2,2),(-8,-10)     |              2
+ [(-10,2),(-10,3)]             | (2.5,3.5),(2.5,2.5) |           12.5
+ [(-10,2),(-10,3)]             | (3,3),(3,3)         |             13
+ [(0,-20),(30,-20)]            | (2,2),(0,0)         |             20
+ [(0,-20),(30,-20)]            | (3,3),(1,1)         |             21
+ [(0,-20),(30,-20)]            | (-2,2),(-8,-10)     |  10.1980390272
+ [(0,-20),(30,-20)]            | (2.5,3.5),(2.5,2.5) |           22.5
+ [(0,-20),(30,-20)]            | (3,3),(3,3)         |             23
+ [(NaN,1),(NaN,90)]            | (2,2),(0,0)         |            NaN
+ [(NaN,1),(NaN,90)]            | (3,3),(1,1)         |            NaN
+ [(NaN,1),(NaN,90)]            | (-2,2),(-8,-10)     |            NaN
+ [(NaN,1),(NaN,90)]            | (2.5,3.5),(2.5,2.5) |            NaN
+ [(NaN,1),(NaN,90)]            | (3,3),(3,3)         |            NaN
+(40 rows)
+
+-- Intersect with line segment
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s ?# l1.s;
+               s               |      s       
+-------------------------------+--------------
+ [(0,0),(6,6)]                 | {0,-1,5}
+ [(-1000000,200),(300000,-40)] | {0,-1,5}
+ [(-1000000,200),(300000,-40)] | {1,0,5}
+ [(0,0),(6,6)]                 | {0,3,0}
+ [(-1000000,200),(300000,-40)] | {0,3,0}
+ [(-1000000,200),(300000,-40)] | {1,-1,0}
+ [(10,-10),(-3,-4)]            | {-0.4,-1,-6}
+ [(-1000000,200),(300000,-40)] | {-0.4,-1,-6}
+ [(1,2),(3,4)]                 | {0,-1,3}
+ [(0,0),(6,6)]                 | {0,-1,3}
+ [(-1000000,200),(300000,-40)] | {0,-1,3}
+ [(-10,2),(-10,3)]             | {0,-1,3}
+ [(1,2),(3,4)]                 | {-1,0,3}
+ [(0,0),(6,6)]                 | {-1,0,3}
+ [(10,-10),(-3,-4)]            | {-1,0,3}
+ [(-1000000,200),(300000,-40)] | {-1,0,3}
+ [(0,-20),(30,-20)]            | {-1,0,3}
+(17 rows)
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+         s          |         f1          
+--------------------+---------------------
+ [(1,2),(3,4)]      | (2,2),(0,0)
+ [(1,2),(3,4)]      | (3,3),(1,1)
+ [(1,2),(3,4)]      | (2.5,3.5),(2.5,2.5)
+ [(0,0),(6,6)]      | (2,2),(0,0)
+ [(0,0),(6,6)]      | (3,3),(1,1)
+ [(0,0),(6,6)]      | (2.5,3.5),(2.5,2.5)
+ [(0,0),(6,6)]      | (3,3),(3,3)
+ [(10,-10),(-3,-4)] | (-2,2),(-8,-10)
+(8 rows)
+
+-- Intersection point with line segment
+SELECT l1.s, l2.s, l1.s # l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               | ?column? 
+-------------------------------+-------------------------------+----------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 | 
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            | 
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] | 
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             | 
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             | 
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            | 
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            | 
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 | 
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            | 
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] | 
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             | 
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             | 
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            | 
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            | 
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 | 
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 | 
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            | 
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] | 
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             | 
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             | 
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            | 
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            | 
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 | 
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 | 
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            | 
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] | 
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             | 
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             | 
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            | 
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            | 
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 | 
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 | 
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            | 
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] | 
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             | 
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             | 
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            | 
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            | 
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 | 
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 | 
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            | 
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] | 
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             | 
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             | 
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            | 
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            | 
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 | 
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 | 
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            | 
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] | 
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             | 
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             | 
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            | 
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            | 
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 | 
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 | 
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            | 
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] | 
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             | 
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             | 
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            | 
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            | 
+(64 rows)
+
+-- Closest point to line
+SELECT l.s, l1.s, l.s ## l1.s FROM LSEG_TBL l, LINE_TBL l1;
+ERROR:  function "close_sl" not implemented
+-- Closest point to line segment
+SELECT l1.s, l2.s, l1.s ## l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+               s               |               s               |            ?column?             
+-------------------------------+-------------------------------+---------------------------------
+ [(1,2),(3,4)]                 | [(1,2),(3,4)]                 | 
+ [(1,2),(3,4)]                 | [(0,0),(6,6)]                 | 
+ [(1,2),(3,4)]                 | [(10,-10),(-3,-4)]            | (-1.98536585366,-4.46829268293)
+ [(1,2),(3,4)]                 | [(-1000000,200),(300000,-40)] | (3.00210167283,15.3840611505)
+ [(1,2),(3,4)]                 | [(11,22),(33,44)]             | 
+ [(1,2),(3,4)]                 | [(-10,2),(-10,3)]             | (-10,2)
+ [(1,2),(3,4)]                 | [(0,-20),(30,-20)]            | (1,-20)
+ [(1,2),(3,4)]                 | [(NaN,1),(NaN,90)]            | 
+ [(0,0),(6,6)]                 | [(1,2),(3,4)]                 | 
+ [(0,0),(6,6)]                 | [(0,0),(6,6)]                 | 
+ [(0,0),(6,6)]                 | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
+ [(0,0),(6,6)]                 | [(-1000000,200),(300000,-40)] | (6.00173233982,15.3835073725)
+ [(0,0),(6,6)]                 | [(11,22),(33,44)]             | 
+ [(0,0),(6,6)]                 | [(-10,2),(-10,3)]             | (-10,2)
+ [(0,0),(6,6)]                 | [(0,-20),(30,-20)]            | (0,-20)
+ [(0,0),(6,6)]                 | [(NaN,1),(NaN,90)]            | 
+ [(10,-10),(-3,-4)]            | [(1,2),(3,4)]                 | (1,2)
+ [(10,-10),(-3,-4)]            | [(0,0),(6,6)]                 | (0,0)
+ [(10,-10),(-3,-4)]            | [(10,-10),(-3,-4)]            | 
+ [(10,-10),(-3,-4)]            | [(-1000000,200),(300000,-40)] | (-2.99642119965,15.3851685701)
+ [(10,-10),(-3,-4)]            | [(11,22),(33,44)]             | (11,22)
+ [(10,-10),(-3,-4)]            | [(-10,2),(-10,3)]             | (-10,2)
+ [(10,-10),(-3,-4)]            | [(0,-20),(30,-20)]            | (10,-20)
+ [(10,-10),(-3,-4)]            | [(NaN,1),(NaN,90)]            | 
+ [(-1000000,200),(300000,-40)] | [(1,2),(3,4)]                 | (3,4)
+ [(-1000000,200),(300000,-40)] | [(0,0),(6,6)]                 | (6,6)
+ [(-1000000,200),(300000,-40)] | [(10,-10),(-3,-4)]            | (-3,-4)
+ [(-1000000,200),(300000,-40)] | [(-1000000,200),(300000,-40)] | 
+ [(-1000000,200),(300000,-40)] | [(11,22),(33,44)]             | (11,22)
+ [(-1000000,200),(300000,-40)] | [(-10,2),(-10,3)]             | (-10,3)
+ [(-1000000,200),(300000,-40)] | [(0,-20),(30,-20)]            | (30,-20)
+ [(-1000000,200),(300000,-40)] | [(NaN,1),(NaN,90)]            | 
+ [(11,22),(33,44)]             | [(1,2),(3,4)]                 | 
+ [(11,22),(33,44)]             | [(0,0),(6,6)]                 | 
+ [(11,22),(33,44)]             | [(10,-10),(-3,-4)]            | (-1.3512195122,-4.76097560976)
+ [(11,22),(33,44)]             | [(-1000000,200),(300000,-40)] | (10.9987783234,15.3825848409)
+ [(11,22),(33,44)]             | [(11,22),(33,44)]             | 
+ [(11,22),(33,44)]             | [(-10,2),(-10,3)]             | (-10,3)
+ [(11,22),(33,44)]             | [(0,-20),(30,-20)]            | (11,-20)
+ [(11,22),(33,44)]             | [(NaN,1),(NaN,90)]            | 
+ [(-10,2),(-10,3)]             | [(1,2),(3,4)]                 | (1,2)
+ [(-10,2),(-10,3)]             | [(0,0),(6,6)]                 | (0,0)
+ [(-10,2),(-10,3)]             | [(10,-10),(-3,-4)]            | (-3,-4)
+ [(-10,2),(-10,3)]             | [(-1000000,200),(300000,-40)] | (-9.99771326872,15.3864611163)
+ [(-10,2),(-10,3)]             | [(11,22),(33,44)]             | (11,22)
+ [(-10,2),(-10,3)]             | [(-10,2),(-10,3)]             | 
+ [(-10,2),(-10,3)]             | [(0,-20),(30,-20)]            | (0,-20)
+ [(-10,2),(-10,3)]             | [(NaN,1),(NaN,90)]            | 
+ [(0,-20),(30,-20)]            | [(1,2),(3,4)]                 | (1,2)
+ [(0,-20),(30,-20)]            | [(0,0),(6,6)]                 | (0,0)
+ [(0,-20),(30,-20)]            | [(10,-10),(-3,-4)]            | (10,-10)
+ [(0,-20),(30,-20)]            | [(-1000000,200),(300000,-40)] | (30.0065315217,15.3790757173)
+ [(0,-20),(30,-20)]            | [(11,22),(33,44)]             | (11,22)
+ [(0,-20),(30,-20)]            | [(-10,2),(-10,3)]             | (-10,2)
+ [(0,-20),(30,-20)]            | [(0,-20),(30,-20)]            | 
+ [(0,-20),(30,-20)]            | [(NaN,1),(NaN,90)]            | 
+ [(NaN,1),(NaN,90)]            | [(1,2),(3,4)]                 | 
+ [(NaN,1),(NaN,90)]            | [(0,0),(6,6)]                 | 
+ [(NaN,1),(NaN,90)]            | [(10,-10),(-3,-4)]            | 
+ [(NaN,1),(NaN,90)]            | [(-1000000,200),(300000,-40)] | 
+ [(NaN,1),(NaN,90)]            | [(11,22),(33,44)]             | 
+ [(NaN,1),(NaN,90)]            | [(-10,2),(-10,3)]             | 
+ [(NaN,1),(NaN,90)]            | [(0,-20),(30,-20)]            | 
+ [(NaN,1),(NaN,90)]            | [(NaN,1),(NaN,90)]            | 
+(64 rows)
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LSEG_TBL l, BOX_TBL b;
+               s               |         f1          |  ?column?   
+-------------------------------+---------------------+-------------
+ [(1,2),(3,4)]                 | (2,2),(0,0)         | (1,2)
+ [(1,2),(3,4)]                 | (3,3),(1,1)         | (1.5,2.5)
+ [(1,2),(3,4)]                 | (-2,2),(-8,-10)     | (-2,2)
+ [(1,2),(3,4)]                 | (2.5,3.5),(2.5,2.5) | (2.25,3.25)
+ [(1,2),(3,4)]                 | (3,3),(3,3)         | (3,3)
+ [(0,0),(6,6)]                 | (2,2),(0,0)         | (1,1)
+ [(0,0),(6,6)]                 | (3,3),(1,1)         | (2,2)
+ [(0,0),(6,6)]                 | (-2,2),(-8,-10)     | (-2,0)
+ [(0,0),(6,6)]                 | (2.5,3.5),(2.5,2.5) | (2.75,2.75)
+ [(0,0),(6,6)]                 | (3,3),(3,3)         | (3,3)
+ [(10,-10),(-3,-4)]            | (2,2),(0,0)         | (0,0)
+ [(10,-10),(-3,-4)]            | (3,3),(1,1)         | (1,1)
+ [(10,-10),(-3,-4)]            | (-2,2),(-8,-10)     | (-3,-4)
+ [(10,-10),(-3,-4)]            | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ [(10,-10),(-3,-4)]            | (3,3),(3,3)         | (3,3)
+ [(-1000000,200),(300000,-40)] | (2,2),(0,0)         | (2,2)
+ [(-1000000,200),(300000,-40)] | (3,3),(1,1)         | (3,3)
+ [(-1000000,200),(300000,-40)] | (-2,2),(-8,-10)     | (-2,2)
+ [(-1000000,200),(300000,-40)] | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ [(-1000000,200),(300000,-40)] | (3,3),(3,3)         | (3,3)
+ [(11,22),(33,44)]             | (2,2),(0,0)         | (2,2)
+ [(11,22),(33,44)]             | (3,3),(1,1)         | (3,3)
+ [(11,22),(33,44)]             | (-2,2),(-8,-10)     | (-2,2)
+ [(11,22),(33,44)]             | (2.5,3.5),(2.5,2.5) | (2.5,3.5)
+ [(11,22),(33,44)]             | (3,3),(3,3)         | (3,3)
+ [(-10,2),(-10,3)]             | (2,2),(0,0)         | (0,2)
+ [(-10,2),(-10,3)]             | (3,3),(1,1)         | (1,2)
+ [(-10,2),(-10,3)]             | (-2,2),(-8,-10)     | (-8,2)
+ [(-10,2),(-10,3)]             | (2.5,3.5),(2.5,2.5) | (2.5,3)
+ [(-10,2),(-10,3)]             | (3,3),(3,3)         | (3,3)
+ [(0,-20),(30,-20)]            | (2,2),(0,0)         | (0,0)
+ [(0,-20),(30,-20)]            | (3,3),(1,1)         | (1,1)
+ [(0,-20),(30,-20)]            | (-2,2),(-8,-10)     | (-2,-10)
+ [(0,-20),(30,-20)]            | (2.5,3.5),(2.5,2.5) | (2.5,2.5)
+ [(0,-20),(30,-20)]            | (3,3),(3,3)         | (3,3)
+ [(NaN,1),(NaN,90)]            | (2,2),(0,0)         | 
+ [(NaN,1),(NaN,90)]            | (3,3),(1,1)         | 
+ [(NaN,1),(NaN,90)]            | (-2,2),(-8,-10)     | 
+ [(NaN,1),(NaN,90)]            | (2.5,3.5),(2.5,2.5) | 
+ [(NaN,1),(NaN,90)]            | (3,3),(3,3)         | 
+(40 rows)
+
+-- On line
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s <@ l1.s;
+               s               |                   s                   
+-------------------------------+---------------------------------------
+ [(0,0),(6,6)]                 | {1,-1,0}
+ [(-1000000,200),(300000,-40)] | {-0.000184615384615,-1,15.3846153846}
+(2 rows)
+
+-- On box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s <@ b.f1;
+ s | f1 
+---+----
+(0 rows)
 
 --
 -- Boxes
 --
 SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
  six |                              box                               
 -----+----------------------------------------------------------------
      | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
      | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
      | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
      | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
      | (107.071067812,207.071067812),(92.9289321881,192.928932188)
      | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
+     | (3,5),(3,5)
+     | (NaN,NaN),(NaN,NaN)
+(8 rows)
 
 -- translation
 SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
+ twentyfour |             translation             
+------------+-------------------------------------
             | (2,2),(0,0)
             | (3,3),(1,1)
+            | (-2,2),(-8,-10)
             | (2.5,3.5),(2.5,2.5)
             | (3,3),(3,3)
             | (-8,2),(-10,0)
             | (-7,3),(-9,1)
+            | (-12,2),(-18,-10)
             | (-7.5,3.5),(-7.5,2.5)
             | (-7,3),(-7,3)
             | (-1,6),(-3,4)
             | (0,7),(-2,5)
+            | (-5,6),(-11,-6)
             | (-0.5,7.5),(-0.5,6.5)
             | (0,7),(0,7)
             | (7.1,36.5),(5.1,34.5)
             | (8.1,37.5),(6.1,35.5)
+            | (3.1,36.5),(-2.9,24.5)
             | (7.6,38),(7.6,37)
             | (8.1,37.5),(8.1,37.5)
             | (-3,-10),(-5,-12)
             | (-2,-9),(-4,-11)
+            | (-7,-10),(-13,-22)
             | (-2.5,-8.5),(-2.5,-9.5)
             | (-2,-9),(-2,-9)
+            | (2,2),(1e-300,-1e-300)
+            | (3,3),(1,1)
+            | (-2,2),(-8,-10)
+            | (2.5,3.5),(2.5,2.5)
+            | (3,3),(3,3)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (1e+300,Infinity),(1e+300,Infinity)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
             | (12,12),(10,10)
             | (13,13),(11,11)
+            | (8,12),(2,0)
             | (12.5,13.5),(12.5,12.5)
             | (13,13),(13,13)
-(24 rows)
+(45 rows)
 
 SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
+ twentyfour |               translation               
+------------+-----------------------------------------
             | (2,2),(0,0)
             | (3,3),(1,1)
+            | (-2,2),(-8,-10)
             | (2.5,3.5),(2.5,2.5)
             | (3,3),(3,3)
             | (12,2),(10,0)
             | (13,3),(11,1)
+            | (8,2),(2,-10)
             | (12.5,3.5),(12.5,2.5)
             | (13,3),(13,3)
             | (5,-2),(3,-4)
             | (6,-1),(4,-3)
+            | (1,-2),(-5,-14)
             | (5.5,-0.5),(5.5,-1.5)
             | (6,-1),(6,-1)
             | (-3.1,-32.5),(-5.1,-34.5)
             | (-2.1,-31.5),(-4.1,-33.5)
+            | (-7.1,-32.5),(-13.1,-44.5)
             | (-2.6,-31),(-2.6,-32)
             | (-2.1,-31.5),(-2.1,-31.5)
             | (7,14),(5,12)
             | (8,15),(6,13)
+            | (3,14),(-3,2)
             | (7.5,15.5),(7.5,14.5)
             | (8,15),(8,15)
+            | (2,2),(-1e-300,1e-300)
+            | (3,3),(1,1)
+            | (-2,2),(-8,-10)
+            | (2.5,3.5),(2.5,2.5)
+            | (3,3),(3,3)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (-1e+300,-Infinity),(-1e+300,-Infinity)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
+            | (NaN,NaN),(NaN,NaN)
             | (-8,-8),(-10,-10)
             | (-7,-7),(-9,-9)
+            | (-12,-8),(-18,-20)
             | (-7.5,-6.5),(-7.5,-7.5)
             | (-7,-7),(-7,-7)
-(24 rows)
+(45 rows)
 
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
+-- Multiply with point
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+         f1          |     f1     |          ?column?           
+---------------------+------------+-----------------------------
+ (2,2),(0,0)         | (5.1,34.5) | (0,79.2),(-58.8,0)
+ (2,2),(0,0)         | (10,10)    | (0,40),(0,0)
+ (3,3),(1,1)         | (5.1,34.5) | (-29.4,118.8),(-88.2,39.6)
+ (3,3),(1,1)         | (10,10)    | (0,60),(0,20)
+ (-2,2),(-8,-10)     | (5.1,34.5) | (304.2,-58.8),(-79.2,-327)
+ (-2,2),(-8,-10)     | (10,10)    | (20,0),(-40,-180)
+ (2.5,3.5),(2.5,2.5) | (5.1,34.5) | (-73.5,104.1),(-108,99)
+ (2.5,3.5),(2.5,2.5) | (10,10)    | (0,60),(-10,50)
+ (3,3),(3,3)         | (5.1,34.5) | (-88.2,118.8),(-88.2,118.8)
+ (3,3),(3,3)         | (10,10)    | (0,60),(0,60)
+(10 rows)
 
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,0),(-0.2,-0.2)
-        | (0.08,0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
+-- Overflow error
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] > 1000;
+         f1          |        f1         |                  ?column?                  
+---------------------+-------------------+--------------------------------------------
+ (2,2),(0,0)         | (1e+300,Infinity) | (NaN,NaN),(-Infinity,Infinity)
+ (2,2),(0,0)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (3,3),(1,1)         | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (3,3),(1,1)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (-2,2),(-8,-10)     | (1e+300,Infinity) | (Infinity,-Infinity),(-Infinity,-Infinity)
+ (-2,2),(-8,-10)     | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (2.5,3.5),(2.5,2.5) | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (2.5,3.5),(2.5,2.5) | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+ (3,3),(3,3)         | (1e+300,Infinity) | (-Infinity,Infinity),(-Infinity,Infinity)
+ (3,3),(3,3)         | (NaN,NaN)         | (NaN,NaN),(NaN,NaN)
+(10 rows)
 
+-- Divide by point
+SELECT b.f1, p.f1, b.f1 / p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+         f1          |     f1     |                               ?column?                               
+---------------------+------------+----------------------------------------------------------------------
+ (2,2),(0,0)         | (5.1,34.5) | (0.0651176557644,0),(0,-0.0483449262493)
+ (2,2),(0,0)         | (10,10)    | (0.2,0),(0,0)
+ (3,3),(1,1)         | (5.1,34.5) | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
+ (3,3),(1,1)         | (10,10)    | (0.3,0),(0.1,0)
+ (-2,2),(-8,-10)     | (5.1,34.5) | (0.0483449262493,0.18499334024),(-0.317201914064,0.0651176557644)
+ (-2,2),(-8,-10)     | (10,10)    | (0,0.2),(-0.9,-0.1)
+ (2.5,3.5),(2.5,2.5) | (5.1,34.5) | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
+ (2.5,3.5),(2.5,2.5) | (10,10)    | (0.3,0.05),(0.25,0)
+ (3,3),(3,3)         | (5.1,34.5) | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
+ (3,3),(3,3)         | (10,10)    | (0.3,0),(0.3,0)
+(10 rows)
+
+-- To box
 SELECT f1::box
 	FROM POINT_TBL;
-          f1           
------------------------
+                 f1                  
+-------------------------------------
  (0,0),(0,0)
  (-10,0),(-10,0)
  (-3,4),(-3,4)
  (5.1,34.5),(5.1,34.5)
  (-5,-12),(-5,-12)
+ (1e-300,-1e-300),(1e-300,-1e-300)
+ (1e+300,Infinity),(1e+300,Infinity)
+ (NaN,NaN),(NaN,NaN)
  (10,10),(10,10)
-(6 rows)
+(9 rows)
 
 SELECT bound_box(a.f1, b.f1)
 	FROM BOX_TBL a, BOX_TBL b;
       bound_box      
 ---------------------
  (2,2),(0,0)
  (3,3),(0,0)
+ (2,2),(-8,-10)
  (2.5,3.5),(0,0)
  (3,3),(0,0)
  (3,3),(0,0)
  (3,3),(1,1)
+ (3,3),(-8,-10)
  (3,3.5),(1,1)
  (3,3),(1,1)
+ (2,2),(-8,-10)
+ (3,3),(-8,-10)
+ (-2,2),(-8,-10)
+ (2.5,3.5),(-8,-10)
+ (3,3),(-8,-10)
  (2.5,3.5),(0,0)
  (3,3.5),(1,1)
+ (2.5,3.5),(-8,-10)
  (2.5,3.5),(2.5,2.5)
  (3,3.5),(2.5,2.5)
  (3,3),(0,0)
  (3,3),(1,1)
+ (3,3),(-8,-10)
  (3,3.5),(2.5,2.5)
  (3,3),(3,3)
-(16 rows)
+(25 rows)
+
+-- Below box
+SELECT b1.f1, b2.f1, b1.f1 <^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          | ?column? 
+---------------------+---------------------+----------
+ (2,2),(0,0)         | (2,2),(0,0)         | f
+ (2,2),(0,0)         | (3,3),(1,1)         | f
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | f
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | t
+ (2,2),(0,0)         | (3,3),(3,3)         | t
+ (3,3),(1,1)         | (2,2),(0,0)         | f
+ (3,3),(1,1)         | (3,3),(1,1)         | f
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | f
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(1,1)         | (3,3),(3,3)         | t
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | f
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | f
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | f
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | t
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | t
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | f
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | f
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | f
+ (3,3),(3,3)         | (2,2),(0,0)         | f
+ (3,3),(3,3)         | (3,3),(1,1)         | f
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | f
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(3,3)         | (3,3),(3,3)         | t
+(25 rows)
+
+-- Above box
+SELECT b1.f1, b2.f1, b1.f1 >^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          | ?column? 
+---------------------+---------------------+----------
+ (2,2),(0,0)         | (2,2),(0,0)         | f
+ (2,2),(0,0)         | (3,3),(1,1)         | f
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | f
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | f
+ (2,2),(0,0)         | (3,3),(3,3)         | f
+ (3,3),(1,1)         | (2,2),(0,0)         | f
+ (3,3),(1,1)         | (3,3),(1,1)         | f
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | f
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(1,1)         | (3,3),(3,3)         | f
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | f
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | f
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | f
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | f
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | f
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | t
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | f
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | t
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | f
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | f
+ (3,3),(3,3)         | (2,2),(0,0)         | t
+ (3,3),(3,3)         | (3,3),(1,1)         | t
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | t
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | f
+ (3,3),(3,3)         | (3,3),(3,3)         | t
+(25 rows)
+
+-- Intersection point with box
+SELECT b1.f1, b2.f1, b1.f1 # b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          |      ?column?       
+---------------------+---------------------+---------------------
+ (2,2),(0,0)         | (2,2),(0,0)         | (2,2),(0,0)
+ (2,2),(0,0)         | (3,3),(1,1)         | (2,2),(1,1)
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | 
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) | 
+ (2,2),(0,0)         | (3,3),(3,3)         | 
+ (3,3),(1,1)         | (2,2),(0,0)         | (2,2),(1,1)
+ (3,3),(1,1)         | (3,3),(1,1)         | (3,3),(1,1)
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | 
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | (2.5,3),(2.5,2.5)
+ (3,3),(1,1)         | (3,3),(3,3)         | (3,3),(3,3)
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | 
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | 
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     | (-2,2),(-8,-10)
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | 
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | 
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         | 
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | (2.5,3),(2.5,2.5)
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | 
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5)
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         | 
+ (3,3),(3,3)         | (2,2),(0,0)         | 
+ (3,3),(3,3)         | (3,3),(1,1)         | (3,3),(3,3)
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | 
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) | 
+ (3,3),(3,3)         | (3,3),(3,3)         | (3,3),(3,3)
+(25 rows)
+
+-- Diagonal
+SELECT f1, diagonal(f1) FROM BOX_TBL;
+         f1          |       diagonal        
+---------------------+-----------------------
+ (2,2),(0,0)         | [(2,2),(0,0)]
+ (3,3),(1,1)         | [(3,3),(1,1)]
+ (-2,2),(-8,-10)     | [(-2,2),(-8,-10)]
+ (2.5,3.5),(2.5,2.5) | [(2.5,3.5),(2.5,2.5)]
+ (3,3),(3,3)         | [(3,3),(3,3)]
+(5 rows)
+
+-- Distance to box
+SELECT b1.f1, b2.f1, b1.f1 <-> b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+         f1          |         f1          |   ?column?    
+---------------------+---------------------+---------------
+ (2,2),(0,0)         | (2,2),(0,0)         |             0
+ (2,2),(0,0)         | (3,3),(1,1)         | 1.41421356237
+ (2,2),(0,0)         | (-2,2),(-8,-10)     | 7.81024967591
+ (2,2),(0,0)         | (2.5,3.5),(2.5,2.5) |           2.5
+ (2,2),(0,0)         | (3,3),(3,3)         | 2.82842712475
+ (3,3),(1,1)         | (2,2),(0,0)         | 1.41421356237
+ (3,3),(1,1)         | (3,3),(1,1)         |             0
+ (3,3),(1,1)         | (-2,2),(-8,-10)     | 9.21954445729
+ (3,3),(1,1)         | (2.5,3.5),(2.5,2.5) | 1.11803398875
+ (3,3),(1,1)         | (3,3),(3,3)         | 1.41421356237
+ (-2,2),(-8,-10)     | (2,2),(0,0)         | 7.81024967591
+ (-2,2),(-8,-10)     | (3,3),(1,1)         | 9.21954445729
+ (-2,2),(-8,-10)     | (-2,2),(-8,-10)     |             0
+ (-2,2),(-8,-10)     | (2.5,3.5),(2.5,2.5) | 10.2591422643
+ (-2,2),(-8,-10)     | (3,3),(3,3)         | 10.6301458127
+ (2.5,3.5),(2.5,2.5) | (2,2),(0,0)         |           2.5
+ (2.5,3.5),(2.5,2.5) | (3,3),(1,1)         | 1.11803398875
+ (2.5,3.5),(2.5,2.5) | (-2,2),(-8,-10)     | 10.2591422643
+ (2.5,3.5),(2.5,2.5) | (2.5,3.5),(2.5,2.5) |             0
+ (2.5,3.5),(2.5,2.5) | (3,3),(3,3)         |           0.5
+ (3,3),(3,3)         | (2,2),(0,0)         | 2.82842712475
+ (3,3),(3,3)         | (3,3),(1,1)         | 1.41421356237
+ (3,3),(3,3)         | (-2,2),(-8,-10)     | 10.6301458127
+ (3,3),(3,3)         | (2.5,3.5),(2.5,2.5) |           0.5
+ (3,3),(3,3)         | (3,3),(3,3)         |             0
+(25 rows)
 
 --
 -- Paths
 --
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
+-- Points
+SELECT f1, npoints(f1) FROM PATH_TBL;
+            f1             | npoints 
+---------------------------+---------
+ [(1,2),(3,4)]             |       2
+ ((1,2),(3,4))             |       2
+ [(0,0),(3,0),(4,5),(1,6)] |       4
+ ((1,2),(3,4))             |       2
+ ((1,2),(3,4))             |       2
+ [(1,2),(3,4)]             |       2
+ ((10,20))                 |       1
+ [(11,12),(13,14)]         |       2
+ ((11,12),(13,14))         |       2
+(9 rows)
 
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
+-- Area
+SELECT f1, area(f1) FROM PATH_TBL;
+            f1             | area 
+---------------------------+------
+ [(1,2),(3,4)]             |     
+ ((1,2),(3,4))             |    0
+ [(0,0),(3,0),(4,5),(1,6)] |     
+ ((1,2),(3,4))             |    0
+ ((1,2),(3,4))             |    0
+ [(1,2),(3,4)]             |     
+ ((10,20))                 |    0
+ [(11,12),(13,14)]         |     
+ ((11,12),(13,14))         |    0
+(9 rows)
 
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
+-- Length
+SELECT f1, @-@ f1 FROM PATH_TBL;
+            f1             |   ?column?    
+---------------------------+---------------
+ [(1,2),(3,4)]             | 2.82842712475
+ ((1,2),(3,4))             | 5.65685424949
+ [(0,0),(3,0),(4,5),(1,6)] | 11.2612971738
+ ((1,2),(3,4))             | 5.65685424949
+ ((1,2),(3,4))             | 5.65685424949
+ [(1,2),(3,4)]             | 2.82842712475
+ ((10,20))                 |             0
+ [(11,12),(13,14)]         | 2.82842712475
+ ((11,12),(13,14))         | 5.65685424949
+(9 rows)
 
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
+-- Center
+SELECT f1, @@ f1 FROM PATH_TBL;
+ERROR:  function "path_center" not implemented
+-- To polygon
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isclosed(f1);
+        f1         |        f1         
+-------------------+-------------------
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((1,2),(3,4))     | ((1,2),(3,4))
+ ((10,20))         | ((10,20))
+ ((11,12),(13,14)) | ((11,12),(13,14))
+(5 rows)
+
+-- Open path cannot be converted to polygon error
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isopen(f1);
+ERROR:  open path cannot be converted to polygon
+-- Has points less than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 < p2.f1;
+        f1         |            f1             
+-------------------+---------------------------
+ [(1,2),(3,4)]     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))     | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]     | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))         | [(1,2),(3,4)]
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | ((1,2),(3,4))
+ ((10,20))         | [(1,2),(3,4)]
+ ((10,20))         | [(11,12),(13,14)]
+ ((10,20))         | ((11,12),(13,14))
+ [(11,12),(13,14)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((11,12),(13,14)) | [(0,0),(3,0),(4,5),(1,6)]
+(15 rows)
+
+-- Has points less than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 <= p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | [(1,2),(3,4)]
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)]
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | ((1,2),(3,4))
+ ((10,20))                 | [(1,2),(3,4)]
+ ((10,20))                 | ((10,20))
+ ((10,20))                 | [(11,12),(13,14)]
+ ((10,20))                 | ((11,12),(13,14))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(66 rows)
+
+-- Has points equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 = p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | ((10,20))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(51 rows)
+
+-- Has points greater than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 >= p2.f1;
+            f1             |            f1             
+---------------------------+---------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | ((1,2),(3,4))
+ ((1,2),(3,4))             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | [(11,12),(13,14)]
+ ((1,2),(3,4))             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | [(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))
+ [(1,2),(3,4)]             | [(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))
+ ((10,20))                 | ((10,20))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | ((1,2),(3,4))
+ [(11,12),(13,14)]         | [(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((10,20))
+ [(11,12),(13,14)]         | [(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | ((1,2),(3,4))
+ ((11,12),(13,14))         | [(1,2),(3,4)]
+ ((11,12),(13,14))         | ((10,20))
+ ((11,12),(13,14))         | [(11,12),(13,14)]
+ ((11,12),(13,14))         | ((11,12),(13,14))
+(66 rows)
+
+-- Has points greater than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 > p2.f1;
+            f1             |        f1         
+---------------------------+-------------------
+ [(1,2),(3,4)]             | ((10,20))
+ ((1,2),(3,4))             | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))
+ ((1,2),(3,4))             | ((10,20))
+ ((1,2),(3,4))             | ((10,20))
+ [(1,2),(3,4)]             | ((10,20))
+ [(11,12),(13,14)]         | ((10,20))
+ ((11,12),(13,14))         | ((10,20))
+(15 rows)
+
+-- Add path
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+            f1             |            f1             |                     ?column?                      
+---------------------------+---------------------------+---------------------------------------------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4),(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))                 | 
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         | [(1,2),(3,4),(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6),(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6),(0,0),(3,0),(4,5),(1,6)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6),(1,2),(3,4)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))                 | 
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6),(11,12),(13,14)]
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | ((1,2),(3,4))             | 
+ ((1,2),(3,4))             | [(1,2),(3,4)]             | 
+ ((1,2),(3,4))             | ((10,20))                 | 
+ ((1,2),(3,4))             | [(11,12),(13,14)]         | 
+ ((1,2),(3,4))             | ((11,12),(13,14))         | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4),(0,0),(3,0),(4,5),(1,6)]
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | ((1,2),(3,4))             | 
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             | [(1,2),(3,4),(1,2),(3,4)]
+ [(1,2),(3,4)]             | ((10,20))                 | 
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         | [(1,2),(3,4),(11,12),(13,14)]
+ [(1,2),(3,4)]             | ((11,12),(13,14))         | 
+ ((10,20))                 | [(1,2),(3,4)]             | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | ((1,2),(3,4))             | 
+ ((10,20))                 | [(1,2),(3,4)]             | 
+ ((10,20))                 | ((10,20))                 | 
+ ((10,20))                 | [(11,12),(13,14)]         | 
+ ((10,20))                 | ((11,12),(13,14))         | 
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             | [(11,12),(13,14),(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14),(0,0),(3,0),(4,5),(1,6)]
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | ((1,2),(3,4))             | 
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             | [(11,12),(13,14),(1,2),(3,4)]
+ [(11,12),(13,14)]         | ((10,20))                 | 
+ [(11,12),(13,14)]         | [(11,12),(13,14)]         | [(11,12),(13,14),(11,12),(13,14)]
+ [(11,12),(13,14)]         | ((11,12),(13,14))         | 
+ ((11,12),(13,14))         | [(1,2),(3,4)]             | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)] | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | ((1,2),(3,4))             | 
+ ((11,12),(13,14))         | [(1,2),(3,4)]             | 
+ ((11,12),(13,14))         | ((10,20))                 | 
+ ((11,12),(13,14))         | [(11,12),(13,14)]         | 
+ ((11,12),(13,14))         | ((11,12),(13,14))         | 
+(81 rows)
+
+-- Add point
+SELECT p.f1, p1.f1, p.f1 + p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                                 ?column?                                  
+---------------------------+-------------------+---------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((10,20))                 | (0,0)             | ((10,20))
+ [(11,12),(13,14)]         | (0,0)             | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (0,0)             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (-10,0)           | [(-9,2),(-7,4)]
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(-10,0),(-7,0),(-6,5),(-9,6)]
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ ((1,2),(3,4))             | (-10,0)           | ((-9,2),(-7,4))
+ [(1,2),(3,4)]             | (-10,0)           | [(-9,2),(-7,4)]
+ ((10,20))                 | (-10,0)           | ((0,20))
+ [(11,12),(13,14)]         | (-10,0)           | [(1,12),(3,14)]
+ ((11,12),(13,14))         | (-10,0)           | ((1,12),(3,14))
+ [(1,2),(3,4)]             | (-3,4)            | [(-2,6),(0,8)]
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(-3,4),(0,4),(1,9),(-2,10)]
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ ((1,2),(3,4))             | (-3,4)            | ((-2,6),(0,8))
+ [(1,2),(3,4)]             | (-3,4)            | [(-2,6),(0,8)]
+ ((10,20))                 | (-3,4)            | ((7,24))
+ [(11,12),(13,14)]         | (-3,4)            | [(8,16),(10,18)]
+ ((11,12),(13,14))         | (-3,4)            | ((8,16),(10,18))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(6.1,36.5),(8.1,38.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(5.1,34.5),(8.1,34.5),(9.1,39.5),(6.1,40.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((6.1,36.5),(8.1,38.5))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(6.1,36.5),(8.1,38.5)]
+ ((10,20))                 | (5.1,34.5)        | ((15.1,54.5))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(16.1,46.5),(18.1,48.5)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((16.1,46.5),(18.1,48.5))
+ [(1,2),(3,4)]             | (-5,-12)          | [(-4,-10),(-2,-8)]
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(-5,-12),(-2,-12),(-1,-7),(-4,-6)]
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ ((1,2),(3,4))             | (-5,-12)          | ((-4,-10),(-2,-8))
+ [(1,2),(3,4)]             | (-5,-12)          | [(-4,-10),(-2,-8)]
+ ((10,20))                 | (-5,-12)          | ((5,8))
+ [(11,12),(13,14)]         | (-5,-12)          | [(6,0),(8,2)]
+ ((11,12),(13,14))         | (-5,-12)          | ((6,0),(8,2))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(1e-300,-1e-300),(3,-1e-300),(4,5),(1,6)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((10,20))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity),(1e+300,Infinity),(1e+300,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((1e+300,Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(1e+300,Infinity),(1e+300,Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((1e+300,Infinity),(1e+300,Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(11,12),(13,14)]
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(10,10),(13,10),(14,15),(11,16)]
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ ((1,2),(3,4))             | (10,10)           | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (10,10)           | [(11,12),(13,14)]
+ ((10,20))                 | (10,10)           | ((20,30))
+ [(11,12),(13,14)]         | (10,10)           | [(21,22),(23,24)]
+ ((11,12),(13,14))         | (10,10)           | ((21,22),(23,24))
+(81 rows)
+
+-- Subtract point
+SELECT p.f1, p1.f1, p.f1 - p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                                     ?column?                                      
+---------------------------+-------------------+-----------------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(3,0),(4,5),(1,6)]
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ ((1,2),(3,4))             | (0,0)             | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (0,0)             | [(1,2),(3,4)]
+ ((10,20))                 | (0,0)             | ((10,20))
+ [(11,12),(13,14)]         | (0,0)             | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (0,0)             | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (-10,0)           | [(11,2),(13,4)]
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(10,0),(13,0),(14,5),(11,6)]
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ ((1,2),(3,4))             | (-10,0)           | ((11,2),(13,4))
+ [(1,2),(3,4)]             | (-10,0)           | [(11,2),(13,4)]
+ ((10,20))                 | (-10,0)           | ((20,20))
+ [(11,12),(13,14)]         | (-10,0)           | [(21,12),(23,14)]
+ ((11,12),(13,14))         | (-10,0)           | ((21,12),(23,14))
+ [(1,2),(3,4)]             | (-3,4)            | [(4,-2),(6,0)]
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(3,-4),(6,-4),(7,1),(4,2)]
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ ((1,2),(3,4))             | (-3,4)            | ((4,-2),(6,0))
+ [(1,2),(3,4)]             | (-3,4)            | [(4,-2),(6,0)]
+ ((10,20))                 | (-3,4)            | ((13,16))
+ [(11,12),(13,14)]         | (-3,4)            | [(14,8),(16,10)]
+ ((11,12),(13,14))         | (-3,4)            | ((14,8),(16,10))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-4.1,-32.5),(-2.1,-30.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(-5.1,-34.5),(-2.1,-34.5),(-1.1,-29.5),(-4.1,-28.5)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-4.1,-32.5),(-2.1,-30.5))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-4.1,-32.5),(-2.1,-30.5)]
+ ((10,20))                 | (5.1,34.5)        | ((4.9,-14.5))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(5.9,-22.5),(7.9,-20.5)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((5.9,-22.5),(7.9,-20.5))
+ [(1,2),(3,4)]             | (-5,-12)          | [(6,14),(8,16)]
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(5,12),(8,12),(9,17),(6,18)]
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ ((1,2),(3,4))             | (-5,-12)          | ((6,14),(8,16))
+ [(1,2),(3,4)]             | (-5,-12)          | [(6,14),(8,16)]
+ ((10,20))                 | (-5,-12)          | ((15,32))
+ [(11,12),(13,14)]         | (-5,-12)          | [(16,24),(18,26)]
+ ((11,12),(13,14))         | (-5,-12)          | ((16,24),(18,26))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(-1e-300,1e-300),(3,1e-300),(4,5),(1,6)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((1,2),(3,4))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(1,2),(3,4)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((10,20))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(11,12),(13,14)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((11,12),(13,14))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity),(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((-1e+300,-Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(-1e+300,-Infinity),(-1e+300,-Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((-1e+300,-Infinity),(-1e+300,-Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(-9,-8),(-7,-6)]
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(-10,-10),(-7,-10),(-6,-5),(-9,-4)]
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ ((1,2),(3,4))             | (10,10)           | ((-9,-8),(-7,-6))
+ [(1,2),(3,4)]             | (10,10)           | [(-9,-8),(-7,-6)]
+ ((10,20))                 | (10,10)           | ((0,10))
+ [(11,12),(13,14)]         | (10,10)           | [(1,2),(3,4)]
+ ((11,12),(13,14))         | (10,10)           | ((1,2),(3,4))
+(81 rows)
+
+-- Multiply with point
+SELECT p.f1, p1.f1, p.f1 * p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+            f1             |        f1         |                               ?column?                               
+---------------------------+-------------------+----------------------------------------------------------------------
+ [(1,2),(3,4)]             | (0,0)             | [(0,0),(0,0)]
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (0,0)             | [(0,0),(0,0),(0,0),(0,0)]
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ ((1,2),(3,4))             | (0,0)             | ((0,0),(0,0))
+ [(1,2),(3,4)]             | (0,0)             | [(0,0),(0,0)]
+ ((10,20))                 | (0,0)             | ((0,0))
+ [(11,12),(13,14)]         | (0,0)             | [(0,0),(0,0)]
+ ((11,12),(13,14))         | (0,0)             | ((0,0),(0,0))
+ [(1,2),(3,4)]             | (-10,0)           | [(-10,-20),(-30,-40)]
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ [(0,0),(3,0),(4,5),(1,6)] | (-10,0)           | [(0,0),(-30,0),(-40,-50),(-10,-60)]
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ ((1,2),(3,4))             | (-10,0)           | ((-10,-20),(-30,-40))
+ [(1,2),(3,4)]             | (-10,0)           | [(-10,-20),(-30,-40)]
+ ((10,20))                 | (-10,0)           | ((-100,-200))
+ [(11,12),(13,14)]         | (-10,0)           | [(-110,-120),(-130,-140)]
+ ((11,12),(13,14))         | (-10,0)           | ((-110,-120),(-130,-140))
+ [(1,2),(3,4)]             | (-3,4)            | [(-11,-2),(-25,0)]
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ [(0,0),(3,0),(4,5),(1,6)] | (-3,4)            | [(0,0),(-9,12),(-32,1),(-27,-14)]
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ ((1,2),(3,4))             | (-3,4)            | ((-11,-2),(-25,0))
+ [(1,2),(3,4)]             | (-3,4)            | [(-11,-2),(-25,0)]
+ ((10,20))                 | (-3,4)            | ((-110,-20))
+ [(11,12),(13,14)]         | (-3,4)            | [(-81,8),(-95,10)]
+ ((11,12),(13,14))         | (-3,4)            | ((-81,8),(-95,10))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-63.9,44.7),(-122.7,123.9)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5)        | [(0,0),(15.3,103.5),(-152.1,163.5),(-201.9,65.1)]
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ ((1,2),(3,4))             | (5.1,34.5)        | ((-63.9,44.7),(-122.7,123.9))
+ [(1,2),(3,4)]             | (5.1,34.5)        | [(-63.9,44.7),(-122.7,123.9)]
+ ((10,20))                 | (5.1,34.5)        | ((-639,447))
+ [(11,12),(13,14)]         | (5.1,34.5)        | [(-357.9,440.7),(-416.7,519.9)]
+ ((11,12),(13,14))         | (5.1,34.5)        | ((-357.9,440.7),(-416.7,519.9))
+ [(1,2),(3,4)]             | (-5,-12)          | [(19,-22),(33,-56)]
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(0,0),(-15,-36),(40,-73),(67,-42)]
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ ((1,2),(3,4))             | (-5,-12)          | ((19,-22),(33,-56))
+ [(1,2),(3,4)]             | (-5,-12)          | [(19,-22),(33,-56)]
+ ((10,20))                 | (-5,-12)          | ((190,-220))
+ [(11,12),(13,14)]         | (-5,-12)          | [(89,-192),(103,-226)]
+ ((11,12),(13,14))         | (-5,-12)          | ((89,-192),(103,-226))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(3e-300,1e-300),(7e-300,1e-300)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e-300,-1e-300)  | [(0,0),(3e-300,-3e-300),(9e-300,1e-300),(7e-300,5e-300)]
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ ((1,2),(3,4))             | (1e-300,-1e-300)  | ((3e-300,1e-300),(7e-300,1e-300))
+ [(1,2),(3,4)]             | (1e-300,-1e-300)  | [(3e-300,1e-300),(7e-300,1e-300)]
+ ((10,20))                 | (1e-300,-1e-300)  | ((3e-299,1e-299))
+ [(11,12),(13,14)]         | (1e-300,-1e-300)  | [(2.3e-299,1e-300),(2.7e-299,1e-300)]
+ ((11,12),(13,14))         | (1e-300,-1e-300)  | ((2.3e-299,1e-300),(2.7e-299,1e-300))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(0,0),(3,0),(4,5),(1,6)] | (1e+300,Infinity) | [(NaN,NaN),(NaN,Infinity),(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ ((1,2),(3,4))             | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(1,2),(3,4)]             | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((10,20))                 | (1e+300,Infinity) | ((-Infinity,Infinity))
+ [(11,12),(13,14)]         | (1e+300,Infinity) | [(-Infinity,Infinity),(-Infinity,Infinity)]
+ ((11,12),(13,14))         | (1e+300,Infinity) | ((-Infinity,Infinity),(-Infinity,Infinity))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(0,0),(3,0),(4,5),(1,6)] | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN),(NaN,NaN),(NaN,NaN)]
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ ((1,2),(3,4))             | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((10,20))                 | (NaN,NaN)         | ((NaN,NaN))
+ [(11,12),(13,14)]         | (NaN,NaN)         | [(NaN,NaN),(NaN,NaN)]
+ ((11,12),(13,14))         | (NaN,NaN)         | ((NaN,NaN),(NaN,NaN))
+ [(1,2),(3,4)]             | (10,10)           | [(-10,30),(-10,70)]
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)           | [(0,0),(30,30),(-10,90),(-50,70)]
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ ((1,2),(3,4))             | (10,10)           | ((-10,30),(-10,70))
+ [(1,2),(3,4)]             | (10,10)           | [(-10,30),(-10,70)]
+ ((10,20))                 | (10,10)           | ((-100,300))
+ [(11,12),(13,14)]         | (10,10)           | [(-10,230),(-10,270)]
+ ((11,12),(13,14))         | (10,10)           | ((-10,230),(-10,270))
+(81 rows)
+
+-- Divide by point
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+            f1             |     f1     |                                                    ?column?                                                     
+---------------------------+------------+-----------------------------------------------------------------------------------------------------------------
+ [(1,2),(3,4)]             | (5.1,34.5) | [(0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952)]
+ [(1,2),(3,4)]             | (10,10)    | [(0.15,0.05),(0.35,0.05)]
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ [(0,0),(3,0),(4,5),(1,6)] | (5.1,34.5) | [(0,0),(0.0125795471363,-0.0850969365103),(0.158600957032,-0.0924966701199),(0.174387055399,-0.00320655123082)]
+ [(0,0),(3,0),(4,5),(1,6)] | (10,10)    | [(0,0),(0.15,-0.15),(0.45,0.05),(0.35,0.25)]
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ ((1,2),(3,4))             | (5.1,34.5) | ((0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952))
+ ((1,2),(3,4))             | (10,10)    | ((0.15,0.05),(0.35,0.05))
+ [(1,2),(3,4)]             | (5.1,34.5) | [(0.0609244733856,-0.0199792807459),(0.12604212915,-0.0683242069952)]
+ [(1,2),(3,4)]             | (10,10)    | [(0.15,0.05),(0.35,0.05)]
+ ((10,20))                 | (5.1,34.5) | ((0.609244733856,-0.199792807459))
+ ((10,20))                 | (10,10)    | ((1.5,0.5))
+ [(11,12),(13,14)]         | (5.1,34.5) | [(0.386512752208,-0.261703911993),(0.451630407972,-0.310048838242)]
+ [(11,12),(13,14)]         | (10,10)    | [(1.15,0.05),(1.35,0.05)]
+ ((11,12),(13,14))         | (5.1,34.5) | ((0.386512752208,-0.261703911993),(0.451630407972,-0.310048838242))
+ ((11,12),(13,14))         | (10,10)    | ((1.15,0.05),(1.35,0.05))
+(18 rows)
+
+-- Division by 0 error
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to path
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+            f1             |            f1             |    ?column?    
+---------------------------+---------------------------+----------------
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((10,20))                 |  17.4642491966
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         |   11.313708499
+ [(1,2),(3,4)]             | ((11,12),(13,14))         |   11.313708499
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | [(0,0),(3,0),(4,5),(1,6)] |              0
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((1,2),(3,4))             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | [(1,2),(3,4)]             | 0.784464540553
+ [(0,0),(3,0),(4,5),(1,6)] | ((10,20))                 |  16.1554944214
+ [(0,0),(3,0),(4,5),(1,6)] | [(11,12),(13,14)]         |  9.89949493661
+ [(0,0),(3,0),(4,5),(1,6)] | ((11,12),(13,14))         |  9.89949493661
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | ((1,2),(3,4))             |              0
+ ((1,2),(3,4))             | [(1,2),(3,4)]             |              0
+ ((1,2),(3,4))             | ((10,20))                 |  17.4642491966
+ ((1,2),(3,4))             | [(11,12),(13,14)]         |   11.313708499
+ ((1,2),(3,4))             | ((11,12),(13,14))         |   11.313708499
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(0,0),(3,0),(4,5),(1,6)] | 0.784464540553
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | ((1,2),(3,4))             |              0
+ [(1,2),(3,4)]             | [(1,2),(3,4)]             |              0
+ [(1,2),(3,4)]             | ((10,20))                 |  17.4642491966
+ [(1,2),(3,4)]             | [(11,12),(13,14)]         |   11.313708499
+ [(1,2),(3,4)]             | ((11,12),(13,14))         |   11.313708499
+ ((10,20))                 | [(1,2),(3,4)]             |  17.4642491966
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | [(0,0),(3,0),(4,5),(1,6)] |  16.1554944214
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | ((1,2),(3,4))             |  17.4642491966
+ ((10,20))                 | [(1,2),(3,4)]             |  17.4642491966
+ ((10,20))                 | ((10,20))                 |              0
+ ((10,20))                 | [(11,12),(13,14)]         |   6.7082039325
+ ((10,20))                 | ((11,12),(13,14))         |   6.7082039325
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             |   11.313708499
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | [(0,0),(3,0),(4,5),(1,6)] |  9.89949493661
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | ((1,2),(3,4))             |   11.313708499
+ [(11,12),(13,14)]         | [(1,2),(3,4)]             |   11.313708499
+ [(11,12),(13,14)]         | ((10,20))                 |   6.7082039325
+ [(11,12),(13,14)]         | [(11,12),(13,14)]         |              0
+ [(11,12),(13,14)]         | ((11,12),(13,14))         |              0
+ ((11,12),(13,14))         | [(1,2),(3,4)]             |   11.313708499
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | [(0,0),(3,0),(4,5),(1,6)] |  9.89949493661
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | ((1,2),(3,4))             |   11.313708499
+ ((11,12),(13,14))         | [(1,2),(3,4)]             |   11.313708499
+ ((11,12),(13,14))         | ((10,20))                 |   6.7082039325
+ ((11,12),(13,14))         | [(11,12),(13,14)]         |              0
+ ((11,12),(13,14))         | ((11,12),(13,14))         |              0
+(81 rows)
 
 --
 -- Polygons
 --
 -- containment
 SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
    FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
+ twentyfour |        f1         |             f1             | contains 
+------------+-------------------+----------------------------+----------
+            | (0,0)             | ((2,0),(2,4),(0,0))        | t
+            | (0,0)             | ((3,1),(3,3),(1,0))        | f
+            | (0,0)             | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (0,0)             | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (0,0)             | ((0,0))                    | t
+            | (0,0)             | ((0,1),(0,1))              | f
+            | (-10,0)           | ((2,0),(2,4),(0,0))        | f
+            | (-10,0)           | ((3,1),(3,3),(1,0))        | f
+            | (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-10,0)           | ((0,0))                    | f
+            | (-10,0)           | ((0,1),(0,1))              | f
+            | (-3,4)            | ((2,0),(2,4),(0,0))        | f
+            | (-3,4)            | ((3,1),(3,3),(1,0))        | f
+            | (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-3,4)            | ((0,0))                    | f
+            | (-3,4)            | ((0,1),(0,1))              | f
+            | (5.1,34.5)        | ((2,0),(2,4),(0,0))        | f
+            | (5.1,34.5)        | ((3,1),(3,3),(1,0))        | f
+            | (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (5.1,34.5)        | ((0,0))                    | f
+            | (5.1,34.5)        | ((0,1),(0,1))              | f
+            | (-5,-12)          | ((2,0),(2,4),(0,0))        | f
+            | (-5,-12)          | ((3,1),(3,3),(1,0))        | f
+            | (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-5,-12)          | ((0,0))                    | f
+            | (-5,-12)          | ((0,1),(0,1))              | f
+            | (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        | t
+            | (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        | f
+            | (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e-300,-1e-300)  | ((0,0))                    | t
+            | (1e-300,-1e-300)  | ((0,1),(0,1))              | f
+            | (1e+300,Infinity) | ((2,0),(2,4),(0,0))        | f
+            | (1e+300,Infinity) | ((3,1),(3,3),(1,0))        | f
+            | (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e+300,Infinity) | ((0,0))                    | f
+            | (1e+300,Infinity) | ((0,1),(0,1))              | f
+            | (NaN,NaN)         | ((2,0),(2,4),(0,0))        | t
+            | (NaN,NaN)         | ((3,1),(3,3),(1,0))        | t
+            | (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  | t
+            | (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  | t
+            | (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) | t
+            | (NaN,NaN)         | ((0,0))                    | t
+            | (NaN,NaN)         | ((0,1),(0,1))              | t
+            | (10,10)           | ((2,0),(2,4),(0,0))        | f
+            | (10,10)           | ((3,1),(3,3),(1,0))        | f
+            | (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (10,10)           | ((0,0))                    | f
+            | (10,10)           | ((0,1),(0,1))              | f
+(63 rows)
 
 SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
    FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
+ twentyfour |        f1         |             f1             | contained 
+------------+-------------------+----------------------------+-----------
+            | (0,0)             | ((2,0),(2,4),(0,0))        | t
+            | (0,0)             | ((3,1),(3,3),(1,0))        | f
+            | (0,0)             | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (0,0)             | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (0,0)             | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (0,0)             | ((0,0))                    | t
+            | (0,0)             | ((0,1),(0,1))              | f
+            | (-10,0)           | ((2,0),(2,4),(0,0))        | f
+            | (-10,0)           | ((3,1),(3,3),(1,0))        | f
+            | (-10,0)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-10,0)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-10,0)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-10,0)           | ((0,0))                    | f
+            | (-10,0)           | ((0,1),(0,1))              | f
+            | (-3,4)            | ((2,0),(2,4),(0,0))        | f
+            | (-3,4)            | ((3,1),(3,3),(1,0))        | f
+            | (-3,4)            | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-3,4)            | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-3,4)            | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-3,4)            | ((0,0))                    | f
+            | (-3,4)            | ((0,1),(0,1))              | f
+            | (5.1,34.5)        | ((2,0),(2,4),(0,0))        | f
+            | (5.1,34.5)        | ((3,1),(3,3),(1,0))        | f
+            | (5.1,34.5)        | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (5.1,34.5)        | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (5.1,34.5)        | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (5.1,34.5)        | ((0,0))                    | f
+            | (5.1,34.5)        | ((0,1),(0,1))              | f
+            | (-5,-12)          | ((2,0),(2,4),(0,0))        | f
+            | (-5,-12)          | ((3,1),(3,3),(1,0))        | f
+            | (-5,-12)          | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (-5,-12)          | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (-5,-12)          | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (-5,-12)          | ((0,0))                    | f
+            | (-5,-12)          | ((0,1),(0,1))              | f
+            | (1e-300,-1e-300)  | ((2,0),(2,4),(0,0))        | t
+            | (1e-300,-1e-300)  | ((3,1),(3,3),(1,0))        | f
+            | (1e-300,-1e-300)  | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e-300,-1e-300)  | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e-300,-1e-300)  | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e-300,-1e-300)  | ((0,0))                    | t
+            | (1e-300,-1e-300)  | ((0,1),(0,1))              | f
+            | (1e+300,Infinity) | ((2,0),(2,4),(0,0))        | f
+            | (1e+300,Infinity) | ((3,1),(3,3),(1,0))        | f
+            | (1e+300,Infinity) | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (1e+300,Infinity) | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (1e+300,Infinity) | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (1e+300,Infinity) | ((0,0))                    | f
+            | (1e+300,Infinity) | ((0,1),(0,1))              | f
+            | (NaN,NaN)         | ((2,0),(2,4),(0,0))        | t
+            | (NaN,NaN)         | ((3,1),(3,3),(1,0))        | t
+            | (NaN,NaN)         | ((1,2),(3,4),(5,6),(7,8))  | t
+            | (NaN,NaN)         | ((7,8),(5,6),(3,4),(1,2))  | t
+            | (NaN,NaN)         | ((1,2),(7,8),(5,6),(3,-4)) | t
+            | (NaN,NaN)         | ((0,0))                    | t
+            | (NaN,NaN)         | ((0,1),(0,1))              | t
+            | (10,10)           | ((2,0),(2,4),(0,0))        | f
+            | (10,10)           | ((3,1),(3,3),(1,0))        | f
+            | (10,10)           | ((1,2),(3,4),(5,6),(7,8))  | f
+            | (10,10)           | ((7,8),(5,6),(3,4),(1,2))  | f
+            | (10,10)           | ((1,2),(7,8),(5,6),(3,-4)) | f
+            | (10,10)           | ((0,0))                    | f
+            | (10,10)           | ((0,1),(0,1))              | f
+(63 rows)
 
 SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
    FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
+ four | npoints |          polygon           
+------+---------+----------------------------
       |       3 | ((2,0),(2,4),(0,0))
       |       3 | ((3,1),(3,3),(1,0))
+      |       4 | ((1,2),(3,4),(5,6),(7,8))
+      |       4 | ((7,8),(5,6),(3,4),(1,2))
+      |       4 | ((1,2),(7,8),(5,6),(3,-4))
       |       1 | ((0,0))
       |       2 | ((0,1),(0,1))
-(4 rows)
+(7 rows)
 
 SELECT '' AS four, polygon(f1)
    FROM BOX_TBL;
  four |                  polygon                  
 ------+-------------------------------------------
       | ((0,0),(0,2),(2,2),(2,0))
       | ((1,1),(1,3),(3,3),(3,1))
+      | ((-8,-10),(-8,2),(-2,2),(-2,-10))
       | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
       | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, polygon(f1)
    FROM PATH_TBL WHERE isclosed(f1);
  four |      polygon      
 ------+-------------------
       | ((1,2),(3,4))
       | ((1,2),(3,4))
       | ((1,2),(3,4))
+      | ((10,20))
       | ((11,12),(13,14))
-(4 rows)
+(5 rows)
 
 SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
    FROM PATH_TBL
    WHERE isopen(f1);
  four |         open_path         |          polygon          
 ------+---------------------------+---------------------------
       | [(1,2),(3,4)]             | ((1,2),(3,4))
       | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
       | [(1,2),(3,4)]             | ((1,2),(3,4))
       | [(11,12),(13,14)]         | ((11,12),(13,14))
 (4 rows)
 
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
+-- To box
+SELECT f1, f1::box FROM POLYGON_TBL;
+             f1             |      f1      
+----------------------------+--------------
+ ((2,0),(2,4),(0,0))        | (2,4),(0,0)
+ ((3,1),(3,3),(1,0))        | (3,3),(1,0)
+ ((1,2),(3,4),(5,6),(7,8))  | (7,8),(1,2)
+ ((7,8),(5,6),(3,4),(1,2))  | (7,8),(1,2)
+ ((1,2),(7,8),(5,6),(3,-4)) | (7,8),(1,-4)
+ ((0,0))                    | (0,0),(0,0)
+ ((0,1),(0,1))              | (0,1),(0,1)
+(7 rows)
 
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
+-- To path
+SELECT f1, f1::path FROM POLYGON_TBL;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(7 rows)
 
+-- Same as polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 ~= p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(9 rows)
+
+-- Contained by polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <@ p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(12 rows)
+
+-- Contains polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 @> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(12 rows)
+
+-- Overlap with polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 && p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(25 rows)
+
+-- Left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 << p2.f1;
+      f1       |             f1             
+---------------+----------------------------
+ ((0,0))       | ((3,1),(3,3),(1,0))
+ ((0,0))       | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))       | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))       | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1)) | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1)) | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1)) | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1)) | ((1,2),(7,8),(5,6),(3,-4))
+(8 rows)
+
+-- Overlap of left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &< p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))                    | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1))              | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(32 rows)
+
+-- Right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 >> p2.f1;
+             f1             |      f1       
+----------------------------+---------------
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((0,1),(0,1))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1))
+(8 rows)
+
+-- Overlap of right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((2,0),(2,4),(0,0))        | ((0,1),(0,1))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((0,1),(0,1))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((3,1),(3,3),(1,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,0))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(37 rows)
+
+-- Below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <<| p2.f1;
+      f1       |            f1             
+---------------+---------------------------
+ ((0,0))       | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))       | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))       | ((0,1),(0,1))
+ ((0,1),(0,1)) | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1)) | ((7,8),(5,6),(3,4),(1,2))
+(5 rows)
+
+-- Overlap or below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &<| p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(3,4),(5,6),(7,8))
+ ((0,0))                    | ((7,8),(5,6),(3,4),(1,2))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,0))                    | ((0,1),(0,1))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(3,4),(5,6),(7,8))
+ ((0,1),(0,1))              | ((7,8),(5,6),(3,4),(1,2))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(31 rows)
+
+-- Above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |>> p2.f1;
+            f1             |      f1       
+---------------------------+---------------
+ ((1,2),(3,4),(5,6),(7,8)) | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8)) | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2)) | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2)) | ((0,1),(0,1))
+ ((0,1),(0,1))             | ((0,0))
+(5 rows)
+
+-- Overlap or above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |&> p2.f1;
+             f1             |             f1             
+----------------------------+----------------------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((2,0),(2,4),(0,0))        | ((0,0))
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4))
+ ((3,1),(3,3),(1,0))        | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((3,1),(3,3),(1,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((3,1),(3,3),(1,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((2,0),(2,4),(0,0))
+ ((0,0))                    | ((3,1),(3,3),(1,0))
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,0))                    | ((0,0))
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4))
+ ((0,1),(0,1))              | ((0,0))
+ ((0,1),(0,1))              | ((0,1),(0,1))
+(32 rows)
+
+-- Distance to polygon
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2;
+ERROR:  function "poly_distance" not implemented
 --
 -- Circles
 --
 SELECT '' AS six, circle(f1, 50.0)
    FROM POINT_TBL;
- six |     circle      
------+-----------------
+ six |         circle         
+-----+------------------------
      | <(0,0),50>
      | <(-10,0),50>
      | <(-3,4),50>
      | <(5.1,34.5),50>
      | <(-5,-12),50>
+     | <(1e-300,-1e-300),50>
+     | <(1e+300,Infinity),50>
+     | <(NaN,NaN),50>
      | <(10,10),50>
-(6 rows)
+(9 rows)
 
 SELECT '' AS four, circle(f1)
    FROM BOX_TBL;
- four |        circle         
-------+-----------------------
+ four |         circle         
+------+------------------------
       | <(1,1),1.41421356237>
       | <(2,2),1.41421356237>
+      | <(-5,-4),6.7082039325>
       | <(2.5,3),0.5>
       | <(3,3),0>
-(4 rows)
+(5 rows)
 
 SELECT '' AS two, circle(f1)
    FROM POLYGON_TBL
    WHERE (# f1) >= 3;
  two |                    circle                     
 -----+-----------------------------------------------
      | <(1.33333333333,1.33333333333),2.04168905064>
      | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
+     | <(4,5),2.82842712475>
+     | <(4,5),2.82842712475>
+     | <(4,3),4.80664375676>
+(5 rows)
 
 SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
    FROM CIRCLE_TBL c1, POINT_TBL p1
    WHERE (p1.f1 <-> c1.f1) > 0
    ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
+ twentyfour |     circle     |       point       |   distance    
+------------+----------------+-------------------+---------------
+            | <(1,2),3>      | (-3,4)            |   1.472135955
+            | <(5,1),3>      | (0,0)             | 2.09901951359
+            | <(5,1),3>      | (1e-300,-1e-300)  | 2.09901951359
+            | <(5,1),3>      | (-3,4)            | 5.54400374532
+            | <(3,5),0>      | (0,0)             | 5.83095189485
+            | <(3,5),0>      | (1e-300,-1e-300)  | 5.83095189485
+            | <(3,5),0>      | (-3,4)            |  6.0827625303
+            | <(1,3),5>      | (-10,0)           | 6.40175425099
+            | <(1,3),5>      | (10,10)           | 6.40175425099
+            | <(5,1),3>      | (10,10)           | 7.29563014099
+            | <(1,2),3>      | (-10,0)           |  8.1803398875
+            | <(3,5),0>      | (10,10)           | 8.60232526704
+            | <(1,2),3>      | (10,10)           | 9.04159457879
+            | <(1,3),5>      | (-5,-12)          | 11.1554944214
+            | <(5,1),3>      | (-10,0)           | 12.0332963784
+            | <(1,2),3>      | (-5,-12)          | 12.2315462117
+            | <(5,1),3>      | (-5,-12)          | 13.4012194669
+            | <(3,5),0>      | (-10,0)           | 13.9283882772
+            | <(3,5),0>      | (-5,-12)          | 18.7882942281
+            | <(1,3),5>      | (5.1,34.5)        | 26.7657047773
+            | <(3,5),0>      | (5.1,34.5)        | 29.5746513082
+            | <(1,2),3>      | (5.1,34.5)        | 29.7575945393
+            | <(5,1),3>      | (5.1,34.5)        | 30.5001492534
+            | <(100,200),10> | (5.1,34.5)        | 180.778038568
+            | <(100,200),10> | (10,10)           | 200.237960416
+            | <(100,200),10> | (-3,4)            | 211.415898255
+            | <(100,200),10> | (0,0)             |  213.60679775
+            | <(100,200),10> | (1e-300,-1e-300)  |  213.60679775
+            | <(100,200),10> | (-10,0)           |  218.25424421
+            | <(100,200),10> | (-5,-12)          | 226.577682802
+            | <(3,5),0>      | (1e+300,Infinity) |      Infinity
+            | <(1,2),3>      | (1e+300,Infinity) |      Infinity
+            | <(5,1),3>      | (1e+300,Infinity) |      Infinity
+            | <(1,3),5>      | (1e+300,Infinity) |      Infinity
+            | <(100,200),10> | (1e+300,Infinity) |      Infinity
+            | <(1,2),100>    | (1e+300,Infinity) |      Infinity
+            | <(100,1),115>  | (1e+300,Infinity) |      Infinity
+            | <(3,5),0>      | (NaN,NaN)         |           NaN
+            | <(1,2),3>      | (NaN,NaN)         |           NaN
+            | <(5,1),3>      | (NaN,NaN)         |           NaN
+            | <(1,3),5>      | (NaN,NaN)         |           NaN
+            | <(100,200),10> | (NaN,NaN)         |           NaN
+            | <(1,2),100>    | (NaN,NaN)         |           NaN
+            | <(100,1),115>  | (NaN,NaN)         |           NaN
+            | <(3,5),NaN>    | (-10,0)           |           NaN
+            | <(3,5),NaN>    | (-5,-12)          |           NaN
+            | <(3,5),NaN>    | (-3,4)            |           NaN
+            | <(3,5),NaN>    | (0,0)             |           NaN
+            | <(3,5),NaN>    | (1e-300,-1e-300)  |           NaN
+            | <(3,5),NaN>    | (5.1,34.5)        |           NaN
+            | <(3,5),NaN>    | (10,10)           |           NaN
+            | <(3,5),NaN>    | (1e+300,Infinity) |           NaN
+            | <(3,5),NaN>    | (NaN,NaN)         |           NaN
+(53 rows)
+
+-- To polygon
+SELECT f1, f1::polygon FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+       f1       |                                                                                                          f1                                                                                                          
+----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ <(5,1),3>      | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
+ <(1,2),100>    | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
+ <(1,3),5>      | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
+ <(1,2),3>      | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
+ <(100,200),10> | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
+ <(100,1),115>  | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
+(6 rows)
+
+-- To polygon with less points
+SELECT f1, polygon(8, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+       f1       |                                                                             polygon                                                                              
+----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ <(5,1),3>      | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
+ <(1,2),100>    | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
+ <(1,3),5>      | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
+ <(1,2),3>      | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
+ <(100,200),10> | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
+ <(100,1),115>  | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
+(6 rows)
+
+-- Too less points error
+SELECT f1, polygon(1, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+ERROR:  must request at least 2 points
+-- Zero radius error
+SELECT f1, polygon(10, f1) FROM CIRCLE_TBL WHERE f1 < '<(0,0),1>';
+ERROR:  cannot convert circle with radius zero to polygon
+-- Same as circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 ~= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+ <(3,5),NaN>    | <(3,5),0>
+ <(3,5),NaN>    | <(3,5),NaN>
+(9 rows)
+
+-- Overlap with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 && c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,1),115>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(100,1),115>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(33 rows)
+
+-- Overlap or left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &< c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(28 rows)
+
+-- Left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 << c2.f1;
+    f1     |       f1       
+-----------+----------------
+ <(5,1),3> | <(100,200),10>
+ <(1,3),5> | <(100,200),10>
+ <(1,2),3> | <(100,200),10>
+ <(3,5),0> | <(100,200),10>
+(4 rows)
+
+-- Right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >> c2.f1;
+       f1       |    f1     
+----------------+-----------
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(3,5),0>
+(4 rows)
+
+-- Overlap or right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(28 rows)
+
+-- Contained by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <@ c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(17 rows)
+
+-- Contain by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 @> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(3,5),0>
+(17 rows)
+
+-- Below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <<| c2.f1;
+      f1       |       f1       
+---------------+----------------
+ <(5,1),3>     | <(100,200),10>
+ <(5,1),3>     | <(3,5),0>
+ <(1,2),100>   | <(100,200),10>
+ <(1,3),5>     | <(100,200),10>
+ <(1,2),3>     | <(100,200),10>
+ <(100,1),115> | <(100,200),10>
+ <(3,5),0>     | <(100,200),10>
+(7 rows)
+
+-- Above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |>> c2.f1;
+       f1       |      f1       
+----------------+---------------
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(3,5),0>      | <(5,1),3>
+(7 rows)
+
+-- Overlap or below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &<| c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Overlap or above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |&> c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 = c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(9 rows)
+
+-- Area not equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 != c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(100,1),115>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,1),115>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(40 rows)
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 > c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(3,5),0>
+(20 rows)
+
+-- Area less than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(100,1),115>
+ <(100,1),115>  | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area greater than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >= c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(5,1),3>
+ <(5,1),3>      | <(1,2),3>
+ <(5,1),3>      | <(3,5),0>
+ <(1,2),100>    | <(5,1),3>
+ <(1,2),100>    | <(1,2),100>
+ <(1,2),100>    | <(1,3),5>
+ <(1,2),100>    | <(1,2),3>
+ <(1,2),100>    | <(100,200),10>
+ <(1,2),100>    | <(3,5),0>
+ <(1,3),5>      | <(5,1),3>
+ <(1,3),5>      | <(1,3),5>
+ <(1,3),5>      | <(1,2),3>
+ <(1,3),5>      | <(3,5),0>
+ <(1,2),3>      | <(5,1),3>
+ <(1,2),3>      | <(1,2),3>
+ <(1,2),3>      | <(3,5),0>
+ <(100,200),10> | <(5,1),3>
+ <(100,200),10> | <(1,3),5>
+ <(100,200),10> | <(1,2),3>
+ <(100,200),10> | <(100,200),10>
+ <(100,200),10> | <(3,5),0>
+ <(100,1),115>  | <(5,1),3>
+ <(100,1),115>  | <(1,2),100>
+ <(100,1),115>  | <(1,3),5>
+ <(100,1),115>  | <(1,2),3>
+ <(100,1),115>  | <(100,200),10>
+ <(100,1),115>  | <(100,1),115>
+ <(100,1),115>  | <(3,5),0>
+ <(3,5),0>      | <(3,5),0>
+(29 rows)
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+       f1       |       f1       
+----------------+----------------
+ <(5,1),3>      | <(1,2),100>
+ <(5,1),3>      | <(1,3),5>
+ <(5,1),3>      | <(100,200),10>
+ <(5,1),3>      | <(100,1),115>
+ <(1,2),100>    | <(100,1),115>
+ <(1,3),5>      | <(1,2),100>
+ <(1,3),5>      | <(100,200),10>
+ <(1,3),5>      | <(100,1),115>
+ <(1,2),3>      | <(1,2),100>
+ <(1,2),3>      | <(1,3),5>
+ <(1,2),3>      | <(100,200),10>
+ <(1,2),3>      | <(100,1),115>
+ <(100,200),10> | <(1,2),100>
+ <(100,200),10> | <(100,1),115>
+ <(3,5),0>      | <(5,1),3>
+ <(3,5),0>      | <(1,2),100>
+ <(3,5),0>      | <(1,3),5>
+ <(3,5),0>      | <(1,2),3>
+ <(3,5),0>      | <(100,200),10>
+ <(3,5),0>      | <(100,1),115>
+(20 rows)
+
+-- Add point
+SELECT c.f1, p.f1, c.f1 + p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |        ?column?         
+----------------+-------------------+-------------------------
+ <(5,1),3>      | (0,0)             | <(5,1),3>
+ <(1,2),100>    | (0,0)             | <(1,2),100>
+ <(1,3),5>      | (0,0)             | <(1,3),5>
+ <(1,2),3>      | (0,0)             | <(1,2),3>
+ <(100,200),10> | (0,0)             | <(100,200),10>
+ <(100,1),115>  | (0,0)             | <(100,1),115>
+ <(3,5),0>      | (0,0)             | <(3,5),0>
+ <(3,5),NaN>    | (0,0)             | <(3,5),NaN>
+ <(5,1),3>      | (-10,0)           | <(-5,1),3>
+ <(1,2),100>    | (-10,0)           | <(-9,2),100>
+ <(1,3),5>      | (-10,0)           | <(-9,3),5>
+ <(1,2),3>      | (-10,0)           | <(-9,2),3>
+ <(100,200),10> | (-10,0)           | <(90,200),10>
+ <(100,1),115>  | (-10,0)           | <(90,1),115>
+ <(3,5),0>      | (-10,0)           | <(-7,5),0>
+ <(3,5),NaN>    | (-10,0)           | <(-7,5),NaN>
+ <(5,1),3>      | (-3,4)            | <(2,5),3>
+ <(1,2),100>    | (-3,4)            | <(-2,6),100>
+ <(1,3),5>      | (-3,4)            | <(-2,7),5>
+ <(1,2),3>      | (-3,4)            | <(-2,6),3>
+ <(100,200),10> | (-3,4)            | <(97,204),10>
+ <(100,1),115>  | (-3,4)            | <(97,5),115>
+ <(3,5),0>      | (-3,4)            | <(0,9),0>
+ <(3,5),NaN>    | (-3,4)            | <(0,9),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(10.1,35.5),3>
+ <(1,2),100>    | (5.1,34.5)        | <(6.1,36.5),100>
+ <(1,3),5>      | (5.1,34.5)        | <(6.1,37.5),5>
+ <(1,2),3>      | (5.1,34.5)        | <(6.1,36.5),3>
+ <(100,200),10> | (5.1,34.5)        | <(105.1,234.5),10>
+ <(100,1),115>  | (5.1,34.5)        | <(105.1,35.5),115>
+ <(3,5),0>      | (5.1,34.5)        | <(8.1,39.5),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(8.1,39.5),NaN>
+ <(5,1),3>      | (-5,-12)          | <(0,-11),3>
+ <(1,2),100>    | (-5,-12)          | <(-4,-10),100>
+ <(1,3),5>      | (-5,-12)          | <(-4,-9),5>
+ <(1,2),3>      | (-5,-12)          | <(-4,-10),3>
+ <(100,200),10> | (-5,-12)          | <(95,188),10>
+ <(100,1),115>  | (-5,-12)          | <(95,-11),115>
+ <(3,5),0>      | (-5,-12)          | <(-2,-7),0>
+ <(3,5),NaN>    | (-5,-12)          | <(-2,-7),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(5,1),3>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(1,2),100>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(1,3),5>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(1,2),3>
+ <(100,200),10> | (1e-300,-1e-300)  | <(100,200),10>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(100,1),115>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(3,5),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(3,5),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(1e+300,Infinity),3>
+ <(1,2),100>    | (1e+300,Infinity) | <(1e+300,Infinity),100>
+ <(1,3),5>      | (1e+300,Infinity) | <(1e+300,Infinity),5>
+ <(1,2),3>      | (1e+300,Infinity) | <(1e+300,Infinity),3>
+ <(100,200),10> | (1e+300,Infinity) | <(1e+300,Infinity),10>
+ <(100,1),115>  | (1e+300,Infinity) | <(1e+300,Infinity),115>
+ <(3,5),0>      | (1e+300,Infinity) | <(1e+300,Infinity),0>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(1e+300,Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),100>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),5>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),10>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),115>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),0>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(15,11),3>
+ <(1,2),100>    | (10,10)           | <(11,12),100>
+ <(1,3),5>      | (10,10)           | <(11,13),5>
+ <(1,2),3>      | (10,10)           | <(11,12),3>
+ <(100,200),10> | (10,10)           | <(110,210),10>
+ <(100,1),115>  | (10,10)           | <(110,11),115>
+ <(3,5),0>      | (10,10)           | <(13,15),0>
+ <(3,5),NaN>    | (10,10)           | <(13,15),NaN>
+(72 rows)
+
+-- Subtract point
+SELECT c.f1, p.f1, c.f1 - p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |         ?column?          
+----------------+-------------------+---------------------------
+ <(5,1),3>      | (0,0)             | <(5,1),3>
+ <(1,2),100>    | (0,0)             | <(1,2),100>
+ <(1,3),5>      | (0,0)             | <(1,3),5>
+ <(1,2),3>      | (0,0)             | <(1,2),3>
+ <(100,200),10> | (0,0)             | <(100,200),10>
+ <(100,1),115>  | (0,0)             | <(100,1),115>
+ <(3,5),0>      | (0,0)             | <(3,5),0>
+ <(3,5),NaN>    | (0,0)             | <(3,5),NaN>
+ <(5,1),3>      | (-10,0)           | <(15,1),3>
+ <(1,2),100>    | (-10,0)           | <(11,2),100>
+ <(1,3),5>      | (-10,0)           | <(11,3),5>
+ <(1,2),3>      | (-10,0)           | <(11,2),3>
+ <(100,200),10> | (-10,0)           | <(110,200),10>
+ <(100,1),115>  | (-10,0)           | <(110,1),115>
+ <(3,5),0>      | (-10,0)           | <(13,5),0>
+ <(3,5),NaN>    | (-10,0)           | <(13,5),NaN>
+ <(5,1),3>      | (-3,4)            | <(8,-3),3>
+ <(1,2),100>    | (-3,4)            | <(4,-2),100>
+ <(1,3),5>      | (-3,4)            | <(4,-1),5>
+ <(1,2),3>      | (-3,4)            | <(4,-2),3>
+ <(100,200),10> | (-3,4)            | <(103,196),10>
+ <(100,1),115>  | (-3,4)            | <(103,-3),115>
+ <(3,5),0>      | (-3,4)            | <(6,1),0>
+ <(3,5),NaN>    | (-3,4)            | <(6,1),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(-0.1,-33.5),3>
+ <(1,2),100>    | (5.1,34.5)        | <(-4.1,-32.5),100>
+ <(1,3),5>      | (5.1,34.5)        | <(-4.1,-31.5),5>
+ <(1,2),3>      | (5.1,34.5)        | <(-4.1,-32.5),3>
+ <(100,200),10> | (5.1,34.5)        | <(94.9,165.5),10>
+ <(100,1),115>  | (5.1,34.5)        | <(94.9,-33.5),115>
+ <(3,5),0>      | (5.1,34.5)        | <(-2.1,-29.5),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(-2.1,-29.5),NaN>
+ <(5,1),3>      | (-5,-12)          | <(10,13),3>
+ <(1,2),100>    | (-5,-12)          | <(6,14),100>
+ <(1,3),5>      | (-5,-12)          | <(6,15),5>
+ <(1,2),3>      | (-5,-12)          | <(6,14),3>
+ <(100,200),10> | (-5,-12)          | <(105,212),10>
+ <(100,1),115>  | (-5,-12)          | <(105,13),115>
+ <(3,5),0>      | (-5,-12)          | <(8,17),0>
+ <(3,5),NaN>    | (-5,-12)          | <(8,17),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(5,1),3>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(1,2),100>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(1,3),5>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(1,2),3>
+ <(100,200),10> | (1e-300,-1e-300)  | <(100,200),10>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(100,1),115>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(3,5),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(3,5),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(-1e+300,-Infinity),3>
+ <(1,2),100>    | (1e+300,Infinity) | <(-1e+300,-Infinity),100>
+ <(1,3),5>      | (1e+300,Infinity) | <(-1e+300,-Infinity),5>
+ <(1,2),3>      | (1e+300,Infinity) | <(-1e+300,-Infinity),3>
+ <(100,200),10> | (1e+300,Infinity) | <(-1e+300,-Infinity),10>
+ <(100,1),115>  | (1e+300,Infinity) | <(-1e+300,-Infinity),115>
+ <(3,5),0>      | (1e+300,Infinity) | <(-1e+300,-Infinity),0>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(-1e+300,-Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),100>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),5>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),3>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),10>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),115>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),0>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(-5,-9),3>
+ <(1,2),100>    | (10,10)           | <(-9,-8),100>
+ <(1,3),5>      | (10,10)           | <(-9,-7),5>
+ <(1,2),3>      | (10,10)           | <(-9,-8),3>
+ <(100,200),10> | (10,10)           | <(90,190),10>
+ <(100,1),115>  | (10,10)           | <(90,-9),115>
+ <(3,5),0>      | (10,10)           | <(-7,-5),0>
+ <(3,5),NaN>    | (10,10)           | <(-7,-5),NaN>
+(72 rows)
+
+-- Multiply with point
+SELECT c.f1, p.f1, c.f1 * p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+       f1       |        f1         |                  ?column?                  
+----------------+-------------------+--------------------------------------------
+ <(5,1),3>      | (0,0)             | <(0,0),0>
+ <(1,2),100>    | (0,0)             | <(0,0),0>
+ <(1,3),5>      | (0,0)             | <(0,0),0>
+ <(1,2),3>      | (0,0)             | <(0,0),0>
+ <(100,200),10> | (0,0)             | <(0,0),0>
+ <(100,1),115>  | (0,0)             | <(0,0),0>
+ <(3,5),0>      | (0,0)             | <(0,0),0>
+ <(3,5),NaN>    | (0,0)             | <(0,0),NaN>
+ <(5,1),3>      | (-10,0)           | <(-50,-10),30>
+ <(1,2),100>    | (-10,0)           | <(-10,-20),1000>
+ <(1,3),5>      | (-10,0)           | <(-10,-30),50>
+ <(1,2),3>      | (-10,0)           | <(-10,-20),30>
+ <(100,200),10> | (-10,0)           | <(-1000,-2000),100>
+ <(100,1),115>  | (-10,0)           | <(-1000,-10),1150>
+ <(3,5),0>      | (-10,0)           | <(-30,-50),0>
+ <(3,5),NaN>    | (-10,0)           | <(-30,-50),NaN>
+ <(5,1),3>      | (-3,4)            | <(-19,17),15>
+ <(1,2),100>    | (-3,4)            | <(-11,-2),500>
+ <(1,3),5>      | (-3,4)            | <(-15,-5),25>
+ <(1,2),3>      | (-3,4)            | <(-11,-2),15>
+ <(100,200),10> | (-3,4)            | <(-1100,-200),50>
+ <(100,1),115>  | (-3,4)            | <(-304,397),575>
+ <(3,5),0>      | (-3,4)            | <(-29,-3),0>
+ <(3,5),NaN>    | (-3,4)            | <(-29,-3),NaN>
+ <(5,1),3>      | (5.1,34.5)        | <(-9,177.6),104.624758064>
+ <(1,2),100>    | (5.1,34.5)        | <(-63.9,44.7),3487.49193547>
+ <(1,3),5>      | (5.1,34.5)        | <(-98.4,49.8),174.374596774>
+ <(1,2),3>      | (5.1,34.5)        | <(-63.9,44.7),104.624758064>
+ <(100,200),10> | (5.1,34.5)        | <(-6390,4470),348.749193547>
+ <(100,1),115>  | (5.1,34.5)        | <(475.5,3455.1),4010.6157258>
+ <(3,5),0>      | (5.1,34.5)        | <(-157.2,129),0>
+ <(3,5),NaN>    | (5.1,34.5)        | <(-157.2,129),NaN>
+ <(5,1),3>      | (-5,-12)          | <(-13,-65),39>
+ <(1,2),100>    | (-5,-12)          | <(19,-22),1300>
+ <(1,3),5>      | (-5,-12)          | <(31,-27),65>
+ <(1,2),3>      | (-5,-12)          | <(19,-22),39>
+ <(100,200),10> | (-5,-12)          | <(1900,-2200),130>
+ <(100,1),115>  | (-5,-12)          | <(-488,-1205),1495>
+ <(3,5),0>      | (-5,-12)          | <(45,-61),0>
+ <(3,5),NaN>    | (-5,-12)          | <(45,-61),NaN>
+ <(5,1),3>      | (1e-300,-1e-300)  | <(6e-300,-4e-300),4.24264068712e-300>
+ <(1,2),100>    | (1e-300,-1e-300)  | <(3e-300,1e-300),1.41421356237e-298>
+ <(1,3),5>      | (1e-300,-1e-300)  | <(4e-300,2e-300),7.07106781187e-300>
+ <(1,2),3>      | (1e-300,-1e-300)  | <(3e-300,1e-300),4.24264068712e-300>
+ <(100,200),10> | (1e-300,-1e-300)  | <(3e-298,1e-298),1.41421356237e-299>
+ <(100,1),115>  | (1e-300,-1e-300)  | <(1.01e-298,-9.9e-299),1.62634559673e-298>
+ <(3,5),0>      | (1e-300,-1e-300)  | <(8e-300,2e-300),0>
+ <(3,5),NaN>    | (1e-300,-1e-300)  | <(8e-300,2e-300),NaN>
+ <(5,1),3>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,2),100>    | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,3),5>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(1,2),3>      | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(100,200),10> | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(100,1),115>  | (1e+300,Infinity) | <(-Infinity,Infinity),Infinity>
+ <(3,5),0>      | (1e+300,Infinity) | <(-Infinity,Infinity),NaN>
+ <(3,5),NaN>    | (1e+300,Infinity) | <(-Infinity,Infinity),NaN>
+ <(5,1),3>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,2),100>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,3),5>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(1,2),3>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(100,200),10> | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(100,1),115>  | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(3,5),0>      | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(3,5),NaN>    | (NaN,NaN)         | <(NaN,NaN),NaN>
+ <(5,1),3>      | (10,10)           | <(40,60),42.4264068712>
+ <(1,2),100>    | (10,10)           | <(-10,30),1414.21356237>
+ <(1,3),5>      | (10,10)           | <(-20,40),70.7106781187>
+ <(1,2),3>      | (10,10)           | <(-10,30),42.4264068712>
+ <(100,200),10> | (10,10)           | <(-1000,3000),141.421356237>
+ <(100,1),115>  | (10,10)           | <(990,1010),1626.34559673>
+ <(3,5),0>      | (10,10)           | <(-20,80),0>
+ <(3,5),NaN>    | (10,10)           | <(-20,80),NaN>
+(72 rows)
+
+-- Divide by point
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+       f1       |     f1     |                       ?column?                       
+----------------+------------+------------------------------------------------------
+ <(5,1),3>      | (5.1,34.5) | <(0.0493315573973,-0.137635045138),0.0860217042937>
+ <(5,1),3>      | (10,10)    | <(0.3,-0.2),0.212132034356>
+ <(1,2),100>    | (5.1,34.5) | <(0.0609244733856,-0.0199792807459),2.86739014312>
+ <(1,2),100>    | (10,10)    | <(0.15,0.05),7.07106781187>
+ <(1,3),5>      | (5.1,34.5) | <(0.0892901188891,-0.0157860983671),0.143369507156>
+ <(1,3),5>      | (10,10)    | <(0.2,0.1),0.353553390593>
+ <(1,2),3>      | (5.1,34.5) | <(0.0609244733856,-0.0199792807459),0.0860217042937>
+ <(1,2),3>      | (10,10)    | <(0.15,0.05),0.212132034356>
+ <(100,200),10> | (5.1,34.5) | <(6.09244733856,-1.99792807459),0.286739014312>
+ <(100,200),10> | (10,10)    | <(15,5),0.707106781187>
+ <(100,1),115>  | (5.1,34.5) | <(0.44768388338,-2.83237136796),3.29749866459>
+ <(100,1),115>  | (10,10)    | <(5.05,-4.95),8.13172798365>
+ <(3,5),0>      | (5.1,34.5) | <(0.154407774653,-0.0641310246164),0>
+ <(3,5),0>      | (10,10)    | <(0.4,0.1),0>
+ <(3,5),NaN>    | (5.1,34.5) | <(0.154407774653,-0.0641310246164),NaN>
+ <(3,5),NaN>    | (10,10)    | <(0.4,0.1),NaN>
+(16 rows)
+
+-- Overflow error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] > 1000;
+ERROR:  value out of range: overflow
+-- Division by 0 error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1 ~= '(0,0)'::point;
+ERROR:  division by zero
+-- Distance to polygon
+SELECT c.f1, p.f1, c.f1 <-> p.f1 FROM CIRCLE_TBL c, POLYGON_TBL p;
+       f1       |             f1             |    ?column?    
+----------------+----------------------------+----------------
+ <(5,1),3>      | ((2,0),(2,4),(0,0))        |              0
+ <(5,1),3>      | ((3,1),(3,3),(1,0))        |              0
+ <(5,1),3>      | ((1,2),(3,4),(5,6),(7,8))  | 0.535533905933
+ <(5,1),3>      | ((7,8),(5,6),(3,4),(1,2))  | 0.535533905933
+ <(5,1),3>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(5,1),3>      | ((0,0))                    |  2.09901951359
+ <(5,1),3>      | ((0,1),(0,1))              |              2
+ <(1,2),100>    | ((2,0),(2,4),(0,0))        |              0
+ <(1,2),100>    | ((3,1),(3,3),(1,0))        |              0
+ <(1,2),100>    | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,2),100>    | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,2),100>    | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,2),100>    | ((0,0))                    |              0
+ <(1,2),100>    | ((0,1),(0,1))              |              0
+ <(1,3),5>      | ((2,0),(2,4),(0,0))        |              0
+ <(1,3),5>      | ((3,1),(3,3),(1,0))        |              0
+ <(1,3),5>      | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,3),5>      | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,3),5>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,3),5>      | ((0,0))                    |              0
+ <(1,3),5>      | ((0,1),(0,1))              |              0
+ <(1,2),3>      | ((2,0),(2,4),(0,0))        |              0
+ <(1,2),3>      | ((3,1),(3,3),(1,0))        |              0
+ <(1,2),3>      | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(1,2),3>      | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(1,2),3>      | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(1,2),3>      | ((0,0))                    |              0
+ <(1,2),3>      | ((0,1),(0,1))              |              0
+ <(100,200),10> | ((2,0),(2,4),(0,0))        |  209.134661795
+ <(100,200),10> | ((3,1),(3,3),(1,0))        |  209.585974051
+ <(100,200),10> | ((1,2),(3,4),(5,6),(7,8))  |  203.337760371
+ <(100,200),10> | ((7,8),(5,6),(3,4),(1,2))  |  203.337760371
+ <(100,200),10> | ((1,2),(7,8),(5,6),(3,-4)) |  203.337760371
+ <(100,200),10> | ((0,0))                    |   213.60679775
+ <(100,200),10> | ((0,1),(0,1))              |  212.712819568
+ <(100,1),115>  | ((2,0),(2,4),(0,0))        |              0
+ <(100,1),115>  | ((3,1),(3,3),(1,0))        |              0
+ <(100,1),115>  | ((1,2),(3,4),(5,6),(7,8))  |              0
+ <(100,1),115>  | ((7,8),(5,6),(3,4),(1,2))  |              0
+ <(100,1),115>  | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ <(100,1),115>  | ((0,0))                    |              0
+ <(100,1),115>  | ((0,1),(0,1))              |              0
+ <(3,5),0>      | ((2,0),(2,4),(0,0))        |  1.41421356237
+ <(3,5),0>      | ((3,1),(3,3),(1,0))        |              2
+ <(3,5),0>      | ((1,2),(3,4),(5,6),(7,8))  | 0.707106781187
+ <(3,5),0>      | ((7,8),(5,6),(3,4),(1,2))  | 0.707106781187
+ <(3,5),0>      | ((1,2),(7,8),(5,6),(3,-4)) | 0.707106781187
+ <(3,5),0>      | ((0,0))                    |  5.83095189485
+ <(3,5),0>      | ((0,1),(0,1))              |              5
+ <(3,5),NaN>    | ((2,0),(2,4),(0,0))        |            NaN
+ <(3,5),NaN>    | ((3,1),(3,3),(1,0))        |            NaN
+ <(3,5),NaN>    | ((1,2),(3,4),(5,6),(7,8))  |            NaN
+ <(3,5),NaN>    | ((7,8),(5,6),(3,4),(1,2))  |            NaN
+ <(3,5),NaN>    | ((1,2),(7,8),(5,6),(3,-4)) |            NaN
+ <(3,5),NaN>    | ((0,0))                    |            NaN
+ <(3,5),NaN>    | ((0,1),(0,1))              |            NaN
+(56 rows)
 
diff --git a/src/test/regress/expected/geometry_2.out b/src/test/regress/expected/geometry_2.out
deleted file mode 100644
index 5a922bcd3f..0000000000
--- a/src/test/regress/expected/geometry_2.out
+++ /dev/null
@@ -1,563 +0,0 @@
---
--- GEOMETRY
---
--- Back off displayed precision a little bit to reduce platform-to-platform
--- variation in results.
-SET extra_float_digits TO -3;
---
--- Points
---
-SELECT '' AS four, center(f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS four, (@@ f1) AS center
-   FROM BOX_TBL;
- four | center  
-------+---------
-      | (1,1)
-      | (2,2)
-      | (2.5,3)
-      | (3,3)
-(4 rows)
-
-SELECT '' AS six, point(f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS six, (@@ f1) AS center
-   FROM CIRCLE_TBL;
- six |  center   
------+-----------
-     | (5,1)
-     | (1,2)
-     | (1,3)
-     | (1,2)
-     | (100,200)
-     | (100,1)
-(6 rows)
-
-SELECT '' AS two, (@@ f1) AS center
-   FROM POLYGON_TBL
-   WHERE (# f1) > 2;
- two |            center             
------+-------------------------------
-     | (1.33333333333,1.33333333333)
-     | (2.33333333333,1.33333333333)
-(2 rows)
-
--- "is horizontal" function
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE ishorizontal(p1.f1, point '(0,0)');
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is horizontal" operator
-SELECT '' AS two, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?- point '(0,0)';
- two |   f1    
------+---------
-     | (0,0)
-     | (-10,0)
-(2 rows)
-
--- "is vertical" function
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE isvertical(p1.f1, point '(5.1,34.5)');
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
--- "is vertical" operator
-SELECT '' AS one, p1.f1
-   FROM POINT_TBL p1
-   WHERE p1.f1 ?| point '(5.1,34.5)';
- one |     f1     
------+------------
-     | (5.1,34.5)
-(1 row)
-
---
--- Line segments
---
--- intersection
-SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-   FROM LSEG_TBL l, POINT_TBL p;
-ERROR:  operator does not exist: lseg # point
-LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
-                                           ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
- thirty |     f1     |               s               |             closest              
---------+------------+-------------------------------+----------------------------------
-        | (0,0)      | [(1,2),(3,4)]                 | (1,2)
-        | (0,0)      | [(0,0),(6,6)]                 | (0,0)
-        | (0,0)      | [(10,-10),(-3,-4)]            | (-2.0487804878,-4.43902439024)
-        | (0,0)      | [(-1000000,200),(300000,-40)] | (0.00284023658959,15.3846148603)
-        | (0,0)      | [(11,22),(33,44)]             | (11,22)
-        | (-10,0)    | [(1,2),(3,4)]                 | (1,2)
-        | (-10,0)    | [(0,0),(6,6)]                 | (0,0)
-        | (-10,0)    | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-10,0)    | [(-1000000,200),(300000,-40)] | (-9.99715942258,15.386461014)
-        | (-10,0)    | [(11,22),(33,44)]             | (11,22)
-        | (-3,4)     | [(1,2),(3,4)]                 | (1,2)
-        | (-3,4)     | [(0,0),(6,6)]                 | (0.5,0.5)
-        | (-3,4)     | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (-3,4)     | [(-1000000,200),(300000,-40)] | (-2.99789812268,15.3851688427)
-        | (-3,4)     | [(11,22),(33,44)]             | (11,22)
-        | (5.1,34.5) | [(1,2),(3,4)]                 | (3,4)
-        | (5.1,34.5) | [(0,0),(6,6)]                 | (6,6)
-        | (5.1,34.5) | [(10,-10),(-3,-4)]            | (-3,-4)
-        | (5.1,34.5) | [(-1000000,200),(300000,-40)] | (5.09647083221,15.3836744977)
-        | (5.1,34.5) | [(11,22),(33,44)]             | (14.3,25.3)
-        | (-5,-12)   | [(1,2),(3,4)]                 | (1,2)
-        | (-5,-12)   | [(0,0),(6,6)]                 | (0,0)
-        | (-5,-12)   | [(10,-10),(-3,-4)]            | (-1.60487804878,-4.64390243902)
-        | (-5,-12)   | [(-1000000,200),(300000,-40)] | (-4.99494420846,15.3855375282)
-        | (-5,-12)   | [(11,22),(33,44)]             | (11,22)
-        | (10,10)    | [(1,2),(3,4)]                 | (3,4)
-        | (10,10)    | [(0,0),(6,6)]                 | (6,6)
-        | (10,10)    | [(10,-10),(-3,-4)]            | (2.39024390244,-6.48780487805)
-        | (10,10)    | [(-1000000,200),(300000,-40)] | (10.000993742,15.3827690473)
-        | (10,10)    | [(11,22),(33,44)]             | (11,22)
-(30 rows)
-
---
--- Boxes
---
-SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
- six |                              box                               
------+----------------------------------------------------------------
-     | (7.12132034356,3.12132034356),(2.87867965644,-1.12132034356)
-     | (71.7106781187,72.7106781187),(-69.7106781187,-68.7106781187)
-     | (4.53553390593,6.53553390593),(-2.53553390593,-0.535533905933)
-     | (3.12132034356,4.12132034356),(-1.12132034356,-0.12132034356)
-     | (107.071067812,207.071067812),(92.9289321881,192.928932188)
-     | (181.317279836,82.3172798365),(18.6827201635,-80.3172798365)
-(6 rows)
-
--- translation
-SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |       translation       
-------------+-------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (-8,2),(-10,0)
-            | (-7,3),(-9,1)
-            | (-7.5,3.5),(-7.5,2.5)
-            | (-7,3),(-7,3)
-            | (-1,6),(-3,4)
-            | (0,7),(-2,5)
-            | (-0.5,7.5),(-0.5,6.5)
-            | (0,7),(0,7)
-            | (7.1,36.5),(5.1,34.5)
-            | (8.1,37.5),(6.1,35.5)
-            | (7.6,38),(7.6,37)
-            | (8.1,37.5),(8.1,37.5)
-            | (-3,-10),(-5,-12)
-            | (-2,-9),(-4,-11)
-            | (-2.5,-8.5),(-2.5,-9.5)
-            | (-2,-9),(-2,-9)
-            | (12,12),(10,10)
-            | (13,13),(11,11)
-            | (12.5,13.5),(12.5,12.5)
-            | (13,13),(13,13)
-(24 rows)
-
-SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |        translation        
-------------+---------------------------
-            | (2,2),(0,0)
-            | (3,3),(1,1)
-            | (2.5,3.5),(2.5,2.5)
-            | (3,3),(3,3)
-            | (12,2),(10,0)
-            | (13,3),(11,1)
-            | (12.5,3.5),(12.5,2.5)
-            | (13,3),(13,3)
-            | (5,-2),(3,-4)
-            | (6,-1),(4,-3)
-            | (5.5,-0.5),(5.5,-1.5)
-            | (6,-1),(6,-1)
-            | (-3.1,-32.5),(-5.1,-34.5)
-            | (-2.1,-31.5),(-4.1,-33.5)
-            | (-2.6,-31),(-2.6,-32)
-            | (-2.1,-31.5),(-2.1,-31.5)
-            | (7,14),(5,12)
-            | (8,15),(6,13)
-            | (7.5,15.5),(7.5,14.5)
-            | (8,15),(8,15)
-            | (-8,-8),(-10,-10)
-            | (-7,-7),(-9,-9)
-            | (-7.5,-6.5),(-7.5,-7.5)
-            | (-7,-7),(-7,-7)
-(24 rows)
-
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
- twentyfour |          rotation           
-------------+-----------------------------
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (0,0),(0,0)
-            | (-0,0),(-20,-20)
-            | (-10,-10),(-30,-30)
-            | (-25,-25),(-25,-35)
-            | (-30,-30),(-30,-30)
-            | (-0,2),(-14,0)
-            | (-7,3),(-21,1)
-            | (-17.5,2.5),(-21.5,-0.5)
-            | (-21,3),(-21,3)
-            | (0,79.2),(-58.8,0)
-            | (-29.4,118.8),(-88.2,39.6)
-            | (-73.5,104.1),(-108,99)
-            | (-88.2,118.8),(-88.2,118.8)
-            | (14,-0),(0,-34)
-            | (21,-17),(7,-51)
-            | (29.5,-42.5),(17.5,-47.5)
-            | (21,-51),(21,-51)
-            | (0,40),(0,0)
-            | (0,60),(0,20)
-            | (0,60),(-10,50)
-            | (0,60),(0,60)
-(24 rows)
-
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
- twenty |                               rotation                               
---------+----------------------------------------------------------------------
-        | (0,-0),(-0.2,-0.2)
-        | (0.08,-0),(0,-0.56)
-        | (0.0651176557644,0),(0,-0.0483449262493)
-        | (-0,0.0828402366864),(-0.201183431953,0)
-        | (0.2,0),(0,0)
-        | (-0.1,-0.1),(-0.3,-0.3)
-        | (0.12,-0.28),(0.04,-0.84)
-        | (0.0976764836466,-0.0241724631247),(0.0325588278822,-0.072517389374)
-        | (-0.100591715976,0.12426035503),(-0.301775147929,0.0414201183432)
-        | (0.3,0),(0.1,0)
-        | (-0.25,-0.25),(-0.25,-0.35)
-        | (0.26,-0.7),(0.1,-0.82)
-        | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
-        | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
-        | (0.3,0.05),(0.25,0)
-        | (-0.3,-0.3),(-0.3,-0.3)
-        | (0.12,-0.84),(0.12,-0.84)
-        | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
-        | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
-        | (0.3,0),(0.3,0)
-(20 rows)
-
-SELECT f1::box
-	FROM POINT_TBL;
-          f1           
------------------------
- (0,0),(0,0)
- (-10,0),(-10,0)
- (-3,4),(-3,4)
- (5.1,34.5),(5.1,34.5)
- (-5,-12),(-5,-12)
- (10,10),(10,10)
-(6 rows)
-
-SELECT bound_box(a.f1, b.f1)
-	FROM BOX_TBL a, BOX_TBL b;
-      bound_box      
----------------------
- (2,2),(0,0)
- (3,3),(0,0)
- (2.5,3.5),(0,0)
- (3,3),(0,0)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(1,1)
- (3,3),(1,1)
- (2.5,3.5),(0,0)
- (3,3.5),(1,1)
- (2.5,3.5),(2.5,2.5)
- (3,3.5),(2.5,2.5)
- (3,3),(0,0)
- (3,3),(1,1)
- (3,3.5),(2.5,2.5)
- (3,3),(3,3)
-(16 rows)
-
---
--- Paths
---
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
- eight | npoints |           path            
--------+---------+---------------------------
-       |       2 | [(1,2),(3,4)]
-       |       2 | ((1,2),(3,4))
-       |       4 | [(0,0),(3,0),(4,5),(1,6)]
-       |       2 | ((1,2),(3,4))
-       |       2 | ((1,2),(3,4))
-       |       2 | [(1,2),(3,4)]
-       |       2 | [(11,12),(13,14)]
-       |       2 | ((11,12),(13,14))
-(8 rows)
-
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
- four |        path         
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
-
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
- eight |             dist_add              
--------+-----------------------------------
-       | [(11,12),(13,14)]
-       | ((11,12),(13,14))
-       | [(10,10),(13,10),(14,15),(11,16)]
-       | ((11,12),(13,14))
-       | ((11,12),(13,14))
-       | [(11,12),(13,14)]
-       | [(21,22),(23,24)]
-       | ((21,22),(23,24))
-(8 rows)
-
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
- eight |           dist_mul           
--------+------------------------------
-       | [(4,3),(10,5)]
-       | ((4,3),(10,5))
-       | [(0,0),(6,-3),(13,6),(8,11)]
-       | ((4,3),(10,5))
-       | ((4,3),(10,5))
-       | [(4,3),(10,5)]
-       | [(34,13),(40,15)]
-       | ((34,13),(40,15))
-(8 rows)
-
---
--- Polygons
---
--- containment
-SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contains 
-------------+------------+---------------------+----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
-   FROM POLYGON_TBL poly, POINT_TBL p;
- twentyfour |     f1     |         f1          | contained 
-------------+------------+---------------------+-----------
-            | (0,0)      | ((2,0),(2,4),(0,0)) | t
-            | (0,0)      | ((3,1),(3,3),(1,0)) | f
-            | (0,0)      | ((0,0))             | t
-            | (0,0)      | ((0,1),(0,1))       | f
-            | (-10,0)    | ((2,0),(2,4),(0,0)) | f
-            | (-10,0)    | ((3,1),(3,3),(1,0)) | f
-            | (-10,0)    | ((0,0))             | f
-            | (-10,0)    | ((0,1),(0,1))       | f
-            | (-3,4)     | ((2,0),(2,4),(0,0)) | f
-            | (-3,4)     | ((3,1),(3,3),(1,0)) | f
-            | (-3,4)     | ((0,0))             | f
-            | (-3,4)     | ((0,1),(0,1))       | f
-            | (5.1,34.5) | ((2,0),(2,4),(0,0)) | f
-            | (5.1,34.5) | ((3,1),(3,3),(1,0)) | f
-            | (5.1,34.5) | ((0,0))             | f
-            | (5.1,34.5) | ((0,1),(0,1))       | f
-            | (-5,-12)   | ((2,0),(2,4),(0,0)) | f
-            | (-5,-12)   | ((3,1),(3,3),(1,0)) | f
-            | (-5,-12)   | ((0,0))             | f
-            | (-5,-12)   | ((0,1),(0,1))       | f
-            | (10,10)    | ((2,0),(2,4),(0,0)) | f
-            | (10,10)    | ((3,1),(3,3),(1,0)) | f
-            | (10,10)    | ((0,0))             | f
-            | (10,10)    | ((0,1),(0,1))       | f
-(24 rows)
-
-SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
-   FROM POLYGON_TBL;
- four | npoints |       polygon       
-------+---------+---------------------
-      |       3 | ((2,0),(2,4),(0,0))
-      |       3 | ((3,1),(3,3),(1,0))
-      |       1 | ((0,0))
-      |       2 | ((0,1),(0,1))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM BOX_TBL;
- four |                  polygon                  
-------+-------------------------------------------
-      | ((0,0),(0,2),(2,2),(2,0))
-      | ((1,1),(1,3),(3,3),(3,1))
-      | ((2.5,2.5),(2.5,3.5),(2.5,3.5),(2.5,2.5))
-      | ((3,3),(3,3),(3,3),(3,3))
-(4 rows)
-
-SELECT '' AS four, polygon(f1)
-   FROM PATH_TBL WHERE isclosed(f1);
- four |      polygon      
-------+-------------------
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((1,2),(3,4))
-      | ((11,12),(13,14))
-(4 rows)
-
-SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
-   FROM PATH_TBL
-   WHERE isopen(f1);
- four |         open_path         |          polygon          
-------+---------------------------+---------------------------
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(0,0),(3,0),(4,5),(1,6)] | ((0,0),(3,0),(4,5),(1,6))
-      | [(1,2),(3,4)]             | ((1,2),(3,4))
-      | [(11,12),(13,14)]         | ((11,12),(13,14))
-(4 rows)
-
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
- six |                                                                                                       polygon                                                                                                        
------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.40192378865,2.5),(3.5,3.59807621135),(5,4),(6.5,3.59807621135),(7.59807621135,2.5),(8,1),(7.59807621135,-0.5),(6.5,-1.59807621135),(5,-2),(3.5,-1.59807621135),(2.40192378865,-0.5))
-     | ((-99,2),(-85.6025403784,52),(-49,88.6025403784),(1,102),(51,88.6025403784),(87.6025403784,52),(101,2),(87.6025403784,-48),(51,-84.6025403784),(1,-98),(-49,-84.6025403784),(-85.6025403784,-48))
-     | ((-4,3),(-3.33012701892,5.5),(-1.5,7.33012701892),(1,8),(3.5,7.33012701892),(5.33012701892,5.5),(6,3),(5.33012701892,0.5),(3.5,-1.33012701892),(1,-2),(-1.5,-1.33012701892),(-3.33012701892,0.5))
-     | ((-2,2),(-1.59807621135,3.5),(-0.5,4.59807621135),(1,5),(2.5,4.59807621135),(3.59807621135,3.5),(4,2),(3.59807621135,0.5),(2.5,-0.598076211353),(1,-1),(-0.5,-0.598076211353),(-1.59807621135,0.5))
-     | ((90,200),(91.3397459622,205),(95,208.660254038),(100,210),(105,208.660254038),(108.660254038,205),(110,200),(108.660254038,195),(105,191.339745962),(100,190),(95,191.339745962),(91.3397459622,195))
-     | ((-15,1),(0.40707856479,58.5),(42.5,100.592921435),(100,116),(157.5,100.592921435),(199.592921435,58.5),(215,1),(199.592921435,-56.5),(157.5,-98.5929214352),(100,-114),(42.5,-98.5929214352),(0.40707856479,-56.5))
-(6 rows)
-
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
- six |                                                                             polygon                                                                              
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
-     | ((2,1),(2.87867965644,3.12132034356),(5,4),(7.12132034356,3.12132034356),(8,1),(7.12132034356,-1.12132034356),(5,-2),(2.87867965644,-1.12132034356))
-     | ((-99,2),(-69.7106781187,72.7106781187),(1,102),(71.7106781187,72.7106781187),(101,2),(71.7106781187,-68.7106781187),(1,-98),(-69.7106781187,-68.7106781187))
-     | ((-4,3),(-2.53553390593,6.53553390593),(1,8),(4.53553390593,6.53553390593),(6,3),(4.53553390593,-0.535533905933),(1,-2),(-2.53553390593,-0.535533905933))
-     | ((-2,2),(-1.12132034356,4.12132034356),(1,5),(3.12132034356,4.12132034356),(4,2),(3.12132034356,-0.12132034356),(1,-1),(-1.12132034356,-0.12132034356))
-     | ((90,200),(92.9289321881,207.071067812),(100,210),(107.071067812,207.071067812),(110,200),(107.071067812,192.928932188),(100,190),(92.9289321881,192.928932188))
-     | ((-15,1),(18.6827201635,82.3172798365),(100,116),(181.317279836,82.3172798365),(215,1),(181.317279836,-80.3172798365),(100,-114),(18.6827201635,-80.3172798365))
-(6 rows)
-
---
--- Circles
---
-SELECT '' AS six, circle(f1, 50.0)
-   FROM POINT_TBL;
- six |     circle      
------+-----------------
-     | <(0,0),50>
-     | <(-10,0),50>
-     | <(-3,4),50>
-     | <(5.1,34.5),50>
-     | <(-5,-12),50>
-     | <(10,10),50>
-(6 rows)
-
-SELECT '' AS four, circle(f1)
-   FROM BOX_TBL;
- four |        circle         
-------+-----------------------
-      | <(1,1),1.41421356237>
-      | <(2,2),1.41421356237>
-      | <(2.5,3),0.5>
-      | <(3,3),0>
-(4 rows)
-
-SELECT '' AS two, circle(f1)
-   FROM POLYGON_TBL
-   WHERE (# f1) >= 3;
- two |                    circle                     
------+-----------------------------------------------
-     | <(1.33333333333,1.33333333333),2.04168905064>
-     | <(2.33333333333,1.33333333333),1.47534300379>
-(2 rows)
-
-SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
-   FROM CIRCLE_TBL c1, POINT_TBL p1
-   WHERE (p1.f1 <-> c1.f1) > 0
-   ORDER BY distance, area(c1.f1), p1.f1[0];
- twentyfour |     circle     |   point    |   distance    
-------------+----------------+------------+---------------
-            | <(1,2),3>      | (-3,4)     |   1.472135955
-            | <(5,1),3>      | (0,0)      | 2.09901951359
-            | <(5,1),3>      | (-3,4)     | 5.54400374532
-            | <(1,3),5>      | (-10,0)    | 6.40175425099
-            | <(1,3),5>      | (10,10)    | 6.40175425099
-            | <(5,1),3>      | (10,10)    | 7.29563014099
-            | <(1,2),3>      | (-10,0)    |  8.1803398875
-            | <(1,2),3>      | (10,10)    | 9.04159457879
-            | <(1,3),5>      | (-5,-12)   | 11.1554944214
-            | <(5,1),3>      | (-10,0)    | 12.0332963784
-            | <(1,2),3>      | (-5,-12)   | 12.2315462117
-            | <(5,1),3>      | (-5,-12)   | 13.4012194669
-            | <(1,3),5>      | (5.1,34.5) | 26.7657047773
-            | <(1,2),3>      | (5.1,34.5) | 29.7575945393
-            | <(5,1),3>      | (5.1,34.5) | 30.5001492534
-            | <(100,200),10> | (5.1,34.5) | 180.778038568
-            | <(100,200),10> | (10,10)    | 200.237960416
-            | <(100,200),10> | (-3,4)     | 211.415898255
-            | <(100,200),10> | (0,0)      |  213.60679775
-            | <(100,200),10> | (-10,0)    |  218.25424421
-            | <(100,200),10> | (-5,-12)   | 226.577682802
-(21 rows)
-
diff --git a/src/test/regress/expected/line.out b/src/test/regress/expected/line.out
index f20abdc430..bf780daa2c 100644
--- a/src/test/regress/expected/line.out
+++ b/src/test/regress/expected/line.out
@@ -1,271 +1,87 @@
 --
 -- LINE
 -- Infinite lines
 --
 --DROP TABLE LINE_TBL;
 CREATE TABLE LINE_TBL (s line);
-INSERT INTO LINE_TBL VALUES ('{1,-1,1}');
-INSERT INTO LINE_TBL VALUES ('(0,0),(6,6)');
+INSERT INTO LINE_TBL VALUES ('{0,-1,5}');	-- A == 0
+INSERT INTO LINE_TBL VALUES ('{1,0,5}');	-- B == 0
+INSERT INTO LINE_TBL VALUES ('{0,3,0}');	-- A == C == 0
+INSERT INTO LINE_TBL VALUES (' (0,0), (6,6)');
 INSERT INTO LINE_TBL VALUES ('10,-10 ,-5,-4');
 INSERT INTO LINE_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LINE_TBL VALUES ('(11,22,33,44)');
-INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
-ERROR:  invalid line specification: must be two distinct points
-LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
-                                     ^
+INSERT INTO LINE_TBL VALUES ('{3,NaN,5}');
+INSERT INTO LINE_TBL VALUES ('{NaN,NaN,NaN}');
 -- horizontal
 INSERT INTO LINE_TBL VALUES ('[(1,3),(2,3)]');
 -- vertical
-INSERT INTO LINE_TBL VALUES ('[(3,1),(3,2)]');
+INSERT INTO LINE_TBL VALUES (line(point '(3,1)', point '(3,2)'));
 -- bad values for parser testing
+INSERT INTO LINE_TBL VALUES ('{}');
+ERROR:  invalid input syntax for type line: "{}"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{}');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0');
+ERROR:  invalid input syntax for type line: "{0"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0,0}');
+ERROR:  invalid input syntax for type line: "{0,0}"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0}');
+                                     ^
+INSERT INTO LINE_TBL VALUES ('{0,0,1');
+ERROR:  invalid input syntax for type line: "{0,0,1"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1');
+                                     ^
 INSERT INTO LINE_TBL VALUES ('{0,0,1}');
 ERROR:  invalid line specification: A and B cannot both be zero
 LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1}');
                                      ^
+INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
+ERROR:  invalid input syntax for type line: "{0,0,1} x"
+LINE 1: INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
+                                     ^
 INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
 ERROR:  invalid input syntax for type line: "(3asdf,2 ,3,4r2)"
 LINE 1: INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
                                      ^
 INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
 ERROR:  invalid input syntax for type line: "[1,2,3, 4"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
                                      ^
 INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
 ERROR:  invalid input syntax for type line: "[(,2),(3,4)]"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
                                      ^
 INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
 ERROR:  invalid input syntax for type line: "[(1,2),(3,4)"
 LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
                                      ^
+INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
+ERROR:  invalid line specification: must be two distinct points
+LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
+                                     ^
+INSERT INTO LINE_TBL VALUES (line(point '(1,0)', point '(1,0)'));
+ERROR:  invalid line specification: must be two distinct points
 select * from LINE_TBL;
                       s                      
 ---------------------------------------------
- {1,-1,1}
+ {0,-1,5}
+ {1,0,5}
+ {0,3,0}
  {1,-1,0}
  {-0.4,-1,-6}
  {-0.000184615384615385,-1,15.3846153846154}
- {1,-1,11}
+ {3,NaN,5}
+ {NaN,NaN,NaN}
  {0,-1,3}
  {-1,0,3}
-(7 rows)
+(10 rows)
 
--- functions and operators
-SELECT * FROM LINE_TBL WHERE (s <-> line '[(1,2),(3,4)]') < 10;
-                      s                      
----------------------------------------------
- {1,-1,1}
- {1,-1,0}
- {-0.4,-1,-6}
- {-0.000184615384615385,-1,15.3846153846154}
- {1,-1,11}
- {0,-1,3}
- {-1,0,3}
-(7 rows)
-
-SELECT * FROM LINE_TBL WHERE (point '(0.1,0.1)' <-> s) < 1;
-    s     
-----------
- {1,-1,1}
- {1,-1,0}
-(2 rows)
-
-SELECT * FROM LINE_TBL WHERE (lseg '[(0.1,0.1),(0.2,0.2)]' <-> s) < 1;
-    s     
-----------
- {1,-1,1}
- {1,-1,0}
-(2 rows)
-
-SELECT line '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
- ?column? 
-----------
-        2
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
- ?column? 
-----------
-        2
-(1 row)
-
-SELECT point '(-1,1)' <-> line '[(-3,0),(-4,0)]';
- ?column? 
-----------
-        1
-(1 row)
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(2,0),(0,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# box '(0,0,2,2)';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(3,0),(4,1)]' ?# box '(0,0,2,2)';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(1,1)' <@ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT point '(1,1)' <@ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(1,1)' @ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT point '(1,1)' @ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT lseg '[(1,1),(2,2)]' <@ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' <@ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT lseg '[(1,1),(2,2)]' @ line '[(0,0),(2,2)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT lseg '[(1,1),(2,1)]' @ line '[(0,0),(1,0)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT point '(0,1)' ## line '[(0,0),(1,1)]';
- ?column?  
------------
- (0.5,0.5)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ## lseg '[(1,0),(2,0)]';
- ?column? 
-----------
- (1,0)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(2,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(1,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(2,1)]';
- ?column? 
-----------
- 
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(1,1)]';
- ?column? 
-----------
- (1,1)
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(2,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line '[(0,0),(1,0)]' ?-| line '[(0,0),(0,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(0,0),(1,1)]' ?-| line '[(1,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT ?- line '[(0,0),(1,0)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT ?- line '[(0,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT ?| line '[(0,0),(0,1)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT ?| line '[(0,0),(1,1)]';  -- false
- ?column? 
-----------
- f
-(1 row)
-
-SELECT line(point '(1,2)', point '(3,4)');
-   line   
-----------
- {1,-1,1}
-(1 row)
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,5)]';  -- true
- ?column? 
-----------
- t
-(1 row)
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,4)]';  -- false
- ?column? 
-----------
- f
+select '{nan, 1, nan}'::line = '{nan, 1, nan}'::line as true,
+	   '{nan, 1, nan}'::line = '{nan, 2, nan}'::line as false;
+ true | false 
+------+-------
+ t    | f
 (1 row)
 
diff --git a/src/test/regress/expected/lseg.out b/src/test/regress/expected/lseg.out
index bba1f3ee80..7e878b5577 100644
--- a/src/test/regress/expected/lseg.out
+++ b/src/test/regress/expected/lseg.out
@@ -1,21 +1,24 @@
 --
 -- LSEG
 -- Line segments
 --
 --DROP TABLE LSEG_TBL;
 CREATE TABLE LSEG_TBL (s lseg);
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('(0,0),(6,6)');
 INSERT INTO LSEG_TBL VALUES ('10,-10 ,-3,-4');
 INSERT INTO LSEG_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LSEG_TBL VALUES ('(11,22,33,44)');
+INSERT INTO LSEG_TBL VALUES (lseg(point(11, 22), point(33,44)));
+INSERT INTO LSEG_TBL VALUES ('[(-10,2),(-10,3)]');	-- vertical
+INSERT INTO LSEG_TBL VALUES ('[(0,-20),(30,-20)]');	-- horizontal
+INSERT INTO LSEG_TBL VALUES ('[(NaN,1),(NaN,90)]');	-- NaN
 -- bad values for parser testing
 INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
 ERROR:  invalid input syntax for type lseg: "(3asdf,2 ,3,4r2)"
 LINE 1: INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
                                      ^
 INSERT INTO LSEG_TBL VALUES ('[1,2,3, 4');
 ERROR:  invalid input syntax for type lseg: "[1,2,3, 4"
 LINE 1: INSERT INTO LSEG_TBL VALUES ('[1,2,3, 4');
                                      ^
 INSERT INTO LSEG_TBL VALUES ('[(,2),(3,4)]');
@@ -27,26 +30,15 @@ ERROR:  invalid input syntax for type lseg: "[(1,2),(3,4)"
 LINE 1: INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)');
                                      ^
 select * from LSEG_TBL;
                s               
 -------------------------------
  [(1,2),(3,4)]
  [(0,0),(6,6)]
  [(10,-10),(-3,-4)]
  [(-1000000,200),(300000,-40)]
  [(11,22),(33,44)]
-(5 rows)
-
-SELECT * FROM LSEG_TBL WHERE s <= lseg '[(1,2),(3,4)]';
-       s       
----------------
- [(1,2),(3,4)]
-(1 row)
-
-SELECT * FROM LSEG_TBL WHERE (s <-> lseg '[(1,2),(3,4)]') < 10;
-         s          
---------------------
- [(1,2),(3,4)]
- [(0,0),(6,6)]
- [(10,-10),(-3,-4)]
-(3 rows)
+ [(-10,2),(-10,3)]
+ [(0,-20),(30,-20)]
+ [(NaN,1),(NaN,90)]
+(8 rows)
 
diff --git a/src/test/regress/expected/path.out b/src/test/regress/expected/path.out
index 08d6d61dda..bd6e467752 100644
--- a/src/test/regress/expected/path.out
+++ b/src/test/regress/expected/path.out
@@ -1,79 +1,82 @@
 --
 -- PATH
 --
 --DROP TABLE PATH_TBL;
 CREATE TABLE PATH_TBL (f1 path);
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)]');
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
-INSERT INTO PATH_TBL VALUES ('[(0,0),(3,0),(4,5),(1,6)]');
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
-INSERT INTO PATH_TBL VALUES ('1,2 ,3,4');
-INSERT INTO PATH_TBL VALUES ('[1,2,3, 4]');
-INSERT INTO PATH_TBL VALUES ('[11,12,13,14]');
-INSERT INTO PATH_TBL VALUES ('(11,12,13,14)');
+INSERT INTO PATH_TBL VALUES (' ( ( 1 , 2 ) , ( 3 , 4 ) ) ');
+INSERT INTO PATH_TBL VALUES ('[ (0,0),(3,0),(4,5),(1,6) ]');
+INSERT INTO PATH_TBL VALUES ('((1,2) ,(3,4 ))');
+INSERT INTO PATH_TBL VALUES ('1,2 ,3,4 ');
+INSERT INTO PATH_TBL VALUES (' [1,2,3, 4] ');
+INSERT INTO PATH_TBL VALUES ('((10,20))');	-- Only one point
+INSERT INTO PATH_TBL VALUES ('[ 11,12,13,14 ]');
+INSERT INTO PATH_TBL VALUES ('( 11,12,13,14) ');
 -- bad values for parser testing
+INSERT INTO PATH_TBL VALUES ('[]');
+ERROR:  invalid input syntax for type path: "[]"
+LINE 1: INSERT INTO PATH_TBL VALUES ('[]');
+                                     ^
 INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
 ERROR:  invalid input syntax for type path: "[(,2),(3,4)]"
 LINE 1: INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
                                      ^
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
 ERROR:  invalid input syntax for type path: "[(1,2),(3,4)"
 LINE 1: INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
                                      ^
-SELECT f1 FROM PATH_TBL;
-            f1             
----------------------------
- [(1,2),(3,4)]
- ((1,2),(3,4))
- [(0,0),(3,0),(4,5),(1,6)]
- ((1,2),(3,4))
- ((1,2),(3,4))
- [(1,2),(3,4)]
- [(11,12),(13,14)]
- ((11,12),(13,14))
-(8 rows)
-
+INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+ERROR:  invalid input syntax for type path: "(1,2,3,4"
+LINE 1: INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+                                     ^
+INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
+ERROR:  invalid input syntax for type path: "(1,2),(3,4)]"
+LINE 1: INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
+                                     ^
 SELECT '' AS count, f1 AS open_path FROM PATH_TBL WHERE isopen(f1);
  count |         open_path         
 -------+---------------------------
        | [(1,2),(3,4)]
        | [(0,0),(3,0),(4,5),(1,6)]
        | [(1,2),(3,4)]
        | [(11,12),(13,14)]
 (4 rows)
 
 SELECT '' AS count, f1 AS closed_path FROM PATH_TBL WHERE isclosed(f1);
  count |    closed_path    
 -------+-------------------
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
+       | ((10,20))
        | ((11,12),(13,14))
-(4 rows)
+(5 rows)
 
 SELECT '' AS count, pclose(f1) AS closed_path FROM PATH_TBL;
  count |        closed_path        
 -------+---------------------------
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((0,0),(3,0),(4,5),(1,6))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
        | ((1,2),(3,4))
+       | ((10,20))
        | ((11,12),(13,14))
        | ((11,12),(13,14))
-(8 rows)
+(9 rows)
 
 SELECT '' AS count, popen(f1) AS open_path FROM PATH_TBL;
  count |         open_path         
 -------+---------------------------
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
        | [(0,0),(3,0),(4,5),(1,6)]
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
        | [(1,2),(3,4)]
+       | [(10,20)]
        | [(11,12),(13,14)]
        | [(11,12),(13,14)]
-(8 rows)
+(9 rows)
 
diff --git a/src/test/regress/expected/point.out b/src/test/regress/expected/point.out
index bfc0962749..c18e865370 100644
--- a/src/test/regress/expected/point.out
+++ b/src/test/regress/expected/point.out
@@ -1,43 +1,57 @@
 --
 -- POINT
 --
 CREATE TABLE POINT_TBL(f1 point);
 INSERT INTO POINT_TBL(f1) VALUES ('(0.0,0.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-10.0,0.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-3.0,4.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(5.1, 34.5)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-5.0,-12.0)');
+INSERT INTO POINT_TBL(f1) VALUES ('(1e-300,-1e-300)');	-- To underflow
+INSERT INTO POINT_TBL(f1) VALUES ('(1e+300,Inf)');		-- To overflow
+INSERT INTO POINT_TBL(f1) VALUES (' ( Nan , NaN ) ');
 -- bad format points
 INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
 ERROR:  invalid input syntax for type point: "asdfasdf"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
                                           ^
 INSERT INTO POINT_TBL(f1) VALUES ('10.0,10.0');
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
 ERROR:  invalid input syntax for type point: "(10.0 10.0)"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
                                           ^
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+ERROR:  invalid input syntax for type point: "(10.0, 10.0) x"
+LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+                                          ^
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
 ERROR:  invalid input syntax for type point: "(10.0,10.0"
 LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
                                           ^
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');	-- Out of range
+ERROR:  "1e+500" is out of range for type double precision
+LINE 1: INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');
+                                          ^
 SELECT '' AS six, * FROM POINT_TBL;
- six |     f1     
------+------------
+ six |        f1         
+-----+-------------------
      | (0,0)
      | (-10,0)
      | (-3,4)
      | (5.1,34.5)
      | (-5,-12)
+     | (1e-300,-1e-300)
+     | (1e+300,Infinity)
+     | (NaN,NaN)
      | (10,10)
-(6 rows)
+(9 rows)
 
 -- left of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE p.f1 << '(0.0, 0.0)';
  three |    f1    
 -------+----------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
 (3 rows)
 
@@ -85,172 +99,282 @@ 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    
--------+----------
+ three |        f1         
+-------+-------------------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
-(3 rows)
+       | (1e-300,-1e-300)
+       | (1e+300,Infinity)
+       | (NaN,NaN)
+(6 rows)
 
 SELECT '' AS two, p.* FROM POINT_TBL p
    WHERE p.f1 <@ path '[(0,0),(-10,0),(-10,10)]';
- two |   f1    
------+---------
+ two |        f1        
+-----+------------------
      | (0,0)
      | (-10,0)
-(2 rows)
+     | (1e-300,-1e-300)
+(3 rows)
 
 SELECT '' AS three, p.* FROM POINT_TBL p
    WHERE not box '(0,0,100,100)' @> p.f1;
- three |    f1    
--------+----------
+ three |        f1         
+-------+-------------------
        | (-10,0)
        | (-3,4)
        | (-5,-12)
-(3 rows)
+       | (1e-300,-1e-300)
+       | (1e+300,Infinity)
+       | (NaN,NaN)
+(6 rows)
 
 SELECT '' AS six, p.f1, p.f1 <-> point '(0,0)' AS dist
    FROM POINT_TBL p
    ORDER BY dist;
- six |     f1     |       dist       
------+------------+------------------
-     | (0,0)      |                0
-     | (-3,4)     |                5
-     | (-10,0)    |               10
-     | (-5,-12)   |               13
-     | (10,10)    |  14.142135623731
-     | (5.1,34.5) | 34.8749193547455
-(6 rows)
+ six |        f1         |         dist         
+-----+-------------------+----------------------
+     | (0,0)             |                    0
+     | (1e-300,-1e-300)  | 1.4142135623731e-300
+     | (-3,4)            |                    5
+     | (-10,0)           |                   10
+     | (-5,-12)          |                   13
+     | (10,10)           |      14.142135623731
+     | (5.1,34.5)        |     34.8749193547455
+     | (1e+300,Infinity) |             Infinity
+     | (NaN,NaN)         |                  NaN
+(9 rows)
 
 SELECT '' AS thirtysix, p1.f1 AS point1, p2.f1 AS point2, p1.f1 <-> p2.f1 AS dist
    FROM POINT_TBL p1, POINT_TBL p2
    ORDER BY dist, p1.f1[0], p2.f1[0];
- thirtysix |   point1   |   point2   |       dist       
------------+------------+------------+------------------
-           | (-10,0)    | (-10,0)    |                0
-           | (-5,-12)   | (-5,-12)   |                0
-           | (-3,4)     | (-3,4)     |                0
-           | (0,0)      | (0,0)      |                0
-           | (5.1,34.5) | (5.1,34.5) |                0
-           | (10,10)    | (10,10)    |                0
-           | (-3,4)     | (0,0)      |                5
-           | (0,0)      | (-3,4)     |                5
-           | (-10,0)    | (-3,4)     | 8.06225774829855
-           | (-3,4)     | (-10,0)    | 8.06225774829855
-           | (-10,0)    | (0,0)      |               10
-           | (0,0)      | (-10,0)    |               10
-           | (-10,0)    | (-5,-12)   |               13
-           | (-5,-12)   | (-10,0)    |               13
-           | (-5,-12)   | (0,0)      |               13
-           | (0,0)      | (-5,-12)   |               13
-           | (0,0)      | (10,10)    |  14.142135623731
-           | (10,10)    | (0,0)      |  14.142135623731
-           | (-3,4)     | (10,10)    | 14.3178210632764
-           | (10,10)    | (-3,4)     | 14.3178210632764
-           | (-5,-12)   | (-3,4)     | 16.1245154965971
-           | (-3,4)     | (-5,-12)   | 16.1245154965971
-           | (-10,0)    | (10,10)    | 22.3606797749979
-           | (10,10)    | (-10,0)    | 22.3606797749979
-           | (5.1,34.5) | (10,10)    | 24.9851956166046
-           | (10,10)    | (5.1,34.5) | 24.9851956166046
-           | (-5,-12)   | (10,10)    | 26.6270539113887
-           | (10,10)    | (-5,-12)   | 26.6270539113887
-           | (-3,4)     | (5.1,34.5) | 31.5572495632937
-           | (5.1,34.5) | (-3,4)     | 31.5572495632937
-           | (0,0)      | (5.1,34.5) | 34.8749193547455
-           | (5.1,34.5) | (0,0)      | 34.8749193547455
-           | (-10,0)    | (5.1,34.5) | 37.6597928831267
-           | (5.1,34.5) | (-10,0)    | 37.6597928831267
-           | (-5,-12)   | (5.1,34.5) | 47.5842410888311
-           | (5.1,34.5) | (-5,-12)   | 47.5842410888311
-(36 rows)
+ thirtysix |      point1       |      point2       |         dist         
+-----------+-------------------+-------------------+----------------------
+           | (-10,0)           | (-10,0)           |                    0
+           | (-5,-12)          | (-5,-12)          |                    0
+           | (-3,4)            | (-3,4)            |                    0
+           | (0,0)             | (0,0)             |                    0
+           | (1e-300,-1e-300)  | (1e-300,-1e-300)  |                    0
+           | (5.1,34.5)        | (5.1,34.5)        |                    0
+           | (10,10)           | (10,10)           |                    0
+           | (0,0)             | (1e-300,-1e-300)  | 1.4142135623731e-300
+           | (1e-300,-1e-300)  | (0,0)             | 1.4142135623731e-300
+           | (-3,4)            | (0,0)             |                    5
+           | (-3,4)            | (1e-300,-1e-300)  |                    5
+           | (0,0)             | (-3,4)            |                    5
+           | (1e-300,-1e-300)  | (-3,4)            |                    5
+           | (-10,0)           | (-3,4)            |     8.06225774829855
+           | (-3,4)            | (-10,0)           |     8.06225774829855
+           | (-10,0)           | (0,0)             |                   10
+           | (-10,0)           | (1e-300,-1e-300)  |                   10
+           | (0,0)             | (-10,0)           |                   10
+           | (1e-300,-1e-300)  | (-10,0)           |                   10
+           | (-10,0)           | (-5,-12)          |                   13
+           | (-5,-12)          | (-10,0)           |                   13
+           | (-5,-12)          | (0,0)             |                   13
+           | (-5,-12)          | (1e-300,-1e-300)  |                   13
+           | (0,0)             | (-5,-12)          |                   13
+           | (1e-300,-1e-300)  | (-5,-12)          |                   13
+           | (0,0)             | (10,10)           |      14.142135623731
+           | (1e-300,-1e-300)  | (10,10)           |      14.142135623731
+           | (10,10)           | (0,0)             |      14.142135623731
+           | (10,10)           | (1e-300,-1e-300)  |      14.142135623731
+           | (-3,4)            | (10,10)           |     14.3178210632764
+           | (10,10)           | (-3,4)            |     14.3178210632764
+           | (-5,-12)          | (-3,4)            |     16.1245154965971
+           | (-3,4)            | (-5,-12)          |     16.1245154965971
+           | (-10,0)           | (10,10)           |     22.3606797749979
+           | (10,10)           | (-10,0)           |     22.3606797749979
+           | (5.1,34.5)        | (10,10)           |     24.9851956166046
+           | (10,10)           | (5.1,34.5)        |     24.9851956166046
+           | (-5,-12)          | (10,10)           |     26.6270539113887
+           | (10,10)           | (-5,-12)          |     26.6270539113887
+           | (-3,4)            | (5.1,34.5)        |     31.5572495632937
+           | (5.1,34.5)        | (-3,4)            |     31.5572495632937
+           | (0,0)             | (5.1,34.5)        |     34.8749193547455
+           | (1e-300,-1e-300)  | (5.1,34.5)        |     34.8749193547455
+           | (5.1,34.5)        | (0,0)             |     34.8749193547455
+           | (5.1,34.5)        | (1e-300,-1e-300)  |     34.8749193547455
+           | (-10,0)           | (5.1,34.5)        |     37.6597928831267
+           | (5.1,34.5)        | (-10,0)           |     37.6597928831267
+           | (-5,-12)          | (5.1,34.5)        |     47.5842410888311
+           | (5.1,34.5)        | (-5,-12)          |     47.5842410888311
+           | (-10,0)           | (1e+300,Infinity) |             Infinity
+           | (-5,-12)          | (1e+300,Infinity) |             Infinity
+           | (-3,4)            | (1e+300,Infinity) |             Infinity
+           | (0,0)             | (1e+300,Infinity) |             Infinity
+           | (1e-300,-1e-300)  | (1e+300,Infinity) |             Infinity
+           | (5.1,34.5)        | (1e+300,Infinity) |             Infinity
+           | (10,10)           | (1e+300,Infinity) |             Infinity
+           | (1e+300,Infinity) | (-10,0)           |             Infinity
+           | (1e+300,Infinity) | (-5,-12)          |             Infinity
+           | (1e+300,Infinity) | (-3,4)            |             Infinity
+           | (1e+300,Infinity) | (0,0)             |             Infinity
+           | (1e+300,Infinity) | (1e-300,-1e-300)  |             Infinity
+           | (1e+300,Infinity) | (5.1,34.5)        |             Infinity
+           | (1e+300,Infinity) | (10,10)           |             Infinity
+           | (-10,0)           | (NaN,NaN)         |                  NaN
+           | (-5,-12)          | (NaN,NaN)         |                  NaN
+           | (-3,4)            | (NaN,NaN)         |                  NaN
+           | (0,0)             | (NaN,NaN)         |                  NaN
+           | (1e-300,-1e-300)  | (NaN,NaN)         |                  NaN
+           | (5.1,34.5)        | (NaN,NaN)         |                  NaN
+           | (10,10)           | (NaN,NaN)         |                  NaN
+           | (1e+300,Infinity) | (1e+300,Infinity) |                  NaN
+           | (1e+300,Infinity) | (NaN,NaN)         |                  NaN
+           | (NaN,NaN)         | (-10,0)           |                  NaN
+           | (NaN,NaN)         | (-5,-12)          |                  NaN
+           | (NaN,NaN)         | (-3,4)            |                  NaN
+           | (NaN,NaN)         | (0,0)             |                  NaN
+           | (NaN,NaN)         | (1e-300,-1e-300)  |                  NaN
+           | (NaN,NaN)         | (5.1,34.5)        |                  NaN
+           | (NaN,NaN)         | (10,10)           |                  NaN
+           | (NaN,NaN)         | (1e+300,Infinity) |                  NaN
+           | (NaN,NaN)         | (NaN,NaN)         |                  NaN
+(81 rows)
 
 SELECT '' AS thirty, p1.f1 AS point1, p2.f1 AS point2
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3;
- thirty |   point1   |   point2   
---------+------------+------------
-        | (0,0)      | (-10,0)
-        | (0,0)      | (-3,4)
-        | (0,0)      | (5.1,34.5)
-        | (0,0)      | (-5,-12)
-        | (0,0)      | (10,10)
-        | (-10,0)    | (0,0)
-        | (-10,0)    | (-3,4)
-        | (-10,0)    | (5.1,34.5)
-        | (-10,0)    | (-5,-12)
-        | (-10,0)    | (10,10)
-        | (-3,4)     | (0,0)
-        | (-3,4)     | (-10,0)
-        | (-3,4)     | (5.1,34.5)
-        | (-3,4)     | (-5,-12)
-        | (-3,4)     | (10,10)
-        | (5.1,34.5) | (0,0)
-        | (5.1,34.5) | (-10,0)
-        | (5.1,34.5) | (-3,4)
-        | (5.1,34.5) | (-5,-12)
-        | (5.1,34.5) | (10,10)
-        | (-5,-12)   | (0,0)
-        | (-5,-12)   | (-10,0)
-        | (-5,-12)   | (-3,4)
-        | (-5,-12)   | (5.1,34.5)
-        | (-5,-12)   | (10,10)
-        | (10,10)    | (0,0)
-        | (10,10)    | (-10,0)
-        | (10,10)    | (-3,4)
-        | (10,10)    | (5.1,34.5)
-        | (10,10)    | (-5,-12)
-(30 rows)
+ thirty |      point1       |      point2       
+--------+-------------------+-------------------
+        | (0,0)             | (-10,0)
+        | (0,0)             | (-3,4)
+        | (0,0)             | (5.1,34.5)
+        | (0,0)             | (-5,-12)
+        | (0,0)             | (1e+300,Infinity)
+        | (0,0)             | (NaN,NaN)
+        | (0,0)             | (10,10)
+        | (-10,0)           | (0,0)
+        | (-10,0)           | (-3,4)
+        | (-10,0)           | (5.1,34.5)
+        | (-10,0)           | (-5,-12)
+        | (-10,0)           | (1e-300,-1e-300)
+        | (-10,0)           | (1e+300,Infinity)
+        | (-10,0)           | (NaN,NaN)
+        | (-10,0)           | (10,10)
+        | (-3,4)            | (0,0)
+        | (-3,4)            | (-10,0)
+        | (-3,4)            | (5.1,34.5)
+        | (-3,4)            | (-5,-12)
+        | (-3,4)            | (1e-300,-1e-300)
+        | (-3,4)            | (1e+300,Infinity)
+        | (-3,4)            | (NaN,NaN)
+        | (-3,4)            | (10,10)
+        | (5.1,34.5)        | (0,0)
+        | (5.1,34.5)        | (-10,0)
+        | (5.1,34.5)        | (-3,4)
+        | (5.1,34.5)        | (-5,-12)
+        | (5.1,34.5)        | (1e-300,-1e-300)
+        | (5.1,34.5)        | (1e+300,Infinity)
+        | (5.1,34.5)        | (NaN,NaN)
+        | (5.1,34.5)        | (10,10)
+        | (-5,-12)          | (0,0)
+        | (-5,-12)          | (-10,0)
+        | (-5,-12)          | (-3,4)
+        | (-5,-12)          | (5.1,34.5)
+        | (-5,-12)          | (1e-300,-1e-300)
+        | (-5,-12)          | (1e+300,Infinity)
+        | (-5,-12)          | (NaN,NaN)
+        | (-5,-12)          | (10,10)
+        | (1e-300,-1e-300)  | (-10,0)
+        | (1e-300,-1e-300)  | (-3,4)
+        | (1e-300,-1e-300)  | (5.1,34.5)
+        | (1e-300,-1e-300)  | (-5,-12)
+        | (1e-300,-1e-300)  | (1e+300,Infinity)
+        | (1e-300,-1e-300)  | (NaN,NaN)
+        | (1e-300,-1e-300)  | (10,10)
+        | (1e+300,Infinity) | (0,0)
+        | (1e+300,Infinity) | (-10,0)
+        | (1e+300,Infinity) | (-3,4)
+        | (1e+300,Infinity) | (5.1,34.5)
+        | (1e+300,Infinity) | (-5,-12)
+        | (1e+300,Infinity) | (1e-300,-1e-300)
+        | (1e+300,Infinity) | (1e+300,Infinity)
+        | (1e+300,Infinity) | (NaN,NaN)
+        | (1e+300,Infinity) | (10,10)
+        | (NaN,NaN)         | (0,0)
+        | (NaN,NaN)         | (-10,0)
+        | (NaN,NaN)         | (-3,4)
+        | (NaN,NaN)         | (5.1,34.5)
+        | (NaN,NaN)         | (-5,-12)
+        | (NaN,NaN)         | (1e-300,-1e-300)
+        | (NaN,NaN)         | (1e+300,Infinity)
+        | (NaN,NaN)         | (NaN,NaN)
+        | (NaN,NaN)         | (10,10)
+        | (10,10)           | (0,0)
+        | (10,10)           | (-10,0)
+        | (10,10)           | (-3,4)
+        | (10,10)           | (5.1,34.5)
+        | (10,10)           | (-5,-12)
+        | (10,10)           | (1e-300,-1e-300)
+        | (10,10)           | (1e+300,Infinity)
+        | (10,10)           | (NaN,NaN)
+(72 rows)
 
 -- put distance result into output to allow sorting with GEQ optimizer - tgl 97/05/10
 SELECT '' AS fifteen, p1.f1 AS point1, p2.f1 AS point2, (p1.f1 <-> p2.f1) AS distance
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3 and p1.f1 << p2.f1
    ORDER BY distance, p1.f1[0], p2.f1[0];
- fifteen |   point1   |   point2   |     distance     
----------+------------+------------+------------------
-         | (-3,4)     | (0,0)      |                5
-         | (-10,0)    | (-3,4)     | 8.06225774829855
-         | (-10,0)    | (0,0)      |               10
-         | (-10,0)    | (-5,-12)   |               13
-         | (-5,-12)   | (0,0)      |               13
-         | (0,0)      | (10,10)    |  14.142135623731
-         | (-3,4)     | (10,10)    | 14.3178210632764
-         | (-5,-12)   | (-3,4)     | 16.1245154965971
-         | (-10,0)    | (10,10)    | 22.3606797749979
-         | (5.1,34.5) | (10,10)    | 24.9851956166046
-         | (-5,-12)   | (10,10)    | 26.6270539113887
-         | (-3,4)     | (5.1,34.5) | 31.5572495632937
-         | (0,0)      | (5.1,34.5) | 34.8749193547455
-         | (-10,0)    | (5.1,34.5) | 37.6597928831267
-         | (-5,-12)   | (5.1,34.5) | 47.5842410888311
-(15 rows)
+ fifteen |      point1      |      point2       |     distance     
+---------+------------------+-------------------+------------------
+         | (-3,4)           | (0,0)             |                5
+         | (-3,4)           | (1e-300,-1e-300)  |                5
+         | (-10,0)          | (-3,4)            | 8.06225774829855
+         | (-10,0)          | (0,0)             |               10
+         | (-10,0)          | (1e-300,-1e-300)  |               10
+         | (-10,0)          | (-5,-12)          |               13
+         | (-5,-12)         | (0,0)             |               13
+         | (-5,-12)         | (1e-300,-1e-300)  |               13
+         | (0,0)            | (10,10)           |  14.142135623731
+         | (1e-300,-1e-300) | (10,10)           |  14.142135623731
+         | (-3,4)           | (10,10)           | 14.3178210632764
+         | (-5,-12)         | (-3,4)            | 16.1245154965971
+         | (-10,0)          | (10,10)           | 22.3606797749979
+         | (5.1,34.5)       | (10,10)           | 24.9851956166046
+         | (-5,-12)         | (10,10)           | 26.6270539113887
+         | (-3,4)           | (5.1,34.5)        | 31.5572495632937
+         | (0,0)            | (5.1,34.5)        | 34.8749193547455
+         | (1e-300,-1e-300) | (5.1,34.5)        | 34.8749193547455
+         | (-10,0)          | (5.1,34.5)        | 37.6597928831267
+         | (-5,-12)         | (5.1,34.5)        | 47.5842410888311
+         | (-10,0)          | (1e+300,Infinity) |         Infinity
+         | (-5,-12)         | (1e+300,Infinity) |         Infinity
+         | (-3,4)           | (1e+300,Infinity) |         Infinity
+         | (0,0)            | (1e+300,Infinity) |         Infinity
+         | (1e-300,-1e-300) | (1e+300,Infinity) |         Infinity
+         | (5.1,34.5)       | (1e+300,Infinity) |         Infinity
+         | (10,10)          | (1e+300,Infinity) |         Infinity
+(27 rows)
 
 -- put distance result into output to allow sorting with GEQ optimizer - tgl 97/05/10
 SELECT '' AS three, p1.f1 AS point1, p2.f1 AS point2, (p1.f1 <-> p2.f1) AS distance
    FROM POINT_TBL p1, POINT_TBL p2
    WHERE (p1.f1 <-> p2.f1) > 3 and p1.f1 << p2.f1 and p1.f1 >^ p2.f1
    ORDER BY distance;
- three |   point1   |  point2  |     distance     
--------+------------+----------+------------------
-       | (-3,4)     | (0,0)    |                5
-       | (-10,0)    | (-5,-12) |               13
-       | (5.1,34.5) | (10,10)  | 24.9851956166046
-(3 rows)
+ three |   point1   |      point2      |     distance     
+-------+------------+------------------+------------------
+       | (-3,4)     | (0,0)            |                5
+       | (-3,4)     | (1e-300,-1e-300) |                5
+       | (-10,0)    | (-5,-12)         |               13
+       | (5.1,34.5) | (10,10)          | 24.9851956166046
+(4 rows)
 
 -- Test that GiST indexes provide same behavior as sequential scan
 CREATE TEMP TABLE point_gist_tbl(f1 point);
 INSERT INTO point_gist_tbl SELECT '(0,0)' FROM generate_series(0,1000);
 CREATE INDEX point_gist_tbl_index ON point_gist_tbl USING gist (f1);
 INSERT INTO point_gist_tbl VALUES ('(0.0000009,0.0000009)');
 SET enable_seqscan TO true;
 SET enable_indexscan TO false;
 SET enable_bitmapscan TO false;
 SELECT COUNT(*) FROM point_gist_tbl WHERE f1 ~= '(0.0000009,0.0000009)'::point;
diff --git a/src/test/regress/expected/polygon.out b/src/test/regress/expected/polygon.out
index 4a1f60427a..be5f76bf9d 100644
--- a/src/test/regress/expected/polygon.out
+++ b/src/test/regress/expected/polygon.out
@@ -1,18 +1,21 @@
 --
 -- POLYGON
 --
 -- polygon logic
 --
 CREATE TABLE POLYGON_TBL(f1 polygon);
 INSERT INTO POLYGON_TBL(f1) VALUES ('(2.0,0.0),(2.0,4.0),(0.0,0.0)');
 INSERT INTO POLYGON_TBL(f1) VALUES ('(3.0,1.0),(3.0,3.0),(1.0,0.0)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(3,4),(5,6),(7,8)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(7,8),(5,6),(3,4),(1,2)'); -- Reverse
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(7,8),(5,6),(3,-4)');
 -- degenerate polygons
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,0.0)');
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,1.0),(0.0,1.0)');
 -- bad polygon input strings
 INSERT INTO POLYGON_TBL(f1) VALUES ('0.0');
 ERROR:  invalid input syntax for type polygon: "0.0"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('0.0');
                                             ^
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0 0.0');
 ERROR:  invalid input syntax for type polygon: "(0.0 0.0"
@@ -24,215 +27,30 @@ LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2)');
                                             ^
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2,3');
 ERROR:  invalid input syntax for type polygon: "(0,1,2,3"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2,3');
                                             ^
 INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
 ERROR:  invalid input syntax for type polygon: "asdf"
 LINE 1: INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
                                             ^
 SELECT '' AS four, * FROM POLYGON_TBL;
- four |         f1          
-------+---------------------
+ four |             f1             
+------+----------------------------
       | ((2,0),(2,4),(0,0))
       | ((3,1),(3,3),(1,0))
+      | ((1,2),(3,4),(5,6),(7,8))
+      | ((7,8),(5,6),(3,4),(1,2))
+      | ((1,2),(7,8),(5,6),(3,-4))
       | ((0,0))
       | ((0,1),(0,1))
-(4 rows)
-
--- overlap
-SELECT '' AS three, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 && '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- three |         f1          
--------+---------------------
-       | ((2,0),(2,4),(0,0))
-       | ((3,1),(3,3),(1,0))
-(2 rows)
-
--- left overlap
-SELECT '' AS four, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &< '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- four |         f1          
-------+---------------------
-      | ((2,0),(2,4),(0,0))
-      | ((3,1),(3,3),(1,0))
-      | ((0,0))
-      | ((0,1),(0,1))
-(4 rows)
-
--- right overlap
-SELECT '' AS two, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- two |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- left of
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 << '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |      f1       
------+---------------
-     | ((0,0))
-     | ((0,1),(0,1))
-(2 rows)
-
--- right of
-SELECT '' AS zero, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 >> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- zero | f1 
-------+----
-(0 rows)
-
--- contained
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- same
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
--- contains
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
- one |         f1          
------+---------------------
-     | ((3,1),(3,3),(1,0))
-(1 row)
-
---
--- polygon logic
---
--- left of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- left overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
- true 
-------
- f
-(1 row)
-
--- right overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' &> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- right of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' >> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- contained in
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- contains
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((0,4),(6,4),(3,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
-SELECT '((1,1),(1,4),(5,4),(5,3),(2,3),(2,2),(5,2),(5,1))'::polygon @> '((3,2),(3,3),(4,3),(4,2))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((0,0),(0,3),(3,3),(3,0))'::polygon @> '((2,1),(2,2),(3,2),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
--- same
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
- false 
--------
- f
-(1 row)
-
--- overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' && polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
- true 
-------
- t
-(1 row)
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon && '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
-SELECT '((1,4),(1,1),(4,1),(4,2),(2,2),(2,4),(1,4))'::polygon && '((3,3),(4,3),(4,4),(3,4),(3,3))'::polygon AS "false";
- false 
--------
- f
-(1 row)
-
-SELECT '((200,800),(800,800),(800,200),(200,200))' &&  '(1000,1000,0,0)'::polygon AS "true";
- true 
-------
- t
-(1 row)
-
--- distance from a point
-SELECT	'(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
-	'(1,1)'::point <-> '((0,0),(2,2),(1,3))'::polygon as on_segment,
-	'(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;
- on_corner | on_segment | inside |   near_corner   | near_segment 
------------+------------+--------+-----------------+--------------
-         0 |          0 |      0 | 1.4142135623731 |          3.2
-(1 row)
+(7 rows)
 
 --
 -- 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
diff --git a/src/test/regress/sql/box.sql b/src/test/regress/sql/box.sql
index 135ac108eb..6710fc90f5 100644
--- a/src/test/regress/sql/box.sql
+++ b/src/test/regress/sql/box.sql
@@ -18,29 +18,38 @@
 
 -- boxes are specified by two points, given by four floats x1,y1,x2,y2
 
 
 CREATE TABLE BOX_TBL (f1 box);
 
 INSERT INTO BOX_TBL (f1) VALUES ('(2.0,2.0,0.0,0.0)');
 
 INSERT INTO BOX_TBL (f1) VALUES ('(1.0,1.0,3.0,3.0)');
 
+INSERT INTO BOX_TBL (f1) VALUES ('((-8, 2), (-2, -10))');
+
+
 -- degenerate cases where the box is a line or a point
 -- note that lines and points boxes all have zero area
 INSERT INTO BOX_TBL (f1) VALUES ('(2.5, 2.5, 2.5,3.5)');
 
 INSERT INTO BOX_TBL (f1) VALUES ('(3.0, 3.0,3.0,3.0)');
 
 -- badly formatted box inputs
 INSERT INTO BOX_TBL (f1) VALUES ('(2.3, 4.5)');
 
+INSERT INTO BOX_TBL (f1) VALUES ('[1, 2, 3, 4)');
+
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4]');
+
+INSERT INTO BOX_TBL (f1) VALUES ('(1, 2, 3, 4) x');
+
 INSERT INTO BOX_TBL (f1) VALUES ('asdfasdf(ad');
 
 
 SELECT '' AS four, * FROM BOX_TBL;
 
 SELECT '' AS four, b.*, area(b.f1) as barea
    FROM BOX_TBL b;
 
 -- overlap
 SELECT '' AS three, b.f1
diff --git a/src/test/regress/sql/circle.sql b/src/test/regress/sql/circle.sql
index c0284b2b59..46c96e1400 100644
--- a/src/test/regress/sql/circle.sql
+++ b/src/test/regress/sql/circle.sql
@@ -7,26 +7,34 @@ CREATE TABLE CIRCLE_TBL (f1 circle);
 INSERT INTO CIRCLE_TBL VALUES ('<(5,1),3>');
 
 INSERT INTO CIRCLE_TBL VALUES ('<(1,2),100>');
 
 INSERT INTO CIRCLE_TBL VALUES ('1,3,5');
 
 INSERT INTO CIRCLE_TBL VALUES ('((1,2),3)');
 
 INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10>');
 
-INSERT INTO CIRCLE_TBL VALUES ('<(100,1),115>');
+INSERT INTO CIRCLE_TBL VALUES (' < ( 100 , 1 ) , 115 > ');
+
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),0>');	-- Zero radius
+
+INSERT INTO CIRCLE_TBL VALUES ('<(3,5),NaN>');	-- NaN radius
 
 -- bad values
 
 INSERT INTO CIRCLE_TBL VALUES ('<(-100,0),-100>');
 
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10');
+
+INSERT INTO CIRCLE_TBL VALUES ('<(100,200),10> x');
+
 INSERT INTO CIRCLE_TBL VALUES ('1abc,3,5');
 
 INSERT INTO CIRCLE_TBL VALUES ('(3,(1,2),3)');
 
 SELECT * FROM CIRCLE_TBL;
 
 SELECT '' AS six, center(f1) AS center
   FROM CIRCLE_TBL;
 
 SELECT '' AS six, radius(f1) AS radius
diff --git a/src/test/regress/sql/geometry.sql b/src/test/regress/sql/geometry.sql
index 1429ee772a..ce98b3e90c 100644
--- a/src/test/regress/sql/geometry.sql
+++ b/src/test/regress/sql/geometry.sql
@@ -39,74 +39,298 @@ SELECT '' AS two, p1.f1
 -- "is vertical" function
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE isvertical(p1.f1, point '(5.1,34.5)');
 
 -- "is vertical" operator
 SELECT '' AS one, p1.f1
    FROM POINT_TBL p1
    WHERE p1.f1 ?| point '(5.1,34.5)';
 
+-- Slope
+SELECT p1.f1, p2.f1, slope(p1.f1, p2.f1) FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Add point
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Subtract point
+SELECT p1.f1, p2.f1, p1.f1 - p2.f1 FROM POINT_TBL p1, POINT_TBL p2;
+
+-- Multiply with point
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+
+-- Underflow error
+SELECT p1.f1, p2.f1, p1.f1 * p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p1.f1[0] < 1;
+
+-- Divide by point
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] BETWEEN 1 AND 1000;
+
+-- Overflow error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1[0] > 1000;
+
+-- Division by 0 error
+SELECT p1.f1, p2.f1, p1.f1 / p2.f1 FROM POINT_TBL p1, POINT_TBL p2 WHERE p2.f1 ~= '(0,0)'::point;
+
+-- Distance to line
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LINE_TBL l;
+
+-- Distance to line segment
+SELECT p.f1, l.s, p.f1 <-> l.s FROM POINT_TBL p, LSEG_TBL l;
+
+-- Distance to box
+SELECT p.f1, b.f1, p.f1 <-> b.f1 FROM POINT_TBL p, BOX_TBL b;
+
+-- Distance to path
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, PATH_TBL p1;
+
+-- Distance to polygon
+SELECT p.f1, p1.f1, p.f1 <-> p1.f1 FROM POINT_TBL p, POLYGON_TBL p1;
+
+-- Closest point to line
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LINE_TBL l;
+
+-- Closest point to line segment
+SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LSEG_TBL l;
+
+-- Closest point to box
+SELECT p.f1, b.f1, p.f1 ## b.f1 FROM POINT_TBL p, BOX_TBL b;
+
+-- On line
+SELECT p.f1, l.s FROM POINT_TBL p, LINE_TBL l WHERE p.f1 <@ l.s;
+
+-- On line segment
+SELECT p.f1, l.s FROM POINT_TBL p, LSEG_TBL l WHERE p.f1 <@ l.s;
+
+-- On path
+SELECT p.f1, p1.f1 FROM POINT_TBL p, PATH_TBL p1 WHERE p.f1 <@ p1.f1;
+
+--
+-- Lines
+--
+
+-- Vertical
+SELECT s FROM LINE_TBL WHERE ?| s;
+
+-- Horizontal
+SELECT s FROM LINE_TBL WHERE ?- s;
+
+-- Same as line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s = l2.s;
+
+-- Parallel to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?|| l2.s;
+
+-- Perpendicular to line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?-| l2.s;
+
+-- Distance to line
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2;
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LINE_TBL l, BOX_TBL b;
+
+-- Intersect with line
+SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?# l2.s;
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LINE_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+
+-- Intersection point with line
+SELECT l1.s, l2.s, l1.s # l2.s FROM LINE_TBL l1, LINE_TBL l2;
+
+-- Closest point to line segment
+SELECT l.s, l1.s, l.s ## l1.s FROM LINE_TBL l, LSEG_TBL l1;
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LINE_TBL l, BOX_TBL b;
+
 --
 -- Line segments
 --
 
 -- intersection
 SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
    FROM LSEG_TBL l, POINT_TBL p;
 
--- closest point
-SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
-   FROM LSEG_TBL l, POINT_TBL p;
+-- Length
+SELECT s, @-@ s FROM LSEG_TBL;
+
+-- Vertical
+SELECT s FROM LSEG_TBL WHERE ?| s;
+
+-- Horizontal
+SELECT s FROM LSEG_TBL WHERE ?- s;
+
+-- Center
+SELECT s, @@ s FROM LSEG_TBL;
+
+-- To point
+SELECT s, s::point FROM LSEG_TBL;
+
+-- Has points less than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s < l2.s;
+
+-- Has points less than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s <= l2.s;
+
+-- Has points equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s = l2.s;
+
+-- Has points greater than or equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s >= l2.s;
+
+-- Has points greater than line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s > l2.s;
+
+-- Has points not equal to line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s != l2.s;
+
+-- Parallel with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?|| l2.s;
+
+-- Perpendicular with line segment
+SELECT l1.s, l2.s FROM LSEG_TBL l1, LSEG_TBL l2 WHERE l1.s ?-| l2.s;
+
+-- Distance to line
+SELECT l.s, l1.s, l.s <-> l1.s FROM LSEG_TBL l, LINE_TBL l1;
+
+-- Distance to line segment
+SELECT l1.s, l2.s, l1.s <-> l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Distance to box
+SELECT l.s, b.f1, l.s <-> b.f1 FROM LSEG_TBL l, BOX_TBL b;
+
+-- Intersect with line segment
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s ?# l1.s;
+
+-- Intersect with box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s ?# b.f1;
+
+-- Intersection point with line segment
+SELECT l1.s, l2.s, l1.s # l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Closest point to line
+SELECT l.s, l1.s, l.s ## l1.s FROM LSEG_TBL l, LINE_TBL l1;
+
+-- Closest point to line segment
+SELECT l1.s, l2.s, l1.s ## l2.s FROM LSEG_TBL l1, LSEG_TBL l2;
+
+-- Closest point to box
+SELECT l.s, b.f1, l.s ## b.f1 FROM LSEG_TBL l, BOX_TBL b;
+
+-- On line
+SELECT l.s, l1.s FROM LSEG_TBL l, LINE_TBL l1 WHERE l.s <@ l1.s;
+
+-- On box
+SELECT l.s, b.f1 FROM LSEG_TBL l, BOX_TBL b WHERE l.s <@ b.f1;
 
 --
 -- Boxes
 --
 
 SELECT '' as six, box(f1) AS box FROM CIRCLE_TBL;
 
 -- translation
 SELECT '' AS twentyfour, b.f1 + p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
 
 SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
 
--- scaling and rotation
-SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p;
+-- Multiply with point
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
 
-SELECT '' AS twenty, b.f1 / p.f1 AS rotation
-   FROM BOX_TBL b, POINT_TBL p
-   WHERE (p.f1 <-> point '(0,0)') >= 1;
+-- Overflow error
+SELECT b.f1, p.f1, b.f1 * p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] > 1000;
 
+-- Divide by point
+SELECT b.f1, p.f1, b.f1 / p.f1 FROM BOX_TBL b, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+
+-- To box
 SELECT f1::box
 	FROM POINT_TBL;
 
 SELECT bound_box(a.f1, b.f1)
 	FROM BOX_TBL a, BOX_TBL b;
 
+-- Below box
+SELECT b1.f1, b2.f1, b1.f1 <^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Above box
+SELECT b1.f1, b2.f1, b1.f1 >^ b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Intersection point with box
+SELECT b1.f1, b2.f1, b1.f1 # b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
+-- Diagonal
+SELECT f1, diagonal(f1) FROM BOX_TBL;
+
+-- Distance to box
+SELECT b1.f1, b2.f1, b1.f1 <-> b2.f1 FROM BOX_TBL b1, BOX_TBL b2;
+
 --
 -- Paths
 --
 
-SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
+-- Points
+SELECT f1, npoints(f1) FROM PATH_TBL;
 
-SELECT '' AS four, path(f1) FROM POLYGON_TBL;
+-- Area
+SELECT f1, area(f1) FROM PATH_TBL;
 
--- translation
-SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
-   FROM PATH_TBL p1;
+-- Length
+SELECT f1, @-@ f1 FROM PATH_TBL;
 
--- scaling and rotation
-SELECT '' AS eight, p1.f1 * point '(2,-1)' AS dist_mul
-   FROM PATH_TBL p1;
+-- Center
+SELECT f1, @@ f1 FROM PATH_TBL;
+
+-- To polygon
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isclosed(f1);
+
+-- Open path cannot be converted to polygon error
+SELECT f1, f1::polygon FROM PATH_TBL WHERE isopen(f1);
+
+-- Has points less than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 < p2.f1;
+
+-- Has points less than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 <= p2.f1;
+
+-- Has points equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 = p2.f1;
+
+-- Has points greater than or equal to path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 >= p2.f1;
+
+-- Has points greater than path
+SELECT p1.f1, p2.f1 FROM PATH_TBL p1, PATH_TBL p2 WHERE p1.f1 > p2.f1;
+
+-- Add path
+SELECT p1.f1, p2.f1, p1.f1 + p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
+
+-- Add point
+SELECT p.f1, p1.f1, p.f1 + p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+
+-- Subtract point
+SELECT p.f1, p1.f1, p.f1 - p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+
+-- Multiply with point
+SELECT p.f1, p1.f1, p.f1 * p1.f1 FROM PATH_TBL p, POINT_TBL p1;
+
+-- Divide by point
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1[0] BETWEEN 1 AND 1000;
+
+-- Division by 0 error
+SELECT p.f1, p1.f1, p.f1 / p1.f1 FROM PATH_TBL p, POINT_TBL p1 WHERE p1.f1 ~= '(0,0)'::point;
+
+-- Distance to path
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM PATH_TBL p1, PATH_TBL p2;
 
 --
 -- Polygons
 --
 
 -- containment
 SELECT '' AS twentyfour, p.f1, poly.f1, poly.f1 @> p.f1 AS contains
    FROM POLYGON_TBL poly, POINT_TBL p;
 
 SELECT '' AS twentyfour, p.f1, poly.f1, p.f1 <@ poly.f1 AS contained
@@ -118,36 +342,166 @@ SELECT '' AS four, npoints(f1) AS npoints, f1 AS polygon
 SELECT '' AS four, polygon(f1)
    FROM BOX_TBL;
 
 SELECT '' AS four, polygon(f1)
    FROM PATH_TBL WHERE isclosed(f1);
 
 SELECT '' AS four, f1 AS open_path, polygon( pclose(f1)) AS polygon
    FROM PATH_TBL
    WHERE isopen(f1);
 
--- convert circles to polygons using the default number of points
-SELECT '' AS six, polygon(f1)
-   FROM CIRCLE_TBL;
+-- To box
+SELECT f1, f1::box FROM POLYGON_TBL;
 
--- convert the circle to an 8-point polygon
-SELECT '' AS six, polygon(8, f1)
-   FROM CIRCLE_TBL;
+-- To path
+SELECT f1, f1::path FROM POLYGON_TBL;
+
+-- Same as polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 ~= p2.f1;
+
+-- Contained by polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <@ p2.f1;
+
+-- Contains polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 @> p2.f1;
+
+-- Overlap with polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 && p2.f1;
+
+-- Left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 << p2.f1;
+
+-- Overlap of left of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &< p2.f1;
+
+-- Right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 >> p2.f1;
+
+-- Overlap of right of polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &> p2.f1;
+
+-- Below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 <<| p2.f1;
+
+-- Overlap or below polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 &<| p2.f1;
+
+-- Above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |>> p2.f1;
+
+-- Overlap or above polygon
+SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |&> p2.f1;
+
+-- Distance to polygon
+SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2;
 
 --
 -- Circles
 --
 
 SELECT '' AS six, circle(f1, 50.0)
    FROM POINT_TBL;
 
 SELECT '' AS four, circle(f1)
    FROM BOX_TBL;
 
 SELECT '' AS two, circle(f1)
    FROM POLYGON_TBL
    WHERE (# f1) >= 3;
 
 SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
    FROM CIRCLE_TBL c1, POINT_TBL p1
    WHERE (p1.f1 <-> c1.f1) > 0
    ORDER BY distance, area(c1.f1), p1.f1[0];
+
+-- To polygon
+SELECT f1, f1::polygon FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+
+-- To polygon with less points
+SELECT f1, polygon(8, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+
+-- Too less points error
+SELECT f1, polygon(1, f1) FROM CIRCLE_TBL WHERE f1 >= '<(0,0),1>';
+
+-- Zero radius error
+SELECT f1, polygon(10, f1) FROM CIRCLE_TBL WHERE f1 < '<(0,0),1>';
+
+-- Same as circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 ~= c2.f1;
+
+-- Overlap with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 && c2.f1;
+
+-- Overlap or left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &< c2.f1;
+
+-- Left of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 << c2.f1;
+
+-- Right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >> c2.f1;
+
+-- Overlap or right of circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &> c2.f1;
+
+-- Contained by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <@ c2.f1;
+
+-- Contain by circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 @> c2.f1;
+
+-- Below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <<| c2.f1;
+
+-- Above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |>> c2.f1;
+
+-- Overlap or below circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 &<| c2.f1;
+
+-- Overlap or above circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 |&> c2.f1;
+
+-- Area equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 = c2.f1;
+
+-- Area not equal with circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 != c2.f1;
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 > c2.f1;
+
+-- Area less than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 <= c2.f1;
+
+-- Area greater than or equal circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 >= c2.f1;
+
+-- Area less than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+
+-- Area greater than circle
+SELECT c1.f1, c2.f1 FROM CIRCLE_TBL c1, CIRCLE_TBL c2 WHERE c1.f1 < c2.f1;
+
+-- Add point
+SELECT c.f1, p.f1, c.f1 + p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Subtract point
+SELECT c.f1, p.f1, c.f1 - p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Multiply with point
+SELECT c.f1, p.f1, c.f1 * p.f1 FROM CIRCLE_TBL c, POINT_TBL p;
+
+-- Divide by point
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] BETWEEN 1 AND 1000;
+
+-- Overflow error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1[0] > 1000;
+
+-- Division by 0 error
+SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1 ~= '(0,0)'::point;
+
+-- Distance to polygon
+SELECT c.f1, p.f1, c.f1 <-> p.f1 FROM CIRCLE_TBL c, POLYGON_TBL p;
diff --git a/src/test/regress/sql/line.sql b/src/test/regress/sql/line.sql
index 94067b0cee..f589ffecc8 100644
--- a/src/test/regress/sql/line.sql
+++ b/src/test/regress/sql/line.sql
@@ -1,87 +1,42 @@
 --
 -- LINE
 -- Infinite lines
 --
 
 --DROP TABLE LINE_TBL;
 CREATE TABLE LINE_TBL (s line);
 
-INSERT INTO LINE_TBL VALUES ('{1,-1,1}');
-INSERT INTO LINE_TBL VALUES ('(0,0),(6,6)');
+INSERT INTO LINE_TBL VALUES ('{0,-1,5}');	-- A == 0
+INSERT INTO LINE_TBL VALUES ('{1,0,5}');	-- B == 0
+INSERT INTO LINE_TBL VALUES ('{0,3,0}');	-- A == C == 0
+INSERT INTO LINE_TBL VALUES (' (0,0), (6,6)');
 INSERT INTO LINE_TBL VALUES ('10,-10 ,-5,-4');
 INSERT INTO LINE_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LINE_TBL VALUES ('(11,22,33,44)');
 
-INSERT INTO LINE_TBL VALUES ('[(1,0),(1,0)]');
+INSERT INTO LINE_TBL VALUES ('{3,NaN,5}');
+INSERT INTO LINE_TBL VALUES ('{NaN,NaN,NaN}');
 
 -- horizontal
 INSERT INTO LINE_TBL VALUES ('[(1,3),(2,3)]');
 -- vertical
-INSERT INTO LINE_TBL VALUES ('[(3,1),(3,2)]');
+INSERT INTO LINE_TBL VALUES (line(point '(3,1)', point '(3,2)'));
 
 -- bad values for parser testing
+INSERT INTO LINE_TBL VALUES ('{}');
+INSERT INTO LINE_TBL VALUES ('{0');
+INSERT INTO LINE_TBL VALUES ('{0,0}');
+INSERT INTO LINE_TBL VALUES ('{0,0,1');
 INSERT INTO LINE_TBL VALUES ('{0,0,1}');
+INSERT INTO LINE_TBL VALUES ('{0,0,1} x');
 INSERT INTO LINE_TBL VALUES ('(3asdf,2 ,3,4r2)');
 INSERT INTO LINE_TBL VALUES ('[1,2,3, 4');
 INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]');
 INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)');
+INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
+
+INSERT INTO LINE_TBL VALUES (line(point '(1,0)', point '(1,0)'));
 
 select * from LINE_TBL;
 
-
--- functions and operators
-
-SELECT * FROM LINE_TBL WHERE (s <-> line '[(1,2),(3,4)]') < 10;
-
-SELECT * FROM LINE_TBL WHERE (point '(0.1,0.1)' <-> s) < 1;
-
-SELECT * FROM LINE_TBL WHERE (lseg '[(0.1,0.1),(0.2,0.2)]' <-> s) < 1;
-
-SELECT line '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
-SELECT lseg '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]';
-SELECT point '(-1,1)' <-> line '[(-3,0),(-4,0)]';
-
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(2,0),(0,2)]';  -- true
-SELECT lseg '[(1,1),(5,5)]' ?# line '[(0,0),(1,0)]';  -- false
-
-SELECT line '[(0,0),(1,1)]' ?# box '(0,0,2,2)';  -- true
-SELECT line '[(3,0),(4,1)]' ?# box '(0,0,2,2)';  -- false
-
-SELECT point '(1,1)' <@ line '[(0,0),(2,2)]';  -- true
-SELECT point '(1,1)' <@ line '[(0,0),(1,0)]';  -- false
-
-SELECT point '(1,1)' @ line '[(0,0),(2,2)]';  -- true
-SELECT point '(1,1)' @ line '[(0,0),(1,0)]';  -- false
-
-SELECT lseg '[(1,1),(2,2)]' <@ line '[(0,0),(2,2)]';  -- true
-SELECT lseg '[(1,1),(2,1)]' <@ line '[(0,0),(1,0)]';  -- false
-
-SELECT lseg '[(1,1),(2,2)]' @ line '[(0,0),(2,2)]';  -- true
-SELECT lseg '[(1,1),(2,1)]' @ line '[(0,0),(1,0)]';  -- false
-
-SELECT point '(0,1)' ## line '[(0,0),(1,1)]';
-
-SELECT line '[(0,0),(1,1)]' ## lseg '[(1,0),(2,0)]';
-
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(2,1)]';  -- false
-SELECT line '[(0,0),(1,1)]' ?# line '[(1,0),(1,1)]';  -- true
-
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(2,1)]';
-SELECT line '[(0,0),(1,1)]' # line '[(1,0),(1,1)]';
-
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(2,1)]';  -- true
-SELECT line '[(0,0),(1,1)]' ?|| line '[(1,0),(1,1)]';  -- false
-
-SELECT line '[(0,0),(1,0)]' ?-| line '[(0,0),(0,1)]';  -- true
-SELECT line '[(0,0),(1,1)]' ?-| line '[(1,0),(1,1)]';  -- false
-
-SELECT ?- line '[(0,0),(1,0)]';  -- true
-SELECT ?- line '[(0,0),(1,1)]';  -- false
-
-SELECT ?| line '[(0,0),(0,1)]';  -- true
-SELECT ?| line '[(0,0),(1,1)]';  -- false
-
-SELECT line(point '(1,2)', point '(3,4)');
-
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,5)]';  -- true
-SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,4)]';  -- false
+select '{nan, 1, nan}'::line = '{nan, 1, nan}'::line as true,
+	   '{nan, 1, nan}'::line = '{nan, 2, nan}'::line as false;
diff --git a/src/test/regress/sql/lseg.sql b/src/test/regress/sql/lseg.sql
index 07c5a29e0a..f266ca3e09 100644
--- a/src/test/regress/sql/lseg.sql
+++ b/src/test/regress/sql/lseg.sql
@@ -3,23 +3,22 @@
 -- Line segments
 --
 
 --DROP TABLE LSEG_TBL;
 CREATE TABLE LSEG_TBL (s lseg);
 
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('(0,0),(6,6)');
 INSERT INTO LSEG_TBL VALUES ('10,-10 ,-3,-4');
 INSERT INTO LSEG_TBL VALUES ('[-1e6,2e2,3e5, -4e1]');
-INSERT INTO LSEG_TBL VALUES ('(11,22,33,44)');
+INSERT INTO LSEG_TBL VALUES (lseg(point(11, 22), point(33,44)));
+INSERT INTO LSEG_TBL VALUES ('[(-10,2),(-10,3)]');	-- vertical
+INSERT INTO LSEG_TBL VALUES ('[(0,-20),(30,-20)]');	-- horizontal
+INSERT INTO LSEG_TBL VALUES ('[(NaN,1),(NaN,90)]');	-- NaN
 
 -- bad values for parser testing
 INSERT INTO LSEG_TBL VALUES ('(3asdf,2 ,3,4r2)');
 INSERT INTO LSEG_TBL VALUES ('[1,2,3, 4');
 INSERT INTO LSEG_TBL VALUES ('[(,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)');
 
 select * from LSEG_TBL;
-
-SELECT * FROM LSEG_TBL WHERE s <= lseg '[(1,2),(3,4)]';
-
-SELECT * FROM LSEG_TBL WHERE (s <-> lseg '[(1,2),(3,4)]') < 10;
diff --git a/src/test/regress/sql/path.sql b/src/test/regress/sql/path.sql
index 7e69b539ad..318decf974 100644
--- a/src/test/regress/sql/path.sql
+++ b/src/test/regress/sql/path.sql
@@ -1,38 +1,44 @@
 --
 -- PATH
 --
 
 --DROP TABLE PATH_TBL;
 
 CREATE TABLE PATH_TBL (f1 path);
 
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)]');
 
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
+INSERT INTO PATH_TBL VALUES (' ( ( 1 , 2 ) , ( 3 , 4 ) ) ');
 
-INSERT INTO PATH_TBL VALUES ('[(0,0),(3,0),(4,5),(1,6)]');
+INSERT INTO PATH_TBL VALUES ('[ (0,0),(3,0),(4,5),(1,6) ]');
 
-INSERT INTO PATH_TBL VALUES ('((1,2),(3,4))');
+INSERT INTO PATH_TBL VALUES ('((1,2) ,(3,4 ))');
 
-INSERT INTO PATH_TBL VALUES ('1,2 ,3,4');
+INSERT INTO PATH_TBL VALUES ('1,2 ,3,4 ');
 
-INSERT INTO PATH_TBL VALUES ('[1,2,3, 4]');
+INSERT INTO PATH_TBL VALUES (' [1,2,3, 4] ');
 
-INSERT INTO PATH_TBL VALUES ('[11,12,13,14]');
+INSERT INTO PATH_TBL VALUES ('((10,20))');	-- Only one point
 
-INSERT INTO PATH_TBL VALUES ('(11,12,13,14)');
+INSERT INTO PATH_TBL VALUES ('[ 11,12,13,14 ]');
+
+INSERT INTO PATH_TBL VALUES ('( 11,12,13,14) ');
 
 -- bad values for parser testing
+INSERT INTO PATH_TBL VALUES ('[]');
+
 INSERT INTO PATH_TBL VALUES ('[(,2),(3,4)]');
 
 INSERT INTO PATH_TBL VALUES ('[(1,2),(3,4)');
 
-SELECT f1 FROM PATH_TBL;
+INSERT INTO PATH_TBL VALUES ('(1,2,3,4');
+
+INSERT INTO PATH_TBL VALUES ('(1,2),(3,4)]');
 
 SELECT '' AS count, f1 AS open_path FROM PATH_TBL WHERE isopen(f1);
 
 SELECT '' AS count, f1 AS closed_path FROM PATH_TBL WHERE isclosed(f1);
 
 SELECT '' AS count, pclose(f1) AS closed_path FROM PATH_TBL;
 
 SELECT '' AS count, popen(f1) AS open_path FROM PATH_TBL;
diff --git a/src/test/regress/sql/point.sql b/src/test/regress/sql/point.sql
index 63a803a809..a209f3bfeb 100644
--- a/src/test/regress/sql/point.sql
+++ b/src/test/regress/sql/point.sql
@@ -7,29 +7,39 @@ CREATE TABLE POINT_TBL(f1 point);
 INSERT INTO POINT_TBL(f1) VALUES ('(0.0,0.0)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-10.0,0.0)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-3.0,4.0)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(5.1, 34.5)');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(-5.0,-12.0)');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(1e-300,-1e-300)');	-- To underflow
+
+INSERT INTO POINT_TBL(f1) VALUES ('(1e+300,Inf)');		-- To overflow
+
+INSERT INTO POINT_TBL(f1) VALUES (' ( Nan , NaN ) ');
+
 -- bad format points
 INSERT INTO POINT_TBL(f1) VALUES ('asdfasdf');
 
 INSERT INTO POINT_TBL(f1) VALUES ('10.0,10.0');
 
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0 10.0)');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 10.0) x');
+
 INSERT INTO POINT_TBL(f1) VALUES ('(10.0,10.0');
 
+INSERT INTO POINT_TBL(f1) VALUES ('(10.0, 1e+500)');	-- Out of range
+
 
 SELECT '' AS six, * FROM POINT_TBL;
 
 -- left of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE p.f1 << '(0.0, 0.0)';
 
 -- right of
 SELECT '' AS three, p.* FROM POINT_TBL p WHERE '(0.0,0.0)' >> p.f1;
 
 -- above
diff --git a/src/test/regress/sql/polygon.sql b/src/test/regress/sql/polygon.sql
index 7e8cb08cd8..d3d2fe3457 100644
--- a/src/test/regress/sql/polygon.sql
+++ b/src/test/regress/sql/polygon.sql
@@ -4,126 +4,43 @@
 -- polygon logic
 --
 
 CREATE TABLE POLYGON_TBL(f1 polygon);
 
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(2.0,0.0),(2.0,4.0),(0.0,0.0)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(3.0,1.0),(3.0,3.0),(1.0,0.0)');
 
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(3,4),(5,6),(7,8)');
+INSERT INTO POLYGON_TBL(f1) VALUES ('(7,8),(5,6),(3,4),(1,2)'); -- Reverse
+INSERT INTO POLYGON_TBL(f1) VALUES ('(1,2),(7,8),(5,6),(3,-4)');
+
 -- degenerate polygons
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,0.0)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0,1.0),(0.0,1.0)');
 
 -- bad polygon input strings
 INSERT INTO POLYGON_TBL(f1) VALUES ('0.0');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0.0 0.0');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2)');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('(0,1,2,3');
 
 INSERT INTO POLYGON_TBL(f1) VALUES ('asdf');
 
 
 SELECT '' AS four, * FROM POLYGON_TBL;
 
--- overlap
-SELECT '' AS three, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 && '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- left overlap
-SELECT '' AS four, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &< '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- right overlap
-SELECT '' AS two, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 &> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- left of
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 << '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- right of
-SELECT '' AS zero, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 >> '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- contained
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- same
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
--- contains
-SELECT '' AS one, p.*
-   FROM POLYGON_TBL p
-   WHERE p.f1 @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)';
-
---
--- polygon logic
---
--- left of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- left overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' << polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
-
--- right overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' &> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- right of
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' >> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- contained in
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' <@ polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- contains
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' @> polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "false";
-
-SELECT '((0,4),(6,4),(3,2),(6,0),(0,0))'::polygon @> '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
-
-SELECT '((1,1),(1,4),(5,4),(5,3),(2,3),(2,2),(5,2),(5,1))'::polygon @> '((3,2),(3,3),(4,3),(4,2))'::polygon AS "false";
-
-SELECT '((0,0),(0,3),(3,3),(3,0))'::polygon @> '((2,1),(2,2),(3,2),(3,1))'::polygon AS "true";
-
--- same
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' ~= polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS false;
-
--- overlap
-SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' && polygon '(3.0,1.0),(3.0,3.0),(1.0,0.0)' AS true;
-
-SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon && '((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
-
-SELECT '((1,4),(1,1),(4,1),(4,2),(2,2),(2,4),(1,4))'::polygon && '((3,3),(4,3),(4,4),(3,4),(3,3))'::polygon AS "false";
-SELECT '((200,800),(800,800),(800,200),(200,200))' &&  '(1000,1000,0,0)'::polygon AS "true";
-
--- distance from a point
-SELECT	'(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
-	'(1,1)'::point <-> '((0,0),(2,2),(1,3))'::polygon as on_segment,
-	'(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;
-- 
2.14.3 (Apple Git-98)

#95Emre Hasegeli
emre@hasegeli.com
In reply to: Tomas Vondra (#90)
Re: [PATCH] Improve geometric types

Hmmm. It'll be difficult to review such patch without access to a platform
exhibiting such behavior ... IIRC IBM offers free access to open-source
devs, I wonder if that would be a way.

I don't have access to such platform either, and I don't know too much
about this business. I left this patch out for now. It is something
that should affect all float operations not only the geometric types
anyway. Anybody who knows and cares about these platforms can pick
this up.

We can fix -0 issues in localized way, like you have done, if there
would be any more.

#96Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Emre Hasegeli (#94)
Re: [PATCH] Improve geometric types

On 08/01/2018 01:40 PM, Emre Hasegeli wrote:

Ah, so there's an assumption that NaNs are handled earlier and never reach
this place? That's probably a safe assumption. I haven't thought about that,
it simply seemed suspicious that the code mixes direct comparisons and
float8_mi() calls.

The comparison functions handle NaNs. The arithmetic functions handle
returning error on underflow, overflow and division by zero. I
assumed we want to return error on those in any case, but we don't
want to handle NaNs at every place.

Not sure, I'll leave that up to you. I don't mind doing it in a separate
patch (I'd probably prefer that over mixing it into unrelated patch).

It is attached separately.

OK, thanks.

So, have we reached conclusion about all the bits I mentioned on 7/31?
The delta and float8/double cast are fixed, and for computeDistance
(i.e. doing comparisons directly or using float8_lt), the code may seem
a bit inconsistent, but it is in fact correct as the NaNs are handled
elsewhere. That seems reasonable, but perhaps a comment pointing that
out would be nice.

regards

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

#97Kyotaro HORIGUCHI
horiguchi.kyotaro@lab.ntt.co.jp
In reply to: Tomas Vondra (#96)
Re: [PATCH] Improve geometric types

At Thu, 2 Aug 2018 11:50:55 +0200, Tomas Vondra <tomas.vondra@2ndquadrant.com> wrote in <ce3cf95a-4751-c168-54ae-636c486e06cd@2ndquadrant.com>

On 08/01/2018 01:40 PM, Emre Hasegeli wrote:

Ah, so there's an assumption that NaNs are handled earlier and never
reach
this place? That's probably a safe assumption. I haven't thought about
that,
it simply seemed suspicious that the code mixes direct comparisons and
float8_mi() calls.

The comparison functions handle NaNs. The arithmetic functions handle
returning error on underflow, overflow and division by zero. I
assumed we want to return error on those in any case, but we don't
want to handle NaNs at every place.

Not sure, I'll leave that up to you. I don't mind doing it in a
separate
patch (I'd probably prefer that over mixing it into unrelated patch).

It is attached separately.

OK, thanks.

So, have we reached conclusion about all the bits I mentioned on 7/31?
The delta and float8/double cast are fixed, and for computeDistance
(i.e. doing comparisons directly or using float8_lt), the code may
seem a bit inconsistent, but it is in fact correct as the NaNs are
handled elsewhere. That seems reasonable, but perhaps a comment
pointing that out would be nice.

I'm not confident on replacing double to float8 partially in gist
code. After the 0002 patch applied, I see most of problematic
usage of double or bare arithmetic on dimentional values in
gistproc.c.

static inline float
non_negative(float val)
{
if (val >= 0.0f)
return val;
else
return 0.0f;
}

It is used as "non_negative(overlap)", where overlap is float4,
which is calculated using float8_mi. Float4 makes sense only if
we need to store a large number of it to somewhere but they are
just working varialbles. Couldn't we eliminate float4 that
doesn't have a requirement to do so?

regards.

--
Kyotaro Horiguchi
NTT Open Source Software Center

#98Kyotaro HORIGUCHI
horiguchi.kyotaro@lab.ntt.co.jp
In reply to: Emre Hasegeli (#94)
Re: [PATCH] Improve geometric types

At Fri, 03 Aug 2018 13:38:40 +0900 (Tokyo Standard Time), Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp> wrote in <20180803.133840.180843182.horiguchi.kyotaro@lab.ntt.co.jp>

At Thu, 2 Aug 2018 11:50:55 +0200, Tomas Vondra <tomas.vondra@2ndquadrant.com> wrote in <ce3cf95a-4751-c168-54ae-636c486e06cd@2ndquadrant.com>

On 08/01/2018 01:40 PM, Emre Hasegeli wrote:

Ah, so there's an assumption that NaNs are handled earlier and never
reach
this place? That's probably a safe assumption. I haven't thought about
that,
it simply seemed suspicious that the code mixes direct comparisons and
float8_mi() calls.

The comparison functions handle NaNs. The arithmetic functions handle
returning error on underflow, overflow and division by zero. I
assumed we want to return error on those in any case, but we don't
want to handle NaNs at every place.

Not sure, I'll leave that up to you. I don't mind doing it in a
separate
patch (I'd probably prefer that over mixing it into unrelated patch).

It is attached separately.

OK, thanks.

So, have we reached conclusion about all the bits I mentioned on 7/31?
The delta and float8/double cast are fixed, and for computeDistance
(i.e. doing comparisons directly or using float8_lt), the code may
seem a bit inconsistent, but it is in fact correct as the NaNs are
handled elsewhere. That seems reasonable, but perhaps a comment
pointing that out would be nice.

I'm not confident on replacing double to float8 partially in gist
code. After the 0002 patch applied, I see most of problematic
usage of double or bare arithmetic on dimentional values in
gistproc.c.

static inline float
non_negative(float val)
{
if (val >= 0.0f)
return val;
else
return 0.0f;
}

This takes float(4) and it is used as "non_negative(overlap)",
where overlap is float4, which is calculated using float8_mi.
Float4 makes sense if we store a large number of values somewhere
but they are just working varialbles. Couldn't we eliminate
float(4) whthout any specifc requirement?

I'm fine with the 0002-geo-float-v14 except the above.

regards.

--
Kyotaro Horiguchi
NTT Open Source Software Center

#99Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Kyotaro HORIGUCHI (#97)
Re: [PATCH] Improve geometric types

On 08/03/2018 06:40 AM, Kyotaro HORIGUCHI wrote:

...

I'm not confident on replacing double to float8 partially in gist
code. After the 0002 patch applied, I see most of problematic
usage of double or bare arithmetic on dimentional values in
gistproc.c.

static inline float
non_negative(float val)
{
if (val >= 0.0f)
return val;
else
return 0.0f;
}

It is used as "non_negative(overlap)", where overlap is float4,
which is calculated using float8_mi. Float4 makes sense only if
we need to store a large number of it to somewhere but they are
just working varialbles. Couldn't we eliminate float4 that
doesn't have a requirement to do so?

I'm not sure I follow. The patch does not modify non_negative() at all,
and we still call it like this:

if (non_negative(overlap) < non_negative(context->overlap) ||
(range > context->range &&
non_negative(overlap) <= non_negative(context->overlap)))
selectthis = true;

where all the "overlap" values are still float4. The only thing that
changed here is that instead of doing the arithmetic operations directly
we call float8_mi/float8_div to benefit from the float8 handling.

So I'm not sure how does the patch beaks this? And what do you mean by
'eliminate float4'?

thank you

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

#100Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Tomas Vondra (#99)
Re: [PATCH] Improve geometric types

On 08/03/2018 02:39 PM, Tomas Vondra wrote:

On 08/03/2018 06:40 AM, Kyotaro HORIGUCHI wrote:

...

I'm not confident on replacing double to float8 partially in gist
code. After the 0002 patch applied, I see most of problematic
usage of double or bare arithmetic on dimentional values in
gistproc.c.

static inline float
non_negative(float val)
{
    if (val >= 0.0f)
        return val;
    else
        return 0.0f;
}

It is used as "non_negative(overlap)", where overlap is float4,
which is calculated using float8_mi.  Float4 makes sense only if
we need to store a large number of it to somewhere but they are
just working varialbles. Couldn't we eliminate float4 that
doesn't have a requirement to do so?

I'm not sure I follow. The patch does not modify non_negative() at all,
and we still call it like this:

    if (non_negative(overlap) < non_negative(context->overlap) ||
        (range > context->range &&
         non_negative(overlap) <= non_negative(context->overlap)))
        selectthis = true;

where all the "overlap" values are still float4. The only thing that
changed here is that instead of doing the arithmetic operations directly
we call float8_mi/float8_div to benefit from the float8 handling.

So I'm not sure how does the patch beaks this? And what do you mean by
'eliminate float4'?

Kyotaro-san, can you explain what your concerns regarding this bit are?
I'd like to get 0002 committed, but I'm not sure I understand your point
about the changes in gist code, so I can't address them. And I certainly
don't want to just ignore them ...

regards

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

#101Kyotaro HORIGUCHI
horiguchi.kyotaro@lab.ntt.co.jp
In reply to: Tomas Vondra (#100)
Re: [PATCH] Improve geometric types

At Wed, 8 Aug 2018 14:39:54 +0200, Tomas Vondra <tomas.vondra@2ndquadrant.com> wrote in <6ecb4f61-1fb1-08a1-31d6-e58e9c352374@2ndquadrant.com>

On 08/03/2018 02:39 PM, Tomas Vondra wrote:

On 08/03/2018 06:40 AM, Kyotaro HORIGUCHI wrote:

...

I'm not confident on replacing double to float8 partially in gist
code. After the 0002 patch applied, I see most of problematic
usage of double or bare arithmetic on dimentional values in
gistproc.c.

static inline float
non_negative(float val)
{
    if (val >= 0.0f)
        return val;
    else
        return 0.0f;
}

It is used as "non_negative(overlap)", where overlap is float4,
which is calculated using float8_mi.  Float4 makes sense only if
we need to store a large number of it to somewhere but they are
just working varialbles. Couldn't we eliminate float4 that
doesn't have a requirement to do so?

I'm not sure I follow. The patch does not modify non_negative() at
all, and we still call it like this:
    if (non_negative(overlap) < non_negative(context->overlap) ||
        (range > context->range &&
         non_negative(overlap) <= non_negative(context->overlap)))
        selectthis = true;
where all the "overlap" values are still float4. The only thing that
changed here is that instead of doing the arithmetic operations
directly we call float8_mi/float8_div to benefit from the float8
handling.
So I'm not sure how does the patch beaks this? And what do you mean by
'eliminate float4'?

Kyotaro-san, can you explain what your concerns regarding this bit
are? I'd like to get 0002 committed, but I'm not sure I understand
your point about the changes in gist code, so I can't address
them. And I certainly don't want to just ignore them ...

It doesn't break nothing so nothing must be done with this. Just
I was a bit uneasy to see meaninglessly used foat4. Sorry for
the unnecessary argument.

After all I don't object to commit it in this shape.

regards.

--
Kyotaro Horiguchi
NTT Open Source Software Center

#102Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Kyotaro HORIGUCHI (#101)
Re: [PATCH] Improve geometric types

On 08/09/2018 11:42 AM, Kyotaro HORIGUCHI wrote:

At Wed, 8 Aug 2018 14:39:54 +0200, Tomas Vondra <tomas.vondra@2ndquadrant.com> wrote in <6ecb4f61-1fb1-08a1-31d6-e58e9c352374@2ndquadrant.com>

On 08/03/2018 02:39 PM, Tomas Vondra wrote:

On 08/03/2018 06:40 AM, Kyotaro HORIGUCHI wrote:

...

I'm not confident on replacing double to float8 partially in gist
code. After the 0002 patch applied, I see most of problematic
usage of double or bare arithmetic on dimentional values in
gistproc.c.

static inline float
non_negative(float val)
{
    if (val >= 0.0f)
        return val;
    else
        return 0.0f;
}

It is used as "non_negative(overlap)", where overlap is float4,
which is calculated using float8_mi.  Float4 makes sense only if
we need to store a large number of it to somewhere but they are
just working varialbles. Couldn't we eliminate float4 that
doesn't have a requirement to do so?

I'm not sure I follow. The patch does not modify non_negative() at
all, and we still call it like this:
    if (non_negative(overlap) < non_negative(context->overlap) ||
        (range > context->range &&
         non_negative(overlap) <= non_negative(context->overlap)))
        selectthis = true;
where all the "overlap" values are still float4. The only thing that
changed here is that instead of doing the arithmetic operations
directly we call float8_mi/float8_div to benefit from the float8
handling.
So I'm not sure how does the patch beaks this? And what do you mean by
'eliminate float4'?

Kyotaro-san, can you explain what your concerns regarding this bit
are? I'd like to get 0002 committed, but I'm not sure I understand
your point about the changes in gist code, so I can't address
them. And I certainly don't want to just ignore them ...

It doesn't break nothing so nothing must be done with this. Just
I was a bit uneasy to see meaninglessly used foat4. Sorry for
the unnecessary argument.

After all I don't object to commit it in this shape.

Understood. Thanks for the explanation.

I've pushed parts 0001 and 0002, as submitted on August 1. Let's see if
that upsets some of the buildfarm animals.

regards

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

#103Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Tomas Vondra (#102)
1 attachment(s)
Re: [PATCH] Improve geometric types

Hi,

the buildfarm seems to be mostly happy so far, so I've taken a quick
look at the remaining two parts. The patches still apply, but I'm
getting plenty of failures in regression tests, due to 0.0 being
replaced by -0.0.

This reminds me 74294c7301, except that these patches don't seem to
remove any such checks by mistake. Instead it seems to be caused by
simply switching to float8_ methods. The attached patch fixes the issue
for me, although I'm not claiming it's the right way to fix it.

Another thing I noticed is the last few lines from line_interpt_line are
actually unreachable, because there's now 'else return false' branch.

regards

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

Attachments:

negative-zero-fixes.patchtext/x-patch; name=negative-zero-fixes.patchDownload
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index e0a9a0fa4f..97b3349ff8 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -1251,6 +1251,14 @@ line_interpt_line(Point *result, LINE *l1, LINE *l2)
 					   float8_mi(float8_mul(l1->A, l2->B),
 								 float8_mul(l2->A, l1->B)));
 		y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
+
+		/* on some platforms, the preceding expression tends to produce -0 */
+		if (x == 0.0)
+			x = 0.0;
+
+		/* on some platforms, the preceding expression tends to produce -0 */
+		if (y == 0.0)
+			y = 0.0;
 	}
 	else if (!FPzero(l2->B))
 	{
@@ -1262,6 +1270,14 @@ line_interpt_line(Point *result, LINE *l1, LINE *l2)
 					   float8_mi(float8_mul(l2->A, l1->B),
 								 float8_mul(l1->A, l2->B)));
 		y = float8_div(-float8_pl(float8_mul(l2->A, x), l2->C), l2->B);
+
+		/* on some platforms, the preceding expression tends to produce -0 */
+		if (x == 0.0)
+			x = 0.0;
+
+		/* on some platforms, the preceding expression tends to produce -0 */
+		if (y == 0.0)
+			y = 0.0;
 	}
 	else
 		return false;
@@ -1798,6 +1814,12 @@ point_send(PG_FUNCTION_ARGS)
 static inline void
 point_construct(Point *result, float8 x, float8 y)
 {
+	if (x == 0.0)
+		x = 0.0;
+
+	if (y == 0.0)
+		y = 0.0;
+
 	result->x = x;
 	result->y = y;
 }
#104Emre Hasegeli
emre@hasegeli.com
In reply to: Tomas Vondra (#103)
2 attachment(s)
Re: [PATCH] Improve geometric types

the buildfarm seems to be mostly happy so far, so I've taken a quick
look at the remaining two parts. The patches still apply, but I'm
getting plenty of failures in regression tests, due to 0.0 being
replaced by -0.0.

I think we are better off fixing them locally at the moment like your
patch does. We should consider to eliminate -0 globally for all
floating point based datatypes later. I simplified and incorporated
your change to line_interpt_line() into mine.

I am not sure about normalising -0s on point_construct(). We
currently allow points to be initialized with -0s. I think it is fair
for us to return -0 when -x and 0 are multiplied. That is the current
behavior and the behavior of the float datatypes. I adjusted the
results of the new regression tests accordingly.

Another thing I noticed is the last few lines from line_interpt_line are
actually unreachable, because there's now 'else return false' branch.

Which lines do you mean exactly? I don't see any being unreachable.

Attachments:

0001-line-fixes-v14.patchapplication/octet-stream; name=0001-line-fixes-v14.patchDownload
From 67487904687e6afbdb05b4ea1a376cfabfe7fff8 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sun, 28 May 2017 11:35:17 +0200
Subject: [PATCH 1/2] line-fixes-v14

Fix obvious problems around the line datatype

I have noticed some line operators retuning wrong results, and Tom Lane
spotted similar problems on more places.  Source history reveals that
during 1990s, the internal format of the line datatype is changed, but
most functions haven't got the hint.  The fixes include:

* Reject invalid specification A=B=0 on receive
* Reject same points on line_construct_pp()
* Fix perpendicular operator when negative values are involved
* Avoid division by zero on perpendicular operator
* Fix intersection and distance operators when neither A nor B are 1
* Return NULL for closest point when objects are parallel
* Check whether closest point of line segments is the intersection point
* Fix closest point of line segments being on the wrong segment

The changes are also aiming make line operators more symmetric and less
sensitive to floating point precision loss.  The EPSILON interferes with
every minor change in different ways.  It is hard to guess which
behaviour is more expected, but we can assume threating both sides of
the operators more equally is more expected.

Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com

Parallel discussions:

* https://www.postgresql.org/message-id/CAE2gYzw_-z%3DV2kh8QqFjenu%3D8MJXzOP44wRW%3DAzzeamrmTT1%3DQ%40mail.gmail.com
* https://www.postgresql.org/message-id/20180201.205138.34583581.horiguchi.kyotaro@lab.ntt.co.jp
---
 src/backend/utils/adt/geo_ops.c | 164 +++++++++++++++++++++++++++-------------
 1 file changed, 111 insertions(+), 53 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 13dc1ab6e6..e7c1160131 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -41,20 +41,21 @@ static inline void point_add_point(Point *result, Point *pt1, Point *pt2);
 static inline void point_sub_point(Point *result, Point *pt1, Point *pt2);
 static inline void point_mul_point(Point *result, Point *pt1, Point *pt2);
 static inline void point_div_point(Point *result, Point *pt1, Point *pt2);
 static inline bool point_eq_point(Point *pt1, Point *pt2);
 static inline float8 point_dt(Point *pt1, Point *pt2);
 static inline float8 point_sl(Point *pt1, Point *pt2);
 static int	point_inside(Point *p, int npts, Point *plist);
 
 /* Routines for lines */
 static inline void line_construct(LINE *result, Point *pt, float8 m);
+static inline float8 line_sl(LINE *line);
 static inline float8 line_invsl(LINE *line);
 static bool	line_interpt_line(Point *result, LINE *l1, LINE *l2);
 static bool line_contain_point(LINE *line, Point *point);
 static float8 line_closept_point(Point *result, LINE *line, Point *pt);
 
 /* Routines for line segments */
 static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
 static inline float8 lseg_sl(LSEG *lseg);
 static inline float8 lseg_invsl(LSEG *lseg);
 static bool	lseg_interpt_line(Point *result, LSEG *lseg, LINE *line);
@@ -973,20 +974,25 @@ line_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	LINE	   *line;
 
 	line = (LINE *) palloc(sizeof(LINE));
 
 	line->A = pq_getmsgfloat8(buf);
 	line->B = pq_getmsgfloat8(buf);
 	line->C = pq_getmsgfloat8(buf);
 
+	if (FPzero(line->A) && FPzero(line->B))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("invalid line specification: A and B cannot both be zero")));
+
 	PG_RETURN_LINE_P(line);
 }
 
 /*
  *		line_send			- converts line to binary format
  */
 Datum
 line_send(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
@@ -1033,20 +1039,25 @@ line_construct(LINE *result, Point *pt, float8 m)
 /* line_construct_pp()
  * two points
  */
 Datum
 line_construct_pp(PG_FUNCTION_ARGS)
 {
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 	LINE	   *result = (LINE *) palloc(sizeof(LINE));
 
+	if (point_eq_point(pt1, pt2))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("invalid line specification: must be two distinct points")));
+
 	line_construct(result, pt1, point_sl(pt1, pt2));
 
 	PG_RETURN_LINE_P(result);
 }
 
 
 /*----------------------------------------------------------
  *	Relative position routines.
  *---------------------------------------------------------*/
 
@@ -1069,25 +1080,29 @@ line_parallel(PG_FUNCTION_ARGS)
 }
 
 Datum
 line_perp(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
 
 	if (FPzero(l1->A))
 		PG_RETURN_BOOL(FPzero(l2->B));
-	else if (FPzero(l1->B))
+	if (FPzero(l2->A))
+		PG_RETURN_BOOL(FPzero(l1->B));
+	if (FPzero(l1->B))
 		PG_RETURN_BOOL(FPzero(l2->A));
+	if (FPzero(l2->B))
+		PG_RETURN_BOOL(FPzero(l1->A));
 
-	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->B),
-								   float8_mul(l1->B, l2->A)), -1.0));
+	PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->A),
+								   float8_mul(l1->B, l2->B)), -1.0));
 }
 
 Datum
 line_vertical(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 
 	PG_RETURN_BOOL(FPzero(line->B));
 }
 
@@ -1128,20 +1143,34 @@ line_eq(PG_FUNCTION_ARGS)
 				   (float8_eq(l1->A, l2->A) &&
 					float8_eq(l1->B, l2->B) &&
 					float8_eq(l1->C, l2->C)));
 }
 
 
 /*----------------------------------------------------------
  *	Line arithmetic routines.
  *---------------------------------------------------------*/
 
+/*
+ * Return slope of the line
+ */
+static inline float8
+line_sl(LINE *line)
+{
+	if (FPzero(line->A))
+		return 0.0;
+	if (FPzero(line->B))
+		return DBL_MAX;
+	return float8_div(line->A, -line->B);
+}
+
+
 /*
  * Return inverse slope of the line
  */
 static inline float8
 line_invsl(LINE *line)
 {
 	if (FPzero(line->A))
 		return DBL_MAX;
 	if (FPzero(line->B))
 		return 0.0;
@@ -1150,30 +1179,35 @@ line_invsl(LINE *line)
 
 
 /* line_distance()
  * Distance between two lines.
  */
 Datum
 line_distance(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
-	float8		result;
-	Point		tmp;
+	float8		ratio;
 
 	if (line_interpt_line(NULL, l1, l2))	/* intersecting? */
 		PG_RETURN_FLOAT8(0.0);
-	if (FPzero(l1->B))			/* vertical? */
-		PG_RETURN_FLOAT8(fabs(float8_mi(l1->C, l2->C)));
-	point_construct(&tmp, 0.0, l1->C);
-	result = line_closept_point(NULL, l2, &tmp);
-	PG_RETURN_FLOAT8(result);
+
+	if (!FPzero(l1->A) && !isnan(l1->A) && !FPzero(l2->A) && !isnan(l2->A))
+		ratio = float8_div(l1->A, l2->A);
+	else if (!FPzero(l1->B) && !isnan(l1->B) && !FPzero(l2->B) && !isnan(l2->B))
+		ratio = float8_div(l1->B, l2->B);
+	else
+		ratio = 1.0;
+
+	PG_RETURN_FLOAT8(float8_div(fabs(float8_mi(l1->C,
+											   float8_mul(ratio, l2->C))),
+								HYPOT(l1->A, l1->B)));
 }
 
 /* line_interpt()
  * Point where two lines l1, l2 intersect (if any)
  */
 Datum
 line_interpt(PG_FUNCTION_ARGS)
 {
 	LINE	   *l1 = PG_GETARG_LINE_P(0);
 	LINE	   *l2 = PG_GETARG_LINE_P(1);
@@ -1200,41 +1234,50 @@ line_interpt(PG_FUNCTION_ARGS)
  * If the lines have NaN constants, we will return true, and the intersection
  * point would have NaN coordinates.  We shouldn't return false in this case
  * because that would mean the lines are parallel.
  */
 static bool
 line_interpt_line(Point *result, LINE *l1, LINE *l2)
 {
 	float8		x,
 				y;
 
-	if (FPzero(l1->B))			/* l1 vertical? */
-	{
-		if (FPzero(l2->B))		/* l2 vertical? */
-			return false;
-
-		x = l1->C;
-		y = float8_pl(float8_mul(l2->A, x), l2->C);
-	}
-	else if (FPzero(l2->B))		/* l2 vertical? */
-	{
-		x = l2->C;
-		y = float8_pl(float8_mul(l1->A, x), l1->C);
-	}
-	else
+	if (!FPzero(l1->B))
 	{
 		if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
 			return false;
 
-		x = float8_div(float8_mi(l1->C, l2->C), float8_mi(l2->A, l1->A));
-		y = float8_pl(float8_mul(l1->A, x), l1->C);
+		x = float8_div(float8_mi(float8_mul(l1->B, l2->C),
+								 float8_mul(l2->B, l1->C)),
+					   float8_mi(float8_mul(l1->A, l2->B),
+								 float8_mul(l2->A, l1->B)));
+		y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
 	}
+	else if (!FPzero(l2->B))
+	{
+		if (FPeq(l1->A, float8_mul(l2->A, float8_div(l1->B, l2->B))))
+			return false;
+
+		x = float8_div(float8_mi(float8_mul(l2->B, l1->C),
+								 float8_mul(l1->B, l2->C)),
+					   float8_mi(float8_mul(l2->A, l1->B),
+								 float8_mul(l1->A, l2->B)));
+		y = float8_div(-float8_pl(float8_mul(l2->A, x), l2->C), l2->B);
+	}
+	else
+		return false;
+
+	/* On some platforms, the preceding expressions tend to produce -0. */
+	if (x == 0.0)
+		x = 0.0;
+	if (y == 0.0)
+		y = 0.0;
 
 	if (result != NULL)
 		point_construct(result, x, y);
 
 	return true;
 }
 
 
 /***********************************************************************
  **
@@ -2340,30 +2383,22 @@ dist_pb(PG_FUNCTION_ARGS)
 }
 
 /*
  * Distance from a lseg to a line
  */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
-	float8		result;
 
-	if (lseg_interpt_line(NULL, lseg, line))
-		result = 0.0;
-	else
-		/* XXX shouldn't we take the min not max? */
-		result = float8_max(line_closept_point(NULL, line, &lseg->p[0]),
-							line_closept_point(NULL, line, &lseg->p[1]));
-
-	PG_RETURN_FLOAT8(result);
+	PG_RETURN_FLOAT8(lseg_closept_line(NULL, lseg, line));
 }
 
 /*
  * Distance from a lseg to a box
  */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
@@ -2526,34 +2561,40 @@ lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
 /*
  *		The intersection point of a perpendicular of the line
  *		through the point.
  *
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 line_closept_point(Point *result, LINE *line, Point *point)
 {
-	bool		retval PG_USED_FOR_ASSERTS_ONLY;
-	Point       closept;
+	Point		closept;
 	LINE		tmp;
 
-	/* We drop a perpendicular to find the intersection point. */
+	/*
+	 * We drop a perpendicular to find the intersection point.  Ordinarily
+	 * we should always find it, but that can fail in the presence of NaN
+	 * coordinates, and perhaps even from simple roundoff issues.
+	 */
 	line_construct(&tmp, point, line_invsl(line));
-	retval = line_interpt_line(&closept, line, &tmp);
+	if (!line_interpt_line(&closept, &tmp, line))
+	{
+		if (result != NULL)
+			*result = *point;
 
-	Assert(retval);	/* perpendicular lines always intersect */
+		return get_float8_nan();
+	}
 
 	if (result != NULL)
 		*result = closept;
 
-	/* Then we calculate the distance between the points. */
 	return point_dt(&closept, point);
 }
 
 Datum
 close_pl(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	LINE	   *line = PG_GETARG_LINE_P(1);
 	Point	   *result;
 
@@ -2613,52 +2654,66 @@ close_ps(PG_FUNCTION_ARGS)
  * This sets the closest point to the *result if it is not NULL and returns
  * the distance to the closest point.
  */
 static float8
 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
 {
 	Point		point;
 	float8		dist,
 				d;
 
-	d = lseg_closept_point(NULL, l1, &l2->p[0]);
-	dist = d;
-	if (result != NULL)
-		*result = l2->p[0];
+	/* First, we handle the case when the line segments are intersecting. */
+	if (lseg_interpt_lseg(result, l1, l2))
+		return 0.0;
 
-	d = lseg_closept_point(NULL, l1, &l2->p[1]);
+	/*
+	 * Then, we find the closest points from the endpoints of the second
+	 * line segment, and keep the closest one.
+	 */
+	dist = lseg_closept_point(result, l1, &l2->p[0]);
+	d = lseg_closept_point(&point, l1, &l2->p[1]);
 	if (float8_lt(d, dist))
 	{
 		dist = d;
 		if (result != NULL)
-			*result = l2->p[1];
+			*result = point;
 	}
 
-	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[0]), dist))
-		d = lseg_closept_point(result, l1, &point);
-
-	if (float8_lt(lseg_closept_point(&point, l2, &l1->p[1]), dist))
-		d = lseg_closept_point(result, l1, &point);
-
+	/* The closest point can still be one of the endpoints, so we test them. */
+	d = lseg_closept_point(NULL, l2, &l1->p[0]);
 	if (float8_lt(d, dist))
+	{
 		dist = d;
+		if (result != NULL)
+			*result = l1->p[0];
+	}
+	d = lseg_closept_point(NULL, l2, &l1->p[1]);
+	if (float8_lt(d, dist))
+	{
+		dist = d;
+		if (result != NULL)
+			*result = l1->p[1];
+	}
 
 	return dist;
 }
 
 Datum
 close_lseg(PG_FUNCTION_ARGS)
 {
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
+	if (lseg_sl(l1) == lseg_sl(l2))
+		PG_RETURN_NULL();
+
 	result = (Point *) palloc(sizeof(Point));
 
 	if (isnan(lseg_closept_lseg(result, l2, l1)))
 		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
@@ -2819,20 +2874,23 @@ lseg_closept_line(Point *result, LSEG *lseg, LINE *line)
 	}
 }
 
 Datum
 close_ls(PG_FUNCTION_ARGS)
 {
 	LINE	   *line = PG_GETARG_LINE_P(0);
 	LSEG	   *lseg = PG_GETARG_LSEG_P(1);
 	Point	   *result;
 
+	if (lseg_sl(lseg) == line_sl(line))
+		PG_RETURN_NULL();
+
 	result = (Point *) palloc(sizeof(Point));
 
 	if (isnan(lseg_closept_line(result, lseg, line)))
 		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
 
 
 /*
-- 
2.15.2 (Apple Git-101.1)

0002-geo-tests-v10.patch.gzapplication/x-gzip; name=0002-geo-tests-v10.patch.gzDownload
��v[0002-geo-tests-v10.patch������(�s����Q�n�T��_J��9���l6����f(�wG����VVw��@?t���(�c��n�P�7
�?m�o��W��b��d�<9��4�����y~���X��^&yuVEY������Q�<��E4I���8������E��|�x��XF����o������������a��j1�h==���!i����A���<�z�g�������o"�)�1z�X�v��n;��$''�����^D�Qt��m�����(�v��,�������������6z��D;�k_����l�\���|u�/9��z��~Y��,W�v~mw���YnyCo�.w���f�;���i}�������j�jy6_�.��Q���d�x��n%���b����������#�[G�_/y��YqZo9����|�1��0��8y�����n�N�,vW������C�����^�n�v{�������	�������h~~.`��^���+��.W�%��+!&/�������m�Ru�I��/�>i��?.�W����y�i�ZsJ],����7�����%�F6;�4���o��w��f��F�sN|��=k8����������	��<?/�EN������������.z#��]�K��{^�//9R'��	����qq%$C���a���#-����F`+e�fi
R<<���)��p2}���]m�����nw�}������K|���^s���"^o^�v��r�-�?������������Yv��-��=����j���v�������x����~-������~�o?����{�������"~-�r9=��f'�vs������B4��������/���kN��������k�����P�(j��U�k�n��ru���
���������QZ�-�����O��8<�����E3�/���Fz^��A�nG���������j�.~]����Z��bY��u��5������`-.�R���?��ch��H`���D,Mu�����R����d�E)��Z�U`��RK�
�E
�!kIV����0V�9�W�*"�"�����q��zq>���2��o��H�9yp�?���/.������7�knjy��[�������5w��O��������9\���hJ���8���eF)eg
��Rb�;�����G3B�g��$U���'�_���h={0[�_��~/�'���f�@|�o��D4b���^��v���AE��~YG������q�J<|���D�.�s��~%�wd�+���'�W���q���/�{}���z��w������$������^�^<U_���������y4�7�q2�'����!�^^����e��z�Y�E.h��r�&��&9I�yT�.\0"k�
��yD�1���F<���T��x"J�w�m��4l�|q����������H�d���34qQ"�������B�s�v��������L[$Fl�-"��={��a��<�X�������n�k�0�7�0����oO���}�8"�[D�#?NYN'�@->>R+����K�V���d�G�N���:5h�h���zH�x����-{t
��|{�J�?��{+�R�K��m�������"�w/���t������=�K���'���w��D���3��O���hB��JO�S��<dS�rx���{i�EQn��9WA4fs*���������$�6�_��$k�E`W_���J>y��A������J�������z<��E�%>)H�A!���
j�a)i�k.1���"����_���{�Y,�_������y���,��w���k��6a��{���C�KbO����M��o�<��7������h��xw�O�_��$�=@���HB<�Q�Sm�5!xTg%��:	��sb#�lB;!���Y�~sj��&������������3��?j���vY��M���t�>3�T\�?�u�:�U����&���4VL��������Ed����I��zH�o���S(:�O;�g��i�����
Ds.T����t���!t��3.(��^"���gf"},1Qk���������|�������|�/�����G�7��HN��J�.,�w|�pX��2��$z@�/���J����A��8���EZ�]����j5���&F@e����t����K����s	k�"�}k���jF6����k�E�y���x7�d�����W���t�|~*��/"�$&�����Y�X�7���/1ye��_����f!��XN�_���7r�i	���Yr���8G~h���?P���y�+O�c���{�"Y�BL��<���g^>�p����>���O�}���M6���O���KS:�}��!.2�i��r-9U�||M���}��o$��L�O��f���4E�HZ�����'_?�w������w���=^}���?G��;���2�gKh��5y���<�'i���1]���Y>�c��
8W*])*M���x�6%�6�t����}��w�u�J��/�w
�O4�P�my4����Sv:�����0��������UrRCf�,������D�"Q���������P��Q4���\E���$��&��#n��������?DX���/����O�O���k[�I�G?�/�[�f���R��m�4^-D���@�y�������I�����1�!��k�H�:��'��:5&����{�6��g�M��U[�C������O�\yvD����~���4.����a��t��.�Wc��G���h~��,S���)�4���3y7 �,���0|<�)
�����u<?i"�����E^^DR�@�g��e�N�_������D����_t���������m=���u�AW;����?9����R��������$�O�XWO�������oko�Bk�N���6V����3�
����S�{�wQ@f)�.�:���!xeZ.��_�d�J�>iv��R�R�2#-#�'O?��$�fg�;��t��<l����nz��{�j=�w�1>�L�|�Z��G�gr�����h�K�oR�|4;�_4b���Wg@�9���S�'k��:HO��&�N���<}���g����k�e���YG�B,�mx!F��T�R� ��r?�����
D�}��y�e�E�����uo�8-(aY��UUe�IF���ho�)R{�V0�v	�Y��*
� �F`4�8�y��$M��P���7��+qFX�J�3Z���o�����eB8����]��zg����;R�/����{��Q���HB�_�8>c�"��(z�����+�|�L������$Q��g���n��&%�(?�^^4*���J�L�4�	PY$��������F3(��A�YYY�'�����my:����'I�
�a2k0��6���#���[�����s���e��e3��{-�%��K���8=u6QS��5�7��?��	'���	]�����3��,k(�wg~���������-�����@���@SC�v2hB3��dV�+\�d��i��4s(\���y�ME���,��E,E��<p�]�Z���w��kDl#
s]t�$�Hg��N��}=��wu��4�1D��<}!��0E[2�SV
��4~0�<����=�����6X�{�Pr�j��i�&X��k�t�������~o/U
����`A��W��b*��eE*��s�(_�N����>~������x��0�����8��5�y#��r}+C����w�s�e��$�Z�f)6��dR:]W�j�:(�"�p{B�R������D�I���3��'�����_<����O��	V$&L>��{�g63S
_�Z��J��I�SKW��q�
v0	��0��M�Z-x
?�3��vW��q����SR��F�� 1���wj#��4����#bT�9�7�����%\��|�0�;��,��<9�K����ts��D_�k���6�D�+u�$�>���}�3��9�V��^i#U/y���7N�j�����a�I*�|$�f����(�����-!~���hE:��9��:2#j6$L�BR$���]���C�d��M�.���e�G��[�n��g����H�������?�n4��w��]��c/�F��L��	D�lJK�[����RU�S��������!�����������2�f��H��gog�����Gi��v�J������������z<rH1�VH����9U=���X�|)`�����S�9n�`3��H���UI��q�e���%�,��5����i&�g��iYfr����/������'y�O�K��m��i4c��/O>���L�
M;G�5�l���	��-��\Xo,1���[�i�����ze����?���~�DtV>l��}����p�e��b�����(Eb��L�_
����7�h������~��Fo���?�����v�tBd�$�6���~���\9x��5����Md�F��4�}us�(F@�����V��&�������}�vlzG���8�)r���8���"+ri*VVZh}I��������NH�3�O���q����������B����_pTO4X������x7Q���<U�?�y@��g������3����Qd����EU�#,-s��)M�k���
>���?���g��[S��g������"������r����M��T���~���������m:����n`hY��g���B��Tx�IgIi)�V��&!�1-�"/)!5���Y#$Pe@H�C	T-$`�N!�����l1	�P���K��<|f�0��IH�$Y�hR�Eal�iI����AHp�	P/$P���$q�����_Q�����6T��n�V�-���Pe�,a`�!I�<aU�j�l�$(������e�����dH��iM/P���l�
B�~JSe�%�ly��`���nwc�3�����j� $����S�g����\������\����+T����BUF	�26pP�[�ae��8+�,���IHp-���U�jI���L6��!$@�6!Q�ZA���e�����*;����UH�-;-�����X+[,��2ZH�������aA���*���W��MC�~�
UvI��-�d�����!��`xwT�[���3��MJ�fqe������C���X>���(��������������i�nm23�&����f�>�o�D���%n���0c�N��	��>e�!:��,Df�>!�y����=-k����,��=o�;^n�\d��Yc��,2Gr���8���M���e�������\���&�|Z+@l��Y�r�b����1��<ri03q�4�������Ad�L7u�lYO��i2�G���dL�yenJ��r�Z���=�` {�I0��������ig�pI/�3!S]���e�Tu���tF!�Y�]����%�����5���5����bZ#i�*< sT��LO��2%�?_��R��L@Mh������32����tR)d���!*�����gi&|�m�H2y�>���nI@e��g���la�G>�]��xd���X��G�Q��;����K��#�Z\�gb����I�^����(���qtm�qY's�gT,q�?��<�z����v����8i�^���^GM�xgn�\$������3��M6���4?���Y�pvm��v��q�7����e.:wCt���7{}r7����L���������3{�I2y3+%[��
�����?�����Y~�q�0|�����������H��H���=fGf��5$p�7�����73��Y�,l
�3�K�T��	�2����	L�t6�����I���bS8�-��>f�F
��r77+w�X�/w���������P��
s����0f�7e��=v��`������J?g��������]��r����=.q��*�!�1�����=~�$"��$I��ir8�={��N/��O��	���$���5��@\�
})4�&R�88J�X�C���h�6t��A��Z��1M�,#q5���/_��nmce�h����j�<�H5Y\��j�U*�
[1���Z`3�>��LiX�zZ{x�5:3�v*�t�A�B�������_W������/�b�Yo�aSED��O���CX����|�z�0�j��(}��yy��^�C��O�P�N3��o��O���?�����L~{`"������n�8II�HIYQ�4�i��,O�,a�<�nn5li2�1gFY2�n�$���<�j�w/ND���u-�]�����������,',��**&0J*�����*H���@J^���},�B����9#4-D)�=ZL3��������Q�.(�;����j����^�2"�� S�%�O�"b�N������h[h�N[cf3���{�v�\���M��X}����Qv
��J��\l�
R�l�ut�\)'QHL.���9f}v*~
����F���������	K�|%��9����N�� 6�Q��N��o.�Nx^�)�&M�cpy�]}r
N�Yn��gER�	I��pf�\�H���"��,f������JM'k�7����3/��1x�3P�R�?SL�����q0@ �8LS �i
���c���"N
��EIHY��h
��I^e��������?�En��A�<HS�r8�`j
1��)�0TS��0MI��5%���*�"�Kf�����1)���#��0����)�?�H^%,7��r����h��)�>%7�4�V��X�0M3�f4E1c����|�T���ye��)������LY�,��R�D\���4�� M��)F9�lF�\�Z�!���)�0�)�� �B��C|
�GS�8�<�c-���xi
-�O�XQqGex�O�SLr,�Nd
�)��d�@��zkJ]��!JSH��T�c�SVX4�7�C��A�b���q
H�CF�@��_S��j���;�����3����)X�hMA<PS�������A���x�O�O�<HS`C�/+�!Yb@oMA����4x���pL�>HS�Y��/``�E�C�)���S �^Y�2����hMi�W�Uu�x�O�SLr,�i}���D�����F����u%~���?����g`��}��u�A^3����F"���<���(L��?���I>�-���i��	io?���?���'���JM��UF@b����a����Y�p�s�#q������S�TH�����S��i$&=hsI��hU�;�hA-����O�D#�C���N8 �o�d�B�!1�=cUY��C_9"�)C�Ee���fE���Y)�9f�Pr���!���<#f!�H���?������ � 9Nl�������*3�T��#��N���i�
'G�|��B�	�q]��2KL��(9����v��������45�
����G���,[P�TyBM��������4��23M����U17a.���:�!f�PrDX��D[^/|��#^�b��;)M!����<�h��Iq�_�x|D�4��8�����#��b5qQ��%�B��������\���,�,7M��#�����n�����*NE(B��k"G@�8,���=�g��B�l��8���w�m ��

��ABE��,�9a�#' �!1B�GX�Pq6��89r����>���9o���l���l ��1B�#�x�Nl{dd���8�U1�m��<����r��y��YJ�&�1���!RV�!Mn��#5G��1B��T�@�*N��t�J��H�T9�Q�#?��L	�9����}����z}Yo�is�/�
9�����+��<l�g\��`��o�����n}*/m�W�>S�Y��8�e�)M"/n����F��c���2><���U�{\k���>�b7�S��%�(���6��s��X�|E(�t �F�	��ql��Ei�c�L:>0g)��RS��B:�I��p�#����I���y.t�?Su��'��H���y������P3��<N����y���t4�9�����$��tb�j^U��*5V7����r�WU�SD6�������t�y�t����0
k��6�)JJ����H���t$�M����y�I��w��� ��cz7�'�<�M��G�	��p�����3�U�A:Wu����7J��r<���.���c��R�A:�v�5�l�s9�I������tU\��k*v����3����T$�3�[7���+�<��<��#����$��!��|�����������?������7��|��5���;p��8k-<�YL �wh �`����4�2�C���dLF��8������5 �yp�R"p!L��c�!�a���M����/��Z������a3����d���CX���R\wOq���
g�AL�����w) b���x,���5a2Rw�!�C��8'YFK�,0-:qX6.��R>25c��l:���:���Yb6��E���&����3a��&f�E�)���{���e#q�WMY�[��l} ^�?<�~�����5�'��d���CX���L$II�&Uj^u��2.�4%\������x-�X �Q[V�@���F���H����������k%�O������,�u`2Rw�!�C�p���
��]�@������P�q�p�G�d���CX���1A����@���x�Gqr�gQ�Q�����YeL����H���Xa3��t�����8�M���@�b�/��^�B�O�����>����d�����7�i�MR)���@=�q_�a�1g��\/�N|X���N'�������ed�K���m�����@3$��L,){���4���!b"�(���D�~86Z��8636�R�6�d�a6���h!���DI_�����O�����1���HR���,�PQ���#�
���6F6�.��*Y�YAXN����F�z#i��	��*3��,l�����F^�,��T��������e���}�����s6�JX�.IE���p�UTB�fT=r��6�WD��F�LD�QeqEK&n<0n��q@>!�#��q@>!�\��	q�!��p����p��#��F�o�c`��.6"���Z���� �6�����b#3�|��������`a#j������� q,l�����qo�/���f�&i!���L�v|u��.����2�m5�|r=��4�z����A�H������3�Yk"2���=_�v��H5+�)j�J/>N�r��5x����c��
8�D5qYZB�4���FT]���f�<_�Ty��U��G�M�n@#�p���$�!Q�iQ73B����i��Q���`�;�l���`����F��Qf2���*��Q�G���(��/.������B$�m�F��
v�1���RF�N-� �������T��<NX*�Dee.�_�6F�'�TvY�D���d$/��X#p����*O�f�`�_�"cPC2-�����P�f�����"�/)EK7�����c����J$����#�nm�u�*O��d�6�Y^�iUF��}�u-V�B��k�Z�;�:�Q��C�E]3.H��E6���Lf�v��B��{���������w�QyJ��1�+2Z�)�c��oY���|g���GE����~b�x7u��&��x]��N���f@���nFq�*�%3�<��Su)?�>����>��JV�(m��)�f<��@����M�w�?i/���d2�B��o4/Q���*7(Q~��r�E%��8V~M�=�n%���Q�j���NKu�8��{�T�C��|�;���I��;�Z��m8;�~GS�k-��Ng�����'����)�_�c���`F�>�4���,a,igE���sy���8�9&�����q��h>��1��-��[���u�',��p\�*� [d&��q*������X��q����!e9c�ym���`������4EC"-�mL,�(n��O������`}��
���PXp��!U�g��
�I����������u�t��*��/�0�R���L8�/^����>�������i�����b�c���N+7V��x�%�����B���zD��C3T�QH)��;)T���j�o�0���2p��-#{x�p�D`�C(.�P�"�V	E(��0$���"����S\�x��;!��f�����9��{����vV��
�%�����6�fe��������\��fa��$6>�!T��N����_��WU��&4���t:����'���S��e>���U��oN�$����["��#Rb�+>�d���W����|z�-�+�j�g����F�sq��v�z��N�y���������/?�������`bY�f��q�n���
C���s��9��>����T���
���qw}e����[lcN��c��K��A�?�������m,�'�����>"���W��<��=!��l�l~����[	���w������7{n*v���];�^��3�*o2rP
���r�{�}�Z����+�9����o�<~��91�sQ��d�VOWBA�{��M�^6��������`��2ZM���h����IQ�<Gl���v��v��Bwmx�WdB��5]�`� ��UY����ct��D��f'X�o���'��H}����~�X_v%?�����~��b�[��/:�6������|��:���^�9�f�Y�s�����9�j� �_�n��f�M���o�|�[�"�r\����QM#m0���dyE���{���8��>�r
���4UR"e)�F.�R��\m�Xf��*�\S
�h
UN�C�����:��QZ9E��T�D�
JQN����~��_\,.��CT����������'l#,P#�5:1�Q����T�w��v�M���f�Uz������rg
����UYl.������|3�i�i�e��A�6�}X�PQ�V�`�sizQ]�@�W���C�X��:Z���~��;�k�
���T'���4��������%��r�'����!����d~X�u�H�c�C@#C����24��4�Ek�Q��2��U9��a����X{k#:h��F������X���%��Q?m,�H��� ��3L9
� ������}#t�o����^�RW����h�q#� ��t�F,���+Up�A�
��7�@�F� ��!��Q�m�&��:@�X{k#komH���6bAh#t�6z��qT&LQ��0mD��F$�!���:D�y�m-%:LQ���/��Q�m�N�h#t�6����F<�������}��wZ�Q.t�6z��qT&@���:@�X{k#kom���F������!kaF��hZ�k��*$h�:t��P��a6��Y�8��4��:��:��_��*:d��\�2n�Zvc/�]�a�?nDc�?n��*
7�A{���C��H�!�F�>��xk��$�q���Y�����v!)��"��%�;�?{����(zu�:�-������O/���h���b!�u,�e���o���l����a��'����z:w�Y�l3`5��+}B�����	X9�"�9J�*���#c�	Y��#`��2��%�K�^� t�?`�=`��Z��;p�y�Y�����9��	�����	Z��W����i���(C&&Cg��	������g�&�'�Bf�B�������������|frgh��}	�r	�K	�(	�	���������^�6{J d 4�����������i��S�!y���p@J6 ����H_�%�N9��C�����2�2s���������X�{����Zo?�� �d��������G���A��amu<2��{�?ex�=8>��Dsp�@�������p� ��}E�z�'���$2�����|k�-���)U��w�u�����YD��O��E������y5 ����U�
�Ew�oN��62��
M~�
��]�&���coU����U�g��������*�y��Z������7������!��FBp�}�A��
�]_<�6U�I/�7�������)5`���+����5���y%�����6�<��[R�`{y�Q��N0�q���|{��3�f/�w&>�rn��H��1�\�|��Y�2+H*�N��^�@�G*������6�,����s��S�c���F�yF��M4��w�jc����*���;T�3�U�f��ou�����,N���4%��X^�J��*����!�:�6� ��@��L�_�+��nA���UK
����������H\9�����b��&V�]l��(%s_l���z�7��� �X������|1?r�������5KG�#��h�M�A����7N�C`cu66�)��������	NO����O�������K�u*�����Ez��[/��C�;D/���H���#���_d/���G�-�,��+�D?��&��G�F�,$ra�^q���oc����*�#����Z�yN�cN�]��sY�i���&���a|��9����q7������i���l���^Iv����7�~�I�lj� o=	_.�/s���F^���qG��Z ��x��K�V�o���u��g���A	�b�{����G���C��u<������CV�x��A����~�����-���-�hxHA���7�H�A�LD���H<�.��1��D��HT���K/Pv���
o��8�"�$���A�-$�[�c-��D�CZH<~v�l^{�t��qx�G�q���/�p��t�A��3\Gd���)^�����h�v��C�C�����/�?H��!397��v�x��B��-mx��.�+�������
�-W�,F����r���)WhPn��c��+�r�Av�\�Aa�����]R��&��������a :b�&�|�Hl=�8��P��
����mXxH9��g�C�0����,���;D��)(���[�M���=���rX�.�����%����|t���h<p5�����w�d��{�T�8������x���V�it����'��zU��Q������O�}�B����I�"��\l���&:_/�������at����Nd�#��@����<����r���������p$wo�����U���]D��y4�����v�.�8���*z�|�f��s����9�����lY������6>�q���"q2�:�{����i���S����u������ZT�6�}�M3��j�x�p�9E��
ib����
�k;��L&�,�;�'iY�������*��X�]�K��2eyVVY�
-�2O�_�QV�c[C!�^�p�������]��*���dUJiV�$�9Mb�@QA�=G|)��vQ4���8A���?U��.�RA��*	�yC���e�����7Y����)�,:�3����,m{�T��Z 'U����MV��E�VEa��A�4fS����"RW�~(�Zmo���vP���nk�����u	p�8���&��vS�EFK+X�$hK;`���������{/���GG�$��u����iU�"m&�(�$i������[k�o�.V�wo�p�S��>��z�4\��D�z+�*��{����4.�0���E&��y[rnp�$��i
��M���()Ir�dy;�H�;N�����s����W%+(m�[�q��4�����Kdy�Hl�����L���b�[��/����������>�n��(P��ZC�t��7������������A�@"���J7�F����P�61�M��(<D����d�A��G��rT�}���������	1�D��.������f���{��a��������7�����5����b+���a5s�����eu	�v����m;[/��!Xf\�KN/�1�����ED,�uA�!�����1K�0���A�*��T	�T����<��������C��C �YP�z�'@@�J�&h�����_�7W��������X�t���0���������l]�����7�����a�����8;�I
g�����=�1��Q��Pcx�����!��g��G��~�#��S0wU��4#b0F��<;��+��0���||�w����2���-c����9���������b�[l����nqE�NW��*�`89���o�KAM�
�E��
�`ky�����8����Mo����.�q���>(:1���8�����u���><TrF_#�4K�����|��KrN�����q&7�9|4v��N����l��a?-yT�Tv��������M��z�BuU���dnM�5��e�A���k�#��C����8H����7�pU����"vm��P�U�$�wS���J�y;CN���$$MR����S�U�Oq'|���J.�;(�hs@q71��,�F#��7������"�Q� |��V
B���# �=��BH��a���Z|������/6�������b�[%gC��y:��l��j���!w�����v7_�-�t���G�S�_e+�r���i��t��J�.�06��X�AX� �	�������6#0)�%c��>!�i�2��;n9F���}r���0r�b�80J��#��4v�q8`��F�1��W�Cq��0��Nq�8c�=����x���c���h{�:56��� I^�����k��c������1p�"�*�d8{�<�����8�$�IJ	�r�
�=��1R����
WMR��4��1pgER�	I3F0r��~��v�10K���y�e����������t�2�c����*c�q���/�	������8.��C���J�^�%E�P��1���f�$A�h��V�Q��8���d� %��IA���-�r�����J�~��"����H9F�v�q8`��v����� �mr|��r�!���.���x�9���p�9>c���M�a�U��;��#���SS�O�����=��y`���&F�a�;��2t��06>����}Pr�v���;���%*>�L*>&�+>���a�X�8-s������)b*����Os�Lo��k��w1���.Q�aX����n�7C��70��\���!��UQ�,OX�������$S���|�U�F������w��^�`��S��BH�"a
�C�	!�5H�.q=K2q:6fJ�)�$�IU&����CqL��C�-@�����9���w�����8�m�C�m�.�*NVdeZ
rX��TY��uAq4��!���[=6ZD���<vb@���w�FC����*L���C0����j�e�%=�����n�z,�p�����N�w/K `m����b��$��e��'��CZ��Ty�f�:9�m6f�L	����9Q����w ����w�O��I���hm|v
h8�u���-����@��$���T)�)������GR��\1�E����:�p��<�HY���:�p(6������r���+�����!V���!C�z`���x� ��O'yjL�Z.�9T��>e��zK_��	��V�����!��	������i�K������9��FgVJ5��0T��l����h}GRh��_��w�Mb�����s���B����0v�k �o�@��G�yB+0LnAb\�@�1M�,��"C%�$.��H�<-��bf�
$&L�lh�U4+1``��_�~pY�kl�2ee����@bB����0�S��;�'��S��E@SW���*���@b��1~&Vn��0``S�+hR��Du
$1��q�)�����x�){����3�s�b��m�]���b.���n[��?w�5�s��b�3
`���);�iKbT�,$F��q�9;I���b$WD��)3��A@������D����[Oa�4�n���?�����-��l��6\�zG$�}���<�d���nj����W������(bM���7�Ul��<V�y���`6u�����������u��s����������f��6�5B�7�7��
<���������>u�Ic�?��5o]�f��n�K���ET6���jP �&��u����bd���4{x�Z@����V���p��a��pX����cHr:���Ua�={q��/{q��.{q�
.$9����UZ�6�8l%�\��
��[.[Q�$�S.[5�Z������a���~�a���pB��m/Z��Z����T�a���F�a���8B�c/XU�Z��;Y9��w�:�&�<d������U>��8l%�\�Z��[.[��$�S.[u3\g���z����<��|�O>A�������F���U�$���h����o��9����%Z��q@d��+��|��@�g�����G�x��We��L��y�8�KZQ��R��\��q�P����%k�IrB�$��?z��y=B��WO�RX
If4N��(�)`bB��c���pX���2V��0�����w�w���/U�K�5�oF.L�!!�L�|�������SJ�'��I�e��� q�/��_��:���A4Y�"Yp�L�|1B:M�!��<��5U|��5�GH����nuc�����^�������F*K�����*����/��[����?z�N���Rv���@}������������x=u@.o2��Pa<�/�XJl4$$gHT}���M�Mt��a�~{�:,���]9$��!8�'y�HFI!�J��
�#QE�a�B=N�K���K*���IC��O>9�=%7��<D^���Lv�M��j/d3^��>�����1��.���)�xgY��! ���f��RF��G���������0I��i0o����W��l�������S���@;l�.�u�n$kI�B�,v{������n�i�v������q�{o�$��F%F���6��DV���y������n�L���Q��C��Cu�H���h�� �0A��P�H�G�G��.��+��6v�����v�Y���h��"�
m?��G��
\���{�NN�v������I�<�{7i9�D�7�?�r��b[�jZ�w/�o�����@d��K�������}��w��8�D1�M�G��D�\2��e�D�I����e9������(����<;���
����T�%3�����T����q����*�*6��_
�^s�Q~2���i�����I��=�����R���e�()K.��OFIbF
ZT%��%��6��q^��&$g\��D}}2�t��w�f��d��'�}����]SR\��f��^��zUr���~Y�v�^��6��<�.�?��Z��@wj4��������Nf
�N���"-
����������A���m��_�6�
�w��������S��g��9�@�H�1`6+:��W�����L�z��_&S��t/�J���(f;r.W�iQc&��f5|�w���)�e�L|M���xS7���Y ����|�����������_������^�v*�
�(���)�8^�EA�05m��
��mH�;h��+��1�����Uf�T
obR�Y<x}�z�\-w�$�����
�nP��W�)�Q���ld"��� He]�B�Qs�+K9����kA���.�R��4�{R�����9!'���v�i��a��x���N�4X�h����H�=V��VD��:�=(�N��{���5���f��'�e ���?�7��j�h�+2�t~���w�.�����B�H$��2 k/%���Liw�c����B�S��r"#��C/#kr��!�d��+d���??�8��M�������3|�/U���V!e3z0����@@q�A4�z��0.�~1�#������rom�����h�:��w������;���y����t�{�7���^����9��Y��s�����2���1�.������"M]�69��h6CJ*m��v,*��~��t`D���kY�%���5�G�����eL���sa&|�}[�M����b���5(�	3������5�S�0\_2�FsN��&���,- "	@�@���)�HZ^��d�y)D*���]������b���xW�#�rtI�z�������E����(�C�c���{��I�����#�vV���s��'�	�Z��!3��0��e(`�5��GL�������o��kQ����+�I�5�{��iR�T�v����$m�[*�X�����{
���2��V��������&n.��"���6������k�����T�zm�=)K��G��Ed�.�����g�S��h���@�|��r�A������1����r��^�!E�e����
&i����9M+����C�e�P��e�6�'��,e���fbe;p�u��������`������/���Q���TE��P�<��\GBSR�4g��E]��,+KZ��%���)XY�"��$YE
�q�S�DJ��eY�\RI��V�")I[�������O���M����"5�d������"H@9�4�d�����*2�PU�$�*�����v�<�#���*�d���J����=��2+P�����$�@R��K����(�I4x�dhX��2�i@�b��x�,1@K��K
�����x%Lx��b��b�K��l��#�SDT�?��[~0�B���D���><���Z����=���@@����!������XiYX<Z�@�@b�P}Y8DFaa*+5���c�yy��^�s
>����1�s��b��=�qr@�F7���
r����K����iU1������#b9GE�$O�=zb9"��5������1���h���E#�"���Y(V�^:���9�N��"�������P��E��ue���v�@���_5+A�!����"�=���������Q����A����)�����iR
�V_��V�?��t����oy�������fW�!nd$�69�HR��Y�3��*��y�����3�S�O���L����z�N�1�D�	��j��?���lB�B3Mg�\������%����������w/ ��Pg��{�:�����3�����A�f):Ky���\��l������5o����7����_'>Pa�n�/\��_�f��|���������,�`y�<��-�l�m3��
�^y�G.y�vQ���_�%�|��3�o��~�r���i|O��/�y����YX�%��������������Q���|���4�����^��5�{�2���o�����
5����F���X�v��6�B�mO��i�=�v������ov�jk}���4���{xO��=���������d�������zT_��
<=AO�<|��K��^}���r�z��_t�@��������Z��o+���L�����<��h~P�h��z�4
������Ay�KM�t�����E��!05;=��U��A>���������X,!L�Dxz�".IB�*/��x������x}|1��BZ�9���1����t�p�U,�L�4+�-�>������8S�������~z�_�=������1�U�.�<e�����YB��$�����O+�x7?��������������q���
��������	��u�J�y!����~�{S�]��],_��M��Tn�,����^Mz�+����/^|�������������|N�������uma��w$Xb���?(�F�# ���tZ���A�p%�X�C��-�r�����*+��r�K&hA�����9�������9�����}]�L��2�2�h�I4,l�H��Zw�Z��<r�K�&TJ�!�����$tL��������OZ��w5i�x2` �zB��<T�.<���d�|����^J'���+W���f1��v������X���� ��]�l&�tKe��d�d��\��T�fKA�D�8��������-
-�y-�������G���|����V��.ka��i��W���pmq�A����R6�}��w}?��b�z�FS��g�G�P�n��(��D�7��dq��e��1DZ9T�����V�(���^}s�����_�Q�{��4��VS��w�-�HP4�����f�U�GX���"��Q2�zJ�����=�n��� N%*�Q#���T~��+,��46CoF������u]wA�^�'"���d}�&�k���w�9�U�bad����z-�r+/�;[���	�h/�g�����Q�������W��g�^.Vuv6_	��\Dg����
'�H'�����������\_#���}3�FM���n���y]����Np^����:O��]__�@���=��C���`a�����>�4
�S�}�E*�]7�����^_)���@�-�'D�zP���h�������1�������m�Zg���l_:�p}�(�
?|�������@�m�(�A��n����Xm������b��,�yXJ�;^�Ww4��q�>�0������v�>�aX~�x�S��`""L
."�4�l+���UFi�|?
�`��c��cY@�,p}Fam�����A�mx�yn��:����|D>��c��'��=c����w��]c���N���W�������8/#�8��f1�-6�In��~����]�x��KF|�@�/��CyP�j��~*�o�	���������]������A�.�w��p|-k��4�t�����c����8����6���'X��!���8�P��}
��!u��D���s��(�7��>D�OS���<�9O�'\�����A�wNtp�5c��j��(D6�S������>%��`�����M����AB&��x
��Z����0��
���	�YQ!����A=<:����# ��vX��,w��_�����\"qv���]�}x��[�<��#g�Pt�u�Gm� �!��2��r{���L���#@qpy�!!B�:(tX�c�wP��Fl����/�Q:l.BG���=��W�m����AB&�����x�j�II�_���}���MO$|	���n��+q]���8/
H�t�&!�FX?����{����nPD�rx_��������W����5����O4����U����Ha�Ap��C{]Q���:.B�P(���k/�t��7�q�6�Bp@<������dk����D��+�v�\�l��J�=��P|F���$���AQ���)��RH7�����Z�@8)���S�"sy�m)���A�6f�& $���8)�d�����Z����4�1�<"�"	�D��,�cb�K"�[�B.���Y@a\@Xn]��AU�q]M������0&pd��6� &�u���B�3q	����H�F��8��XF�lo�-�j>��(9�n������~�N]�P�kD�����)�=������5��>.����"���
��17v]�����!�A�b��O����xk�{�
8;�V�����������R��p�����6&���u4��%���Sb��0K�XT����|���a�>�f�A<�����8}��{	�A�)��	P��3�]l��g����^�6���3�?�PY��g����f��f@\�f>�,�+�D��bB�,@3	@�����+Fc�i�zN�fhS�0��K[���� a�w@�L��R	@�S�;��}��0tF�������g�j��x�L�x�h �2���?�1*��3*���M��ff�����D����@�(
���a=6
F���,AW�	�%�D}Z#S��I�,+,w����J�(��>�C������?������I�>Fc�i�zN�l�(�BB�s�F��s9��S\��5�sj��5U��f>���Y�t�dR���2�8�a38��g���qiwT�{�q��7���s�`$���������Y%�T�e���"`nY�6 r�"����G��:�Y����q�7
�=�e,�9�0�e<g�X�?s��������]��r��9}��3}��8�P3A��Z�L�
L,��2I��;.���`ZzN(-{NZ�����qq��J������W��nh�
������7�@>.z�us4�{���P���H�[cB*$�d}a\ X�K�	�s�3��+���2h���1cTN/��T0�iH�F��8���n�9���q(��/�UY��CH`V;gq5M�X.�&����?�����<4s�Y,���f�!�w�7?iBx�9�~�����<��{���"p�a��B����$�e��#�9a��.'rFCTa���NE���MGpCQ;����B���2��[�3i�En�.�Dn��J�T�Q��(��Z%k$L
�����Yo���~�M�a�Mk4��W�]�Me�E�8$9
�<gH8LZU�'p���{(5f�hO�fO�p���Ouq:�0p�	=lVE�9�[�@�:6���n��#���)~h����E��9��9��0�B�b�:cU`"p��%l^�)�����ld����H���Z�I4�������&��p�����?/���w���O1S-��?$?F_>~�����D$�����K���i�6q�>~{:z���1�v�?�����8����i�X��|�'�����I�f�p�$&4ORJh%��F�hJ���2�>�r/tu���I�����2��c�a=�!�=�i��G�fE��a9���YR��3>��q��<I��H�%xg�</��Y�(RVI�1>8%x�$�2�U�l����*j5�H����ez�u;��������]�#��|�Ye�*Xx-��{�J�|��(MJ��	��J�k���,I��*�F2����d%M;�a�L�)�#}�a��5���>>X�)�,"R"��r��B-6��f�h!����{�^�{�P�"<Rx����g��\i�����Ah�����{����N��B!5��� ����i��e,����A%qQ�i�f��q����]��F��"�$�����#�}���NV$eZUn��Fc�FP/Y����y��`4b��#6^ ���^ Co����~#�^�l�\��F��x��d���,�R��n��Y�eUq8|��7Ff�����w�FY�;���%�w���A�M��%�Z�}F^��1d?>��F��x�6��I�Y2����U�fn�,�dk���C	���U �q�5`4b��#�E ��oH���1�d�����j��1��k�h���Gl�@:0��#�@��3D'�l&���__�{�^m�g��n�\�]�v'Q3Gp�^���h�����j3m�0xe�K��i=��K7p8`����~��??}RO�
���NfJ�ai�:���k":1O	�s�S���Fe��\�*��N�K�����Q��MJl���u^9����"�v���{�+2lg�]��W\�:P�uP�Z�����?Zdzu0��'4q�������8E��_��n��:H�hu������G���G���Oo1�?�:`&4m���&6�l�L��
���Z�|�������zH���a��D(�b:��]Q����B!�H�uk8���,m
a(W�K$%�R����{j�&�7
w�yp���MHn��3r
����{S �q���M�7!~�4���&���0n��_��	B��&|U�7A^�����&���>�	m��M��n�[i�t����f��	A��M�7���>Q�������=�!xq���� �(������</�!xr�����Onq@s�����7�y�&��M$7�,����&��n �	h7xe��nB�t�~�F7!~�i������>�i8{������s��t�\��y��������W/�JX�e��2�wknw���ukrGKY����r�w9kT&�.gm�p����]����]��.g��w9k3����]��.g}��6A��Y�X���u?g]g�W�D����/6?�Q����Wl�yj��nR%M��M�4��_'������5���`����;��2\l �-k�b�M$����A
Z]���+������K}M
��4�R���/��{-Q���l\k�!Xf���6*�W���,HF$MY�9&{�`_dV�w�������H��i}U����oT���TaZ��_���?��C��3������vq.
�Y���Fr�n�>��
e��+Z��E�x2��h}�X�$����%��}]����V�IK/��tmtOl&#��w{��7�Ul�a������^���c�t";��b��������V�
��������h�f�/^��.v������&Z��O?���4��.��c�r��o�}����?�r�Y:��h���9�7�������.�H�&���(�������U�9%�e�9
O�o
�w����7�D� fd]^���w:���P�}7fUU;�2���fi�Kr����jZ��c��$�22xU$�UV5K���L��gU��<x�CQ@�z�Jg6c1c	�EB��N���"N�B}!+���d�\B��$�y}���Vz��q����k�l\�`�4���L[o�����$]� ���#�i[��a��K%<���D�gy���O�Yq�O�5\-���
2�!	�V��!�mBK���B���6�<�����@4����T�VIQfyZT���	+���s�������h����d�����[H�iF9�r���5e��������dP@G��&��
x�?|��^����K�^���3`��

�_�O��[�����h^y*�Z��������,ZdD	Y�2��������,k[w��-jD+��q�L	jD�R6"����r&��."��/�`�5F0G�SnO4DeQ�E�sm��-&�0�0��yO��A�6�P�pk�$���Z�/�U\�$/JB�bZP��&�Z�	�R���k���^9(�f�e��IV�i�����Z�v�z��?�������U��=����Y���\cs2T�pb+�mW��%e���q���9��V��)NZ-GT��k����A�p�_��&$����1#-���=/\���A���j�fe2��Z��^I��j'O��U����+�����,����I�3�v_l�Z�=�%�i���l��k+T�yl-���l!��o�|��f�pr`Q�8�\�M�g���w�d%kE�(Ye���J;���n���hD	[�$�8�h� O�/��
�Ik`���h�B�6�����Vj���-S��Nl}4T�-��WO^l.���/K���[�����[��X���Z�&P�
5����[� ������}4q���&4�q�P���>;]!�4��������s\���:�����_��YH��lr�/k���{�P�K�Q���Q��B�NJ0v�2rqY�]_V`��� �5�8����g�h���"��&�&���{c��T���AE�S2�x�8�ZL	6\�����*n��IeKE�?���5V��>��|�f|?}��E����f�YGE�bh5���c��L"�l0�s�(��a��6G��}��VG1��7&�rc��k���$�MI����n�rU0�oS�{���_2e6�?<B�C"�������/�_���G%�^k�����2v��6���Y���`�����6%��%���R����6����]�����h�������������!�50�f��q���7��U�96��9cB+x~��N�z#dz�.�t�q���8�����@���Fj����v7_�-��a@�9m�9�S�+�N���gO�=�.�ju�[�W�oE+?�7��6Z�w�����B\I-��h.���>���=��]o����$N����[<����^q�1n����w�����]�IK�G�9�,9U��]�J%��uG������������@o��%{���
{-������.�ng|hT����Y���>e������Q0k����'T��)I)aYNYq�����{��_6p�������Q8��q!�ci$A��p�~Y��TL9ak��8� :�,b��-^;O0��L�4'k�'��L���������IJ��J�$OUI��Z�E�R.����:����Gm���eJBy�S����4.�<OY��E~j�����3�^,$)�ZGy �r��F����e�ai����s�/��@DT���F�|������E_��=����|Rk��!���H���>>����Su��`��7�7�<��;mhW�D���P�*��U��u��0��.`U��*��U�V�8KS!bi�(�0��L�������,�o�]U��Q���Z��i��,!������2&e�XU�@�~U��J�pV�YQ���W��,K����a���rq0��j�4��d�8��@��Ve�;�Ti�#��^KD�_��"I��`n���U\d� 1w*n����{��DE��ZM�3*Hr����!.
.e�����H����E�����*�	w�YY�R�~UU�y]�I^T(��VU����)W:!����HP���(r�K*\1_b�����Y�0����0��<��hg,Ts;�`6�]!��:!��{Bz���&B����,.Y�1(���������<��d�s�M�M��
��	8������B�gr�����r�b��<����4�F��A�tn^����[��t�������s�@���[��^0q�+�d��p(��W�RJK��pk����8@*n����(��n^����Aw�C�^���������`�t����j���{1��� �EnC���	���"?�����0���8�<�?�7���������� }n7��?��������A�f�7��p3���$7���>xB�_Pl���~ K��Y�8}�w/`��CpK�$c�����Kwxbsrl?YX������{�d9��_�`�r�Oo��Q?�5�� �����z��������p�����@����F>���!��x�����t�����],������'���z��o�����tl���������&�p<7�\y�3��G�[��
=m~h�������z{�k��Eko���h������;��������?�u���/��$08���9�&���5��S �.�S�[��w��������z�O���:�����3}��Zv&@V�{�V�d�����@��?�C{ ��y����}:�R<;��:#��kf����H����p]#��"�%_��=��5v��
�@�u�B��P]#���:����f���z<x���_�5�V@G|�ZA�k �X��HO����K�a�0f�u�9��zt�mT_��m���d�mV��rqs��c!�D=��JX���t*q�Uw�8�-�zv���%x��x&��n"s`�v�`�l��X�7|�_���7qNO����e7��t�=�.�=�{i��������f|:��A'�$}������������x#Iw����]Z"���p���v#��>���n���^~pM�(R@r<�~�N���Y�Y��L�5�q`^��n�0���������I������9N��H�s��N:%�9�Fp�xy�7xY�����+sx����T�13`}��q��AC�����Im�)����g7)?�/��j2���<��b6�U��Y��.M~C����9����M���<Z��j~1���^�a
F]����X$2)�����:�y��?f8��F���7���u����wN$�q9��O�$�����n�|���#B�������7��������?f���b��k>nn���2P����n�[k�c�z3#�����C����>n��ua�>��&��������H
����Y���$����VLew4�z{rz3����!��H������F���	!��Z����i��K2 +q7b
�F�w#�;����;�Ah��y��}�&��0��� 5F���v��rzX���g�����?vopg���9��:��`���o�b�UKp�d��M��,BW��s�T���L�U�7������l1�1�����1`���S%[`�
_,5���5)n���|�*������C���s+&�@5���I-|1T�l|��$���c#W��3���<+���Z.�S���1�+��U0���d��xL�[�L�����bdX����N�Zf�+�=#cU��s��Z�jUf��5d�,��8�NRd�,C%I�n�����0k����E�����`�U������1pW�`�ecX�#�+X�28�����;#�0�-��T72��q�����mf+������Fv'++�l�dd�����8{�t!��Q��>{5������1��T8����)��MS%����c�:�Js~�Q�L��N
����b=-U���
����W/w����5��c`?�<������=��;[Lu<���C����4��{b������������>�����Sy�����n�g|On��s�/j	
�
�s�g�/+�
��q�5�;������75��8_m�g�_�q5%y�=����
�gT�J���j=���P}��AU����C�\�>#���q�<
��<�������w��6F��W����Q4C�G����T�H.��;'�����������9v������l���U���;$����W�� �f�����~����0��]�
�p�P@@����A�	~�4�P������k_����+}�u����sD�z(�~=�RG�
H��6�_��q�������xs��|}�K��42���IF��g���SG��)���N"30��D&30�&lTB`K�l�O3y�C��+����f�5�Pp�G4���G>>����l&K����#+="�!��+�b�+��@�����]S�V��8<NZ�W�Y����f)	&}��(���SMI ���I;Pr1���U�&/"����l�JR
�P�m)s�J!�:�-kE)kJj�mr��m���Z��\nV��l��-�����zk)���%�Gm�dT���EY����`E^���eCID�[���q�Z�(-�bb��7�����P����� �#�6B%�������JJ��r�r�g��R�����
~L����T/�@
0C�PT�K��\��K^��jj��;B�Bt/�wK}a��L��F������Z����*��c�b���m#&"LC4.�/O����5N��E�G��yk�5��W�����P����%�2%�T���l��%��@�������Q��
M<�E�K�h���e`Bh)�=-	c�Q�0nm	D�1>������p�\�,����<?�OJ^F���$�\f>�LJ����J��u?%%_����I�t(�
�����6�r9:T�1�r����)���&��C0pj���?]^l�a�������N��I����>����������e�?�s�9�����b?���y"���l#!����
���V#5s')u%�B�L_��
4U�Y]H���7����50�n
�
�zz���j"D��;Z���[�zX��y�t�-�q�P2}��d�@,6B��iZ�*cM���#��G�����rsE���Ra>4��:���q*��_c�=w@q���?���CG��=,Q����z+U�����TP��g�ED���Q��!O�����7����U����Y1�g�>;��"�W�7�"�7��F�C�,j5��Jc
j�p\V�����X,�W��U�?L�k��-�&'����~�����lv������Mv���t��~��$��	�������J���$}��G&��'����"���Y_E�������7���>r>]=������i|��}m}��������n�B_wln�Lz��x
\��_an�&�����RovZ������j��������h�h��v�J>|�$�a�Ht\�S�.[�������1�Q�������7�v��&�!���q�+� �,�8Up#p��F�T����7�
nN?�UN�,�*1�	��*'�	��*02
���eU��-a���4x��**-J���"�\���
���!�!�C�C���y�����=�	N
Q���Fu�U��T��-nN��18�����7'Z��bq�PPp�l����Q�="���Qe< 8xHp�*�lZ��>p��,pk��8����Y�gq��c��Y\#8�(��|vvq��E�Z���e������6��������������7�����/77�6��_~`��?G=��������-�p�Sy���u}~�4Q��+)����P���G�(|�Y���e�d���l�2������'�f��w��^\��w?\\*l�o�e+��3����+=��v?�!�Ge����ys�������v��=���_g��f4�����cw��W��J��x6d������=�~r�V����7��w���~���lu�KzQ��
�a��sG���y���}"8$Tt#TymC#�V8��(�0m��/���1��[�O�ZZN~-�Pk�������M��Vj����u�����k(������\��}*��?K���*�Z�1o����/1���~s��~������D��7��7�����k�����|6��iNf��r{��x�hLk�~>���j��.�x6q�\�r�}�`��k����nA&�����d�����zws��S*������b�O����y@Wn�7x]��5e?��%�83g^�7�

�g�M�p<�$4�����s�m�R��s�����V[��NIv&%�a
�[�3��4�}�[T���v�����j������,��<�x�X?+������������uQ6
��������s���,f:<�[0��f�t���������@�L!�����`�����yY3��o��)	�y���9c-��S�U�$0�$x���F+	XsTI�
�T,>%��3��$��!��;���>%���R��m��[s��d��f����W�$P�����X)��_
p��I&~�u7{�aO2�3��5���$2�
�v��>`�'A1�$0ZI�������$S� �������d�(��4>`�'���y�����xwh3���xO��Q�\�����\!`t�
cW��5cW���H%���J��
\���%{
T�(p����}J��9�$1��'�O��4l
LP�����d� ���f8�IB���&T�h�QO�w7A��'����9�I
�D
��8�$��
�
���6W�>k�(���1C`/���
��$P��w�[4,r���.�2����s'
�])G�		i�.���	p|:�{GHZ�\|�oxGH�M3��t��!��GH����=KN�t�����=�h��;}c{�-2c�������NE�$�����E���"3s��`q���9!3p��pi���Z6^H���I�R����F�zE�����&.��
�A[���JB��uu�l����i2WF���jd��U��J��[Qx��������L�9�E��L�{��Kz�=2��:<\��6'\Z�2���6%�0��!w[..u�Z..c�(�YL�,< sT��	��:�?dJ�5*d*�2���;nV����#gd��
���&��D���L�z�HH2`��86�	��H+2�����'�aq	!{�'�E	�"�_v��P��@����=.�������$�(�@fw�����4��qY��p�w\/q}8��xn���6���m��������r��l��dnV��`���)���M�ciQ������S�n�p���r������0W����^���MB��)�7:e�:u��&fo���L��#�����KV�6{���	�7�������8@���� fpm�fo����z�X��L���	���
W�*R�fed�����;���o<�{��I�����IL��#*l
gQa�8�.��t���|���F��n���M���gl��36�2c��)V������SS6������x\�	�6]�2���.�7��%n�]���b���y���nV�r��z4y��Z�?:���	�Z�+mna���B�+��������:����U�d��(Y�N��0������nkM��hQ��� j��hd�"o+s�����N�����G�P`5�=O�OjA�9��=it��l����^�w��Y������<uF��i�"g����
��1�$�8{���'cSnB{;����l������E�S�Z��������n����,���eY�uE�g����F�JM#
}��������
�G�6O�|�O�Fd|4l ��ZU�/�e�H7t���W�
s>u�J�:��5k��IS����$���s�j.+��47�p������kj��� 0�u���C1���Y��/Xx@��q�H��/s��SD,������>=�c����;� ���k�$
C�U����6�P�_j���{�G}����-���D�WB���i\�� lJ���N�����(>�b)�EB���B��F
��>^�\U�=�2/k}��`���Xs�����2�W�g@��8����/��SL,�3/��;<�?R
B���.�1&��2NFD�Y
��(K�)<�R`
�����CH��B��-�hXBH��J��u���Q�!<�R�z8�b'Z
���l)��0�R���4K�~
��"�V���e�o�)����.�V�h��w��R�z[��-D�;c�HKg)>=L��P���3L����cI�,E�X�)L���O!�Rx��1R+ZQU�!�RD�+�m#E!�����Uj<������,Bx��x��������f)��C m������0�O)�&�)��)<�OR,��%W��(y�=�d)��}J)�VuT>���)����&K�����y2��S �G�S`
�����)DY��6���F���#z�Q�!<�R�z�:Nyx��H�-%rJO��<��C��8���W!�R����Bx��Li)=�(v��I���{�Ob�@x����D_A
S���dKA �YJ�Q�!<�R�z8�be)�,����01�b^�����O��)BR����,�!�R�K^W-m�"�����S|z�,�y�})����H���f���W{%~��'����g`��}���~g������<���F�_.��
 ���w�~!�R'>W#��I��i�����^��������~�d�p�,E� �A�i��!� ���j�8��<�������h��f��f�x�&��#��~fkS������1D�� �1�3�2�6M��:���M��(k�����k��f��z��C��P=S]�J��B���w�N�8��%��tb�����Z�O��wSJ�0�_8=��4N���.��(=�RS�VMY�&Qz4�M���#�!YS���R����H���Ho��9/������Qz�U��$/��)}�9(=m.�ML)�o��G�� �1�������p�H��+v��"Z�V�����4)���J�RV�ygy����S��F�&�[&E��!���+i�!��Z�ZU6�,+��.>R�_���F�m�z��R�"�	e�^D)z����lQX��3iq6�(%��)J��}��l��q6�(M�&	Ud|�E3�xE�����z��a)B��f��(��G���zd��������"��)B��"�x-�l�?
!J�G�dJ�����VJ������Ge^�USJ.�h��GL�He��4�B����S������V��G����q�di+���E�~M��)z���7����Q��y�!g��>�6�,�K�������rx��q%]�����/����n}i.m�;�|�U���D�K������ki����1���B
�������x���x���WRG��{I'�u�<`�uL�\)*=V�_�gH��u��U[��n�w��Y��B�J3O�rW���*�R������g����J���|���'��XW�%�US�����P?��*/�����m�u<�������$M�uz�j����Vz���"�J�m[U�QH�T��P��!��'b��x��?����!���`u�YQ	/8E� ���cU.�T�S3o�!�uV����C��)�xT�u ��n�O<��k]�^;?�P�����'��u���0�L�X�h]<�:�a���B��s9L�E������6ot�U�'�;���S�R�d{��o�~��y�e�����0��F�/d�
�_�w?�b�a3��w���Q�W���~K>b������b���u���0��_�,�VPz$0&�����3c�!��{�h��T�iZ����?F�bs���+������/#!-� ,��J����l�Q�����yV6����y��a	PV���;HIX�p��1D����������%Jfj�<��([�W�,y����E'����d�T#S?%Q��"!-� ,��J��6��l���V��������3c���g�u�I����oeJ�������K!�c#�m�������#�����QozbJfj�<�
+�(u����h��IL����R2e�"@ID��HH�DD�u`�	�l�l�����yK ����0%�i%	%�r�Hp��mP2Ss�alD�p���
IIX�&HH�M(�:�t"H���)��9�0�lqJ���l6���z��t(�Z��V����`�.[o�wJfj�<��*��g\�&:HID�\$��
�,���//o�S�����_�=����d�������&��e�T���xh�px�Yca�
^���^	��RY�rQ/��&2�%zu��C�Qt�hVZ�tt\�%��`���"���� 1L,��#4��N��|,N��OA@��j@��l0,F�L���#�[U�{�iA1bR�1�y)��`��!��rN�EA�	yVP�8Hk!��q�t�T�(��*k&*^~1�����+��)x���?�#A@�81��M-[�
��^1
�7M����r@H������*�dJ�����v���Z��r��5�WD��N����Sy��o<�n���8 J��y�C%�	P�q@�����y������	�$�o� ��x
<}#AL�a1�����D��F?���bbDR�c�=P���� ��Qk�Bb�����C#A@�L���0�P��7CpY�Z����������v��u7�Eo�y���\V�?��d�_]�J�`^S���3�Yk:����=_-t��H� �)j�J/5Nj+e5W*HW�Uc+X9�D5}YZ�Y��G#�}�T���G���G��T��Qg��� �qi&I�IT�UZ��^,d�>�j��O
N���� �b35����{��U��e�6o�Z��j���EU0����>�*��:!T�����U��/����K)z-� �:����T�W�*/��{���2�/���N<���\+v�6L���
��j��X/r�f�_��'�f�A��/w11�'��Vl
��?���b�����[���R�v35X����������q�qDr��-
�h+Y����.�Z�����	�}�u-A�B(������{�:�
�GBPp
������M�-+�����	��p��.�>��v�����K^�W��.E]���I��N�e%�S�]�;�=�g�������zoM��x��	��=�uTy��(�Q���`F�G���'h�����fP4����P�����~:�������Mw�?.�N��d��b��o6�*'_a��*?�U9��O~��>p�������_;JW}�H��c��N�?��^���
A����c���q���X���v�{��~G�������v�����C�Q���rm+j������B�����I�/������h��z.O�o|8����?�4���3�S��R��E��>a14�;T��� 3��*�K}�n��i����)��q���Q�3���V�?{���)z�h�H�nc�D�+�y���H?aZ� ��k5,�'��a�>�
O�/z�
�I����a$%�)��_�aOG�����O����K��?0E�����+��,R2�q��\,�B�
'���+��	7Vx��x@�������P(f��T����5�R��@�����Q�N�~��'-�����%B������%3��H�`�R��[%,�H�J���B�	wE�{���!��"�N��������!p�B���k/xX��kOv)&r/XX��������%��-(�PmqX��a��;�J�F�`���<?�k�\U�����b����2���_�`[4���B��M�5b|;�$%�"����oH��^�w#x����D|`�������o��������6:w!�+#�G_f�o>����_I����
�un��{G������4_*�7_��!���o0o}p�Cux��_I���+���s��{@W�_
B�����>�?4��0}��~Y��`��	�S�������@����+���}��}u`�}����
����57L�����'�������qr Yq�b��I�q����C.�).���>��Ib�g�8��p������G��k?]���O�C�:v����{p ��V�c��_5�e�qpZ����0?ay����f��������0!|A���"���kt��L���fX|��~uO:;q�� 3�g�t���y~��w����7������^�����C'�?��
�:����
�=�����?o�w��V���5H���}�IT��&�o��6�z�z�+��r\�|L��]#�)���?���[O|���8��l9�E@u�6+���,I#`YBB���<3vi�]��,�B����+���4ry�S�R�(��*�^e's�A}��]_]m�&��SL��������O�JD�Eb!�j@1�����O�D�qWA2��2��p��|��+�BX^�r�������������v��r\��'!�b8l�a���Qv���.�-�Z�_�
����,1&k��K��v k\����d�`���I�q9���=����=��ud��)(���;5��OI���S�F:�D����*��FF�)��J�p�q��M56�I�FZT-�F5��T��4�����j�X�	��E�`�$�>�����I# Q��I}#e�r�I}#uR��FM�q���F����4,���A�uJ��'���AwB���:�o$�
N�:�oD����8�I}#uR�H����L�5b�N	��E�`�x������l�		���Z#u�5bQ'X#I�Oc2i�����Y#
u�5"�N�F$�)����'X�l)�D�i��B�f�x�>��$X#v�4����O5��T���:�	���H�V��KA�`�$�>��$X#v9B�5bQ'X#�j�5��&[#u�5PS��:�S����:����[#q�5��N�oD/T��4���1��q����S��S��Sb�RP���+]R���e7�b�
�j��M5}��]U�0n��&���S��H�)�F�^��d���`E�]�d�E6��=�o����[������O������d��7�������7
�W��]����W��6z_�����7���vs���q��q��k>�����tq���l3a5��+}R�����IX9��"��%a�I����W��,I]�������!a�A�������H��O�fO�>�O��g�g���EN�:N�N��M��M���O���S�I���L��L�qL�NL�&L���O��g�&�'�Rf�R���������sC�)�������g_R�\R�R&J&@&6��y�����i���R�R�	����<=%���NL3��BN��&�R�	�Vz�3!}����;���gLM &d�-�d�F�109H�
��./��>d��}x��A��.8�5�O��� �����Sh{<2�}<�2|������?��	�=m?X����G�~��~K�F�L���3�����|k�-��;��j?�-'���(�Ed9z8\,��p=���W��QZ���������[~+^D���{�Pj�{n��$!�+���g�{���<f��J�����.<��Ts��h�+������j�����0H����U�p#
p���T)��>o�}�C�yWj�TQ�V(�
�E[�2ky�PO.��XGZ�7���$���o���p��"z�C�G�ow&�y�8fh��U.qB0H�J��)k&��K�'��I�V�eU����������>'97nl�(�=#ir�w�-���e�=�Vt6�U���y�*��f��:�dp�x����\J���UZ)���$M�)�:�>�$��@��TM�h��wB�����$f��
|f��:��V,��J�U��t�*��bM;����e�s��MY3��������k����s�`��n��w���D:�.Y�G3o�M��5�4�qv��k���Q�r
�;�y�l����4��H��q���w�]�V��w�]��u$�%7�.��S��;�.I�}"�I���w�����9�����&,L��*���g8���w������e�T.-�KPg�L�|[��QR=�0��_�����-�������xi��Z��I�wS,8���Z��s�y�n�M�MM��y����l����^Jv5�����>x�-��,�;\P��L�����Rs/��^����&���=c����uE���IT�.��H&r�:�v.�����XT��r�EC���_A[�C�?4��������r�H�M���b���1������h|HE���w�H�EDME���{H<�1IY�C"Qa<$*v�)&	UX'iT��"cDgZg�D*�8$H�"����m�]$�E���d���2�Y�����)���� ��r��v�Q��3`G�d��"��?���zL4��r��#��8�� ���P�����t�hT�nOUP�H�����*�S��Ol��hTq�B��0z�F�+<UQ�B������^Q�����1�B���wQ9�hw�iN���8�EM�a0Fb�#���	@$�� NB� "l����aR����P����j�(��4��<b�����D�����!��b�����L-]}� ���s]x�j�Z��g_Z�Y���K�����'��������o�\�������>�BwA������Zf_=���o����?��o^on������f�5�n~���>��u����i{�>9�&���g�_����7
_�w�?*"w?n���?m�����M������/�hVf�_^o�y���7����?�����By}q�Z������+�����m~�R|?�U�l�4r��������}z�Q�V���>[E����e��a�m�q��y����fM�z2��=&+�����uG��������"E[�����[��K��2U��e�Y��*D�^�O�����0������zT7* ���Rim��5+[�y�t,�O���Q���D�u�c��e��	�O���*�\m��q^�\-Y�4��A��l-s:J�XtT�����u�Y����E[I=X��O*������ U��\,�B6���\��Y��:�d�w��p����k���
��)�T
,[)y�<�~j�.yDKW`�@���v��
<�;�j�z1��{�eml��$M�V���_�jDS�Zi��Y�6D�:��\������U,����l��M�%ZPDd/��.�W5�$���kg���KS>,�FIC�&�\���4��������0��bb���P���',�r�x�6��|������Y�(L��@����zT�����vwy��:��(��������s��A1@��������zs{����]����n���LW�'=.�u,�x������ 6����iU?Dh�BP�M����H*�}����f&�T�	k�y-K�w�����cLK��O>�R	2�^���=��_��N���j������g9������e{
�s����w�6]�3V!Xgb�k�(�����d@E�]E	;����{)K�(���A�'&��r*�16P[E��BcU�1A�K�
0�C,�j#��S hB�������6��f}��]������,��������C�T�b��n���F@d�7��'
�8�7b�q~���h����F8���:Dv�YG`����1����xx����:�	c"}
F�1 rO3#&C`30}�q1x�X�0��{#��{����Q]|�<�o��$��N����/o7�������������	�j$@8�$��������g0SD��"A���`y��?���V
��X�d����1�����N?�:	1N�&�8���+�:�X�1v��P)}����'���O"wI���X?��t&�c�����{?M��������f�������[���� %���O�����kJ��������aE?A.8%�H�����*�QEV�;����m�21 �f�OM$O3��<���9#���&)i���������c�G�C��8��8��	����$f���|��]_]m�w	�2������A���p$���SH	������C�w6�7�����������������&���$��3��gC'\��v<��=�������!]�;����c�_k'�u:�5Ae����J�.�p6��X��!<F��V���s�A�������D1Gx���D	�����#�qu�
��)�K�� �=NA�������q:�#z��8��t�H=F��<��������X��q2�1LF���x��"��N1f�db�?F[�uQ�������Q�����G�q2�1�C\�����e+���q��;�������I�DYqQ��1��H=F/�y�����Rb������h���R0�c�O���t�=�"E^4���n$*>F#�k&Ze��(Qz�E�����R��1zL�1^��9�c�)pJ�1��g�>��,�R�N+�S����E��+�[V�Q���R����f
��Y������z�B,���-�}��#���c�#��G�8qD��G����z|�!=>FxA=NG��#x�c�9����#��q:��AqX���8���/����#z|�������S���I�1�c"b�8���cb�b������4�\���$���w�����8q,>NF���)���	�T|LG�*>NfE,>&#��0+�s����e\��1b*����Os�Lo��;OA]�|���%�#
��q������(�a�F���(c�x��5+�BTX
�l?�!��<8pH�SW�{���X��4x���`������J���-
aD�	!��q���A�>3%�CV��m
}�i�CH�C�P�zH�RTy���Tm����<D�Iq8��=����\��.�0#z�����T���8����xH�C�F�l���a'�p�m�[5���qh=�8=��`�9Fa�N���%#���2u�IT	�EA=��6��� �I'E��2Bx��}.������l?�qb<>�M.X[����Q���)D
%�b��d��	�w ������g�p�I����m(��&<��
q�v@(�M�{4B�e���hY+�BI���,e�I65�bR�����F�p�I�H�,q#z8U��?��|o�vre�'	!Z�b���)��!�B�?���X�4=\T��N
���s��%}������}�	��R�����)��7����y�K������;��#g�3��T��r)�R������F���������0,������B����4a��a15�aq������
&��`1�Q ���UY�m]�C7ySE%�����n���9.���

�b���.��aqGM�H�����<,fL)�
�J�
��1����]/�����fj��b���B��K�r[��f1yS��M#T�@+j���Z(_Jh����F����/f�A]���h_kT�+=��8��b��y���1_��s��Q�<�F�Y��`1jEL����9�b$��#��"
R��,��]S��������z����aC��O��;wl�vf�����v;"q��=g���%��?�uS�-��P�����h9�Ek�k�����+�+��)u�\�a{`����.=���S�3�E��po��{�c��LX��
�"�
A,�
���I�1��`/�����DT��'��~�����37s�vC-X
G.�
�A��Bv8*��,'�dg���P���"�^��GE\/�[M��"���C�3���
C-�����V~��@���Vw��@���Vp!��G��B-�A��q+�pT�����V8*�zq��*$;�zq��)����8je�
��8j��
��8j���qq�*&���8b��
��8b5�
��8b���q��"��T�y��!�����A8*0q�1+���D�����A-�@��q+ypT�����:8*�zq��$;�zq����:�?]�l7�]��������x�'_���O�����.I��s]������s._����,���O"���RI�c��?����<L�I�G�6��J�O�J��jx��?��R��������U5oD�MQ1V%���V��rW
\��OaY,Y���M�����	��O^|TAD�*�`�\�������L��������~�
v\���~����b�����imm�Jr���N��^��.�������3�k�A3�)��g����i��9�����Z����[�z�D���>��p7�^����������K�O�����T��Q5u���Ov~�����hq�O���5����?8�w��;t{�����qI���:"��X�J���	��},�72V	$���n~�m����A��K��kW���g�.���EU
VrV����Z�HR�Ju\�������h*���;�}�0�C���n���q���C�Q�U���4aG�����R6�uoQ�C����\��8����5�)��1�KT���<T����Z��Q���R��a�>�[�2
>�����s����Ms�E��w|��zx��;f�1����P���.a��u)[��uG^�N7�u)������-�%jT��X��u
<�:��~��c
;�����W��C��C5�����h@�o@�e(R!V�Iqh�����gR�c���h;��e�3�=��x����#PW�L.wU�=b������g�HP`�9���-Ifg�����}q��f���k���l����?/5!�Js?�F��Q���}��/�T��b���GC�]=AJ~�
BZ��>��7V��R�`�2v��MU�UYI���l!a���e��_�0���������KQ�B�E��ee��X��Yi��SXh�6,��En4�I����\�_�_
K���7���i���?m
��y�6�Z6��C���U�k^�J(uo
���j��v}��ei�Ni�{�����*���k��K��]_o��z=���JSw��\�~yq���7�G�k���R�Q��-�������������,L{�0���4�u>���ggwK������4��6A:�!#7������0���
���b=a�C����f�i��A�����Lr��X��}��P�vT^e����L�YA�u����O��-Ee�K����������9@�8`���K��s�:U��d���s�j1Au���*
l�w��!���PqC�]���wR2Td�;���+�Y	��w�X�6�	~hS)���I�Ol�H��������_������"���rR�GU�QJ��Q#�G�"50���>�D=�����_���}�y!�CO�9W3��P'��;�����L�A�J/���p'�z�@�����D�U�K��$L9�.��:P��1�r���� MW����}��@��������V�w}Ei~����G�7�����|���12�_�PVe�K�?������c�;/��P��<����O{�:fR�L�4��?� �Co���G�t�������YY�������[�^4���3X��n�yz�#h�$S��T�1�
�l�z��}��M�������e���P�w]?�
w���w��,�������^��FM�rd��yK���:a�?��9.����p�#uU�%J�H�2��%D�0����MiF�������=QP�y�?6y���LP1��l<h���h�
"Xh�^�����f��@1��E���5��2T=��+�ySm-�XJ�E�p�����k%k�GQ�i���$�Tu� M�?j�*C�U�����xs��|}�Kwr�Y����vk7^�m�r�����+���x��>y�4S����3�s�s��C��7����<IsB��h�L*����z��� �G�	(�&��{�G5Z���7k�T)�������-�q]�w���w���5=o��.����z��fz��77���w^0s+s;LE@�`o*��@��3����G�w�>2������2v�+'���t��s�P�����k���`��K�������|U�RM�V%cuU�����,d#�ly�e+��S8y#.���d_y�d.�`m)�j��@'��=����p�Y�qu9����K�4r����TQ���r\���J0.�T��l^���E�KV�����Ue�jV*�KM��U!��=����������dr`�D�k�j�������O�v��0���iS�c��T�4�"��i]YqQ�u�j;4L�uQ������*��X�g�j�2���m%�0��m��M��e���Y��h�)��M�#t�����8eC/��4�����-�e���,W�1-��{t�3�����O��W7��6��7�3��!���x�Nl�`��F�`w`��:�b�z�C}�@
@��*+�*OP��R���=h�dy��#�c��p��"�1V,Uv��]�����&{�Kl����%���18�����;�@�=������#s�+���|��.#F����m+��������-�E%�#~bG8:������c�9���h��E3�"���YX^�[4�m�gd��{�>������������I
�#������0l�l�����~
���[wqX~q����aXOpXX�(��C����g8�e?�k-gZ��I��7o�/~�k��{��p����������{��������d�I���=Z�x~�34�/���(>���O\�k�^8_#��x2�T�t����)3��Z�������/6z0`��|�:=���I_�w�{0Kmx4�����}��3��/����-P�p�A����3��;7�o���^����z��F���w�������
lC����+�=P{=;����3X>���}6S�������q��gh�DH���c�<�'��0=S������o~�D���{����F��+����
9���|��@�%8�������:�w�|wD�(�o��u��ob������<�W�c���v�-�x�a��3�B�m��&zm��5�������x�O�YuH����D��':x��oOt�D_Ot��������������{����b�@���}��/�/o��W��@�������j{�����$�p��Y���:�����{-������J���{/���^�R�1������f|���Z=>E�kw�G�����~
b�r��	3A�q��a�mU�-#v����;x)}1��B^�9���1O�K��'|&t�m����R������S������I7��������OO�K��'�%��>�o�'�Z�d^IA��l%
&�������A����D��.~�^B?�3��� ����{�x�L�K	�������!N��j���;��]<��|��n�]�A�v8���������p��}����E
���/��a ��l�7/��N���~K,�'%dv8�����n�J��+����m~5���8��TYc-����	m�����Q���
�Q���N���A���-o)���D������,tw�������4}�\iB��r�h�=O��,�>���y�t0Nw?�c�gB��5�[����-���GaNF|����taJ����;A>����]�t��P(�E�;�8BOqXPa�
�f�P��V�J�������?O��O�-1%.�x�����a� je�/�3�mzT��������e-����6�j�
�'R�����V.s` K>���6�'��\�����g���a��57�`JD�'�[�@��*���j!��I2����V����h �-��tO�~�^C�;�h��[���7m}8�e���\,{�^a����uG����������U:�>��������=�|���W�O��>����6��?�+�n]�Mwz��~87��x��(I^��R����F��G���R_n��z���|�u�z��h{��{�2#{����+���3��^o���|}�y�|���\���U�������>�o�����o������f}���n����xO��.�������yi�����.�AD�b����%4����]�O����H���Q����4"D�q��Q����Qh��c�_0��A����6��f}e�p#�����"[[����*;��0^���A��NH{#tL�8��-�q<��=�vz<F��s�������idu��wa���;����x$�oc/%2L��F���0.�a:x����PY@�x��0K4z����C���)/@O�e���������o�G�CtL�U���:����|@}�[��>�����9>����n�> ?��[�E\y����}��J���^�n����i�����w��F�>@<A�;JF��@r���S}KP���F����q��{���@��y|� }�� !�����D:���paS���3��e�Ag��1������"�������OA�;�����}~q��k�F������i��3����)�)S����ej4�%g]�9�O�H;�U'a�7���s~r��\��#�ik�hH�NW�Q������X�ZC*��L'�pSBv�S�$������S��yTO����"D8���H�r����<��J�@����a������������Dr�C���>i�G|�"�	���Tk�3�r��������H���h0��NA�Q-;�#^
?�&����,t��"�l
4��NQ�Q��������j
���a���s���C���MO'|��un�K�+�]���8/KH�t�&!�F��#��������
�Z�o����w�p����n��&\?i�D����UkV5F�CT�`�����?��Qx��"i�F��X�z�4����/��-�rC��������%[��6��^�#�.f�W*��A���3C��gi@� 
��$��JAu7�@��9��A�T��"���}��~Y�3o�g3��ib��H�uMfs�����O]�,f�t�6�(�J�41���J�z	R�w;R��EZ�������T���UiNt6.g�q�S$�1��)�_���?�r�/A��1},����7����<8��c���� Et�+B5�����K��\���_a�M" �;�qG3��Vp�� ��6D���
��1��]��������I�b���M����d�{�8���U�������������Z�Yx�����kN�k�l��kn�������k�\\��w�y����������O���s>]��m�%D/�'@���p�yD�~���>I�����v}��f�W�*��|�_?�4�?�r?�.fX�P��-i��$� X��+Es�i�'���/���pq����r�t�#-�n!H�	��4�js��<dl�#g���Q�D��8�L���+k*�8��H�@��z��$kW��H�������J�@���L����@W)O��Q=7f�q�@��r��g	J
�;bj�w�<K�J�]W���5
��������M��v�j�ZX�����9�4_��\
���P���q3��,9�W�~����-������hf`��]Y�����L:w�7����wZ��T��Y/��y�����x{?p?p�V�^Ra�1bV���eG����M��<��5�����R�6�����Y�L�B(��4qa�g�Xj<s�o�v���~��q��1:}��w3}��8xW3I����
L�
L,���$�;-���h^'	���S������{���q�B�%19\pE�O�f�~����+����+��%o�f��v���zi��!���y;J�&�IL�������.��e���I�.�^��+������@3���l����h�tC'y�DHC��|��-��FH��������Y>�8�kE�z�����K�y��P�\����C��������*+~�����2"�=(|]�8��em�):�$�A%k' B�����hh�z����1����(�B}z����k}�}�<��L�b����3��:C�j��r���Qk
D!4���
QZJ]�fj�w�4Ag��F_��$�-\UyZ�O�����8C�p���8�gJx~��Q�z�M��Iobv}�i/N^&�9 �����9�p
��Q�f���M�N��I�O��I�Q����s*�s*waN����]���D���K��J_�B��?��)��}3��8�b�h�C���T�t�X���[�|����&{�Kt��c�T�}��w���O���'O�f,����3��3���m�=�=�?as�����0��U�r)k!��R���`m[��)jY��M�������V�5D#��E��%�_yP��B�D�(
f��MH�����&x��B�jB2��sQ���nKY3Q	CZSm���TC�������-�BpSB5����`��]�Z��.�R���.�JUY2e�� ���I�X��f�q��]������2&�5}L�C�C|�j�W������k�h������h4�b��Zmn�7V�Bu[����M#.���t�&Qg1�����v�;����`��,D��X3���7�:V(��������B���!�����>���"*Rx������$�.�������	����������uB�������c���"���<E�
	Q��*�������}���h����l���X�+����� N��?)L�����F�m�"��� 
1���`oJ�Z�"�B��fl�|��+d�"�BF(�+d��8�?
�/����(�m"��B��M�����T�R�V��W�)�+d�7m���QZ���r���C�{���C�+��B�W
y?����o����� [K����(C����B��M���~���"NQ@!�\�/D+x�(��#D�Z�F;5��{�H��
9���E36m>f�&��BZO�(��#D��$3���)"(�[�h����l�BF(�+d�"�B�3dg�j���}us�����������n}y�js�;��9��>�>�&��C��������0����?��w�t�G!VO7���������n�@8��?[Yd��
�4���*�3��<w`�U�:b�v������r�tOO;�"0�lRKa,��y��p�Eb�����}�i=��b���`p�qa���aP��V���=�=�=#L{�	M\{\\{F����aP���c ���A���A�g�i�;�k��k�h1�=c�=.������[�'������%_��}�Vo��r}�q��0���"�C�\����Z�kB�P�=�l�G��`�hp��d�P(S��Drr�e��S�sO��Db I�sA� �44 �����+M4�4�����&MM��4!4i�i�J�@�&�� Mp�+I� �4���(�1���)MI������l�@�Mp+-�6!4�����M�6ai�#)Q���"����i�H����&��y0��	l�#�&��(M��&�4Dizi@K�@�M�4�
l$�1����&C@�$@i"1�l���+M���+{H�	a��f��?�mBh���k����������E%9mt��,r�l��>��7��Wo.�JX�g��3��km������rgKY����s��9kT&�>g��p��N��}�:J�}��>g�b��9k?����}��>g}���a��Y�x����8g�e����.���P��.�.S��[�
��uV�O��P�� ���_g����P�����4h����\�+2\l���h�b2��pa���0OmL.;(��k��j�O}-������Zr��/��W�Y���BR��!D����6n�����Y�������i��C�U3�A�+>�g�F�x^.����_���S�,�T=������}(RwF�����f������p�b����>�k��������R<:_t�zs��>N�����i�n�C�]��2o~iD����c�&��0J�v�z3�
:����	{����xM���?mnw������fk���eo���/�����b�b��j�]�y�|s����N?�����^��Z�j��������|2�O���N�x}�i�3��CO?��u��xXY����i������MQW�1Q��Q����������*�'�b�&��J��R��E<4c��]���yU�R��2M�N����^{e��V�����``Eg����l:�F������y�qD����D��l%r!
���5-_��%E�5���T��L)���~)��V��w�Z1�����L���e��k.�H�l9���/@!�|��������.�\�����������5��h&��,������#[�����^���`�V@_��=��*���-{,����������G�N��
+�HUYU]�MY��]�M�X�?�\1����N6�2�CcV����=�0��������������Y+��@���Kt�M<�������������1�R���O�;`��=�_o��[����G�����
���g���!S����h` >.q�����l`l�@CQ� �����VVP�C�.��q��:kV&n�G��������I�����ES7U�V�ZU��3�/�2�jO���I�!���(o=Fd�)��Q)0^���fEU7�5����/+L�Y�T��VU3F�Gn��rP,���(K��������d�L���et'x�)�����}�-9�N���`��;w�\Lu}8��m���igM��U�y�3}�s����2-gu�v9f�w�f�^��#3��7���TW��\���m#�Q/����I�}���Z5�]�����J��s������}Z�
$��#O�{��d�3���8�����f���g3c����P��d9�>[��7�W�l��w������l}�����H7����U� `H��:��+o������Ss1����(�k�i4Q�G����#j��z"���>��1Y����g����A��1���I����������O�������*���~����`�	��*R(D����u���A������}0q��&4	I���>?��B.^:]����n��q���^a��iA�����+��TH/�eC���J� ��n�0�n�0�^��E�JG�N�+��
���[� N������w���.�	w����{�x�3��C@l�����qh��l�"� �^��� �?�r9�%�t��}��������,��-�k��u�Pt��A��>�q�$r���qg�����h��$j��:�)����I��7a�[���$���2O���K�U�\�K��[����)������Id�:�Nx�����s�E%����$_H��e�%��f���o'"�er�����P���RHu���������sp�a�����������������1�50����q!eX�Qt������'����J�����������8�g��-2Nw#t;6�zOb�w5[����n}}���{����Y=�w���|������Du�o��w�7��ot-?\���&���e��^_m����~����?u��t��[����MXY��}X�p������+n��i�Lw��
��{ro�}6p�S#�eY<�^u�]�_#u������q5o����|u�}N+��{g^Z�<�;��C��2�N,[�~s6
�=�&*��y�$X.��L��c����<����Y�A�����G�<���8��W0������
�O��������?dB���3�����?Y�z���3�8<K���%����-��������A]
�X�����y���Q[<ox#y��*���U�!���*)�����A�n:g��B���w4�]^�����.MYsX����<�<��971[�d���|����|�}��=�e����]���������,m�/��3�>�6=�yc|C��]'/�+j�LK\][�SP����t���m��8j�Z���Z�d)8D��������	Tu)y�j�����D@���u�����ZG����5�m�����v��6���e�����W�0�����TU"�c��`��m��B�����\�R���jD�6������U�h�}-W�BU����Z�	v@��.k�b���	�A��m
�-W������`��1������R4e��Am�P������=j����`��m8d�cP����������q���s��\��D��\	���J�%�]�_b4����{�p����0��=����g-*lw;��w��B���b��'bZ���	�C�"��2oD�(hZ�|cZA����U4YW�~I��	��Jp�u��K�r{��NN[�vPqYLi0G7���W�	�i0�=]\��5�/��S>��^��
N������q�Z!��F�Q�]#l���k�J��pk��!Gi�0����J�(e�qY���=*���Oi�v�'�~>�����b����G1��������j"�G9QD�T��`��Ln1������}7��Q�C�0�f��G���EL�$	�X��
!�G}�K��a,�\i&`I3��4�h��I�`���4@���a��������4���a�,*
�>��
�����(�3��t�exbr�8Y�����?d��
��G�U
�-�'}F�N�L�T���pS%�����'�?<��?���E��s���p��# �0N��8�������.�;��j�����}�{�{��������E�������p'�� ������#��t�|�3y/��v��i�S�c��ls{{s:{Fu����Wo���v�?o6�����n�����EQ��lno������ E��O=����9�&����+��&�^�g����St���;?,�-?���������e���0�3a�����k�^@�l�r����/ �p^��|�����!���_L�wm�O����[���+H��A�0��HL"����H�&�^�1�l���K�D�	6�zOhpi�;��������1�tCw�x���g�p�� �)0� �����Y��h�����j8rF�������D�E1w3���[yk�cJ[�}�7b���}��D���Fg3g^s����e�x�����">u]D���!����� ��������c���a���
�NX��=����.p�1�4G������������������!���]Q�q�7�v�u��x��@d��v8i��s#��}�g��;�7j�y�,�-
�X
���Z�������4K0���		&:��+F�
�&�����p�9C�_G�JP���F���t{��s����D�\����"�O ���
$���`�����?9�q���6��X���	-y6)�3���Y{����)?6.0�$j�2�{{	2x�o���^��g9fH���4�{��w����$��2>�������Y_��D�m/�����[��X$����D���mH�X�p0��8fU5�|{�>"K;�(9'��q�8��Oj���kR��7d~��)!B_�b���������93]�������t�Cu�o�I1��K��ns;����a��9$Me�o���N�{�-����>���y?Ff�GRx�D�;����%����~�dRv��XO�O��������D�N�w�d�>��>�qoq'����C.������5-\����X����j��a5�����tw�t������1��R��A*��a�w<��z�����/�3M���@j�}0a����@�����<���Pb(��=��}��hn^�K�h�b������#����LZ�K�/��Y�����/`��UW~�x`j�\����A��*#r��!�@0�������
pv�&^�5g�yd�U��9��+?\m���e��#'O��k����V���Wd d�_����"P~�����bg���9UE��|P���B�,��'��C����2\��H_�j�u@�"N�
� @8F����"�������L��tz��W@���0�^�Q�G�O�(h�X1�^c���NV�.0��9�o�#V�#q������/�[�o���Ip�O�8M�-Y�m���3P���`���>������%�,�= ��b�{��7o��n�����~u���td���~p���<�ga��`��{�"eto�ux�B�	@����r%h�{iz����9p�2��j���Y�|b[�Js�6��4b������8ZE����W��q�(��d�q�]#e����]��$�
`��@�5��<���h�}m��@��H�P�2�e���B�������0�7��-�j��8�� ������.
�W��U�@�
���~�|�p$�0���IC~e����?�a���-m���7�P���?G��2���p-u���4h��U�\�=<���7W���W�t�L##���d���)��9>pDn���/�� 2�H$a2c�hR�@%&�������4�G0�z���,i�_�	WzD�Mx���*\���a�=�I:��#2R(��/�0-a�b�	�=�|@��0%mU+�����}U�e^^�^j��`���r)Z�1���J��%�0��Z\un�"2������$%�P	5��2W���s��V�����&�K�����e.��fu-a�F����I9(����.L[�z�L�A���[����p)V�+k^6�D��5�/�����+&�+}3�h	�e�+��	R:Bh#Tr�(���=���Dk,�+'|�/uh�Z���dK�NH��
�C0�E����������,��f��#d/D�����K�DYqQo�{ii���%�q��bM=�+��]�6b�!�4D�����IC�I^txT|��Zc�x��_�/aq
�?i\�Q2)#PbNe�i��Qr+4���������/Q4���f/k\&��������0%	���@$)���31�,�������bYi�������e�[=Lb�e�����h�
�t_PX�SR�5}����M7���K*�?j*��3@��)7�~���Q\h�=�v�|����F&I�|�I���t�����/�|��O�<�X���?g������.������'��I��622������,k5R3w�2QW�,d�����@S������-~��p<\s��������*Z�!B4���k���M��Ej��7J���I7�%�7`�H�	�b#������2�4M�:r�ZqD��Y�(7W���-�C}����7����56��q�������;t4!x����5|*,��2Qei�H^O�~v�PDT�hE����P��	}��j{�[5�m�J�sxf�S�C�+r}Ey�,b#kl;0T��V#��4����
G�e�*��8��"{5���Qu��$�����jrb�}��{��,����`�[`Z_��d7o��G�����O�������^���$��I���~d��}���[,�.���U�=9����|��K�#����A_��/���g���G��!^������&/�u���q���N������~����i2��haj/�f�E�l���{�6^���;��F��jw�����H�v�D��?U��U�o�����9#�����(�	8Mp���0���k�
n
'�"���S7�
nNX;^p#p��&�4��c\�<�����`q��r�`q)��#���x���PV��	N��M����d0xHp*B�����PA.<$8xPpj��W*�o�������%�oT'Y5`,O��18����D��-�mqcp��M�)7��V��X�q<U�#R<U������W��p�b���M��	���H�S08Np^p��y�q�=fq^p���1�3��r�gg�/^d����]��x{{��n��}|�yy��n?���zs��\|�rs�j��������st�����F��^\^m�W7=���<�������������E���L�7	��=z�(��b����o���>�,[�eY���bj��g�A��'�����_�}��������(\\n__�Q�����w��uvu��)��+����������r�7��V�����A����r����������n����y�m��yw������z������6��Y���S��N-l��}��������^���]f�����v��=���_g+%Q�7����,��f�+�w%��2�7P��0�-�O����Wp�/�����&t���>S���y����yH�hJUymB���e�����@�!�;���[��o4�EjG��w���[a����./�x`�?��n���:�}+�^��(W���Y:����`�?�ZY�o.���7�����^�&{���\{�%���z6��If��r{��x��gT{�X>���%'�8�F�~u"���y��]�nn�[aJe\������6�����o�7x�������;(��3;i�e~�j�-��a<�=����lC���
�v���f������N�H�7o�wC��*���]�\}wA��~�����v^�V���������f��.���r��$�R�i�f�x����>��'�q4a��>[�U��{zs���zw��F�n��^^�������6���"[��|�Y��~y�����o�d�._����7*�Q����B������eW*;_oM8��~~u�Ua��X�p�����������Z������F�������}��y���G�G����������;kt��D�n_A��J�@h���u����������x^��n�?z�R����?!�f5H1d]������AV!9od�EU6m�.Y��FVL6U!��*nn)v���ye>;����)�v������y��0U/�lkV�����XZ)�,�5����Iu�c����2X?��|��\s�i�y�s�dU�H^�"���p��U@G��?��&����������u��Y�QQ�R�u�*�Q��%W�FR�/ORV�l�n����r}mup�!�1�J�e+%/����u�� Z��+=�
�BSxTw��jt����rU�{�em��LwkE��Z������B�"H+���6{��%�n~�L2;������6�q#�~�~V�g��E�NV��4�e��^�kk�x
��dWK�����c���oHU8G���g�t�EV!O	dHp~��U"�W�������������D�#��/Oh5���j
u�i�$��
6�s�4��L}=�6��K�n�H��/��k�����&CR�2���HY�o/�iT~Q,3:N�������FU���h�I��,i��GQ�f2�m6O�iAmA����`m}���f�����B|�a����^�@D����=��0u-U��7��\\w�D�/1���2�T���X`r��o�6;�����_�FT���5��s����2����j�x�����/��u
�9m�D�����#��_�U�e#V�y�P�%:���+�P=�6VB������j�S���yv����)y����7\#���#����Y�r#��~]��=,�"�Ct3� �w�EtX���r���~;>b�E:nt��������n&��t��p��,1��+v�zdL���)K�y�0Hh���{��1���-}�1�c���L]<���LV8
N� �=���*���mX6-X^@�4,9d�Btf4c9��W�.q���C������8��63�����U�Kba������|���eA���2jT~������I�A�:�s#������v�Wc��A�	d���	��i��?y;��
t��0<XR17(}s��0�LN	X��N�
�!��=�0&�f��l��II��f��}�LrH�?�.�O��$��IfX`(t���m!����H
b�����#���Y����Jb��hoD0-� j*=-m��amI��&U�`�i�H-������V3��Nh|p�e����������1b��y��0~BL;�-P��9���i�e���j�-��i�e9��y93�K);%b��N�0�p��:p��*��$Gl�d�`��<J3N}C&t�~4f(~���)���m�����K����"����yU5����3�i�WY]4���J�O�Ap������Rg7-�iV�UV��|��tBV%\�I���3��?��**KL�Z`
XD2PAN��������eh��d��N������RZap��6�3&]3��h�I����j�
��l(9��C��.fS�i�.��p#&��Q��f��\yl3P�8	����k9�
���6P�����s���_.�����W��Rm�v4���D�����/����g�{���*�E�q�[��!�R��������'��)�����7����WH`C���#����%�����o��Y+��\])�Y������M������w���V��a#�^FI��������]O^�Y6=J��(�
�k��P��J��GGK��SO��M���Lx�L�W"��+y/Kxd�JA=7�]�P�B�]^��@�����X�\c;����>c��UZ�Z�o,�FWE���lN�i�>���j�f~v�Oe�Pj+V?H{������_�VU8iM�o��o��F�	�p��
��l=&/���[g��8/\��]��x�+���z@�I��M�����&���]�r�n,WS'���=���%�f�)4�����������-a��j��<��o�A�B�~��^�^�7��5�R��L���#�����<E##J�Z\���}����`�S	a:�Q�����''������G�W-�)�)�#���#V&N&N&�~�m����D��Y?L�<���Xyt�8yt�8yLT��.���0���e�-z{v�&�=��M����a��0�q��a���un���.	3�Jd���0������S�:��y"����5_����*���s���8Ni}t�(��1�v�t��Q����u����L+�wK�z�Q!���{�;�]�b�M����UM�>��*��o<�Bk~IyO�^��7:�E'L<���lBw�e��a
!���=Q����b�\L���i��FglUi����R4�W:��Ry�N���j�\��.���\�!v���������l��/�������#�H���h�e�����?�>?���������i6���i����������YV�536�M�7��[`hn����6;��|/�N��a9Q��f|�MSM�i^�)-I�&{V���Q��������WMma����z5.�a��&��������E���H��*)��:��Y���l���V_0b�P���BPLv�M���8���sI�zi�h�I�HX��n����,�����@P�In�I���_�Y�8������,3y8dJ���Vr���f�����ZmX�W��>���o����x��*�%Si�b5`�|��	H����GC���N�����,������9NAE�,�J^7@,�u�,y?���%�\��_�+�-�#�[l�wR�q�v~�9V@g�c;��1��=>*�c�����L7�q�}
��>��w+����P�K�� �����������,D��y� ���~��<�$���%9�����K���=��
$���=����QzOE�C���>@��Q�Q��J��W��=��}��yDK����\��W����4��9���s���u�7���b���J��4;�=`f�ff��rG���,0��#��W�$U}pu�Xo����[�Ne��E���$v��2�Y���(+6��O������H$��R�DmT�I�]�=��<���E|��f����e��)���EW���e�-.�?k�#R�i��8�����'cSY4�iCM�1����y���6)uf���C�e�e&W���r�	�� ��)�v|��'r�	����0�X���c#{LR���O�>��|�?���w�|��	�^���E3�����������]D3���+.�.�4�YU���+p����AP�*u������c�u�5��\We^Q�aP5�]�RO�Y5��^��jhXa�4��I���45�a�#3�^�������U]?�� _U,=BVFT��pF+�(����YU��$/��'�����P;y6+��Y���|:��U��u]a�5P:��jPq1C@}w����A�rj����_h{��5m
db��M�>����)�0���h��!�jfM�uu�M��F��0U��������9��P�I��b���3�&�a���q"2�z�i��We!�`�<O���%�&��9����<_�$��@��dX������uFN�/RC�U*�O ��"��k	@���oz�#y������|�D������g�s2�3XX������~zI������O~�������?�KH�����*�L��i1���
��"=!�A6� 7i�ML�I��y(NS�N"�/��O��lQ��8k�I��I�V	�m�:F�,UJ���D���W�*+�/s��6����3���6���j�6�~I�_�i7i�,�"����[����&1��+�������[�V�O�~3XEb������2�dX�r�;��~^�Fr�4@��b��'��b~��t�ShG.��}�#`VV��A�p��M`���fq��*�W���<��$�������qu.����xM�yM��+�1���`8�D��t��u�
b[���;
!��1��	;��
Y�7��t��|���8F���IS���_�?X��qjaT��g�IN��Z���:�r����J�8R���+�J���t��r���$���jq�
t�&�cI��9D�z�$�HI}]�����M�`���&|���
����
�yr��]S��< ���{���?f"d��I��`�tz����_����KA��%��1\�I���g�����
��bxE`������I��-|W�����Sp��:��rQ�?w7��k*����(3c������~E�s�"����A[yH]_�T�U�*@��q�������*�jcj������	'����L9B7{Kp�TH��A��X�"�&�d��G���{��L�
��X����Y����T����Zb{IH�t��d���'	�sq\2G5�@��_������J�m��4ag��Z��C��������)���9J�@�	2���zX�����4�%p��x���kC���@����.�Gg����B[�v|a>�,���RV���f�����}w����4@����*dgG<iR�]����S�-�?�L����
������}0j���z������"��!�Lv��N����"�q�G�Oc��8�q�MY<�n-�Gi����y��Bg���g��n�gE)s"�����n��D�J:��n���d	���v��/�G���=�?�{z��)�[��-\8$	��]��Enw��05�C�D*#�zN�����X^,��y��M:��mS7������a�,�0,��a�.���������_�[��eaq���,,/��ea
o�]��h�����i�7������]I���ZI��2WRO��A3� �I�"L��$����2�m*���K�Ax��.�`_$eI3��I0��g=
��6�����	P�X�#�1���Y�����$��[��I>%�$���d�X�u��$�����1����/����#��<��q�{��#������r����x�oO>R�����������FNB{^�S�1_���U���vm>��1��G�d�R�g��cM{v����=�S��	�,$&is6=�fgg��dq6m�i]Wy��C�t�����a�:����p�'��������<c�!��+��������������@+cD[�����JO���(������.OF�����9�G��K���D@�"{o�K��)���p+����S|4b'�0sy�Y`����X��P�'�
��=p�����Ga�}����D�����(�\�wD�<�$�(�$	Nz"HFJ�'��3+-5x`������fY������L��~��D9��H����������&=\��
�B#���k���8�@}����n�	�7q�,m&�V���m��LIwb��T������C�������������O��|��:s��v��C!}f$�b�Fah��F1\+�|E�J��Zh�Z�jAv>OG����V�k��S�9��@����� ���9i����dp�|���y]�&�e����*�4�������$�.���J;v����_�)��27Y~�R�D
O�}Bv(�0����G�;�O��@#dNc`�v\�T�_�����+Z�������xN���s�C ��2�!��7��|>Nt���?������ �
��Wv:����Iu����$��Y��?�m
��k��4�@S�Iv���(�tTA��C���F?v=���>D6�s@��Do�����70/��s��o��}������*�*%zY��W�5y�.W{����
�8X�v"���'���\P�Z�*�qk����8���7j����Z���.����H�T>0���4�p����FlW�Zwqi�DZ���j�P���]93&�:��p^x�������h��k�k�*�ZMS��4��.�O�t������)��b�h!v.H������f(�31��Z:�U6%2�[�U�C��k2i?"�+b����SMV��������JA����
��k��6!�N@�����tk�-y���(��h
���T����t��-����M����?�������}���2��U�������T�8�!u�����'�K�	~�O��R�th�L��$�0J})5E	��I�9���RZ��r�Po7�UY������w���D�x��g�]���ECS�����5j��������Q���`
�T
]�
E���t��:���4��s�%�����d�K����������Zn0���� �%X?����[O������%(��_�#�e���d���
!��6R��
.�����P���m@������s"�\WV�E������=�V^#�t_V�G����<���l�YS��Zu(X��*E����#����Q�������#���8�U
0b�D�����b�pEV7y�N����^�*��^*�n�����M�Y�gUK
T[��,-�"kY9�)�,,!@��h�	�M���f�iZN��Dt@M���d��iU���h��/��]-�U�6s�&UU�%$D�g��)G��z�����b	j-G�XO�����)�|�Q���Q�R���)�2K��NQ�b��~&�OA�2�x�g����sl��z����3��Z���p��Ae��#��*���xt`���=�A�L�]� W�C�t2�0]
��|`�TXc���*U\
Z�0]
s7}�
��8*k�q�D�pU���TQ5h�Bkp�����PTh

2��"��BW�Q��j�B���a�Bk�0T���ru(*d�p���\5@�d\@�����a�B����@e:H1VoWAT���ue9Q1��-C6�qqe:Z\9&E!T��qpe:c1��k0�
k�����E���DC�0{5,���
�W��t��CP9�U�]��hL
�}0�
k��,�5�+���P�S�!k^E�������P���A���~W�@��Xh.:��6����*0C�*0C�*g��?�����e�^�4P!��PT�e8fD�Y�Qa��P��p��Xk��!��
���cQE����""E��b<�HT1}$���h,Wq�hj����M����}������!����~{q����/D��<�������=���|��uc���\�n_���0�~k3��wy0 "���{sw��-�a|�����^���[���������5��v�so�Jp���g���_;�k�4k��������k�?lA�<Sc�S���g������S�4K,�������9p�s��
M��y{Q���]��l�xa|�v"Vr"�{���2��m:�!���&���b�/mF������1��t���u:���R�*#���=��9ba�H�t��a-���,�h�������v���1��t����Yz������)��q/6��@W��DG�-X��Dgh0X��(cbA��]Q5���[B��"K�J��7��|J���������nK��BXKw�NK9Z�{U2X���#B�A��W�kGd��ww����_�/	��p ��o��z�w��� ���������������������5��_��YjB�W��m��9�b7�[�A�J�EP��C��>������aH��z�z���,�$�:���6�6px=�`�G,jq���������s05y�d2r/����
��hdD��7��LFn�7U������M��J"w������������}��!��o����id�D�;k
G��q�|� �p���ax�Z�V�pe��Y�8��D���h��(Y�8��8L�������=��l��{�>�6��l�h6��q����������[�{��S$���$���{��>�@����.����������@d��������8��?�������`>���c���M�9D~�N����_}~���D�P������o��L<~��O�L�]bl:�dK�UA�>����B>�o��v�T���\�vw���^NU�y�����l��������n~I�[����|���\�����Z���o��}7�e����V��oW��r5_��r���l>�wy���7oi���\���6�b]�)kX�|�n����������eJO�"�����60��9I_<7)�����G�'I�=�h�?�g�t�x�����$�f�Xm����_2~�kq?��~��|?��0}<}���/GN�B&�Q�
�����/�d0_�'�]x��D�����$��<;�M,�����:�����Y|�_8
l_�'��v�X�'����{���-��z�v�D���}�XV�����R��"�k�����'�
$��0|+��LAs���.�.O��:i� ����a�
�|��������a���������]j�����|���N����IV��J�rG�&��M��(}I��2rH
�X)F="��"���[�J�)+r��I�BJ�AB��O�\�6X��]�p��xh�iDoC��Y��D���!b%�W�W;%WjG���;e
�^ r�=���:��'����$
�	�.
.��J�|xY�����w�v�<�Z�}� kEp��`�,����W�����5	c6&C�������L��f�f���XIS���$0t�����N��@jA}kWC����������8@��1����R;�6[����"v���\��iKc��8�U��I1�xU����&A%��.�v3��?��j�����!�"�ZCv�X�����
���Q�X)G���P)S����s]m�����n6L���r���H�7�}�$�j3� ��I,&�����f�����l,�'"9��>�W~+2����0����G�K�;�0�p������a��,s���[c�3vtN=���M��l���������@��i7���������5�It����N�ux��j9��=F���|G�:�=��]:���Lx�o��[���!l��(�eT�o~$�pe���wj��b�A6�����C���6��cfW���C������g��e�������%���^������h�y�&
�������s�����^�}T{��ph����]�sq��`��X�1x�l���LhL����N��,��M�K����g��1p�g��8�}��}���(����iEVg-���9��|��w�P�8�h)�C����#����W6�T��i��#&3�=5�(�R5����/FJF�\1��&t:�����������_�C�+�v5?{�b+A#��\�����]rG����dL��j�)���h��-����-%���{����O)�	�?��Jq]���N������w��?x�/_����b��uB��V���b��V�|��M��L�u��/g�yX�R�8���"li�I�9��
[��
[Xc��Z��h����I.>�@��.!oW��x�BG����rO~��Y�k�|���"�y���U��+J��Q���p%�~-%
2�c\"G8y97	�&���yB���[�����r�������j�����#k:'�(-�.�m��-_���{�
�iT�|�&����<�Ak`����+����(XP),-���qy�%��
���H��������������c��z}��/F&yK�h~&��[+8�r�ZL$��G�W�*^�2�!�X��S?t�`�0D�n�lQ_B��e�7�"_T����.g�6+���&�ERJ�Q��|JN��(aIN�!O�����:3���D)�U�C��$�c�c����JA':IYV,�X7up#���dhD��������A��d��Y>O�oV���T8��f����L�n~���>.�=���G�������)m
�:������h���A�	�b����FS$F�F@X��68���%�e���^q���45Ah^Z�K���m�������Q��	P�������d�lg��hg�2��h�<6G+V��%uIN�?����Gd+K�(I���C<5����|}��_m��p�'A"���\im�T6n�����t7�u��aY'�����vw8q��O�M�e(������Sp,���=���NB[VY��h�����5��TlZ�D����r7_^F`���W�������a������*}M�y����={Nm����B�O%��Z�v��U~��LR�v��X�I~X�/�Q�����%Z�i?����p#/���Q�
R	���E��r�<��2�������/�j�����kR"
� ���wn��-0p.����uvk#�[E
���-����'/�,*����"W;�O��=DF�
��g�EW"�8X�nVEZ��I�V���C	^���vZ�����+��������/ c��2�����_���!��$8�����8�����n�X5�{��aO<�%5��3h�|b��3U��^Aq����h����u��Z�!��t}�#ow��l��Z�w��0�)8Ml�<���i�!����m�f���t��a^�o��M3n���4E�Q�=\J���o�=bE�9�	 ���]�����5�0�)���m�=5��Bg����
�{��=_)J3f�������������A���J�������Z�*E�Q|4�8t��I��v�V1�����;& �
YGIa�u4������*SN�^n��/-���D(�����5�4!�������F�ij=����QZ�i�v5_�{�!t����u����nQ��q��G�En�?�x���;#}*�������x}H`#|fSR�up�O ��l��3�p�^��=?`��z�,"���(���yg�9M�x���3_�1}���\�L��n�2(2�2����*��>��8�1jJL�a�l�a��|�_��)���i
}��s<�(f[��>g��x���e���4	R���n{�a����"D-���:R�gv��*����`1�}��>�#�,w��/�xsIw��"��/���n2}Q6����/��;z�Cm������N5�X���Hv���L
��iA�j�_�����P<�_�oC�LA��,���A��`t
4!����v5��(�	`9G�:I�M�?!@U��v�S���w������}�	��9�4���G$-��"*&a����Jir����8�Fq+��s������9�c7�<*h��$lONq_f_y3?;S��h!e��~���b�7&[c�A�V��3���WkW�s����R�[=`�>G��\�da�3��B�t���r��e��vX�l����aW��m)r����1\e��R���������`��#'���q�q:�� �8��Qh�����-�����Y����N����6fw,���-��!X����CP;��-�_���_��.���x��l�5u��B���h~�2�t1aqN�y�n?BHM��/����"w���
 ��%������� ��k���b�S<%�E�'�tjm��X�
1:a�r8��.�k�%
��p<�;��@����'�&1m�O?�yNN��q��{r��il4>k����ns�~A���\�UcZ��bU�1��Kq���s����)���e��6����T��������]7g����TQ[�����E[�7��s�Fh����%��G��tdy�6�|s�6�H	N���~�'������8���6�}n��I>.���J�tv�B�s� ���\S��v�q8:��Mr<�pT��z���-�3k���)b��%��W��A���v����, U�qd��k\�@c�t�#�PxWS�~FX>�Gp��o���[9n�0��UK���:�*[�������*�=&��	����n�<��W���3R���<f����8�v�G��S��������_9�����?�p�io*�%�p���A�);�R�1��1�xd������J��G$�P'���)<4(tC��HP�������>7�iS�#��k��q�|m��'���k���G��S��#��)�5�8�\f+�����<B��\�L��0j}��-��E5�h~�"uQ�#��)Q���5g��b��I��������<�![H�C��"��C0���/b�F/~;���B5����E��
7�"��?'a���e����a�w�S�;ge:���m'��������eq����9����i�������v�-�/�n���b������B� �8}ed���>��)�<vW�;���,�D���1�@Q�yf�L���b��!�~����G�������&&M�$��<��7UP�YJD��3�(%	�4QF�5��i��yR�UB�e���Qs�%9�)�R�zA�b�y~��1US�qv��`Yq�&��[��]��=��j���z-S��c�a�d��<F2h�#�C �'��	)��"��>��}1��a��=w�yTJ����^��!�#�ht�`<��xZ��Q�E����V�������kOHTOuY�_G���G*�g]#���S)����h��a����L��"��<����{%����H��������{8M� �n+��r<��:�r�R����-�����/��@�L=����&��cj��1�;��JPA�P)��%|��
f�%3���*���$��H��~E����6<U�1g��]������l�MX�9������~H�l��3�QU�#w	��I��HqA�-�Mo�7f�f�Qx�4���*3�3`m�:NR��0N�.3Y�)�\Q�q���"���9�E�m>���D�2�k�E:����4�4D�R��6Z�dHa�0���A>u���~��S��-�����
@���b
q����&!�=y���:�����|��'wO���-X��7�����B����N�e5�gm:�.t>�.�E��b\h���B�2,'R�����.����4wGb
�Y����b��^u%�	(2a���s�t�g��is�g�L�~���<�F$5��$�,��'�p���q<.����;�7����Ynh�E"P�� 
�eah�g=
�3�3�t�Q�Yr;J�����(�>K�)l�@?��O[wS���0�tg`���ml���"�^�����U1��M&E�����Y]F����uex8�`�(��v����F��z��HQn�d�(R�%��x,���m�J-�bC�<A�EB{<K�8"�[��'$�����R�Q{��sX�&�#+/O9��o6L&:{zY4Rq�.�h���c�����IE`[Qr�o�������FdV�B/�*^�`a��
#���`��k$o&����8���*�6Y�B�e�_�i��h~c3y��
���C���.3�t���(���Y�`QC�x�X$��hZ����M&�<����v3u�|�QWH$)��$�3+Iq�v��[Z-��.6���*�� ` )(Q3�F�&0�����.(�vra	_n���i�>'�S�����ah���B����
�!!��H�,���.�E�(E��W#��L^y�y(N�t����B�{�z��jO���_\�}t���m�����=��f�q���bb������D�����������q���Kc�wqEY?~����uE��x�\�����L�����-�����=*�
���,�4`JN��,d���<�&s�q|����3�Z������
7�������^�C�t�@���������W9��1�I�$w��?������Ov5�����S].�����]���np�W�~�;X?�%����uM�'�	���:����~��J?���������m�)���������5�Z�_�rM����$�&9=��X�����8K�Ivr����X��M
#105Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Emre Hasegeli (#104)
Re: [PATCH] Improve geometric types

On 08/17/2018 06:40 PM, Emre Hasegeli wrote:

the buildfarm seems to be mostly happy so far, so I've taken a quick
look at the remaining two parts. The patches still apply, but I'm
getting plenty of failures in regression tests, due to 0.0 being
replaced by -0.0.

I think we are better off fixing them locally at the moment like your
patch does. We should consider to eliminate -0 globally for all
floating point based datatypes later. I simplified and incorporated
your change to line_interpt_line() into mine.

I am not sure about normalising -0s on point_construct(). We
currently allow points to be initialized with -0s. I think it is fair
for us to return -0 when -x and 0 are multiplied. That is the current
behavior and the behavior of the float datatypes. I adjusted the
results of the new regression tests accordingly.

Hmmm, I need to think about that a bit more.

BTW how did we end up with the regression differences? Presumably you've
tried that on your machine and it passed. So if we adjust the expected
file, won't it fail on some other machines?

Another thing I noticed is the last few lines from line_interpt_line are
actually unreachable, because there's now 'else return false' branch.

Which lines do you mean exactly? I don't see any being unreachable.

Apologies, I got confused - there are no unreachable lines.

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

#106Emre Hasegeli
emre@hasegeli.com
In reply to: Tomas Vondra (#105)
Re: [PATCH] Improve geometric types

BTW how did we end up with the regression differences? Presumably you've
tried that on your machine and it passed. So if we adjust the expected
file, won't it fail on some other machines?

I had another patch to check for -0 inside float{4,8}_{div,mul}(). I
dropped it on the last set of patches, so the tests were broken. I
get -0 as a result of -x * 0 both on Mac and Linux.

#107Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Emre Hasegeli (#106)
Re: [PATCH] Improve geometric types

On 08/17/2018 08:24 PM, Emre Hasegeli wrote:

BTW how did we end up with the regression differences? Presumably you've
tried that on your machine and it passed. So if we adjust the expected
file, won't it fail on some other machines?

I had another patch to check for -0 inside float{4,8}_{div,mul}(). I
dropped it on the last set of patches, so the tests were broken. I
get -0 as a result of -x * 0 both on Mac and Linux.

OK, that explains is. I won't have time to get this committed before CF
2018-09, but I'll pick it up in September.

regards

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

#108Tom Lane
tgl@sss.pgh.pa.us
In reply to: Emre Hasegeli (#106)
Re: [PATCH] Improve geometric types

Emre Hasegeli <emre@hasegeli.com> writes:

BTW how did we end up with the regression differences? Presumably you've
tried that on your machine and it passed. So if we adjust the expected
file, won't it fail on some other machines?

I had another patch to check for -0 inside float{4,8}_{div,mul}(). I
dropped it on the last set of patches, so the tests were broken. I
get -0 as a result of -x * 0 both on Mac and Linux.

I'll bet a good deal of money that you'll find that does not hold
true across the whole buildfarm.

regards, tom lane

#109Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Tom Lane (#108)
Re: [PATCH] Improve geometric types

On 08/17/2018 08:56 PM, Tom Lane wrote:

Emre Hasegeli <emre@hasegeli.com> writes:

BTW how did we end up with the regression differences? Presumably you've
tried that on your machine and it passed. So if we adjust the expected
file, won't it fail on some other machines?

I had another patch to check for -0 inside float{4,8}_{div,mul}(). I
dropped it on the last set of patches, so the tests were broken. I
get -0 as a result of -x * 0 both on Mac and Linux.

I'll bet a good deal of money that you'll find that does not hold
true across the whole buildfarm.

Hmm, yeah. Based on past experience, the powerpc machines are likely to
stumble on this.

FWIW my understanding is that these failures actually happen in new
tests, it's not an issue introduced by this patch series.

regards

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

#110Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tomas Vondra (#109)
Re: [PATCH] Improve geometric types

Tomas Vondra <tomas.vondra@2ndquadrant.com> writes:

Hmm, yeah. Based on past experience, the powerpc machines are likely to
stumble on this.

FWIW my understanding is that these failures actually happen in new
tests, it's not an issue introduced by this patch series.

Yeah, we've definitely hit such problems before. The geometric logic
seems particularly prone to it because it's doing more and subtler
float arithmetic than the rest of the system ... but it's not the sole
source of minus-zero issues.

regards, tom lane

#111Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Tom Lane (#110)
Re: [PATCH] Improve geometric types

On 08/17/2018 11:23 PM, Tom Lane wrote:

Tomas Vondra <tomas.vondra@2ndquadrant.com> writes:

Hmm, yeah. Based on past experience, the powerpc machines are likely to
stumble on this.

FWIW my understanding is that these failures actually happen in new
tests, it's not an issue introduced by this patch series.

Yeah, we've definitely hit such problems before. The geometric logic
seems particularly prone to it because it's doing more and subtler
float arithmetic than the rest of the system ... but it's not the sole
source of minus-zero issues.

It's not entirely clear to me what's the best way forward with this.

We can go through the patch and fix places with obvious -0 risks, but
then what? I don't have access to any powepc machines, so I can't check
if there are any other failures. So the only thing I could do is commit
and fix based on buildfarm failures ...

Emre, any better ideas?

regards

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

#112Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tomas Vondra (#111)
Re: [PATCH] Improve geometric types

Tomas Vondra <tomas.vondra@2ndquadrant.com> writes:

On 08/17/2018 11:23 PM, Tom Lane wrote:

Yeah, we've definitely hit such problems before. The geometric logic
seems particularly prone to it because it's doing more and subtler
float arithmetic than the rest of the system ... but it's not the sole
source of minus-zero issues.

We can go through the patch and fix places with obvious -0 risks, but
then what? I don't have access to any powepc machines, so I can't check
if there are any other failures. So the only thing I could do is commit
and fix based on buildfarm failures ...

That's the usual solution. I don't see anything particularly wrong
with it. If the buildfarm results suggest a whole mess of problems,
it might be appropriate to revert and rethink; but you shouldn't be
afraid to use the buildfarm as a testbed.

regards, tom lane

#113Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Tom Lane (#112)
Re: [PATCH] Improve geometric types

On 09/03/2018 04:08 AM, Tom Lane wrote:

Tomas Vondra <tomas.vondra@2ndquadrant.com> writes:

On 08/17/2018 11:23 PM, Tom Lane wrote:

Yeah, we've definitely hit such problems before. The geometric logic
seems particularly prone to it because it's doing more and subtler
float arithmetic than the rest of the system ... but it's not the sole
source of minus-zero issues.

We can go through the patch and fix places with obvious -0 risks, but
then what? I don't have access to any powepc machines, so I can't check
if there are any other failures. So the only thing I could do is commit
and fix based on buildfarm failures ...

That's the usual solution. I don't see anything particularly wrong
with it. If the buildfarm results suggest a whole mess of problems,
it might be appropriate to revert and rethink; but you shouldn't be
afraid to use the buildfarm as a testbed.

FWIW I plan to get this committed sometime this week, when I'm available
to fix the expected buildfarm breakage.

regards

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

#114Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Tomas Vondra (#113)
Re: [PATCH] Improve geometric types

On 09/23/2018 11:55 PM, Tomas Vondra wrote:

On 09/03/2018 04:08 AM, Tom Lane wrote:

Tomas Vondra <tomas.vondra@2ndquadrant.com> writes:

On 08/17/2018 11:23 PM, Tom Lane wrote:

Yeah, we've definitely hit such problems before. The geometric logic
seems particularly prone to it because it's doing more and subtler
float arithmetic than the rest of the system ... but it's not the sole
source of minus-zero issues.

We can go through the patch and fix places with obvious -0 risks, but
then what? I don't have access to any powepc machines, so I can't check
if there are any other failures. So the only thing I could do is commit
and fix based on buildfarm failures ...

That's the usual solution. I don't see anything particularly wrong
with it. If the buildfarm results suggest a whole mess of problems,
it might be appropriate to revert and rethink; but you shouldn't be
afraid to use the buildfarm as a testbed.

FWIW I plan to get this committed sometime this week, when I'm available
to fix the expected buildfarm breakage.

Pushed. Now let's wait for the buildfarm to complain ...

regards

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

#115Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tomas Vondra (#114)
Re: [PATCH] Improve geometric types

Tomas Vondra <tomas.vondra@2ndquadrant.com> writes:

Pushed. Now let's wait for the buildfarm to complain ...

gaur's not happy, but rather surprisingly, it looks like we're
mostly OK elsewhere. Do you need me to trace down exactly what's
going wrong on gaur?

regards, tom lane

#116Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Tom Lane (#115)
1 attachment(s)
Re: [PATCH] Improve geometric types

On 09/26/2018 06:45 PM, Tom Lane wrote:

Tomas Vondra <tomas.vondra@2ndquadrant.com> writes:

Pushed. Now let's wait for the buildfarm to complain ...

gaur's not happy, but rather surprisingly, it looks like we're
mostly OK elsewhere. Do you need me to trace down exactly what's
going wrong on gaur?

Hmmm, interesting. It seems both failures happen in the chunk that
multiplies paths with points, i.e. essentially point_mul_point. So it
seems most platforms end up with

(0,0) * (-3,4) = (-0, 0)

while gaur apparently thinks it's (0,0). And indeed, that's what the
attached trivial program does - I'd bet if you run it on gaur, it'll
print 0.000000, not -0.000000.

Or you could just try doing

select '(0,0)'::point * '(-3,4)'::point;

If this is what's going on, I'd say the best solution is to make it
produce (0,0) everywhere, so that we don't expect -0.0 anywhere.

We could do that either by adding the == 0.0 check to yet another place,
or to point_construct() directly. Adding it to point_construct() means
we'll pay the price always, but I guess there are few paths where we
know we don't need it. And if we add it to many places it's likely about
as expensive as adding it to point_construct.

regards

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

Attachments:

test.ctext/x-csrc; name=test.cDownload
#117Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tomas Vondra (#116)
Re: [PATCH] Improve geometric types

Tomas Vondra <tomas.vondra@2ndquadrant.com> writes:

Hmmm, interesting. It seems both failures happen in the chunk that
multiplies paths with points, i.e. essentially point_mul_point. So it
seems most platforms end up with

(0,0) * (-3,4) = (-0, 0)

while gaur apparently thinks it's (0,0). And indeed, that's what the
attached trivial program does - I'd bet if you run it on gaur, it'll
print 0.000000, not -0.000000.

Nope, no cigar:

$ gcc -Wall -O2 test.c
$ ./a.out
-0.000000

(I tried a couple other -O levels to see if that affected anything,
but it didn't.)

I'll try to isolate the problem more closely, but it will take awhile.
That machine is slow :-(

regards, tom lane

#118Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Tom Lane (#117)
Re: [PATCH] Improve geometric types

On 09/26/2018 10:58 PM, Tom Lane wrote:

Tomas Vondra <tomas.vondra@2ndquadrant.com> writes:

Hmmm, interesting. It seems both failures happen in the chunk that
multiplies paths with points, i.e. essentially point_mul_point. So it
seems most platforms end up with

(0,0) * (-3,4) = (-0, 0)

while gaur apparently thinks it's (0,0). And indeed, that's what the
attached trivial program does - I'd bet if you run it on gaur, it'll
print 0.000000, not -0.000000.

Nope, no cigar:

$ gcc -Wall -O2 test.c
$ ./a.out
-0.000000

(I tried a couple other -O levels to see if that affected anything,
but it didn't.)

Interesting ...

I'll try to isolate the problem more closely, but it will take awhile.
That machine is slow :-(

OK, thanks.

regards

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

#119Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tomas Vondra (#116)
Re: [PATCH] Improve geometric types

Tomas Vondra <tomas.vondra@2ndquadrant.com> writes:

On 09/26/2018 06:45 PM, Tom Lane wrote:

gaur's not happy, but rather surprisingly, it looks like we're
mostly OK elsewhere. Do you need me to trace down exactly what's
going wrong on gaur?

Or you could just try doing
select '(0,0)'::point * '(-3,4)'::point;
If this is what's going on, I'd say the best solution is to make it
produce (0,0) everywhere, so that we don't expect -0.0 anywhere.

Actually, it seems simpler than that: gaur produces plus zero already
from the multiplication:

regression=# select '-3'::float8 * '0'::float8;
?column?
----------
0
(1 row)

whereas I get -0 elsewhere. I'm surprised that this doesn't create
more widely-visible regression failures, but there you have it.

We could do that either by adding the == 0.0 check to yet another place,
or to point_construct() directly. Adding it to point_construct() means
we'll pay the price always, but I guess there are few paths where we
know we don't need it. And if we add it to many places it's likely about
as expensive as adding it to point_construct.

If gaur is the only machine showing this failure, which seems more
likely by the hour, I'm not sure that we should give up performance
across-the-board to make it happy. Perhaps a variant expected-file
is a better answer; or we could remove these specific test cases.

Anyway, I'd counsel doing nothing for a day or so, till the buildfarm
breakage from the strerror/snprintf changes clears up. Then we'll
have a better idea of whether any other machines are affected.

regards, tom lane

#120Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Tom Lane (#119)
Re: [PATCH] Improve geometric types

On 09/27/2018 12:48 AM, Tom Lane wrote:

Tomas Vondra <tomas.vondra@2ndquadrant.com> writes:

On 09/26/2018 06:45 PM, Tom Lane wrote:

gaur's not happy, but rather surprisingly, it looks like we're
mostly OK elsewhere. Do you need me to trace down exactly what's
going wrong on gaur?

Or you could just try doing
select '(0,0)'::point * '(-3,4)'::point;
If this is what's going on, I'd say the best solution is to make it
produce (0,0) everywhere, so that we don't expect -0.0 anywhere.

Actually, it seems simpler than that: gaur produces plus zero already
from the multiplication:

regression=# select '-3'::float8 * '0'::float8;
?column?
----------
0
(1 row)

whereas I get -0 elsewhere. I'm surprised that this doesn't create
more widely-visible regression failures, but there you have it.

Hmmm, interesting. But I still don't quite understand why the test
program still produced -0.000000 and not 0.000000. That seems like a
direct contradiction to what we see in regression tests, doesn't it?

We could do that either by adding the == 0.0 check to yet another place,
or to point_construct() directly. Adding it to point_construct() means
we'll pay the price always, but I guess there are few paths where we
know we don't need it. And if we add it to many places it's likely about
as expensive as adding it to point_construct.

If gaur is the only machine showing this failure, which seems more
likely by the hour, I'm not sure that we should give up performance
across-the-board to make it happy. Perhaps a variant expected-file
is a better answer; or we could remove these specific test cases.

Anyway, I'd counsel doing nothing for a day or so, till the buildfarm
breakage from the strerror/snprintf changes clears up. Then we'll
have a better idea of whether any other machines are affected.

Yep, gaur seems to be the only animal affected by this, so no need to
rush anyway.

regards

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

#121Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tomas Vondra (#120)
Re: [PATCH] Improve geometric types

Tomas Vondra <tomas.vondra@2ndquadrant.com> writes:

On 09/27/2018 12:48 AM, Tom Lane wrote:

Actually, it seems simpler than that: gaur produces plus zero already
from the multiplication:
regression=# select '-3'::float8 * '0'::float8;
?column?
----------
0
(1 row)

Hmmm, interesting. But I still don't quite understand why the test
program still produced -0.000000 and not 0.000000. That seems like a
direct contradiction to what we see in regression tests, doesn't it?

OK, so after poking at it for another hour and getting more and more
confused, I realized that gdb was lying to me by printing genuine
minus zero values as just "0". Throw out everything I thought I knew
and start over ...

... and awhile later, this is the answer: on this machine,
printf with "%f" will show the sign of minus zero. But printf
with "%g" will not. Guess which format float8out uses.
(I'll bet that gdb does too, so that its lie wasn't its fault.)

AFAICT at the moment, gaur is doing the underlying IEEE float math
the same as everybody else, which is not very surprising because
HP bought into IEEE math pretty early. Hex-dumping shows conclusively
that point_mul_point *does* emit (-0,0) in the case in question.
But we've got a platform-specific issue with whether the minus zero
gets printed as such. I wonder whether similar effects explain some
of the other platform-specific oddities we've seen with minus zero.

Anyway, at this point I'd say let's just leave gaur broken so far as the
geometric tests are concerned, pending results from the concurrent thread
about possibly rewriting snprintf.c's float handling to not depend on the
platform's sprintf. If that doesn't happen, we can revisit some sort
of narrower fix for this. The narrow fix ought to be in snprintf.c
anyway, not anywhere near the geometric code.

I notice BTW that it's sort of accidental that snprintf.c behaves properly
for minus zero on most machines. The test "value < 0" isn't true, so
it doesn't think there's a sign. When sprintf outputs a "-" anyway,
that's effectively treated as a digit. We'd do the wrong thing with a
format like "%+f", and maybe in other cases too.

regards, tom lane

#122Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Tomas Vondra (#120)
Re: [PATCH] Improve geometric types

If you look at the differing results carefully, there's this one:

*** 3249,3255 ****
!  [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(0,-0),(-15,-36),(40,-73),(67,-42)]
--- 3249,3255 ----
!  [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(0,0),(-15,-36),(40,-73),(67,-42)]

(Third column is first multiplied by second).

I wonder why the expected file has a -0 only in the second position and
not both first and second. These are both positive zeroes being
multiplied by a negative number. Why is 0 * -12 = -0 yet 0 * -5 = 0?
What is going on? Is the sign suppressed for negative zeros only in the
first coordinate? I suppose this is just a side effect of how
float8_mi, _pl, _mul work (in point_mul_point).

Anyway maybe your test case should use more of the float8 op
combinations in order to show the difference.

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

#123Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Alvaro Herrera (#122)
Re: [PATCH] Improve geometric types

On 09/27/2018 07:21 PM, Alvaro Herrera wrote:

If you look at the differing results carefully, there's this one:

*** 3249,3255 ****
!  [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(0,-0),(-15,-36),(40,-73),(67,-42)]
--- 3249,3255 ----
!  [(0,0),(3,0),(4,5),(1,6)] | (-5,-12)          | [(0,0),(-15,-36),(40,-73),(67,-42)]

(Third column is first multiplied by second).

I wonder why the expected file has a -0 only in the second position and
not both first and second. These are both positive zeroes being
multiplied by a negative number. Why is 0 * -12 = -0 yet 0 * -5 = 0?
What is going on? Is the sign suppressed for negative zeros only in the
first coordinate? I suppose this is just a side effect of how
float8_mi, _pl, _mul work (in point_mul_point).

Anyway maybe your test case should use more of the float8 op
combinations in order to show the difference.

I may be missing what you're saying, but point_mul_point is not just a
simple multiplication of coordinates, i.e.

(x1,y1) * (x2,y2) != (x1*x2, y1*y2)

It essentially does this:

((x1 * x2 - y1 * y2), (x1 * y2 + x2 * y1))

so I wouldn't be surprised if this was a difference between _pl and _mi.

regards

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

#124Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Tom Lane (#121)
Re: [PATCH] Improve geometric types

On 09/27/2018 07:05 PM, Tom Lane wrote:

Tomas Vondra <tomas.vondra@2ndquadrant.com> writes:

On 09/27/2018 12:48 AM, Tom Lane wrote:

Actually, it seems simpler than that: gaur produces plus zero already
from the multiplication:
regression=# select '-3'::float8 * '0'::float8;
?column?
----------
0
(1 row)

Hmmm, interesting. But I still don't quite understand why the test
program still produced -0.000000 and not 0.000000. That seems like a
direct contradiction to what we see in regression tests, doesn't it?

OK, so after poking at it for another hour and getting more and more
confused, I realized that gdb was lying to me by printing genuine
minus zero values as just "0". Throw out everything I thought I knew
and start over ...

Heh. A debugger lying to you just a wee bit is fun ...

... and awhile later, this is the answer: on this machine,
printf with "%f" will show the sign of minus zero. But printf
with "%g" will not. Guess which format float8out uses.
(I'll bet that gdb does too, so that its lie wasn't its fault.)

AFAICT at the moment, gaur is doing the underlying IEEE float math
the same as everybody else, which is not very surprising because
HP bought into IEEE math pretty early. Hex-dumping shows conclusively
that point_mul_point *does* emit (-0,0) in the case in question.
But we've got a platform-specific issue with whether the minus zero
gets printed as such. I wonder whether similar effects explain some
of the other platform-specific oddities we've seen with minus zero.

Anyway, at this point I'd say let's just leave gaur broken so far as the
geometric tests are concerned, pending results from the concurrent thread
about possibly rewriting snprintf.c's float handling to not depend on the
platform's sprintf. If that doesn't happen, we can revisit some sort
of narrower fix for this. The narrow fix ought to be in snprintf.c
anyway, not anywhere near the geometric code.

I notice BTW that it's sort of accidental that snprintf.c behaves properly
for minus zero on most machines. The test "value < 0" isn't true, so
it doesn't think there's a sign. When sprintf outputs a "-" anyway,
that's effectively treated as a digit. We'd do the wrong thing with a
format like "%+f", and maybe in other cases too.

OK, makes sense. Thanks for the investigation!

regards

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

#125Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Tomas Vondra (#123)
Re: [PATCH] Improve geometric types

On 2018-Sep-27, Tomas Vondra wrote:

I may be missing what you're saying, but point_mul_point is not just a
simple multiplication of coordinates, i.e.

(x1,y1) * (x2,y2) != (x1*x2, y1*y2)

It essentially does this:

((x1 * x2 - y1 * y2), (x1 * y2 + x2 * y1))

so I wouldn't be surprised if this was a difference between _pl and _mi.

Yeah, I had misinterpreted the operation before reading the code, then
when reading it I realized the formula is what you were saying, so I
updated the final part of my reply but failed to realize I had written
my misunderstanding in the first portion.

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